• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2 *******************************************************************************
3 *   Copyright (C) 2010-2012, International Business Machines
4 *   Corporation and others.  All Rights Reserved.
5 *******************************************************************************
6 *   file name:  bytestrieiterator.cpp
7 *   encoding:   US-ASCII
8 *   tab size:   8 (not used)
9 *   indentation:4
10 *
11 *   created on: 2010nov03
12 *   created by: Markus W. Scherer
13 */
14 
15 #include "unicode/utypes.h"
16 #include "unicode/bytestrie.h"
17 #include "unicode/stringpiece.h"
18 #include "charstr.h"
19 #include "uvectr32.h"
20 
21 U_NAMESPACE_BEGIN
22 
Iterator(const void * trieBytes,int32_t maxStringLength,UErrorCode & errorCode)23 BytesTrie::Iterator::Iterator(const void *trieBytes, int32_t maxStringLength,
24                               UErrorCode &errorCode)
25         : bytes_(static_cast<const uint8_t *>(trieBytes)),
26           pos_(bytes_), initialPos_(bytes_),
27           remainingMatchLength_(-1), initialRemainingMatchLength_(-1),
28           str_(NULL), maxLength_(maxStringLength), value_(0), stack_(NULL) {
29     if(U_FAILURE(errorCode)) {
30         return;
31     }
32     // str_ and stack_ are pointers so that it's easy to turn bytestrie.h into
33     // a public API header for which we would want it to depend only on
34     // other public headers.
35     // Unlike BytesTrie itself, its Iterator performs memory allocations anyway
36     // via the CharString and UVector32 implementations, so this additional
37     // cost is minimal.
38     str_=new CharString();
39     stack_=new UVector32(errorCode);
40     if(U_SUCCESS(errorCode) && (str_==NULL || stack_==NULL)) {
41         errorCode=U_MEMORY_ALLOCATION_ERROR;
42     }
43 }
44 
Iterator(const BytesTrie & trie,int32_t maxStringLength,UErrorCode & errorCode)45 BytesTrie::Iterator::Iterator(const BytesTrie &trie, int32_t maxStringLength,
46                               UErrorCode &errorCode)
47         : bytes_(trie.bytes_), pos_(trie.pos_), initialPos_(trie.pos_),
48           remainingMatchLength_(trie.remainingMatchLength_),
49           initialRemainingMatchLength_(trie.remainingMatchLength_),
50           str_(NULL), maxLength_(maxStringLength), value_(0), stack_(NULL) {
51     if(U_FAILURE(errorCode)) {
52         return;
53     }
54     str_=new CharString();
55     stack_=new UVector32(errorCode);
56     if(U_FAILURE(errorCode)) {
57         return;
58     }
59     if(str_==NULL || stack_==NULL) {
60         errorCode=U_MEMORY_ALLOCATION_ERROR;
61         return;
62     }
63     int32_t length=remainingMatchLength_;  // Actual remaining match length minus 1.
64     if(length>=0) {
65         // Pending linear-match node, append remaining bytes to str_.
66         ++length;
67         if(maxLength_>0 && length>maxLength_) {
68             length=maxLength_;  // This will leave remainingMatchLength>=0 as a signal.
69         }
70         str_->append(reinterpret_cast<const char *>(pos_), length, errorCode);
71         pos_+=length;
72         remainingMatchLength_-=length;
73     }
74 }
75 
~Iterator()76 BytesTrie::Iterator::~Iterator() {
77     delete str_;
78     delete stack_;
79 }
80 
81 BytesTrie::Iterator &
reset()82 BytesTrie::Iterator::reset() {
83     pos_=initialPos_;
84     remainingMatchLength_=initialRemainingMatchLength_;
85     int32_t length=remainingMatchLength_+1;  // Remaining match length.
86     if(maxLength_>0 && length>maxLength_) {
87         length=maxLength_;
88     }
89     str_->truncate(length);
90     pos_+=length;
91     remainingMatchLength_-=length;
92     stack_->setSize(0);
93     return *this;
94 }
95 
96 UBool
hasNext() const97 BytesTrie::Iterator::hasNext() const { return pos_!=NULL || !stack_->isEmpty(); }
98 
99 UBool
next(UErrorCode & errorCode)100 BytesTrie::Iterator::next(UErrorCode &errorCode) {
101     if(U_FAILURE(errorCode)) {
102         return FALSE;
103     }
104     const uint8_t *pos=pos_;
105     if(pos==NULL) {
106         if(stack_->isEmpty()) {
107             return FALSE;
108         }
109         // Pop the state off the stack and continue with the next outbound edge of
110         // the branch node.
111         int32_t stackSize=stack_->size();
112         int32_t length=stack_->elementAti(stackSize-1);
113         pos=bytes_+stack_->elementAti(stackSize-2);
114         stack_->setSize(stackSize-2);
115         str_->truncate(length&0xffff);
116         length=(int32_t)((uint32_t)length>>16);
117         if(length>1) {
118             pos=branchNext(pos, length, errorCode);
119             if(pos==NULL) {
120                 return TRUE;  // Reached a final value.
121             }
122         } else {
123             str_->append((char)*pos++, errorCode);
124         }
125     }
126     if(remainingMatchLength_>=0) {
127         // We only get here if we started in a pending linear-match node
128         // with more than maxLength remaining bytes.
129         return truncateAndStop();
130     }
131     for(;;) {
132         int32_t node=*pos++;
133         if(node>=kMinValueLead) {
134             // Deliver value for the byte sequence so far.
135             UBool isFinal=(UBool)(node&kValueIsFinal);
136             value_=readValue(pos, node>>1);
137             if(isFinal || (maxLength_>0 && str_->length()==maxLength_)) {
138                 pos_=NULL;
139             } else {
140                 pos_=skipValue(pos, node);
141             }
142             sp_.set(str_->data(), str_->length());
143             return TRUE;
144         }
145         if(maxLength_>0 && str_->length()==maxLength_) {
146             return truncateAndStop();
147         }
148         if(node<kMinLinearMatch) {
149             if(node==0) {
150                 node=*pos++;
151             }
152             pos=branchNext(pos, node+1, errorCode);
153             if(pos==NULL) {
154                 return TRUE;  // Reached a final value.
155             }
156         } else {
157             // Linear-match node, append length bytes to str_.
158             int32_t length=node-kMinLinearMatch+1;
159             if(maxLength_>0 && str_->length()+length>maxLength_) {
160                 str_->append(reinterpret_cast<const char *>(pos),
161                             maxLength_-str_->length(), errorCode);
162                 return truncateAndStop();
163             }
164             str_->append(reinterpret_cast<const char *>(pos), length, errorCode);
165             pos+=length;
166         }
167     }
168 }
169 
170 UBool
truncateAndStop()171 BytesTrie::Iterator::truncateAndStop() {
172     pos_=NULL;
173     sp_.set(str_->data(), str_->length());
174     value_=-1;  // no real value for str
175     return TRUE;
176 }
177 
178 // Branch node, needs to take the first outbound edge and push state for the rest.
179 const uint8_t *
branchNext(const uint8_t * pos,int32_t length,UErrorCode & errorCode)180 BytesTrie::Iterator::branchNext(const uint8_t *pos, int32_t length, UErrorCode &errorCode) {
181     while(length>kMaxBranchLinearSubNodeLength) {
182         ++pos;  // ignore the comparison byte
183         // Push state for the greater-or-equal edge.
184         stack_->addElement((int32_t)(skipDelta(pos)-bytes_), errorCode);
185         stack_->addElement(((length-(length>>1))<<16)|str_->length(), errorCode);
186         // Follow the less-than edge.
187         length>>=1;
188         pos=jumpByDelta(pos);
189     }
190     // List of key-value pairs where values are either final values or jump deltas.
191     // Read the first (key, value) pair.
192     uint8_t trieByte=*pos++;
193     int32_t node=*pos++;
194     UBool isFinal=(UBool)(node&kValueIsFinal);
195     int32_t value=readValue(pos, node>>1);
196     pos=skipValue(pos, node);
197     stack_->addElement((int32_t)(pos-bytes_), errorCode);
198     stack_->addElement(((length-1)<<16)|str_->length(), errorCode);
199     str_->append((char)trieByte, errorCode);
200     if(isFinal) {
201         pos_=NULL;
202         sp_.set(str_->data(), str_->length());
203         value_=value;
204         return NULL;
205     } else {
206         return pos+value;
207     }
208 }
209 
210 U_NAMESPACE_END
211