ICU 73.2  73.2
ucharstrie.h
Go to the documentation of this file.
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:  ucharstrie.h
00009 *   encoding:   UTF-8
00010 *   tab size:   8 (not used)
00011 *   indentation:4
00012 *
00013 *   created on: 2010nov14
00014 *   created by: Markus W. Scherer
00015 */
00016 
00017 #ifndef __UCHARSTRIE_H__
00018 #define __UCHARSTRIE_H__
00019 
00026 #include "unicode/utypes.h"
00027 
00028 #if U_SHOW_CPLUSPLUS_API
00029 
00030 #include "unicode/unistr.h"
00031 #include "unicode/uobject.h"
00032 #include "unicode/ustringtrie.h"
00033 
00034 U_NAMESPACE_BEGIN
00035 
00036 class Appendable;
00037 class UCharsTrieBuilder;
00038 class UVector32;
00039 
00053 class U_COMMON_API UCharsTrie : public UMemory {
00054 public:
00069     UCharsTrie(ConstChar16Ptr trieUChars)
00070             : ownedArray_(nullptr), uchars_(trieUChars),
00071               pos_(uchars_), remainingMatchLength_(-1) {}
00072 
00077     ~UCharsTrie();
00078 
00085     UCharsTrie(const UCharsTrie &other)
00086             : ownedArray_(nullptr), uchars_(other.uchars_),
00087               pos_(other.pos_), remainingMatchLength_(other.remainingMatchLength_) {}
00088 
00094     UCharsTrie &reset() {
00095         pos_=uchars_;
00096         remainingMatchLength_=-1;
00097         return *this;
00098     }
00099 
00108     uint64_t getState64() const {
00109         return (static_cast<uint64_t>(remainingMatchLength_ + 2) << kState64RemainingShift) |
00110             (uint64_t)(pos_ - uchars_);
00111     }
00112 
00127     UCharsTrie &resetToState64(uint64_t state) {
00128         remainingMatchLength_ = static_cast<int32_t>(state >> kState64RemainingShift) - 2;
00129         pos_ = uchars_ + (state & kState64PosMask);
00130         return *this;
00131     }
00132 
00138     class State : public UMemory {
00139     public:
00144         State() { uchars=nullptr; }
00145     private:
00146         friend class UCharsTrie;
00147 
00148         const char16_t *uchars;
00149         const char16_t *pos;
00150         int32_t remainingMatchLength;
00151     };
00152 
00160     const UCharsTrie &saveState(State &state) const {
00161         state.uchars=uchars_;
00162         state.pos=pos_;
00163         state.remainingMatchLength=remainingMatchLength_;
00164         return *this;
00165     }
00166 
00177     UCharsTrie &resetToState(const State &state) {
00178         if(uchars_==state.uchars && uchars_!=nullptr) {
00179             pos_=state.pos;
00180             remainingMatchLength_=state.remainingMatchLength;
00181         }
00182         return *this;
00183     }
00184 
00191     UStringTrieResult current() const;
00192 
00200     inline UStringTrieResult first(int32_t uchar) {
00201         remainingMatchLength_=-1;
00202         return nextImpl(uchars_, uchar);
00203     }
00204 
00213     UStringTrieResult firstForCodePoint(UChar32 cp);
00214 
00221     UStringTrieResult next(int32_t uchar);
00222 
00230     UStringTrieResult nextForCodePoint(UChar32 cp);
00231 
00247     UStringTrieResult next(ConstChar16Ptr s, int32_t length);
00248 
00258     inline int32_t getValue() const {
00259         const char16_t *pos=pos_;
00260         int32_t leadUnit=*pos++;
00261         // U_ASSERT(leadUnit>=kMinValueLead);
00262         return leadUnit&kValueIsFinal ?
00263             readValue(pos, leadUnit&0x7fff) : readNodeValue(pos, leadUnit);
00264     }
00265 
00275     inline UBool hasUniqueValue(int32_t &uniqueValue) const {
00276         const char16_t *pos=pos_;
00277         // Skip the rest of a pending linear-match node.
00278         return pos!=nullptr && findUniqueValue(pos+remainingMatchLength_+1, false, uniqueValue);
00279     }
00280 
00288     int32_t getNextUChars(Appendable &out) const;
00289 
00294     class U_COMMON_API Iterator : public UMemory {
00295     public:
00307         Iterator(ConstChar16Ptr trieUChars, int32_t maxStringLength, UErrorCode &errorCode);
00308 
00320         Iterator(const UCharsTrie &trie, int32_t maxStringLength, UErrorCode &errorCode);
00321 
00326         ~Iterator();
00327 
00333         Iterator &reset();
00334 
00339         UBool hasNext() const;
00340 
00355         UBool next(UErrorCode &errorCode);
00356 
00361         const UnicodeString &getString() const { return str_; }
00366         int32_t getValue() const { return value_; }
00367 
00368     private:
00369         UBool truncateAndStop() {
00370             pos_=nullptr;
00371             value_=-1;  // no real value for str
00372             return true;
00373         }
00374 
00375         const char16_t *branchNext(const char16_t *pos, int32_t length, UErrorCode &errorCode);
00376 
00377         const char16_t *uchars_;
00378         const char16_t *pos_;
00379         const char16_t *initialPos_;
00380         int32_t remainingMatchLength_;
00381         int32_t initialRemainingMatchLength_;
00382         UBool skipValue_;  // Skip intermediate value which was already delivered.
00383 
00384         UnicodeString str_;
00385         int32_t maxLength_;
00386         int32_t value_;
00387 
00388         // The stack stores pairs of integers for backtracking to another
00389         // outbound edge of a branch node.
00390         // The first integer is an offset from uchars_.
00391         // The second integer has the str_.length() from before the node in bits 15..0,
00392         // and the remaining branch length in bits 31..16.
00393         // (We could store the remaining branch length minus 1 in bits 30..16 and not use the sign bit,
00394         // but the code looks more confusing that way.)
00395         UVector32 *stack_;
00396     };
00397 
00398 private:
00399     friend class UCharsTrieBuilder;
00400 
00407     UCharsTrie(char16_t *adoptUChars, const char16_t *trieUChars)
00408             : ownedArray_(adoptUChars), uchars_(trieUChars),
00409               pos_(uchars_), remainingMatchLength_(-1) {}
00410 
00411     // No assignment operator.
00412     UCharsTrie &operator=(const UCharsTrie &other) = delete;
00413 
00414     inline void stop() {
00415         pos_=nullptr;
00416     }
00417 
00418     // Reads a compact 32-bit integer.
00419     // pos is already after the leadUnit, and the lead unit has bit 15 reset.
00420     static inline int32_t readValue(const char16_t *pos, int32_t leadUnit) {
00421         int32_t value;
00422         if(leadUnit<kMinTwoUnitValueLead) {
00423             value=leadUnit;
00424         } else if(leadUnit<kThreeUnitValueLead) {
00425             value=((leadUnit-kMinTwoUnitValueLead)<<16)|*pos;
00426         } else {
00427             value=(pos[0]<<16)|pos[1];
00428         }
00429         return value;
00430     }
00431     static inline const char16_t *skipValue(const char16_t *pos, int32_t leadUnit) {
00432         if(leadUnit>=kMinTwoUnitValueLead) {
00433             if(leadUnit<kThreeUnitValueLead) {
00434                 ++pos;
00435             } else {
00436                 pos+=2;
00437             }
00438         }
00439         return pos;
00440     }
00441     static inline const char16_t *skipValue(const char16_t *pos) {
00442         int32_t leadUnit=*pos++;
00443         return skipValue(pos, leadUnit&0x7fff);
00444     }
00445 
00446     static inline int32_t readNodeValue(const char16_t *pos, int32_t leadUnit) {
00447         // U_ASSERT(kMinValueLead<=leadUnit && leadUnit<kValueIsFinal);
00448         int32_t value;
00449         if(leadUnit<kMinTwoUnitNodeValueLead) {
00450             value=(leadUnit>>6)-1;
00451         } else if(leadUnit<kThreeUnitNodeValueLead) {
00452             value=(((leadUnit&0x7fc0)-kMinTwoUnitNodeValueLead)<<10)|*pos;
00453         } else {
00454             value=(pos[0]<<16)|pos[1];
00455         }
00456         return value;
00457     }
00458     static inline const char16_t *skipNodeValue(const char16_t *pos, int32_t leadUnit) {
00459         // U_ASSERT(kMinValueLead<=leadUnit && leadUnit<kValueIsFinal);
00460         if(leadUnit>=kMinTwoUnitNodeValueLead) {
00461             if(leadUnit<kThreeUnitNodeValueLead) {
00462                 ++pos;
00463             } else {
00464                 pos+=2;
00465             }
00466         }
00467         return pos;
00468     }
00469 
00470     static inline const char16_t *jumpByDelta(const char16_t *pos) {
00471         int32_t delta=*pos++;
00472         if(delta>=kMinTwoUnitDeltaLead) {
00473             if(delta==kThreeUnitDeltaLead) {
00474                 delta=(pos[0]<<16)|pos[1];
00475                 pos+=2;
00476             } else {
00477                 delta=((delta-kMinTwoUnitDeltaLead)<<16)|*pos++;
00478             }
00479         }
00480         return pos+delta;
00481     }
00482 
00483     static const char16_t *skipDelta(const char16_t *pos) {
00484         int32_t delta=*pos++;
00485         if(delta>=kMinTwoUnitDeltaLead) {
00486             if(delta==kThreeUnitDeltaLead) {
00487                 pos+=2;
00488             } else {
00489                 ++pos;
00490             }
00491         }
00492         return pos;
00493     }
00494 
00495     static inline UStringTrieResult valueResult(int32_t node) {
00496         return (UStringTrieResult)(USTRINGTRIE_INTERMEDIATE_VALUE-(node>>15));
00497     }
00498 
00499     // Handles a branch node for both next(uchar) and next(string).
00500     UStringTrieResult branchNext(const char16_t *pos, int32_t length, int32_t uchar);
00501 
00502     // Requires remainingLength_<0.
00503     UStringTrieResult nextImpl(const char16_t *pos, int32_t uchar);
00504 
00505     // Helper functions for hasUniqueValue().
00506     // Recursively finds a unique value (or whether there is not a unique one)
00507     // from a branch.
00508     static const char16_t *findUniqueValueFromBranch(const char16_t *pos, int32_t length,
00509                                                   UBool haveUniqueValue, int32_t &uniqueValue);
00510     // Recursively finds a unique value (or whether there is not a unique one)
00511     // starting from a position on a node lead unit.
00512     static UBool findUniqueValue(const char16_t *pos, UBool haveUniqueValue, int32_t &uniqueValue);
00513 
00514     // Helper functions for getNextUChars().
00515     // getNextUChars() when pos is on a branch node.
00516     static void getNextBranchUChars(const char16_t *pos, int32_t length, Appendable &out);
00517 
00518     // UCharsTrie data structure
00519     //
00520     // The trie consists of a series of char16_t-serialized nodes for incremental
00521     // Unicode string/char16_t sequence matching. (char16_t=16-bit unsigned integer)
00522     // The root node is at the beginning of the trie data.
00523     //
00524     // Types of nodes are distinguished by their node lead unit ranges.
00525     // After each node, except a final-value node, another node follows to
00526     // encode match values or continue matching further units.
00527     //
00528     // Node types:
00529     //  - Final-value node: Stores a 32-bit integer in a compact, variable-length format.
00530     //    The value is for the string/char16_t sequence so far.
00531     //  - Match node, optionally with an intermediate value in a different compact format.
00532     //    The value, if present, is for the string/char16_t sequence so far.
00533     //
00534     //  Aside from the value, which uses the node lead unit's high bits:
00535     //
00536     //  - Linear-match node: Matches a number of units.
00537     //  - Branch node: Branches to other nodes according to the current input unit.
00538     //    The node unit is the length of the branch (number of units to select from)
00539     //    minus 1. It is followed by a sub-node:
00540     //    - If the length is at most kMaxBranchLinearSubNodeLength, then
00541     //      there are length-1 (key, value) pairs and then one more comparison unit.
00542     //      If one of the key units matches, then the value is either a final value for
00543     //      the string so far, or a "jump" delta to the next node.
00544     //      If the last unit matches, then matching continues with the next node.
00545     //      (Values have the same encoding as final-value nodes.)
00546     //    - If the length is greater than kMaxBranchLinearSubNodeLength, then
00547     //      there is one unit and one "jump" delta.
00548     //      If the input unit is less than the sub-node unit, then "jump" by delta to
00549     //      the next sub-node which will have a length of length/2.
00550     //      (The delta has its own compact encoding.)
00551     //      Otherwise, skip the "jump" delta to the next sub-node
00552     //      which will have a length of length-length/2.
00553 
00554     // Match-node lead unit values, after masking off intermediate-value bits:
00555 
00556     // 0000..002f: Branch node. If node!=0 then the length is node+1, otherwise
00557     // the length is one more than the next unit.
00558 
00559     // For a branch sub-node with at most this many entries, we drop down
00560     // to a linear search.
00561     static const int32_t kMaxBranchLinearSubNodeLength=5;
00562 
00563     // 0030..003f: Linear-match node, match 1..16 units and continue reading the next node.
00564     static const int32_t kMinLinearMatch=0x30;
00565     static const int32_t kMaxLinearMatchLength=0x10;
00566 
00567     // Match-node lead unit bits 14..6 for the optional intermediate value.
00568     // If these bits are 0, then there is no intermediate value.
00569     // Otherwise, see the *NodeValue* constants below.
00570     static const int32_t kMinValueLead=kMinLinearMatch+kMaxLinearMatchLength;  // 0x0040
00571     static const int32_t kNodeTypeMask=kMinValueLead-1;  // 0x003f
00572 
00573     // A final-value node has bit 15 set.
00574     static const int32_t kValueIsFinal=0x8000;
00575 
00576     // Compact value: After testing and masking off bit 15, use the following thresholds.
00577     static const int32_t kMaxOneUnitValue=0x3fff;
00578 
00579     static const int32_t kMinTwoUnitValueLead=kMaxOneUnitValue+1;  // 0x4000
00580     static const int32_t kThreeUnitValueLead=0x7fff;
00581 
00582     static const int32_t kMaxTwoUnitValue=((kThreeUnitValueLead-kMinTwoUnitValueLead)<<16)-1;  // 0x3ffeffff
00583 
00584     // Compact intermediate-value integer, lead unit shared with a branch or linear-match node.
00585     static const int32_t kMaxOneUnitNodeValue=0xff;
00586     static const int32_t kMinTwoUnitNodeValueLead=kMinValueLead+((kMaxOneUnitNodeValue+1)<<6);  // 0x4040
00587     static const int32_t kThreeUnitNodeValueLead=0x7fc0;
00588 
00589     static const int32_t kMaxTwoUnitNodeValue=
00590         ((kThreeUnitNodeValueLead-kMinTwoUnitNodeValueLead)<<10)-1;  // 0xfdffff
00591 
00592     // Compact delta integers.
00593     static const int32_t kMaxOneUnitDelta=0xfbff;
00594     static const int32_t kMinTwoUnitDeltaLead=kMaxOneUnitDelta+1;  // 0xfc00
00595     static const int32_t kThreeUnitDeltaLead=0xffff;
00596 
00597     static const int32_t kMaxTwoUnitDelta=((kThreeUnitDeltaLead-kMinTwoUnitDeltaLead)<<16)-1;  // 0x03feffff
00598 
00599     // For getState64():
00600     // The remainingMatchLength_ is -1..14=(kMaxLinearMatchLength=0x10)-2
00601     // so we need at least 5 bits for that.
00602     // We add 2 to store it as a positive value 1..16=kMaxLinearMatchLength.
00603     static constexpr int32_t kState64RemainingShift = 59;
00604     static constexpr uint64_t kState64PosMask = (UINT64_C(1) << kState64RemainingShift) - 1;
00605 
00606     char16_t *ownedArray_;
00607 
00608     // Fixed value referencing the UCharsTrie words.
00609     const char16_t *uchars_;
00610 
00611     // Iterator variables.
00612 
00613     // Pointer to next trie unit to read. nullptr if no more matches.
00614     const char16_t *pos_;
00615     // Remaining length of a linear-match node, minus 1. Negative if not in such a node.
00616     int32_t remainingMatchLength_;
00617 };
00618 
00619 U_NAMESPACE_END
00620 
00621 #endif /* U_SHOW_CPLUSPLUS_API */
00622 
00623 #endif  // __UCHARSTRIE_H__