1 /*
2 *******************************************************************************
3 * Copyright (C) 2010-2011, International Business Machines
4 * Corporation and others. All Rights Reserved.
5 *******************************************************************************
6 * file name: stringtriebuilder.cpp
7 * encoding: US-ASCII
8 * tab size: 8 (not used)
9 * indentation:4
10 *
11 * created on: 2010dec24
12 * created by: Markus W. Scherer
13 */
14
15 #include <typeinfo> // for 'typeid' to work
16 #include "unicode/utypes.h"
17 #include "unicode/stringtriebuilder.h"
18 #include "uassert.h"
19 #include "uhash.h"
20
21 U_CDECL_BEGIN
22
23 static int32_t U_CALLCONV
hashStringTrieNode(const UHashTok key)24 hashStringTrieNode(const UHashTok key) {
25 return U_NAMESPACE_QUALIFIER StringTrieBuilder::hashNode(key.pointer);
26 }
27
28 static UBool U_CALLCONV
equalStringTrieNodes(const UHashTok key1,const UHashTok key2)29 equalStringTrieNodes(const UHashTok key1, const UHashTok key2) {
30 return U_NAMESPACE_QUALIFIER StringTrieBuilder::equalNodes(key1.pointer, key2.pointer);
31 }
32
33 U_CDECL_END
34
35 U_NAMESPACE_BEGIN
36
StringTrieBuilder()37 StringTrieBuilder::StringTrieBuilder() : nodes(NULL) {}
38
~StringTrieBuilder()39 StringTrieBuilder::~StringTrieBuilder() {
40 deleteCompactBuilder();
41 }
42
43 void
createCompactBuilder(int32_t sizeGuess,UErrorCode & errorCode)44 StringTrieBuilder::createCompactBuilder(int32_t sizeGuess, UErrorCode &errorCode) {
45 if(U_FAILURE(errorCode)) {
46 return;
47 }
48 nodes=uhash_openSize(hashStringTrieNode, equalStringTrieNodes, NULL,
49 sizeGuess, &errorCode);
50 if(U_SUCCESS(errorCode) && nodes==NULL) {
51 errorCode=U_MEMORY_ALLOCATION_ERROR;
52 }
53 if(U_SUCCESS(errorCode)) {
54 uhash_setKeyDeleter(nodes, uhash_deleteUObject);
55 }
56 }
57
58 void
deleteCompactBuilder()59 StringTrieBuilder::deleteCompactBuilder() {
60 uhash_close(nodes);
61 nodes=NULL;
62 }
63
64 void
build(UStringTrieBuildOption buildOption,int32_t elementsLength,UErrorCode & errorCode)65 StringTrieBuilder::build(UStringTrieBuildOption buildOption, int32_t elementsLength,
66 UErrorCode &errorCode) {
67 if(buildOption==USTRINGTRIE_BUILD_FAST) {
68 writeNode(0, elementsLength, 0);
69 } else /* USTRINGTRIE_BUILD_SMALL */ {
70 createCompactBuilder(2*elementsLength, errorCode);
71 Node *root=makeNode(0, elementsLength, 0, errorCode);
72 if(U_SUCCESS(errorCode)) {
73 root->markRightEdgesFirst(-1);
74 root->write(*this);
75 }
76 deleteCompactBuilder();
77 }
78 }
79
80 // Requires start<limit,
81 // and all strings of the [start..limit[ elements must be sorted and
82 // have a common prefix of length unitIndex.
83 int32_t
writeNode(int32_t start,int32_t limit,int32_t unitIndex)84 StringTrieBuilder::writeNode(int32_t start, int32_t limit, int32_t unitIndex) {
85 UBool hasValue=FALSE;
86 int32_t value=0;
87 int32_t type;
88 if(unitIndex==getElementStringLength(start)) {
89 // An intermediate or final value.
90 value=getElementValue(start++);
91 if(start==limit) {
92 return writeValueAndFinal(value, TRUE); // final-value node
93 }
94 hasValue=TRUE;
95 }
96 // Now all [start..limit[ strings are longer than unitIndex.
97 int32_t minUnit=getElementUnit(start, unitIndex);
98 int32_t maxUnit=getElementUnit(limit-1, unitIndex);
99 if(minUnit==maxUnit) {
100 // Linear-match node: All strings have the same character at unitIndex.
101 int32_t lastUnitIndex=getLimitOfLinearMatch(start, limit-1, unitIndex);
102 writeNode(start, limit, lastUnitIndex);
103 // Break the linear-match sequence into chunks of at most kMaxLinearMatchLength.
104 int32_t length=lastUnitIndex-unitIndex;
105 int32_t maxLinearMatchLength=getMaxLinearMatchLength();
106 while(length>maxLinearMatchLength) {
107 lastUnitIndex-=maxLinearMatchLength;
108 length-=maxLinearMatchLength;
109 writeElementUnits(start, lastUnitIndex, maxLinearMatchLength);
110 write(getMinLinearMatch()+maxLinearMatchLength-1);
111 }
112 writeElementUnits(start, unitIndex, length);
113 type=getMinLinearMatch()+length-1;
114 } else {
115 // Branch node.
116 int32_t length=countElementUnits(start, limit, unitIndex);
117 // length>=2 because minUnit!=maxUnit.
118 writeBranchSubNode(start, limit, unitIndex, length);
119 if(--length<getMinLinearMatch()) {
120 type=length;
121 } else {
122 write(length);
123 type=0;
124 }
125 }
126 return writeValueAndType(hasValue, value, type);
127 }
128
129 // start<limit && all strings longer than unitIndex &&
130 // length different units at unitIndex
131 int32_t
writeBranchSubNode(int32_t start,int32_t limit,int32_t unitIndex,int32_t length)132 StringTrieBuilder::writeBranchSubNode(int32_t start, int32_t limit, int32_t unitIndex, int32_t length) {
133 UChar middleUnits[kMaxSplitBranchLevels];
134 int32_t lessThan[kMaxSplitBranchLevels];
135 int32_t ltLength=0;
136 while(length>getMaxBranchLinearSubNodeLength()) {
137 // Branch on the middle unit.
138 // First, find the middle unit.
139 int32_t i=skipElementsBySomeUnits(start, unitIndex, length/2);
140 // Encode the less-than branch first.
141 middleUnits[ltLength]=getElementUnit(i, unitIndex); // middle unit
142 lessThan[ltLength]=writeBranchSubNode(start, i, unitIndex, length/2);
143 ++ltLength;
144 // Continue for the greater-or-equal branch.
145 start=i;
146 length=length-length/2;
147 }
148 // For each unit, find its elements array start and whether it has a final value.
149 int32_t starts[kMaxBranchLinearSubNodeLength];
150 UBool isFinal[kMaxBranchLinearSubNodeLength-1];
151 int32_t unitNumber=0;
152 do {
153 int32_t i=starts[unitNumber]=start;
154 UChar unit=getElementUnit(i++, unitIndex);
155 i=indexOfElementWithNextUnit(i, unitIndex, unit);
156 isFinal[unitNumber]= start==i-1 && unitIndex+1==getElementStringLength(start);
157 start=i;
158 } while(++unitNumber<length-1);
159 // unitNumber==length-1, and the maxUnit elements range is [start..limit[
160 starts[unitNumber]=start;
161
162 // Write the sub-nodes in reverse order: The jump lengths are deltas from
163 // after their own positions, so if we wrote the minUnit sub-node first,
164 // then its jump delta would be larger.
165 // Instead we write the minUnit sub-node last, for a shorter delta.
166 int32_t jumpTargets[kMaxBranchLinearSubNodeLength-1];
167 do {
168 --unitNumber;
169 if(!isFinal[unitNumber]) {
170 jumpTargets[unitNumber]=writeNode(starts[unitNumber], starts[unitNumber+1], unitIndex+1);
171 }
172 } while(unitNumber>0);
173 // The maxUnit sub-node is written as the very last one because we do
174 // not jump for it at all.
175 unitNumber=length-1;
176 writeNode(start, limit, unitIndex+1);
177 int32_t offset=write(getElementUnit(start, unitIndex));
178 // Write the rest of this node's unit-value pairs.
179 while(--unitNumber>=0) {
180 start=starts[unitNumber];
181 int32_t value;
182 if(isFinal[unitNumber]) {
183 // Write the final value for the one string ending with this unit.
184 value=getElementValue(start);
185 } else {
186 // Write the delta to the start position of the sub-node.
187 value=offset-jumpTargets[unitNumber];
188 }
189 writeValueAndFinal(value, isFinal[unitNumber]);
190 offset=write(getElementUnit(start, unitIndex));
191 }
192 // Write the split-branch nodes.
193 while(ltLength>0) {
194 --ltLength;
195 writeDeltaTo(lessThan[ltLength]);
196 offset=write(middleUnits[ltLength]);
197 }
198 return offset;
199 }
200
201 // Requires start<limit,
202 // and all strings of the [start..limit[ elements must be sorted and
203 // have a common prefix of length unitIndex.
204 StringTrieBuilder::Node *
makeNode(int32_t start,int32_t limit,int32_t unitIndex,UErrorCode & errorCode)205 StringTrieBuilder::makeNode(int32_t start, int32_t limit, int32_t unitIndex, UErrorCode &errorCode) {
206 if(U_FAILURE(errorCode)) {
207 return NULL;
208 }
209 UBool hasValue=FALSE;
210 int32_t value=0;
211 if(unitIndex==getElementStringLength(start)) {
212 // An intermediate or final value.
213 value=getElementValue(start++);
214 if(start==limit) {
215 return registerFinalValue(value, errorCode);
216 }
217 hasValue=TRUE;
218 }
219 Node *node;
220 // Now all [start..limit[ strings are longer than unitIndex.
221 int32_t minUnit=getElementUnit(start, unitIndex);
222 int32_t maxUnit=getElementUnit(limit-1, unitIndex);
223 if(minUnit==maxUnit) {
224 // Linear-match node: All strings have the same character at unitIndex.
225 int32_t lastUnitIndex=getLimitOfLinearMatch(start, limit-1, unitIndex);
226 Node *nextNode=makeNode(start, limit, lastUnitIndex, errorCode);
227 // Break the linear-match sequence into chunks of at most kMaxLinearMatchLength.
228 int32_t length=lastUnitIndex-unitIndex;
229 int32_t maxLinearMatchLength=getMaxLinearMatchLength();
230 while(length>maxLinearMatchLength) {
231 lastUnitIndex-=maxLinearMatchLength;
232 length-=maxLinearMatchLength;
233 node=createLinearMatchNode(start, lastUnitIndex, maxLinearMatchLength, nextNode);
234 nextNode=registerNode(node, errorCode);
235 }
236 node=createLinearMatchNode(start, unitIndex, length, nextNode);
237 } else {
238 // Branch node.
239 int32_t length=countElementUnits(start, limit, unitIndex);
240 // length>=2 because minUnit!=maxUnit.
241 Node *subNode=makeBranchSubNode(start, limit, unitIndex, length, errorCode);
242 node=new BranchHeadNode(length, subNode);
243 }
244 if(hasValue && node!=NULL) {
245 if(matchNodesCanHaveValues()) {
246 ((ValueNode *)node)->setValue(value);
247 } else {
248 node=new IntermediateValueNode(value, registerNode(node, errorCode));
249 }
250 }
251 return registerNode(node, errorCode);
252 }
253
254 // start<limit && all strings longer than unitIndex &&
255 // length different units at unitIndex
256 StringTrieBuilder::Node *
makeBranchSubNode(int32_t start,int32_t limit,int32_t unitIndex,int32_t length,UErrorCode & errorCode)257 StringTrieBuilder::makeBranchSubNode(int32_t start, int32_t limit, int32_t unitIndex,
258 int32_t length, UErrorCode &errorCode) {
259 if(U_FAILURE(errorCode)) {
260 return NULL;
261 }
262 UChar middleUnits[kMaxSplitBranchLevels];
263 Node *lessThan[kMaxSplitBranchLevels];
264 int32_t ltLength=0;
265 while(length>getMaxBranchLinearSubNodeLength()) {
266 // Branch on the middle unit.
267 // First, find the middle unit.
268 int32_t i=skipElementsBySomeUnits(start, unitIndex, length/2);
269 // Create the less-than branch.
270 middleUnits[ltLength]=getElementUnit(i, unitIndex); // middle unit
271 lessThan[ltLength]=makeBranchSubNode(start, i, unitIndex, length/2, errorCode);
272 ++ltLength;
273 // Continue for the greater-or-equal branch.
274 start=i;
275 length=length-length/2;
276 }
277 if(U_FAILURE(errorCode)) {
278 return NULL;
279 }
280 ListBranchNode *listNode=new ListBranchNode();
281 if(listNode==NULL) {
282 errorCode=U_MEMORY_ALLOCATION_ERROR;
283 return NULL;
284 }
285 // For each unit, find its elements array start and whether it has a final value.
286 int32_t unitNumber=0;
287 do {
288 int32_t i=start;
289 UChar unit=getElementUnit(i++, unitIndex);
290 i=indexOfElementWithNextUnit(i, unitIndex, unit);
291 if(start==i-1 && unitIndex+1==getElementStringLength(start)) {
292 listNode->add(unit, getElementValue(start));
293 } else {
294 listNode->add(unit, makeNode(start, i, unitIndex+1, errorCode));
295 }
296 start=i;
297 } while(++unitNumber<length-1);
298 // unitNumber==length-1, and the maxUnit elements range is [start..limit[
299 UChar unit=getElementUnit(start, unitIndex);
300 if(start==limit-1 && unitIndex+1==getElementStringLength(start)) {
301 listNode->add(unit, getElementValue(start));
302 } else {
303 listNode->add(unit, makeNode(start, limit, unitIndex+1, errorCode));
304 }
305 Node *node=registerNode(listNode, errorCode);
306 // Create the split-branch nodes.
307 while(ltLength>0) {
308 --ltLength;
309 node=registerNode(
310 new SplitBranchNode(middleUnits[ltLength], lessThan[ltLength], node), errorCode);
311 }
312 return node;
313 }
314
315 StringTrieBuilder::Node *
registerNode(Node * newNode,UErrorCode & errorCode)316 StringTrieBuilder::registerNode(Node *newNode, UErrorCode &errorCode) {
317 if(U_FAILURE(errorCode)) {
318 delete newNode;
319 return NULL;
320 }
321 if(newNode==NULL) {
322 errorCode=U_MEMORY_ALLOCATION_ERROR;
323 return NULL;
324 }
325 const UHashElement *old=uhash_find(nodes, newNode);
326 if(old!=NULL) {
327 delete newNode;
328 return (Node *)old->key.pointer;
329 }
330 // If uhash_puti() returns a non-zero value from an equivalent, previously
331 // registered node, then uhash_find() failed to find that and we will leak newNode.
332 #if !U_RELEASE
333 int32_t oldValue= // Only in debug mode to avoid a compiler warning about unused oldValue.
334 #endif
335 uhash_puti(nodes, newNode, 1, &errorCode);
336 U_ASSERT(oldValue==0);
337 if(U_FAILURE(errorCode)) {
338 delete newNode;
339 return NULL;
340 }
341 return newNode;
342 }
343
344 StringTrieBuilder::Node *
registerFinalValue(int32_t value,UErrorCode & errorCode)345 StringTrieBuilder::registerFinalValue(int32_t value, UErrorCode &errorCode) {
346 if(U_FAILURE(errorCode)) {
347 return NULL;
348 }
349 FinalValueNode key(value);
350 const UHashElement *old=uhash_find(nodes, &key);
351 if(old!=NULL) {
352 return (Node *)old->key.pointer;
353 }
354 Node *newNode=new FinalValueNode(value);
355 if(newNode==NULL) {
356 errorCode=U_MEMORY_ALLOCATION_ERROR;
357 return NULL;
358 }
359 // If uhash_puti() returns a non-zero value from an equivalent, previously
360 // registered node, then uhash_find() failed to find that and we will leak newNode.
361 #if !U_RELEASE
362 int32_t oldValue= // Only in debug mode to avoid a compiler warning about unused oldValue.
363 #endif
364 uhash_puti(nodes, newNode, 1, &errorCode);
365 U_ASSERT(oldValue==0);
366 if(U_FAILURE(errorCode)) {
367 delete newNode;
368 return NULL;
369 }
370 return newNode;
371 }
372
373 UBool
hashNode(const void * node)374 StringTrieBuilder::hashNode(const void *node) {
375 return ((const Node *)node)->hashCode();
376 }
377
378 UBool
equalNodes(const void * left,const void * right)379 StringTrieBuilder::equalNodes(const void *left, const void *right) {
380 return *(const Node *)left==*(const Node *)right;
381 }
382
383 UOBJECT_DEFINE_NO_RTTI_IMPLEMENTATION(StringTrieBuilder)
384
385 UBool
386 StringTrieBuilder::Node::operator==(const Node &other) const {
387 return this==&other || (typeid(*this)==typeid(other) && hash==other.hash);
388 }
389
390 int32_t
markRightEdgesFirst(int32_t edgeNumber)391 StringTrieBuilder::Node::markRightEdgesFirst(int32_t edgeNumber) {
392 if(offset==0) {
393 offset=edgeNumber;
394 }
395 return edgeNumber;
396 }
397
398 UOBJECT_DEFINE_NO_RTTI_IMPLEMENTATION(StringTrieBuilder::Node)
399
400 UBool
401 StringTrieBuilder::FinalValueNode::operator==(const Node &other) const {
402 if(this==&other) {
403 return TRUE;
404 }
405 if(!Node::operator==(other)) {
406 return FALSE;
407 }
408 const FinalValueNode &o=(const FinalValueNode &)other;
409 return value==o.value;
410 }
411
412 void
write(StringTrieBuilder & builder)413 StringTrieBuilder::FinalValueNode::write(StringTrieBuilder &builder) {
414 offset=builder.writeValueAndFinal(value, TRUE);
415 }
416
417 UBool
operator ==(const Node & other) const418 StringTrieBuilder::ValueNode::operator==(const Node &other) const {
419 if(this==&other) {
420 return TRUE;
421 }
422 if(!Node::operator==(other)) {
423 return FALSE;
424 }
425 const ValueNode &o=(const ValueNode &)other;
426 return hasValue==o.hasValue && (!hasValue || value==o.value);
427 }
428
429 UBool
operator ==(const Node & other) const430 StringTrieBuilder::IntermediateValueNode::operator==(const Node &other) const {
431 if(this==&other) {
432 return TRUE;
433 }
434 if(!ValueNode::operator==(other)) {
435 return FALSE;
436 }
437 const IntermediateValueNode &o=(const IntermediateValueNode &)other;
438 return next==o.next;
439 }
440
441 int32_t
markRightEdgesFirst(int32_t edgeNumber)442 StringTrieBuilder::IntermediateValueNode::markRightEdgesFirst(int32_t edgeNumber) {
443 if(offset==0) {
444 offset=edgeNumber=next->markRightEdgesFirst(edgeNumber);
445 }
446 return edgeNumber;
447 }
448
449 void
write(StringTrieBuilder & builder)450 StringTrieBuilder::IntermediateValueNode::write(StringTrieBuilder &builder) {
451 next->write(builder);
452 offset=builder.writeValueAndFinal(value, FALSE);
453 }
454
455 UBool
operator ==(const Node & other) const456 StringTrieBuilder::LinearMatchNode::operator==(const Node &other) const {
457 if(this==&other) {
458 return TRUE;
459 }
460 if(!ValueNode::operator==(other)) {
461 return FALSE;
462 }
463 const LinearMatchNode &o=(const LinearMatchNode &)other;
464 return length==o.length && next==o.next;
465 }
466
467 int32_t
markRightEdgesFirst(int32_t edgeNumber)468 StringTrieBuilder::LinearMatchNode::markRightEdgesFirst(int32_t edgeNumber) {
469 if(offset==0) {
470 offset=edgeNumber=next->markRightEdgesFirst(edgeNumber);
471 }
472 return edgeNumber;
473 }
474
475 UBool
operator ==(const Node & other) const476 StringTrieBuilder::ListBranchNode::operator==(const Node &other) const {
477 if(this==&other) {
478 return TRUE;
479 }
480 if(!Node::operator==(other)) {
481 return FALSE;
482 }
483 const ListBranchNode &o=(const ListBranchNode &)other;
484 for(int32_t i=0; i<length; ++i) {
485 if(units[i]!=o.units[i] || values[i]!=o.values[i] || equal[i]!=o.equal[i]) {
486 return FALSE;
487 }
488 }
489 return TRUE;
490 }
491
492 int32_t
markRightEdgesFirst(int32_t edgeNumber)493 StringTrieBuilder::ListBranchNode::markRightEdgesFirst(int32_t edgeNumber) {
494 if(offset==0) {
495 firstEdgeNumber=edgeNumber;
496 int32_t step=0;
497 int32_t i=length;
498 do {
499 Node *edge=equal[--i];
500 if(edge!=NULL) {
501 edgeNumber=edge->markRightEdgesFirst(edgeNumber-step);
502 }
503 // For all but the rightmost edge, decrement the edge number.
504 step=1;
505 } while(i>0);
506 offset=edgeNumber;
507 }
508 return edgeNumber;
509 }
510
511 void
write(StringTrieBuilder & builder)512 StringTrieBuilder::ListBranchNode::write(StringTrieBuilder &builder) {
513 // Write the sub-nodes in reverse order: The jump lengths are deltas from
514 // after their own positions, so if we wrote the minUnit sub-node first,
515 // then its jump delta would be larger.
516 // Instead we write the minUnit sub-node last, for a shorter delta.
517 int32_t unitNumber=length-1;
518 Node *rightEdge=equal[unitNumber];
519 int32_t rightEdgeNumber= rightEdge==NULL ? firstEdgeNumber : rightEdge->getOffset();
520 do {
521 --unitNumber;
522 if(equal[unitNumber]!=NULL) {
523 equal[unitNumber]->writeUnlessInsideRightEdge(firstEdgeNumber, rightEdgeNumber, builder);
524 }
525 } while(unitNumber>0);
526 // The maxUnit sub-node is written as the very last one because we do
527 // not jump for it at all.
528 unitNumber=length-1;
529 if(rightEdge==NULL) {
530 builder.writeValueAndFinal(values[unitNumber], TRUE);
531 } else {
532 rightEdge->write(builder);
533 }
534 offset=builder.write(units[unitNumber]);
535 // Write the rest of this node's unit-value pairs.
536 while(--unitNumber>=0) {
537 int32_t value;
538 UBool isFinal;
539 if(equal[unitNumber]==NULL) {
540 // Write the final value for the one string ending with this unit.
541 value=values[unitNumber];
542 isFinal=TRUE;
543 } else {
544 // Write the delta to the start position of the sub-node.
545 U_ASSERT(equal[unitNumber]->getOffset()>0);
546 value=offset-equal[unitNumber]->getOffset();
547 isFinal=FALSE;
548 }
549 builder.writeValueAndFinal(value, isFinal);
550 offset=builder.write(units[unitNumber]);
551 }
552 }
553
554 UBool
operator ==(const Node & other) const555 StringTrieBuilder::SplitBranchNode::operator==(const Node &other) const {
556 if(this==&other) {
557 return TRUE;
558 }
559 if(!Node::operator==(other)) {
560 return FALSE;
561 }
562 const SplitBranchNode &o=(const SplitBranchNode &)other;
563 return unit==o.unit && lessThan==o.lessThan && greaterOrEqual==o.greaterOrEqual;
564 }
565
566 int32_t
markRightEdgesFirst(int32_t edgeNumber)567 StringTrieBuilder::SplitBranchNode::markRightEdgesFirst(int32_t edgeNumber) {
568 if(offset==0) {
569 firstEdgeNumber=edgeNumber;
570 edgeNumber=greaterOrEqual->markRightEdgesFirst(edgeNumber);
571 offset=edgeNumber=lessThan->markRightEdgesFirst(edgeNumber-1);
572 }
573 return edgeNumber;
574 }
575
576 void
write(StringTrieBuilder & builder)577 StringTrieBuilder::SplitBranchNode::write(StringTrieBuilder &builder) {
578 // Encode the less-than branch first.
579 lessThan->writeUnlessInsideRightEdge(firstEdgeNumber, greaterOrEqual->getOffset(), builder);
580 // Encode the greater-or-equal branch last because we do not jump for it at all.
581 greaterOrEqual->write(builder);
582 // Write this node.
583 U_ASSERT(lessThan->getOffset()>0);
584 builder.writeDeltaTo(lessThan->getOffset()); // less-than
585 offset=builder.write(unit);
586 }
587
588 UBool
operator ==(const Node & other) const589 StringTrieBuilder::BranchHeadNode::operator==(const Node &other) const {
590 if(this==&other) {
591 return TRUE;
592 }
593 if(!ValueNode::operator==(other)) {
594 return FALSE;
595 }
596 const BranchHeadNode &o=(const BranchHeadNode &)other;
597 return length==o.length && next==o.next;
598 }
599
600 int32_t
markRightEdgesFirst(int32_t edgeNumber)601 StringTrieBuilder::BranchHeadNode::markRightEdgesFirst(int32_t edgeNumber) {
602 if(offset==0) {
603 offset=edgeNumber=next->markRightEdgesFirst(edgeNumber);
604 }
605 return edgeNumber;
606 }
607
608 void
write(StringTrieBuilder & builder)609 StringTrieBuilder::BranchHeadNode::write(StringTrieBuilder &builder) {
610 next->write(builder);
611 if(length<=builder.getMinLinearMatch()) {
612 offset=builder.writeValueAndType(hasValue, value, length-1);
613 } else {
614 builder.write(length-1);
615 offset=builder.writeValueAndType(hasValue, value, 0);
616 }
617 }
618
619 U_NAMESPACE_END
620