• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 //  rbbisetb.cpp
3 //
4 /*
5 ***************************************************************************
6 *   Copyright (C) 2002-2008 International Business Machines Corporation   *
7 *   and others. All rights reserved.                                      *
8 ***************************************************************************
9 */
10 //
11 //  RBBISetBuilder   Handles processing of Unicode Sets from RBBI rules
12 //                   (part of the rule building process.)
13 //
14 //      Starting with the rules parse tree from the scanner,
15 //
16 //                   -  Enumerate the set of UnicodeSets that are referenced
17 //                      by the RBBI rules.
18 //                   -  compute a set of non-overlapping character ranges
19 //                      with all characters within a range belonging to the same
20 //                      set of input uniocde sets.
21 //                   -  Derive a set of non-overlapping UnicodeSet (like things)
22 //                      that will correspond to columns in the state table for
23 //                      the RBBI execution engine.  All characters within one
24 //                      of these sets belong to the same set of the original
25 //                      UnicodeSets from the user's rules.
26 //                   -  construct the trie table that maps input characters
27 //                      to the index of the matching non-overlapping set of set from
28 //                      the previous step.
29 //
30 
31 #include "unicode/utypes.h"
32 
33 #if !UCONFIG_NO_BREAK_ITERATION
34 
35 #include "unicode/uniset.h"
36 #include "utrie.h"
37 #include "uvector.h"
38 #include "uassert.h"
39 #include "cmemory.h"
40 #include "cstring.h"
41 
42 #include "rbbisetb.h"
43 #include "rbbinode.h"
44 
45 
46 //------------------------------------------------------------------------
47 //
48 //   getFoldedRBBIValue        Call-back function used during building of Trie table.
49 //                             Folding value: just store the offset (16 bits)
50 //                             if there is any non-0 entry.
51 //                             (It'd really be nice if the Trie builder would provide a
52 //                             simple default, so this function could go away from here.)
53 //
54 //------------------------------------------------------------------------
55 /* folding value: just store the offset (16 bits) if there is any non-0 entry */
56 U_CDECL_BEGIN
57 static uint32_t U_CALLCONV
getFoldedRBBIValue(UNewTrie * trie,UChar32 start,int32_t offset)58 getFoldedRBBIValue(UNewTrie *trie, UChar32 start, int32_t offset) {
59     uint32_t value;
60     UChar32 limit;
61     UBool inBlockZero;
62 
63     limit=start+0x400;
64     while(start<limit) {
65         value=utrie_get32(trie, start, &inBlockZero);
66         if(inBlockZero) {
67             start+=UTRIE_DATA_BLOCK_LENGTH;
68         } else if(value!=0) {
69             return (uint32_t)(offset|0x8000);
70         } else {
71             ++start;
72         }
73     }
74     return 0;
75 }
76 
77 
78 U_CDECL_END
79 
80 
81 
82 U_NAMESPACE_BEGIN
83 
84 //------------------------------------------------------------------------
85 //
86 //   Constructor
87 //
88 //------------------------------------------------------------------------
RBBISetBuilder(RBBIRuleBuilder * rb)89 RBBISetBuilder::RBBISetBuilder(RBBIRuleBuilder *rb)
90 {
91     fRB             = rb;
92     fStatus         = rb->fStatus;
93     fRangeList      = 0;
94     fTrie           = 0;
95     fTrieSize       = 0;
96     fGroupCount     = 0;
97     fSawBOF         = FALSE;
98 }
99 
100 
101 //------------------------------------------------------------------------
102 //
103 //   Destructor
104 //
105 //------------------------------------------------------------------------
~RBBISetBuilder()106 RBBISetBuilder::~RBBISetBuilder()
107 {
108     RangeDescriptor   *nextRangeDesc;
109 
110     // Walk through & delete the linked list of RangeDescriptors
111     for (nextRangeDesc = fRangeList; nextRangeDesc!=NULL;) {
112         RangeDescriptor *r = nextRangeDesc;
113         nextRangeDesc      = r->fNext;
114         delete r;
115     }
116 
117     utrie_close(fTrie);
118 }
119 
120 
121 
122 
123 //------------------------------------------------------------------------
124 //
125 //   build          Build the list of non-overlapping character ranges
126 //                  from the Unicode Sets.
127 //
128 //------------------------------------------------------------------------
build()129 void RBBISetBuilder::build() {
130     RBBINode        *usetNode;
131     RangeDescriptor *rlRange;
132 
133     if (fRB->fDebugEnv && uprv_strstr(fRB->fDebugEnv, "usets")) {printSets();}
134 
135     //
136     //  Initialize the process by creating a single range encompassing all characters
137     //  that is in no sets.
138     //
139     fRangeList                = new RangeDescriptor(*fStatus); // will check for status here
140     if (fRangeList == NULL) {
141         *fStatus = U_MEMORY_ALLOCATION_ERROR;
142         return;
143     }
144     fRangeList->fStartChar    = 0;
145     fRangeList->fEndChar      = 0x10ffff;
146 
147     if (U_FAILURE(*fStatus)) {
148         return;
149     }
150 
151     //
152     //  Find the set of non-overlapping ranges of characters
153     //
154     int  ni;
155     for (ni=0; ; ni++) {        // Loop over each of the UnicodeSets encountered in the input rules
156         usetNode = (RBBINode *)this->fRB->fUSetNodes->elementAt(ni);
157         if (usetNode==NULL) {
158             break;
159         }
160 
161         UnicodeSet      *inputSet             = usetNode->fInputSet;
162         int32_t          inputSetRangeCount   = inputSet->getRangeCount();
163         int              inputSetRangeIndex   = 0;
164                          rlRange              = fRangeList;
165 
166         for (;;) {
167             if (inputSetRangeIndex >= inputSetRangeCount) {
168                 break;
169             }
170             UChar32      inputSetRangeBegin  = inputSet->getRangeStart(inputSetRangeIndex);
171             UChar32      inputSetRangeEnd    = inputSet->getRangeEnd(inputSetRangeIndex);
172 
173             // skip over ranges from the range list that are completely
174             //   below the current range from the input unicode set.
175             while (rlRange->fEndChar < inputSetRangeBegin) {
176                 rlRange = rlRange->fNext;
177             }
178 
179             // If the start of the range from the range list is before with
180             //   the start of the range from the unicode set, split the range list range
181             //   in two, with one part being before (wholly outside of) the unicode set
182             //   and the other containing the rest.
183             //   Then continue the loop; the post-split current range will then be skipped
184             //     over
185             if (rlRange->fStartChar < inputSetRangeBegin) {
186                 rlRange->split(inputSetRangeBegin, *fStatus);
187                 if (U_FAILURE(*fStatus)) {
188                     return;
189                 }
190                 continue;
191             }
192 
193             // Same thing at the end of the ranges...
194             // If the end of the range from the range list doesn't coincide with
195             //   the end of the range from the unicode set, split the range list
196             //   range in two.  The first part of the split range will be
197             //   wholly inside the Unicode set.
198             if (rlRange->fEndChar > inputSetRangeEnd) {
199                 rlRange->split(inputSetRangeEnd+1, *fStatus);
200                 if (U_FAILURE(*fStatus)) {
201                     return;
202                 }
203             }
204 
205             // The current rlRange is now entirely within the UnicodeSet range.
206             // Add this unicode set to the list of sets for this rlRange
207             if (rlRange->fIncludesSets->indexOf(usetNode) == -1) {
208                 rlRange->fIncludesSets->addElement(usetNode, *fStatus);
209                 if (U_FAILURE(*fStatus)) {
210                     return;
211                 }
212             }
213 
214             // Advance over ranges that we are finished with.
215             if (inputSetRangeEnd == rlRange->fEndChar) {
216                 inputSetRangeIndex++;
217             }
218             rlRange = rlRange->fNext;
219         }
220     }
221 
222     if (fRB->fDebugEnv && uprv_strstr(fRB->fDebugEnv, "range")) { printRanges();}
223 
224     //
225     //  Group the above ranges, with each group consisting of one or more
226     //    ranges that are in exactly the same set of original UnicodeSets.
227     //    The groups are numbered, and these group numbers are the set of
228     //    input symbols recognized by the run-time state machine.
229     //
230     //    Numbering: # 0  (state table column 0) is unused.
231     //               # 1  is reserved - table column 1 is for end-of-input
232     //               # 2  is reserved - table column 2 is for beginning-in-input
233     //               # 3  is the first range list.
234     //
235     RangeDescriptor *rlSearchRange;
236     for (rlRange = fRangeList; rlRange!=0; rlRange=rlRange->fNext) {
237         for (rlSearchRange=fRangeList; rlSearchRange != rlRange; rlSearchRange=rlSearchRange->fNext) {
238             if (rlRange->fIncludesSets->equals(*rlSearchRange->fIncludesSets)) {
239                 rlRange->fNum = rlSearchRange->fNum;
240                 break;
241             }
242         }
243         if (rlRange->fNum == 0) {
244             fGroupCount ++;
245             rlRange->fNum = fGroupCount+2;
246             rlRange->setDictionaryFlag();
247             addValToSets(rlRange->fIncludesSets, fGroupCount+2);
248         }
249     }
250 
251     // Handle input sets that contain the special string {eof}.
252     //   Column 1 of the state table is reserved for EOF on input.
253     //   Column 2 is reserved for before-the-start-input.
254     //            (This column can be optimized away later if there are no rule
255     //             references to {bof}.)
256     //   Add this column value (1 or 2) to the equivalent expression
257     //     subtree for each UnicodeSet that contains the string {eof}
258     //   Because {bof} and {eof} are not a characters in the normal sense,
259     //   they doesn't affect the computation of ranges or TRIE.
260     static const UChar eofUString[] = {0x65, 0x6f, 0x66, 0};
261     static const UChar bofUString[] = {0x62, 0x6f, 0x66, 0};
262 
263     UnicodeString eofString(eofUString);
264     UnicodeString bofString(bofUString);
265     for (ni=0; ; ni++) {        // Loop over each of the UnicodeSets encountered in the input rules
266         usetNode = (RBBINode *)this->fRB->fUSetNodes->elementAt(ni);
267         if (usetNode==NULL) {
268             break;
269         }
270         UnicodeSet      *inputSet = usetNode->fInputSet;
271         if (inputSet->contains(eofString)) {
272             addValToSet(usetNode, 1);
273         }
274         if (inputSet->contains(bofString)) {
275             addValToSet(usetNode, 2);
276             fSawBOF = TRUE;
277         }
278     }
279 
280 
281     if (fRB->fDebugEnv && uprv_strstr(fRB->fDebugEnv, "rgroup")) {printRangeGroups();}
282     if (fRB->fDebugEnv && uprv_strstr(fRB->fDebugEnv, "esets")) {printSets();}
283 
284     //
285     // Build the Trie table for mapping UChar32 values to the corresponding
286     //   range group number
287     //
288     fTrie = utrie_open(NULL,    //  Pre-existing trie to be filled in
289                       NULL,    //  Data array  (utrie will allocate one)
290                       100000,  //  Max Data Length
291                       0,       //  Initial value for all code points
292                       0,       //  Lead surrogate unit value
293                       TRUE);   //  Keep Latin 1 in separately
294 
295 
296     for (rlRange = fRangeList; rlRange!=0; rlRange=rlRange->fNext) {
297         utrie_setRange32(fTrie, rlRange->fStartChar, rlRange->fEndChar+1, rlRange->fNum, TRUE);
298     }
299 }
300 
301 
302 
303 //-----------------------------------------------------------------------------------
304 //
305 //  getTrieSize()    Return the size that will be required to serialize the Trie.
306 //
307 //-----------------------------------------------------------------------------------
getTrieSize()308 int32_t RBBISetBuilder::getTrieSize() /*const*/ {
309     fTrieSize  = utrie_serialize(fTrie,
310                                     NULL,                // Buffer
311                                     0,                   // Capacity
312                                     getFoldedRBBIValue,
313                                     TRUE,                // Reduce to 16 bits
314                                     fStatus);
315     // RBBIDebugPrintf("Trie table size is %d\n", trieSize);
316     return fTrieSize;
317 }
318 
319 
320 //-----------------------------------------------------------------------------------
321 //
322 //  serializeTrie()   Put the serialized trie at the specified address.
323 //                    Trust the caller to have given us enough memory.
324 //                    getTrieSize() MUST be called first.
325 //
326 //-----------------------------------------------------------------------------------
serializeTrie(uint8_t * where)327 void RBBISetBuilder::serializeTrie(uint8_t *where) {
328     utrie_serialize(fTrie,
329                     where,                   // Buffer
330                     fTrieSize,               // Capacity
331                     getFoldedRBBIValue,
332                     TRUE,                    // Reduce to 16 bits
333                     fStatus);
334 }
335 
336 //------------------------------------------------------------------------
337 //
338 //  addValToSets     Add a runtime-mapped input value to each uset from a
339 //                   list of uset nodes. (val corresponds to a state table column.)
340 //                   For each of the original Unicode sets - which correspond
341 //                   directly to uset nodes - a logically equivalent expression
342 //                   is constructed in terms of the remapped runtime input
343 //                   symbol set.  This function adds one runtime input symbol to
344 //                   a list of sets.
345 //
346 //                   The "logically equivalent expression" is the tree for an
347 //                   or-ing together of all of the symbols that go into the set.
348 //
349 //------------------------------------------------------------------------
addValToSets(UVector * sets,uint32_t val)350 void  RBBISetBuilder::addValToSets(UVector *sets, uint32_t val) {
351     int32_t       ix;
352 
353     for (ix=0; ix<sets->size(); ix++) {
354         RBBINode *usetNode = (RBBINode *)sets->elementAt(ix);
355         addValToSet(usetNode, val);
356     }
357 }
358 
addValToSet(RBBINode * usetNode,uint32_t val)359 void  RBBISetBuilder::addValToSet(RBBINode *usetNode, uint32_t val) {
360     RBBINode *leafNode = new RBBINode(RBBINode::leafChar);
361     if (leafNode == NULL) {
362         *fStatus = U_MEMORY_ALLOCATION_ERROR;
363         return;
364     }
365     leafNode->fVal = (unsigned short)val;
366     if (usetNode->fLeftChild == NULL) {
367         usetNode->fLeftChild = leafNode;
368         leafNode->fParent    = usetNode;
369     } else {
370         // There are already input symbols present for this set.
371         // Set up an OR node, with the previous stuff as the left child
372         //   and the new value as the right child.
373         RBBINode *orNode = new RBBINode(RBBINode::opOr);
374         if (orNode == NULL) {
375             *fStatus = U_MEMORY_ALLOCATION_ERROR;
376             return;
377         }
378         orNode->fLeftChild  = usetNode->fLeftChild;
379         orNode->fRightChild = leafNode;
380         orNode->fLeftChild->fParent  = orNode;
381         orNode->fRightChild->fParent = orNode;
382         usetNode->fLeftChild = orNode;
383         orNode->fParent = usetNode;
384     }
385 }
386 
387 
388 //------------------------------------------------------------------------
389 //
390 //   getNumCharCategories
391 //
392 //------------------------------------------------------------------------
getNumCharCategories() const393 int32_t  RBBISetBuilder::getNumCharCategories() const {
394     return fGroupCount + 3;
395 }
396 
397 
398 //------------------------------------------------------------------------
399 //
400 //   sawBOF
401 //
402 //------------------------------------------------------------------------
sawBOF() const403 UBool  RBBISetBuilder::sawBOF() const {
404     return fSawBOF;
405 }
406 
407 
408 //------------------------------------------------------------------------
409 //
410 //   getFirstChar      Given a runtime RBBI character category, find
411 //                     the first UChar32 that is in the set of chars
412 //                     in the category.
413 //------------------------------------------------------------------------
getFirstChar(int32_t category) const414 UChar32  RBBISetBuilder::getFirstChar(int32_t category) const {
415     RangeDescriptor   *rlRange;
416     UChar32            retVal = (UChar32)-1;
417     for (rlRange = fRangeList; rlRange!=0; rlRange=rlRange->fNext) {
418         if (rlRange->fNum == category) {
419             retVal = rlRange->fStartChar;
420             break;
421         }
422     }
423     return retVal;
424 }
425 
426 
427 
428 //------------------------------------------------------------------------
429 //
430 //   printRanges        A debugging function.
431 //                      dump out all of the range definitions.
432 //
433 //------------------------------------------------------------------------
434 #ifdef RBBI_DEBUG
printRanges()435 void RBBISetBuilder::printRanges() {
436     RangeDescriptor       *rlRange;
437     int                    i;
438 
439     RBBIDebugPrintf("\n\n Nonoverlapping Ranges ...\n");
440     for (rlRange = fRangeList; rlRange!=0; rlRange=rlRange->fNext) {
441         RBBIDebugPrintf("%2i  %4x-%4x  ", rlRange->fNum, rlRange->fStartChar, rlRange->fEndChar);
442 
443         for (i=0; i<rlRange->fIncludesSets->size(); i++) {
444             RBBINode       *usetNode    = (RBBINode *)rlRange->fIncludesSets->elementAt(i);
445             UnicodeString   setName = UNICODE_STRING("anon", 4);
446             RBBINode       *setRef = usetNode->fParent;
447             if (setRef != NULL) {
448                 RBBINode *varRef = setRef->fParent;
449                 if (varRef != NULL  &&  varRef->fType == RBBINode::varRef) {
450                     setName = varRef->fText;
451                 }
452             }
453             RBBI_DEBUG_printUnicodeString(setName); RBBIDebugPrintf("  ");
454         }
455         RBBIDebugPrintf("\n");
456     }
457 }
458 #endif
459 
460 
461 //------------------------------------------------------------------------
462 //
463 //   printRangeGroups     A debugging function.
464 //                        dump out all of the range groups.
465 //
466 //------------------------------------------------------------------------
467 #ifdef RBBI_DEBUG
printRangeGroups()468 void RBBISetBuilder::printRangeGroups() {
469     RangeDescriptor       *rlRange;
470     RangeDescriptor       *tRange;
471     int                    i;
472     int                    lastPrintedGroupNum = 0;
473 
474     RBBIDebugPrintf("\nRanges grouped by Unicode Set Membership...\n");
475     for (rlRange = fRangeList; rlRange!=0; rlRange=rlRange->fNext) {
476         int groupNum = rlRange->fNum & 0xbfff;
477         if (groupNum > lastPrintedGroupNum) {
478             lastPrintedGroupNum = groupNum;
479             RBBIDebugPrintf("%2i  ", groupNum);
480 
481             if (rlRange->fNum & 0x4000) { RBBIDebugPrintf(" <DICT> ");}
482 
483             for (i=0; i<rlRange->fIncludesSets->size(); i++) {
484                 RBBINode       *usetNode    = (RBBINode *)rlRange->fIncludesSets->elementAt(i);
485                 UnicodeString   setName = UNICODE_STRING("anon", 4);
486                 RBBINode       *setRef = usetNode->fParent;
487                 if (setRef != NULL) {
488                     RBBINode *varRef = setRef->fParent;
489                     if (varRef != NULL  &&  varRef->fType == RBBINode::varRef) {
490                         setName = varRef->fText;
491                     }
492                 }
493                 RBBI_DEBUG_printUnicodeString(setName); RBBIDebugPrintf(" ");
494             }
495 
496             i = 0;
497             for (tRange = rlRange; tRange != 0; tRange = tRange->fNext) {
498                 if (tRange->fNum == rlRange->fNum) {
499                     if (i++ % 5 == 0) {
500                         RBBIDebugPrintf("\n    ");
501                     }
502                     RBBIDebugPrintf("  %05x-%05x", tRange->fStartChar, tRange->fEndChar);
503                 }
504             }
505             RBBIDebugPrintf("\n");
506         }
507     }
508     RBBIDebugPrintf("\n");
509 }
510 #endif
511 
512 
513 //------------------------------------------------------------------------
514 //
515 //   printSets          A debugging function.
516 //                      dump out all of the set definitions.
517 //
518 //------------------------------------------------------------------------
519 #ifdef RBBI_DEBUG
printSets()520 void RBBISetBuilder::printSets() {
521     int                   i;
522 
523     RBBIDebugPrintf("\n\nUnicode Sets List\n------------------\n");
524     for (i=0; ; i++) {
525         RBBINode        *usetNode;
526         RBBINode        *setRef;
527         RBBINode        *varRef;
528         UnicodeString    setName;
529 
530         usetNode = (RBBINode *)fRB->fUSetNodes->elementAt(i);
531         if (usetNode == NULL) {
532             break;
533         }
534 
535         RBBIDebugPrintf("%3d    ", i);
536         setName = UNICODE_STRING("anonymous", 9);
537         setRef = usetNode->fParent;
538         if (setRef != NULL) {
539             varRef = setRef->fParent;
540             if (varRef != NULL  &&  varRef->fType == RBBINode::varRef) {
541                 setName = varRef->fText;
542             }
543         }
544         RBBI_DEBUG_printUnicodeString(setName);
545         RBBIDebugPrintf("   ");
546         RBBI_DEBUG_printUnicodeString(usetNode->fText);
547         RBBIDebugPrintf("\n");
548         if (usetNode->fLeftChild != NULL) {
549             usetNode->fLeftChild->printTree(TRUE);
550         }
551     }
552     RBBIDebugPrintf("\n");
553 }
554 #endif
555 
556 
557 
558 //-------------------------------------------------------------------------------------
559 //
560 //  RangeDescriptor copy constructor
561 //
562 //-------------------------------------------------------------------------------------
563 
RangeDescriptor(const RangeDescriptor & other,UErrorCode & status)564 RangeDescriptor::RangeDescriptor(const RangeDescriptor &other, UErrorCode &status) {
565     int  i;
566 
567     this->fStartChar    = other.fStartChar;
568     this->fEndChar      = other.fEndChar;
569     this->fNum          = other.fNum;
570     this->fNext         = NULL;
571     UErrorCode oldstatus = status;
572     this->fIncludesSets = new UVector(status);
573     if (U_FAILURE(oldstatus)) {
574         status = oldstatus;
575     }
576     if (U_FAILURE(status)) {
577         return;
578     }
579     /* test for NULL */
580     if (this->fIncludesSets == 0) {
581         status = U_MEMORY_ALLOCATION_ERROR;
582         return;
583     }
584 
585     for (i=0; i<other.fIncludesSets->size(); i++) {
586         this->fIncludesSets->addElement(other.fIncludesSets->elementAt(i), status);
587     }
588 }
589 
590 
591 //-------------------------------------------------------------------------------------
592 //
593 //  RangeDesriptor default constructor
594 //
595 //-------------------------------------------------------------------------------------
RangeDescriptor(UErrorCode & status)596 RangeDescriptor::RangeDescriptor(UErrorCode &status) {
597     this->fStartChar    = 0;
598     this->fEndChar      = 0;
599     this->fNum          = 0;
600     this->fNext         = NULL;
601     UErrorCode oldstatus = status;
602     this->fIncludesSets = new UVector(status);
603     if (U_FAILURE(oldstatus)) {
604         status = oldstatus;
605     }
606     if (U_FAILURE(status)) {
607         return;
608     }
609     /* test for NULL */
610     if(this->fIncludesSets == 0) {
611         status = U_MEMORY_ALLOCATION_ERROR;
612         return;
613     }
614 
615 }
616 
617 
618 //-------------------------------------------------------------------------------------
619 //
620 //  RangeDesriptor Destructor
621 //
622 //-------------------------------------------------------------------------------------
~RangeDescriptor()623 RangeDescriptor::~RangeDescriptor() {
624     delete  fIncludesSets;
625     fIncludesSets = NULL;
626 }
627 
628 //-------------------------------------------------------------------------------------
629 //
630 //  RangeDesriptor::split()
631 //
632 //-------------------------------------------------------------------------------------
split(UChar32 where,UErrorCode & status)633 void RangeDescriptor::split(UChar32 where, UErrorCode &status) {
634     U_ASSERT(where>fStartChar && where<=fEndChar);
635     RangeDescriptor *nr = new RangeDescriptor(*this, status);
636     if(nr == 0) {
637         status = U_MEMORY_ALLOCATION_ERROR;
638         return;
639     }
640     if (U_FAILURE(status)) {
641         delete nr;
642         return;
643     }
644     //  RangeDescriptor copy constructor copies all fields.
645     //  Only need to update those that are different after the split.
646     nr->fStartChar = where;
647     this->fEndChar = where-1;
648     nr->fNext      = this->fNext;
649     this->fNext    = nr;
650 }
651 
652 
653 //-------------------------------------------------------------------------------------
654 //
655 //   RangeDescriptor::setDictionaryFlag
656 //
657 //            Character Category Numbers that include characters from
658 //            the original Unicode Set named "dictionary" have bit 14
659 //            set to 1.  The RBBI runtime engine uses this to trigger
660 //            use of the word dictionary.
661 //
662 //            This function looks through the Unicode Sets that it
663 //            (the range) includes, and sets the bit in fNum when
664 //            "dictionary" is among them.
665 //
666 //            TODO:  a faster way would be to find the set node for
667 //                   "dictionary" just once, rather than looking it
668 //                   up by name every time.
669 //
670 //-------------------------------------------------------------------------------------
setDictionaryFlag()671 void RangeDescriptor::setDictionaryFlag() {
672     int i;
673 
674     for (i=0; i<this->fIncludesSets->size(); i++) {
675         RBBINode       *usetNode    = (RBBINode *)fIncludesSets->elementAt(i);
676         UnicodeString   setName;
677         RBBINode       *setRef = usetNode->fParent;
678         if (setRef != NULL) {
679             RBBINode *varRef = setRef->fParent;
680             if (varRef != NULL  &&  varRef->fType == RBBINode::varRef) {
681                 setName = varRef->fText;
682             }
683         }
684         if (setName.compare(UNICODE_STRING("dictionary", 10)) == 0) {   // TODO:  no string literals.
685             this->fNum |= 0x4000;
686             break;
687         }
688     }
689 }
690 
691 
692 
693 U_NAMESPACE_END
694 
695 #endif /* #if !UCONFIG_NO_BREAK_ITERATION */
696