|
ICU 73.2
73.2
|
00001 // © 2016 and later: Unicode, Inc. and others. 00002 // License & terms of use: http://www.unicode.org/copyright.html 00003 /* 00004 ******************************************************************************* 00005 * Copyright (C) 2010-2012, International Business Machines 00006 * Corporation and others. All Rights Reserved. 00007 ******************************************************************************* 00008 * file name: bytestrie.h 00009 * encoding: UTF-8 00010 * tab size: 8 (not used) 00011 * indentation:4 00012 * 00013 * created on: 2010sep25 00014 * created by: Markus W. Scherer 00015 */ 00016 00017 #ifndef __BYTESTRIE_H__ 00018 #define __BYTESTRIE_H__ 00019 00025 #include "unicode/utypes.h" 00026 00027 #if U_SHOW_CPLUSPLUS_API 00028 00029 #include "unicode/stringpiece.h" 00030 #include "unicode/uobject.h" 00031 #include "unicode/ustringtrie.h" 00032 00033 class BytesTrieTest; 00034 00035 U_NAMESPACE_BEGIN 00036 00037 class ByteSink; 00038 class BytesTrieBuilder; 00039 class CharString; 00040 class UVector32; 00041 00055 class U_COMMON_API BytesTrie : public UMemory { 00056 public: 00071 BytesTrie(const void *trieBytes) 00072 : ownedArray_(nullptr), bytes_(static_cast<const uint8_t *>(trieBytes)), 00073 pos_(bytes_), remainingMatchLength_(-1) {} 00074 00079 ~BytesTrie(); 00080 00087 BytesTrie(const BytesTrie &other) 00088 : ownedArray_(nullptr), bytes_(other.bytes_), 00089 pos_(other.pos_), remainingMatchLength_(other.remainingMatchLength_) {} 00090 00096 BytesTrie &reset() { 00097 pos_=bytes_; 00098 remainingMatchLength_=-1; 00099 return *this; 00100 } 00101 00110 uint64_t getState64() const { 00111 return (static_cast<uint64_t>(remainingMatchLength_ + 2) << kState64RemainingShift) | 00112 (uint64_t)(pos_ - bytes_); 00113 } 00114 00129 BytesTrie &resetToState64(uint64_t state) { 00130 remainingMatchLength_ = static_cast<int32_t>(state >> kState64RemainingShift) - 2; 00131 pos_ = bytes_ + (state & kState64PosMask); 00132 return *this; 00133 } 00134 00140 class State : public UMemory { 00141 public: 00146 State() { bytes=nullptr; } 00147 private: 00148 friend class BytesTrie; 00149 00150 const uint8_t *bytes; 00151 const uint8_t *pos; 00152 int32_t remainingMatchLength; 00153 }; 00154 00162 const BytesTrie &saveState(State &state) const { 00163 state.bytes=bytes_; 00164 state.pos=pos_; 00165 state.remainingMatchLength=remainingMatchLength_; 00166 return *this; 00167 } 00168 00179 BytesTrie &resetToState(const State &state) { 00180 if(bytes_==state.bytes && bytes_!=nullptr) { 00181 pos_=state.pos; 00182 remainingMatchLength_=state.remainingMatchLength; 00183 } 00184 return *this; 00185 } 00186 00193 UStringTrieResult current() const; 00194 00203 inline UStringTrieResult first(int32_t inByte) { 00204 remainingMatchLength_=-1; 00205 if(inByte<0) { 00206 inByte+=0x100; 00207 } 00208 return nextImpl(bytes_, inByte); 00209 } 00210 00218 UStringTrieResult next(int32_t inByte); 00219 00235 UStringTrieResult next(const char *s, int32_t length); 00236 00246 inline int32_t getValue() const { 00247 const uint8_t *pos=pos_; 00248 int32_t leadByte=*pos++; 00249 // U_ASSERT(leadByte>=kMinValueLead); 00250 return readValue(pos, leadByte>>1); 00251 } 00252 00262 inline UBool hasUniqueValue(int32_t &uniqueValue) const { 00263 const uint8_t *pos=pos_; 00264 // Skip the rest of a pending linear-match node. 00265 return pos!=nullptr && findUniqueValue(pos+remainingMatchLength_+1, false, uniqueValue); 00266 } 00267 00276 int32_t getNextBytes(ByteSink &out) const; 00277 00282 class U_COMMON_API Iterator : public UMemory { 00283 public: 00295 Iterator(const void *trieBytes, int32_t maxStringLength, UErrorCode &errorCode); 00296 00308 Iterator(const BytesTrie &trie, int32_t maxStringLength, UErrorCode &errorCode); 00309 00314 ~Iterator(); 00315 00321 Iterator &reset(); 00322 00327 UBool hasNext() const; 00328 00343 UBool next(UErrorCode &errorCode); 00344 00349 StringPiece getString() const; 00354 int32_t getValue() const { return value_; } 00355 00356 private: 00357 UBool truncateAndStop(); 00358 00359 const uint8_t *branchNext(const uint8_t *pos, int32_t length, UErrorCode &errorCode); 00360 00361 const uint8_t *bytes_; 00362 const uint8_t *pos_; 00363 const uint8_t *initialPos_; 00364 int32_t remainingMatchLength_; 00365 int32_t initialRemainingMatchLength_; 00366 00367 CharString *str_; 00368 int32_t maxLength_; 00369 int32_t value_; 00370 00371 // The stack stores pairs of integers for backtracking to another 00372 // outbound edge of a branch node. 00373 // The first integer is an offset from bytes_. 00374 // The second integer has the str_->length() from before the node in bits 15..0, 00375 // and the remaining branch length in bits 24..16. (Bits 31..25 are unused.) 00376 // (We could store the remaining branch length minus 1 in bits 23..16 and not use bits 31..24, 00377 // but the code looks more confusing that way.) 00378 UVector32 *stack_; 00379 }; 00380 00381 private: 00382 friend class BytesTrieBuilder; 00383 friend class ::BytesTrieTest; 00384 00391 BytesTrie(void *adoptBytes, const void *trieBytes) 00392 : ownedArray_(static_cast<uint8_t *>(adoptBytes)), 00393 bytes_(static_cast<const uint8_t *>(trieBytes)), 00394 pos_(bytes_), remainingMatchLength_(-1) {} 00395 00396 // No assignment operator. 00397 BytesTrie &operator=(const BytesTrie &other) = delete; 00398 00399 inline void stop() { 00400 pos_=nullptr; 00401 } 00402 00403 // Reads a compact 32-bit integer. 00404 // pos is already after the leadByte, and the lead byte is already shifted right by 1. 00405 static int32_t readValue(const uint8_t *pos, int32_t leadByte); 00406 static inline const uint8_t *skipValue(const uint8_t *pos, int32_t leadByte) { 00407 // U_ASSERT(leadByte>=kMinValueLead); 00408 if(leadByte>=(kMinTwoByteValueLead<<1)) { 00409 if(leadByte<(kMinThreeByteValueLead<<1)) { 00410 ++pos; 00411 } else if(leadByte<(kFourByteValueLead<<1)) { 00412 pos+=2; 00413 } else { 00414 pos+=3+((leadByte>>1)&1); 00415 } 00416 } 00417 return pos; 00418 } 00419 static inline const uint8_t *skipValue(const uint8_t *pos) { 00420 int32_t leadByte=*pos++; 00421 return skipValue(pos, leadByte); 00422 } 00423 00424 // Reads a jump delta and jumps. 00425 static const uint8_t *jumpByDelta(const uint8_t *pos); 00426 00427 static inline const uint8_t *skipDelta(const uint8_t *pos) { 00428 int32_t delta=*pos++; 00429 if(delta>=kMinTwoByteDeltaLead) { 00430 if(delta<kMinThreeByteDeltaLead) { 00431 ++pos; 00432 } else if(delta<kFourByteDeltaLead) { 00433 pos+=2; 00434 } else { 00435 pos+=3+(delta&1); 00436 } 00437 } 00438 return pos; 00439 } 00440 00441 static inline UStringTrieResult valueResult(int32_t node) { 00442 return (UStringTrieResult)(USTRINGTRIE_INTERMEDIATE_VALUE-(node&kValueIsFinal)); 00443 } 00444 00445 // Handles a branch node for both next(byte) and next(string). 00446 UStringTrieResult branchNext(const uint8_t *pos, int32_t length, int32_t inByte); 00447 00448 // Requires remainingLength_<0. 00449 UStringTrieResult nextImpl(const uint8_t *pos, int32_t inByte); 00450 00451 // Helper functions for hasUniqueValue(). 00452 // Recursively finds a unique value (or whether there is not a unique one) 00453 // from a branch. 00454 static const uint8_t *findUniqueValueFromBranch(const uint8_t *pos, int32_t length, 00455 UBool haveUniqueValue, int32_t &uniqueValue); 00456 // Recursively finds a unique value (or whether there is not a unique one) 00457 // starting from a position on a node lead byte. 00458 static UBool findUniqueValue(const uint8_t *pos, UBool haveUniqueValue, int32_t &uniqueValue); 00459 00460 // Helper functions for getNextBytes(). 00461 // getNextBytes() when pos is on a branch node. 00462 static void getNextBranchBytes(const uint8_t *pos, int32_t length, ByteSink &out); 00463 static void append(ByteSink &out, int c); 00464 00465 // BytesTrie data structure 00466 // 00467 // The trie consists of a series of byte-serialized nodes for incremental 00468 // string/byte sequence matching. The root node is at the beginning of the trie data. 00469 // 00470 // Types of nodes are distinguished by their node lead byte ranges. 00471 // After each node, except a final-value node, another node follows to 00472 // encode match values or continue matching further bytes. 00473 // 00474 // Node types: 00475 // - Value node: Stores a 32-bit integer in a compact, variable-length format. 00476 // The value is for the string/byte sequence so far. 00477 // One node bit indicates whether the value is final or whether 00478 // matching continues with the next node. 00479 // - Linear-match node: Matches a number of bytes. 00480 // - Branch node: Branches to other nodes according to the current input byte. 00481 // The node byte is the length of the branch (number of bytes to select from) 00482 // minus 1. It is followed by a sub-node: 00483 // - If the length is at most kMaxBranchLinearSubNodeLength, then 00484 // there are length-1 (key, value) pairs and then one more comparison byte. 00485 // If one of the key bytes matches, then the value is either a final value for 00486 // the string/byte sequence so far, or a "jump" delta to the next node. 00487 // If the last byte matches, then matching continues with the next node. 00488 // (Values have the same encoding as value nodes.) 00489 // - If the length is greater than kMaxBranchLinearSubNodeLength, then 00490 // there is one byte and one "jump" delta. 00491 // If the input byte is less than the sub-node byte, then "jump" by delta to 00492 // the next sub-node which will have a length of length/2. 00493 // (The delta has its own compact encoding.) 00494 // Otherwise, skip the "jump" delta to the next sub-node 00495 // which will have a length of length-length/2. 00496 00497 // Node lead byte values. 00498 00499 // 00..0f: Branch node. If node!=0 then the length is node+1, otherwise 00500 // the length is one more than the next byte. 00501 00502 // For a branch sub-node with at most this many entries, we drop down 00503 // to a linear search. 00504 static const int32_t kMaxBranchLinearSubNodeLength=5; 00505 00506 // 10..1f: Linear-match node, match 1..16 bytes and continue reading the next node. 00507 static const int32_t kMinLinearMatch=0x10; 00508 static const int32_t kMaxLinearMatchLength=0x10; 00509 00510 // 20..ff: Variable-length value node. 00511 // If odd, the value is final. (Otherwise, intermediate value or jump delta.) 00512 // Then shift-right by 1 bit. 00513 // The remaining lead byte value indicates the number of following bytes (0..4) 00514 // and contains the value's top bits. 00515 static const int32_t kMinValueLead=kMinLinearMatch+kMaxLinearMatchLength; // 0x20 00516 // It is a final value if bit 0 is set. 00517 static const int32_t kValueIsFinal=1; 00518 00519 // Compact value: After testing bit 0, shift right by 1 and then use the following thresholds. 00520 static const int32_t kMinOneByteValueLead=kMinValueLead/2; // 0x10 00521 static const int32_t kMaxOneByteValue=0x40; // At least 6 bits in the first byte. 00522 00523 static const int32_t kMinTwoByteValueLead=kMinOneByteValueLead+kMaxOneByteValue+1; // 0x51 00524 static const int32_t kMaxTwoByteValue=0x1aff; 00525 00526 static const int32_t kMinThreeByteValueLead=kMinTwoByteValueLead+(kMaxTwoByteValue>>8)+1; // 0x6c 00527 static const int32_t kFourByteValueLead=0x7e; 00528 00529 // A little more than Unicode code points. (0x11ffff) 00530 static const int32_t kMaxThreeByteValue=((kFourByteValueLead-kMinThreeByteValueLead)<<16)-1; 00531 00532 static const int32_t kFiveByteValueLead=0x7f; 00533 00534 // Compact delta integers. 00535 static const int32_t kMaxOneByteDelta=0xbf; 00536 static const int32_t kMinTwoByteDeltaLead=kMaxOneByteDelta+1; // 0xc0 00537 static const int32_t kMinThreeByteDeltaLead=0xf0; 00538 static const int32_t kFourByteDeltaLead=0xfe; 00539 static const int32_t kFiveByteDeltaLead=0xff; 00540 00541 static const int32_t kMaxTwoByteDelta=((kMinThreeByteDeltaLead-kMinTwoByteDeltaLead)<<8)-1; // 0x2fff 00542 static const int32_t kMaxThreeByteDelta=((kFourByteDeltaLead-kMinThreeByteDeltaLead)<<16)-1; // 0xdffff 00543 00544 // For getState64(): 00545 // The remainingMatchLength_ is -1..14=(kMaxLinearMatchLength=0x10)-2 00546 // so we need at least 5 bits for that. 00547 // We add 2 to store it as a positive value 1..16=kMaxLinearMatchLength. 00548 static constexpr int32_t kState64RemainingShift = 59; 00549 static constexpr uint64_t kState64PosMask = (UINT64_C(1) << kState64RemainingShift) - 1; 00550 00551 uint8_t *ownedArray_; 00552 00553 // Fixed value referencing the BytesTrie bytes. 00554 const uint8_t *bytes_; 00555 00556 // Iterator variables. 00557 00558 // Pointer to next trie byte to read. nullptr if no more matches. 00559 const uint8_t *pos_; 00560 // Remaining length of a linear-match node, minus 1. Negative if not in such a node. 00561 int32_t remainingMatchLength_; 00562 }; 00563 00564 U_NAMESPACE_END 00565 00566 #endif /* U_SHOW_CPLUSPLUS_API */ 00567 00568 #endif // __BYTESTRIE_H__
1.7.6.1