1 /*
2 **********************************************************************
3 * Copyright (C) 1999-2007, International Business Machines
4 * Corporation and others. All Rights Reserved.
5 **********************************************************************
6 * Date Name Description
7 * 10/20/99 alan Creation.
8 **********************************************************************
9 */
10
11 #include "unicode/utypes.h"
12 #include "unicode/uniset.h"
13 #include "unicode/parsepos.h"
14 #include "unicode/symtable.h"
15 #include "ruleiter.h"
16 #include "cmemory.h"
17 #include "cstring.h"
18 #include "uhash.h"
19 #include "util.h"
20 #include "uvector.h"
21 #include "charstr.h"
22 #include "ustrfmt.h"
23 #include "uassert.h"
24 #include "hash.h"
25 #include "bmpset.h"
26 #include "unisetspan.h"
27
28 // Define UChar constants using hex for EBCDIC compatibility
29 // Used #define to reduce private static exports and memory access time.
30 #define SET_OPEN ((UChar)0x005B) /*[*/
31 #define SET_CLOSE ((UChar)0x005D) /*]*/
32 #define HYPHEN ((UChar)0x002D) /*-*/
33 #define COMPLEMENT ((UChar)0x005E) /*^*/
34 #define COLON ((UChar)0x003A) /*:*/
35 #define BACKSLASH ((UChar)0x005C) /*\*/
36 #define INTERSECTION ((UChar)0x0026) /*&*/
37 #define UPPER_U ((UChar)0x0055) /*U*/
38 #define LOWER_U ((UChar)0x0075) /*u*/
39 #define OPEN_BRACE ((UChar)123) /*{*/
40 #define CLOSE_BRACE ((UChar)125) /*}*/
41 #define UPPER_P ((UChar)0x0050) /*P*/
42 #define LOWER_P ((UChar)0x0070) /*p*/
43 #define UPPER_N ((UChar)78) /*N*/
44 #define EQUALS ((UChar)0x003D) /*=*/
45
46 // HIGH_VALUE > all valid values. 110000 for codepoints
47 #define UNICODESET_HIGH 0x0110000
48
49 // LOW <= all valid values. ZERO for codepoints
50 #define UNICODESET_LOW 0x000000
51
52 // initial storage. Must be >= 0
53 #define START_EXTRA 16
54
55 // extra amount for growth. Must be >= 0
56 #define GROW_EXTRA START_EXTRA
57
58 U_NAMESPACE_BEGIN
59
~SymbolTable()60 SymbolTable::~SymbolTable() {}
61
UOBJECT_DEFINE_RTTI_IMPLEMENTATION(UnicodeSet)62 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(UnicodeSet)
63
64 /**
65 * Modify the given UChar32 variable so that it is in range, by
66 * pinning values < UNICODESET_LOW to UNICODESET_LOW, and
67 * pinning values > UNICODESET_HIGH-1 to UNICODESET_HIGH-1.
68 * It modifies its argument in-place and also returns it.
69 */
70 static inline UChar32 pinCodePoint(UChar32& c) {
71 if (c < UNICODESET_LOW) {
72 c = UNICODESET_LOW;
73 } else if (c > (UNICODESET_HIGH-1)) {
74 c = (UNICODESET_HIGH-1);
75 }
76 return c;
77 }
78
79 //----------------------------------------------------------------
80 // Debugging
81 //----------------------------------------------------------------
82
83 // DO NOT DELETE THIS CODE. This code is used to debug memory leaks.
84 // To enable the debugging, define the symbol DEBUG_MEM in the line
85 // below. This will result in text being sent to stdout that looks
86 // like this:
87 // DEBUG UnicodeSet: ct 0x00A39B20; 397 [\u0A81-\u0A83\u0A85-
88 // DEBUG UnicodeSet: dt 0x00A39B20; 396 [\u0A81-\u0A83\u0A85-
89 // Each line lists a construction (ct) or destruction (dt) event, the
90 // object address, the number of outstanding objects after the event,
91 // and the pattern of the object in question.
92
93 // #define DEBUG_MEM
94
95 #ifdef DEBUG_MEM
96 #include <stdio.h>
97 static int32_t _dbgCount = 0;
98
_dbgct(UnicodeSet * set)99 static inline void _dbgct(UnicodeSet* set) {
100 UnicodeString str;
101 set->toPattern(str, TRUE);
102 char buf[40];
103 str.extract(0, 39, buf, "");
104 printf("DEBUG UnicodeSet: ct 0x%08X; %d %s\n", set, ++_dbgCount, buf);
105 }
106
_dbgdt(UnicodeSet * set)107 static inline void _dbgdt(UnicodeSet* set) {
108 UnicodeString str;
109 set->toPattern(str, TRUE);
110 char buf[40];
111 str.extract(0, 39, buf, "");
112 printf("DEBUG UnicodeSet: dt 0x%08X; %d %s\n", set, --_dbgCount, buf);
113 }
114
115 #else
116
117 #define _dbgct(set)
118 #define _dbgdt(set)
119
120 #endif
121
122 //----------------------------------------------------------------
123 // UnicodeString in UVector support
124 //----------------------------------------------------------------
125
cloneUnicodeString(UHashTok * dst,UHashTok * src)126 static void U_CALLCONV cloneUnicodeString(UHashTok *dst, UHashTok *src) {
127 dst->pointer = new UnicodeString(*(UnicodeString*)src->pointer);
128 }
129
compareUnicodeString(UHashTok t1,UHashTok t2)130 static int8_t U_CALLCONV compareUnicodeString(UHashTok t1, UHashTok t2) {
131 const UnicodeString &a = *(const UnicodeString*)t1.pointer;
132 const UnicodeString &b = *(const UnicodeString*)t2.pointer;
133 return a.compare(b);
134 }
135
136 //----------------------------------------------------------------
137 // Constructors &c
138 //----------------------------------------------------------------
139
140 /**
141 * Constructs an empty set.
142 */
UnicodeSet()143 UnicodeSet::UnicodeSet() :
144 len(1), capacity(1 + START_EXTRA), list(0), bmpSet(0), buffer(0),
145 bufferCapacity(0), patLen(0), pat(NULL), strings(NULL), stringSpan(NULL)
146 {
147 list = (UChar32*) uprv_malloc(sizeof(UChar32) * capacity);
148 if(list!=NULL){
149 list[0] = UNICODESET_HIGH;
150 }
151 UErrorCode status = U_ZERO_ERROR;
152 allocateStrings(status);
153 _dbgct(this);
154 }
155
156 /**
157 * Constructs a set containing the given range. If <code>end >
158 * start</code> then an empty set is created.
159 *
160 * @param start first character, inclusive, of range
161 * @param end last character, inclusive, of range
162 */
UnicodeSet(UChar32 start,UChar32 end)163 UnicodeSet::UnicodeSet(UChar32 start, UChar32 end) :
164 len(1), capacity(1 + START_EXTRA), list(0), bmpSet(0), buffer(0),
165 bufferCapacity(0), patLen(0), pat(NULL), strings(NULL), stringSpan(NULL)
166 {
167 list = (UChar32*) uprv_malloc(sizeof(UChar32) * capacity);
168 if(list!=NULL){
169 UErrorCode status = U_ZERO_ERROR;
170
171 list[0] = UNICODESET_HIGH;
172 allocateStrings(status);
173 complement(start, end);
174 }
175 _dbgct(this);
176 }
177
178 /**
179 * Constructs a set that is identical to the given UnicodeSet.
180 */
UnicodeSet(const UnicodeSet & o)181 UnicodeSet::UnicodeSet(const UnicodeSet& o) :
182 UnicodeFilter(o),
183 len(0), capacity(o.isFrozen() ? o.len : o.len + GROW_EXTRA), list(0),
184 bmpSet(0),
185 buffer(0), bufferCapacity(0),
186 patLen(0), pat(NULL), strings(NULL), stringSpan(NULL)
187 {
188 list = (UChar32*) uprv_malloc(sizeof(UChar32) * capacity);
189 if(list!=NULL){
190 UErrorCode status = U_ZERO_ERROR;
191 allocateStrings(status);
192 *this = o;
193 }
194 _dbgct(this);
195 }
196
197 // Copy-construct as thawed.
UnicodeSet(const UnicodeSet & o,UBool)198 UnicodeSet::UnicodeSet(const UnicodeSet& o, UBool /* asThawed */) :
199 UnicodeFilter(o),
200 len(0), capacity(o.len + GROW_EXTRA), list(0),
201 bmpSet(0),
202 buffer(0), bufferCapacity(0),
203 patLen(0), pat(NULL), strings(NULL), stringSpan(NULL)
204 {
205 list = (UChar32*) uprv_malloc(sizeof(UChar32) * capacity);
206 if(list!=NULL){
207 UErrorCode status = U_ZERO_ERROR;
208 allocateStrings(status);
209 // *this = o except for bmpSet and stringSpan
210 len = o.len;
211 uprv_memcpy(list, o.list, len*sizeof(UChar32));
212 strings->assign(*o.strings, cloneUnicodeString, status);
213 if (o.pat) {
214 setPattern(UnicodeString(o.pat, o.patLen));
215 }
216 }
217 _dbgct(this);
218 }
219
220 /**
221 * Destructs the set.
222 */
~UnicodeSet()223 UnicodeSet::~UnicodeSet() {
224 _dbgdt(this); // first!
225 uprv_free(list);
226 delete bmpSet;
227 if (buffer) {
228 uprv_free(buffer);
229 }
230 delete strings;
231 delete stringSpan;
232 releasePattern();
233 }
234
235 /**
236 * Assigns this object to be a copy of another.
237 */
operator =(const UnicodeSet & o)238 UnicodeSet& UnicodeSet::operator=(const UnicodeSet& o) {
239 if (this == &o) {
240 return *this;
241 }
242 if (isFrozen()) {
243 return *this;
244 }
245 ensureCapacity(o.len);
246 len = o.len;
247 uprv_memcpy(list, o.list, len*sizeof(UChar32));
248 if (o.bmpSet == NULL) {
249 bmpSet = NULL;
250 } else {
251 bmpSet = new BMPSet(*o.bmpSet, list, len);
252 }
253 UErrorCode ec = U_ZERO_ERROR;
254 strings->assign(*o.strings, cloneUnicodeString, ec);
255 if (o.stringSpan == NULL) {
256 stringSpan = NULL;
257 } else {
258 stringSpan = new UnicodeSetStringSpan(*o.stringSpan, *strings);
259 }
260 releasePattern();
261 if (o.pat) {
262 setPattern(UnicodeString(o.pat, o.patLen));
263 }
264 return *this;
265 }
266
267 /**
268 * Returns a copy of this object. All UnicodeMatcher objects have
269 * to support cloning in order to allow classes using
270 * UnicodeMatchers, such as Transliterator, to implement cloning.
271 */
clone() const272 UnicodeFunctor* UnicodeSet::clone() const {
273 return new UnicodeSet(*this);
274 }
275
cloneAsThawed() const276 UnicodeFunctor *UnicodeSet::cloneAsThawed() const {
277 return new UnicodeSet(*this, TRUE);
278 }
279
280 /**
281 * Compares the specified object with this set for equality. Returns
282 * <tt>true</tt> if the two sets
283 * have the same size, and every member of the specified set is
284 * contained in this set (or equivalently, every member of this set is
285 * contained in the specified set).
286 *
287 * @param o set to be compared for equality with this set.
288 * @return <tt>true</tt> if the specified set is equal to this set.
289 */
operator ==(const UnicodeSet & o) const290 UBool UnicodeSet::operator==(const UnicodeSet& o) const {
291 if (len != o.len) return FALSE;
292 for (int32_t i = 0; i < len; ++i) {
293 if (list[i] != o.list[i]) return FALSE;
294 }
295 if (*strings != *o.strings) return FALSE;
296 return TRUE;
297 }
298
299 /**
300 * Returns the hash code value for this set.
301 *
302 * @return the hash code value for this set.
303 * @see Object#hashCode()
304 */
hashCode(void) const305 int32_t UnicodeSet::hashCode(void) const {
306 int32_t result = len;
307 for (int32_t i = 0; i < len; ++i) {
308 result *= 1000003;
309 result += list[i];
310 }
311 return result;
312 }
313
314 //----------------------------------------------------------------
315 // Public API
316 //----------------------------------------------------------------
317
318 /**
319 * Returns the number of elements in this set (its cardinality),
320 * Note than the elements of a set may include both individual
321 * codepoints and strings.
322 *
323 * @return the number of elements in this set (its cardinality).
324 */
size(void) const325 int32_t UnicodeSet::size(void) const {
326 int32_t n = 0;
327 int32_t count = getRangeCount();
328 for (int32_t i = 0; i < count; ++i) {
329 n += getRangeEnd(i) - getRangeStart(i) + 1;
330 }
331 return n + strings->size();
332 }
333
334 /**
335 * Returns <tt>true</tt> if this set contains no elements.
336 *
337 * @return <tt>true</tt> if this set contains no elements.
338 */
isEmpty(void) const339 UBool UnicodeSet::isEmpty(void) const {
340 return len == 1 && strings->size() == 0;
341 }
342
343 /**
344 * Returns true if this set contains the given character.
345 * @param c character to be checked for containment
346 * @return true if the test condition is met
347 */
contains(UChar32 c) const348 UBool UnicodeSet::contains(UChar32 c) const {
349 // Set i to the index of the start item greater than ch
350 // We know we will terminate without length test!
351 // LATER: for large sets, add binary search
352 //int32_t i = -1;
353 //for (;;) {
354 // if (c < list[++i]) break;
355 //}
356 if (bmpSet != NULL) {
357 return bmpSet->contains(c);
358 }
359 if (stringSpan != NULL) {
360 return stringSpan->contains(c);
361 }
362 if (c >= UNICODESET_HIGH) { // Don't need to check LOW bound
363 return FALSE;
364 }
365 int32_t i = findCodePoint(c);
366 return (UBool)(i & 1); // return true if odd
367 }
368
369 /**
370 * Returns the smallest value i such that c < list[i]. Caller
371 * must ensure that c is a legal value or this method will enter
372 * an infinite loop. This method performs a binary search.
373 * @param c a character in the range MIN_VALUE..MAX_VALUE
374 * inclusive
375 * @return the smallest integer i in the range 0..len-1,
376 * inclusive, such that c < list[i]
377 */
findCodePoint(UChar32 c) const378 int32_t UnicodeSet::findCodePoint(UChar32 c) const {
379 /* Examples:
380 findCodePoint(c)
381 set list[] c=0 1 3 4 7 8
382 === ============== ===========
383 [] [110000] 0 0 0 0 0 0
384 [\u0000-\u0003] [0, 4, 110000] 1 1 1 2 2 2
385 [\u0004-\u0007] [4, 8, 110000] 0 0 0 1 1 2
386 [:Any:] [0, 110000] 1 1 1 1 1 1
387 */
388
389 // Return the smallest i such that c < list[i]. Assume
390 // list[len - 1] == HIGH and that c is legal (0..HIGH-1).
391 if (c < list[0])
392 return 0;
393 // High runner test. c is often after the last range, so an
394 // initial check for this condition pays off.
395 int32_t lo = 0;
396 int32_t hi = len - 1;
397 if (lo >= hi || c >= list[hi-1])
398 return hi;
399 // invariant: c >= list[lo]
400 // invariant: c < list[hi]
401 for (;;) {
402 int32_t i = (lo + hi) >> 1;
403 if (i == lo) {
404 break; // Found!
405 } else if (c < list[i]) {
406 hi = i;
407 } else {
408 lo = i;
409 }
410 }
411 return hi;
412 }
413
414 /**
415 * Returns true if this set contains every character
416 * of the given range.
417 * @param start first character, inclusive, of the range
418 * @param end last character, inclusive, of the range
419 * @return true if the test condition is met
420 */
contains(UChar32 start,UChar32 end) const421 UBool UnicodeSet::contains(UChar32 start, UChar32 end) const {
422 //int32_t i = -1;
423 //for (;;) {
424 // if (start < list[++i]) break;
425 //}
426 int32_t i = findCodePoint(start);
427 return ((i & 1) != 0 && end < list[i]);
428 }
429
430 /**
431 * Returns <tt>true</tt> if this set contains the given
432 * multicharacter string.
433 * @param s string to be checked for containment
434 * @return <tt>true</tt> if this set contains the specified string
435 */
contains(const UnicodeString & s) const436 UBool UnicodeSet::contains(const UnicodeString& s) const {
437 if (s.length() == 0) return FALSE;
438 int32_t cp = getSingleCP(s);
439 if (cp < 0) {
440 return strings->contains((void*) &s);
441 } else {
442 return contains((UChar32) cp);
443 }
444 }
445
446 /**
447 * Returns true if this set contains all the characters and strings
448 * of the given set.
449 * @param c set to be checked for containment
450 * @return true if the test condition is met
451 */
containsAll(const UnicodeSet & c) const452 UBool UnicodeSet::containsAll(const UnicodeSet& c) const {
453 // The specified set is a subset if all of its pairs are contained in
454 // this set. It's possible to code this more efficiently in terms of
455 // direct manipulation of the inversion lists if the need arises.
456 int32_t n = c.getRangeCount();
457 for (int i=0; i<n; ++i) {
458 if (!contains(c.getRangeStart(i), c.getRangeEnd(i))) {
459 return FALSE;
460 }
461 }
462 if (!strings->containsAll(*c.strings)) return FALSE;
463 return TRUE;
464 }
465
466 /**
467 * Returns true if this set contains all the characters
468 * of the given string.
469 * @param s string containing characters to be checked for containment
470 * @return true if the test condition is met
471 */
containsAll(const UnicodeString & s) const472 UBool UnicodeSet::containsAll(const UnicodeString& s) const {
473 return (UBool)(span(s.getBuffer(), s.length(), USET_SPAN_CONTAINED) ==
474 s.length());
475 }
476
477 /**
478 * Returns true if this set contains none of the characters
479 * of the given range.
480 * @param start first character, inclusive, of the range
481 * @param end last character, inclusive, of the range
482 * @return true if the test condition is met
483 */
containsNone(UChar32 start,UChar32 end) const484 UBool UnicodeSet::containsNone(UChar32 start, UChar32 end) const {
485 //int32_t i = -1;
486 //for (;;) {
487 // if (start < list[++i]) break;
488 //}
489 int32_t i = findCodePoint(start);
490 return ((i & 1) == 0 && end < list[i]);
491 }
492
493 /**
494 * Returns true if this set contains none of the characters and strings
495 * of the given set.
496 * @param c set to be checked for containment
497 * @return true if the test condition is met
498 */
containsNone(const UnicodeSet & c) const499 UBool UnicodeSet::containsNone(const UnicodeSet& c) const {
500 // The specified set is a subset if all of its pairs are contained in
501 // this set. It's possible to code this more efficiently in terms of
502 // direct manipulation of the inversion lists if the need arises.
503 int32_t n = c.getRangeCount();
504 for (int32_t i=0; i<n; ++i) {
505 if (!containsNone(c.getRangeStart(i), c.getRangeEnd(i))) {
506 return FALSE;
507 }
508 }
509 if (!strings->containsNone(*c.strings)) return FALSE;
510 return TRUE;
511 }
512
513 /**
514 * Returns true if this set contains none of the characters
515 * of the given string.
516 * @param s string containing characters to be checked for containment
517 * @return true if the test condition is met
518 */
containsNone(const UnicodeString & s) const519 UBool UnicodeSet::containsNone(const UnicodeString& s) const {
520 return (UBool)(span(s.getBuffer(), s.length(), USET_SPAN_NOT_CONTAINED) ==
521 s.length());
522 }
523
524 /**
525 * Returns <tt>true</tt> if this set contains any character whose low byte
526 * is the given value. This is used by <tt>RuleBasedTransliterator</tt> for
527 * indexing.
528 */
matchesIndexValue(uint8_t v) const529 UBool UnicodeSet::matchesIndexValue(uint8_t v) const {
530 /* The index value v, in the range [0,255], is contained in this set if
531 * it is contained in any pair of this set. Pairs either have the high
532 * bytes equal, or unequal. If the high bytes are equal, then we have
533 * aaxx..aayy, where aa is the high byte. Then v is contained if xx <=
534 * v <= yy. If the high bytes are unequal we have aaxx..bbyy, bb>aa.
535 * Then v is contained if xx <= v || v <= yy. (This is identical to the
536 * time zone month containment logic.)
537 */
538 int32_t i;
539 int32_t rangeCount=getRangeCount();
540 for (i=0; i<rangeCount; ++i) {
541 UChar32 low = getRangeStart(i);
542 UChar32 high = getRangeEnd(i);
543 if ((low & ~0xFF) == (high & ~0xFF)) {
544 if ((low & 0xFF) <= v && v <= (high & 0xFF)) {
545 return TRUE;
546 }
547 } else if ((low & 0xFF) <= v || v <= (high & 0xFF)) {
548 return TRUE;
549 }
550 }
551 if (strings->size() != 0) {
552 for (i=0; i<strings->size(); ++i) {
553 const UnicodeString& s = *(const UnicodeString*)strings->elementAt(i);
554 //if (s.length() == 0) {
555 // // Empty strings match everything
556 // return TRUE;
557 //}
558 // assert(s.length() != 0); // We enforce this elsewhere
559 UChar32 c = s.char32At(0);
560 if ((c & 0xFF) == v) {
561 return TRUE;
562 }
563 }
564 }
565 return FALSE;
566 }
567
568 /**
569 * Implementation of UnicodeMatcher::matches(). Always matches the
570 * longest possible multichar string.
571 */
matches(const Replaceable & text,int32_t & offset,int32_t limit,UBool incremental)572 UMatchDegree UnicodeSet::matches(const Replaceable& text,
573 int32_t& offset,
574 int32_t limit,
575 UBool incremental) {
576 if (offset == limit) {
577 // Strings, if any, have length != 0, so we don't worry
578 // about them here. If we ever allow zero-length strings
579 // we much check for them here.
580 if (contains(U_ETHER)) {
581 return incremental ? U_PARTIAL_MATCH : U_MATCH;
582 } else {
583 return U_MISMATCH;
584 }
585 } else {
586 if (strings->size() != 0) { // try strings first
587
588 // might separate forward and backward loops later
589 // for now they are combined
590
591 // TODO Improve efficiency of this, at least in the forward
592 // direction, if not in both. In the forward direction we
593 // can assume the strings are sorted.
594
595 int32_t i;
596 UBool forward = offset < limit;
597
598 // firstChar is the leftmost char to match in the
599 // forward direction or the rightmost char to match in
600 // the reverse direction.
601 UChar firstChar = text.charAt(offset);
602
603 // If there are multiple strings that can match we
604 // return the longest match.
605 int32_t highWaterLength = 0;
606
607 for (i=0; i<strings->size(); ++i) {
608 const UnicodeString& trial = *(const UnicodeString*)strings->elementAt(i);
609
610 //if (trial.length() == 0) {
611 // return U_MATCH; // null-string always matches
612 //}
613 // assert(trial.length() != 0); // We ensure this elsewhere
614
615 UChar c = trial.charAt(forward ? 0 : trial.length() - 1);
616
617 // Strings are sorted, so we can optimize in the
618 // forward direction.
619 if (forward && c > firstChar) break;
620 if (c != firstChar) continue;
621
622 int32_t matchLen = matchRest(text, offset, limit, trial);
623
624 if (incremental) {
625 int32_t maxLen = forward ? limit-offset : offset-limit;
626 if (matchLen == maxLen) {
627 // We have successfully matched but only up to limit.
628 return U_PARTIAL_MATCH;
629 }
630 }
631
632 if (matchLen == trial.length()) {
633 // We have successfully matched the whole string.
634 if (matchLen > highWaterLength) {
635 highWaterLength = matchLen;
636 }
637 // In the forward direction we know strings
638 // are sorted so we can bail early.
639 if (forward && matchLen < highWaterLength) {
640 break;
641 }
642 continue;
643 }
644 }
645
646 // We've checked all strings without a partial match.
647 // If we have full matches, return the longest one.
648 if (highWaterLength != 0) {
649 offset += forward ? highWaterLength : -highWaterLength;
650 return U_MATCH;
651 }
652 }
653 return UnicodeFilter::matches(text, offset, limit, incremental);
654 }
655 }
656
657 /**
658 * Returns the longest match for s in text at the given position.
659 * If limit > start then match forward from start+1 to limit
660 * matching all characters except s.charAt(0). If limit < start,
661 * go backward starting from start-1 matching all characters
662 * except s.charAt(s.length()-1). This method assumes that the
663 * first character, text.charAt(start), matches s, so it does not
664 * check it.
665 * @param text the text to match
666 * @param start the first character to match. In the forward
667 * direction, text.charAt(start) is matched against s.charAt(0).
668 * In the reverse direction, it is matched against
669 * s.charAt(s.length()-1).
670 * @param limit the limit offset for matching, either last+1 in
671 * the forward direction, or last-1 in the reverse direction,
672 * where last is the index of the last character to match.
673 * @return If part of s matches up to the limit, return |limit -
674 * start|. If all of s matches before reaching the limit, return
675 * s.length(). If there is a mismatch between s and text, return
676 * 0
677 */
matchRest(const Replaceable & text,int32_t start,int32_t limit,const UnicodeString & s)678 int32_t UnicodeSet::matchRest(const Replaceable& text,
679 int32_t start, int32_t limit,
680 const UnicodeString& s) {
681 int32_t i;
682 int32_t maxLen;
683 int32_t slen = s.length();
684 if (start < limit) {
685 maxLen = limit - start;
686 if (maxLen > slen) maxLen = slen;
687 for (i = 1; i < maxLen; ++i) {
688 if (text.charAt(start + i) != s.charAt(i)) return 0;
689 }
690 } else {
691 maxLen = start - limit;
692 if (maxLen > slen) maxLen = slen;
693 --slen; // <=> slen = s.length() - 1;
694 for (i = 1; i < maxLen; ++i) {
695 if (text.charAt(start - i) != s.charAt(slen - i)) return 0;
696 }
697 }
698 return maxLen;
699 }
700
701 /**
702 * Implement of UnicodeMatcher
703 */
addMatchSetTo(UnicodeSet & toUnionTo) const704 void UnicodeSet::addMatchSetTo(UnicodeSet& toUnionTo) const {
705 toUnionTo.addAll(*this);
706 }
707
708 /**
709 * Returns the index of the given character within this set, where
710 * the set is ordered by ascending code point. If the character
711 * is not in this set, return -1. The inverse of this method is
712 * <code>charAt()</code>.
713 * @return an index from 0..size()-1, or -1
714 */
indexOf(UChar32 c) const715 int32_t UnicodeSet::indexOf(UChar32 c) const {
716 if (c < MIN_VALUE || c > MAX_VALUE) {
717 return -1;
718 }
719 int32_t i = 0;
720 int32_t n = 0;
721 for (;;) {
722 UChar32 start = list[i++];
723 if (c < start) {
724 return -1;
725 }
726 UChar32 limit = list[i++];
727 if (c < limit) {
728 return n + c - start;
729 }
730 n += limit - start;
731 }
732 }
733
734 /**
735 * Returns the character at the given index within this set, where
736 * the set is ordered by ascending code point. If the index is
737 * out of range, return (UChar32)-1. The inverse of this method is
738 * <code>indexOf()</code>.
739 * @param index an index from 0..size()-1
740 * @return the character at the given index, or (UChar32)-1.
741 */
charAt(int32_t index) const742 UChar32 UnicodeSet::charAt(int32_t index) const {
743 if (index >= 0) {
744 // len2 is the largest even integer <= len, that is, it is len
745 // for even values and len-1 for odd values. With odd values
746 // the last entry is UNICODESET_HIGH.
747 int32_t len2 = len & ~1;
748 for (int32_t i=0; i < len2;) {
749 UChar32 start = list[i++];
750 int32_t count = list[i++] - start;
751 if (index < count) {
752 return (UChar32)(start + index);
753 }
754 index -= count;
755 }
756 }
757 return (UChar32)-1;
758 }
759
760 /**
761 * Make this object represent the range <code>start - end</code>.
762 * If <code>end > start</code> then this object is set to an
763 * an empty range.
764 *
765 * @param start first character in the set, inclusive
766 * @rparam end last character in the set, inclusive
767 */
set(UChar32 start,UChar32 end)768 UnicodeSet& UnicodeSet::set(UChar32 start, UChar32 end) {
769 clear();
770 complement(start, end);
771 return *this;
772 }
773
774 /**
775 * Adds the specified range to this set if it is not already
776 * present. If this set already contains the specified range,
777 * the call leaves this set unchanged. If <code>end > start</code>
778 * then an empty range is added, leaving the set unchanged.
779 *
780 * @param start first character, inclusive, of range to be added
781 * to this set.
782 * @param end last character, inclusive, of range to be added
783 * to this set.
784 */
add(UChar32 start,UChar32 end)785 UnicodeSet& UnicodeSet::add(UChar32 start, UChar32 end) {
786 if (pinCodePoint(start) < pinCodePoint(end)) {
787 UChar32 range[3] = { start, end+1, UNICODESET_HIGH };
788 add(range, 2, 0);
789 } else if (start == end) {
790 add(start);
791 }
792 return *this;
793 }
794
795 // #define DEBUG_US_ADD
796
797 #ifdef DEBUG_US_ADD
798 #include <stdio.h>
dump(UChar32 c)799 void dump(UChar32 c) {
800 if (c <= 0xFF) {
801 printf("%c", (char)c);
802 } else {
803 printf("U+%04X", c);
804 }
805 }
dump(const UChar32 * list,int32_t len)806 void dump(const UChar32* list, int32_t len) {
807 printf("[");
808 for (int32_t i=0; i<len; ++i) {
809 if (i != 0) printf(", ");
810 dump(list[i]);
811 }
812 printf("]");
813 }
814 #endif
815
816 /**
817 * Adds the specified character to this set if it is not already
818 * present. If this set already contains the specified character,
819 * the call leaves this set unchanged.
820 */
add(UChar32 c)821 UnicodeSet& UnicodeSet::add(UChar32 c) {
822 // find smallest i such that c < list[i]
823 // if odd, then it is IN the set
824 // if even, then it is OUT of the set
825 int32_t i = findCodePoint(pinCodePoint(c));
826
827 // already in set?
828 if ((i & 1) != 0 || isFrozen()) return *this;
829
830 // HIGH is 0x110000
831 // assert(list[len-1] == HIGH);
832
833 // empty = [HIGH]
834 // [start_0, limit_0, start_1, limit_1, HIGH]
835
836 // [..., start_k-1, limit_k-1, start_k, limit_k, ..., HIGH]
837 // ^
838 // list[i]
839
840 // i == 0 means c is before the first range
841
842 #ifdef DEBUG_US_ADD
843 printf("Add of ");
844 dump(c);
845 printf(" found at %d", i);
846 printf(": ");
847 dump(list, len);
848 printf(" => ");
849 #endif
850
851 if (c == list[i]-1) {
852 // c is before start of next range
853 list[i] = c;
854 // if we touched the HIGH mark, then add a new one
855 if (c == (UNICODESET_HIGH - 1)) {
856 ensureCapacity(len+1);
857 list[len++] = UNICODESET_HIGH;
858 }
859 if (i > 0 && c == list[i-1]) {
860 // collapse adjacent ranges
861
862 // [..., start_k-1, c, c, limit_k, ..., HIGH]
863 // ^
864 // list[i]
865
866 //for (int32_t k=i-1; k<len-2; ++k) {
867 // list[k] = list[k+2];
868 //}
869 UChar32* dst = list + i - 1;
870 UChar32* src = dst + 2;
871 UChar32* srclimit = list + len;
872 while (src < srclimit) *(dst++) = *(src++);
873
874 len -= 2;
875 }
876 }
877
878 else if (i > 0 && c == list[i-1]) {
879 // c is after end of prior range
880 list[i-1]++;
881 // no need to check for collapse here
882 }
883
884 else {
885 // At this point we know the new char is not adjacent to
886 // any existing ranges, and it is not 10FFFF.
887
888
889 // [..., start_k-1, limit_k-1, start_k, limit_k, ..., HIGH]
890 // ^
891 // list[i]
892
893 // [..., start_k-1, limit_k-1, c, c+1, start_k, limit_k, ..., HIGH]
894 // ^
895 // list[i]
896
897 ensureCapacity(len+2);
898
899 //for (int32_t k=len-1; k>=i; --k) {
900 // list[k+2] = list[k];
901 //}
902 UChar32* src = list + len;
903 UChar32* dst = src + 2;
904 UChar32* srclimit = list + i;
905 while (src > srclimit) *(--dst) = *(--src);
906
907 list[i] = c;
908 list[i+1] = c+1;
909 len += 2;
910 }
911
912 #ifdef DEBUG_US_ADD
913 dump(list, len);
914 printf("\n");
915
916 for (i=1; i<len; ++i) {
917 if (list[i] <= list[i-1]) {
918 // Corrupt array!
919 printf("ERROR: list has been corrupted\n");
920 exit(1);
921 }
922 }
923 #endif
924
925 releasePattern();
926 return *this;
927 }
928
929 /**
930 * Adds the specified multicharacter to this set if it is not already
931 * present. If this set already contains the multicharacter,
932 * the call leaves this set unchanged.
933 * Thus "ch" => {"ch"}
934 * <br><b>Warning: you cannot add an empty string ("") to a UnicodeSet.</b>
935 * @param s the source string
936 * @return the modified set, for chaining
937 */
add(const UnicodeString & s)938 UnicodeSet& UnicodeSet::add(const UnicodeString& s) {
939 if (s.length() == 0 || isFrozen()) return *this;
940 int32_t cp = getSingleCP(s);
941 if (cp < 0) {
942 if (!strings->contains((void*) &s)) {
943 _add(s);
944 releasePattern();
945 }
946 } else {
947 add((UChar32)cp);
948 }
949 return *this;
950 }
951
952 /**
953 * Adds the given string, in order, to 'strings'. The given string
954 * must have been checked by the caller to not be empty and to not
955 * already be in 'strings'.
956 */
_add(const UnicodeString & s)957 void UnicodeSet::_add(const UnicodeString& s) {
958 if (isFrozen()) {
959 return;
960 }
961 UnicodeString* t = new UnicodeString(s);
962 UErrorCode ec = U_ZERO_ERROR;
963 strings->sortedInsert(t, compareUnicodeString, ec);
964 }
965
966 /**
967 * @return a code point IF the string consists of a single one.
968 * otherwise returns -1.
969 * @param string to test
970 */
getSingleCP(const UnicodeString & s)971 int32_t UnicodeSet::getSingleCP(const UnicodeString& s) {
972 //if (s.length() < 1) {
973 // throw new IllegalArgumentException("Can't use zero-length strings in UnicodeSet");
974 //}
975 if (s.length() > 2) return -1;
976 if (s.length() == 1) return s.charAt(0);
977
978 // at this point, len = 2
979 UChar32 cp = s.char32At(0);
980 if (cp > 0xFFFF) { // is surrogate pair
981 return cp;
982 }
983 return -1;
984 }
985
986 /**
987 * Adds each of the characters in this string to the set. Thus "ch" => {"c", "h"}
988 * If this set already any particular character, it has no effect on that character.
989 * @param the source string
990 * @return the modified set, for chaining
991 */
addAll(const UnicodeString & s)992 UnicodeSet& UnicodeSet::addAll(const UnicodeString& s) {
993 UChar32 cp;
994 for (int32_t i = 0; i < s.length(); i += UTF_CHAR_LENGTH(cp)) {
995 cp = s.char32At(i);
996 add(cp);
997 }
998 return *this;
999 }
1000
1001 /**
1002 * Retains EACH of the characters in this string. Note: "ch" == {"c", "h"}
1003 * If this set already any particular character, it has no effect on that character.
1004 * @param the source string
1005 * @return the modified set, for chaining
1006 */
retainAll(const UnicodeString & s)1007 UnicodeSet& UnicodeSet::retainAll(const UnicodeString& s) {
1008 UnicodeSet set;
1009 set.addAll(s);
1010 retainAll(set);
1011 return *this;
1012 }
1013
1014 /**
1015 * Complement EACH of the characters in this string. Note: "ch" == {"c", "h"}
1016 * If this set already any particular character, it has no effect on that character.
1017 * @param the source string
1018 * @return the modified set, for chaining
1019 */
complementAll(const UnicodeString & s)1020 UnicodeSet& UnicodeSet::complementAll(const UnicodeString& s) {
1021 UnicodeSet set;
1022 set.addAll(s);
1023 complementAll(set);
1024 return *this;
1025 }
1026
1027 /**
1028 * Remove EACH of the characters in this string. Note: "ch" == {"c", "h"}
1029 * If this set already any particular character, it has no effect on that character.
1030 * @param the source string
1031 * @return the modified set, for chaining
1032 */
removeAll(const UnicodeString & s)1033 UnicodeSet& UnicodeSet::removeAll(const UnicodeString& s) {
1034 UnicodeSet set;
1035 set.addAll(s);
1036 removeAll(set);
1037 return *this;
1038 }
1039
removeAllStrings()1040 UnicodeSet& UnicodeSet::removeAllStrings() {
1041 strings->removeAllElements();
1042 return *this;
1043 }
1044
1045
1046 /**
1047 * Makes a set from a multicharacter string. Thus "ch" => {"ch"}
1048 * <br><b>Warning: you cannot add an empty string ("") to a UnicodeSet.</b>
1049 * @param the source string
1050 * @return a newly created set containing the given string
1051 */
createFrom(const UnicodeString & s)1052 UnicodeSet* U_EXPORT2 UnicodeSet::createFrom(const UnicodeString& s) {
1053 UnicodeSet *set = new UnicodeSet();
1054 set->add(s);
1055 return set;
1056 }
1057
1058
1059 /**
1060 * Makes a set from each of the characters in the string. Thus "ch" => {"c", "h"}
1061 * @param the source string
1062 * @return a newly created set containing the given characters
1063 */
createFromAll(const UnicodeString & s)1064 UnicodeSet* U_EXPORT2 UnicodeSet::createFromAll(const UnicodeString& s) {
1065 UnicodeSet *set = new UnicodeSet();
1066 set->addAll(s);
1067 return set;
1068 }
1069
1070 /**
1071 * Retain only the elements in this set that are contained in the
1072 * specified range. If <code>end > start</code> then an empty range is
1073 * retained, leaving the set empty.
1074 *
1075 * @param start first character, inclusive, of range to be retained
1076 * to this set.
1077 * @param end last character, inclusive, of range to be retained
1078 * to this set.
1079 */
retain(UChar32 start,UChar32 end)1080 UnicodeSet& UnicodeSet::retain(UChar32 start, UChar32 end) {
1081 if (pinCodePoint(start) <= pinCodePoint(end)) {
1082 UChar32 range[3] = { start, end+1, UNICODESET_HIGH };
1083 retain(range, 2, 0);
1084 } else {
1085 clear();
1086 }
1087 return *this;
1088 }
1089
retain(UChar32 c)1090 UnicodeSet& UnicodeSet::retain(UChar32 c) {
1091 return retain(c, c);
1092 }
1093
1094 /**
1095 * Removes the specified range from this set if it is present.
1096 * The set will not contain the specified range once the call
1097 * returns. If <code>end > start</code> then an empty range is
1098 * removed, leaving the set unchanged.
1099 *
1100 * @param start first character, inclusive, of range to be removed
1101 * from this set.
1102 * @param end last character, inclusive, of range to be removed
1103 * from this set.
1104 */
remove(UChar32 start,UChar32 end)1105 UnicodeSet& UnicodeSet::remove(UChar32 start, UChar32 end) {
1106 if (pinCodePoint(start) <= pinCodePoint(end)) {
1107 UChar32 range[3] = { start, end+1, UNICODESET_HIGH };
1108 retain(range, 2, 2);
1109 }
1110 return *this;
1111 }
1112
1113 /**
1114 * Removes the specified character from this set if it is present.
1115 * The set will not contain the specified range once the call
1116 * returns.
1117 */
remove(UChar32 c)1118 UnicodeSet& UnicodeSet::remove(UChar32 c) {
1119 return remove(c, c);
1120 }
1121
1122 /**
1123 * Removes the specified string from this set if it is present.
1124 * The set will not contain the specified character once the call
1125 * returns.
1126 * @param the source string
1127 * @return the modified set, for chaining
1128 */
remove(const UnicodeString & s)1129 UnicodeSet& UnicodeSet::remove(const UnicodeString& s) {
1130 if (s.length() == 0 || isFrozen()) return *this;
1131 int32_t cp = getSingleCP(s);
1132 if (cp < 0) {
1133 strings->removeElement((void*) &s);
1134 releasePattern();
1135 } else {
1136 remove((UChar32)cp, (UChar32)cp);
1137 }
1138 return *this;
1139 }
1140
1141 /**
1142 * Complements the specified range in this set. Any character in
1143 * the range will be removed if it is in this set, or will be
1144 * added if it is not in this set. If <code>end > start</code>
1145 * then an empty range is xor'ed, leaving the set unchanged.
1146 *
1147 * @param start first character, inclusive, of range to be removed
1148 * from this set.
1149 * @param end last character, inclusive, of range to be removed
1150 * from this set.
1151 */
complement(UChar32 start,UChar32 end)1152 UnicodeSet& UnicodeSet::complement(UChar32 start, UChar32 end) {
1153 if (isFrozen()) {
1154 return *this;
1155 }
1156 if (pinCodePoint(start) <= pinCodePoint(end)) {
1157 UChar32 range[3] = { start, end+1, UNICODESET_HIGH };
1158 exclusiveOr(range, 2, 0);
1159 }
1160 releasePattern();
1161 return *this;
1162 }
1163
complement(UChar32 c)1164 UnicodeSet& UnicodeSet::complement(UChar32 c) {
1165 return complement(c, c);
1166 }
1167
1168 /**
1169 * This is equivalent to
1170 * <code>complement(MIN_VALUE, MAX_VALUE)</code>.
1171 */
complement(void)1172 UnicodeSet& UnicodeSet::complement(void) {
1173 if (isFrozen()) {
1174 return *this;
1175 }
1176 if (list[0] == UNICODESET_LOW) {
1177 ensureBufferCapacity(len-1);
1178 uprv_memcpy(buffer, list + 1, (len-1)*sizeof(UChar32));
1179 --len;
1180 } else {
1181 ensureBufferCapacity(len+1);
1182 uprv_memcpy(buffer + 1, list, len*sizeof(UChar32));
1183 buffer[0] = UNICODESET_LOW;
1184 ++len;
1185 }
1186 swapBuffers();
1187 releasePattern();
1188 return *this;
1189 }
1190
1191 /**
1192 * Complement the specified string in this set.
1193 * The set will not contain the specified string once the call
1194 * returns.
1195 * <br><b>Warning: you cannot add an empty string ("") to a UnicodeSet.</b>
1196 * @param s the string to complement
1197 * @return this object, for chaining
1198 */
complement(const UnicodeString & s)1199 UnicodeSet& UnicodeSet::complement(const UnicodeString& s) {
1200 if (s.length() == 0 || isFrozen()) return *this;
1201 int32_t cp = getSingleCP(s);
1202 if (cp < 0) {
1203 if (strings->contains((void*) &s)) {
1204 strings->removeElement((void*) &s);
1205 } else {
1206 _add(s);
1207 }
1208 releasePattern();
1209 } else {
1210 complement((UChar32)cp, (UChar32)cp);
1211 }
1212 return *this;
1213 }
1214
1215 /**
1216 * Adds all of the elements in the specified set to this set if
1217 * they're not already present. This operation effectively
1218 * modifies this set so that its value is the <i>union</i> of the two
1219 * sets. The behavior of this operation is unspecified if the specified
1220 * collection is modified while the operation is in progress.
1221 *
1222 * @param c set whose elements are to be added to this set.
1223 * @see #add(char, char)
1224 */
addAll(const UnicodeSet & c)1225 UnicodeSet& UnicodeSet::addAll(const UnicodeSet& c) {
1226 add(c.list, c.len, 0);
1227
1228 // Add strings in order
1229 for (int32_t i=0; i<c.strings->size(); ++i) {
1230 const UnicodeString* s = (const UnicodeString*)c.strings->elementAt(i);
1231 if (!strings->contains((void*) s)) {
1232 _add(*s);
1233 }
1234 }
1235 return *this;
1236 }
1237
1238 /**
1239 * Retains only the elements in this set that are contained in the
1240 * specified set. In other words, removes from this set all of
1241 * its elements that are not contained in the specified set. This
1242 * operation effectively modifies this set so that its value is
1243 * the <i>intersection</i> of the two sets.
1244 *
1245 * @param c set that defines which elements this set will retain.
1246 */
retainAll(const UnicodeSet & c)1247 UnicodeSet& UnicodeSet::retainAll(const UnicodeSet& c) {
1248 if (isFrozen()) {
1249 return *this;
1250 }
1251 retain(c.list, c.len, 0);
1252 strings->retainAll(*c.strings);
1253 return *this;
1254 }
1255
1256 /**
1257 * Removes from this set all of its elements that are contained in the
1258 * specified set. This operation effectively modifies this
1259 * set so that its value is the <i>asymmetric set difference</i> of
1260 * the two sets.
1261 *
1262 * @param c set that defines which elements will be removed from
1263 * this set.
1264 */
removeAll(const UnicodeSet & c)1265 UnicodeSet& UnicodeSet::removeAll(const UnicodeSet& c) {
1266 if (isFrozen()) {
1267 return *this;
1268 }
1269 retain(c.list, c.len, 2);
1270 strings->removeAll(*c.strings);
1271 return *this;
1272 }
1273
1274 /**
1275 * Complements in this set all elements contained in the specified
1276 * set. Any character in the other set will be removed if it is
1277 * in this set, or will be added if it is not in this set.
1278 *
1279 * @param c set that defines which elements will be xor'ed from
1280 * this set.
1281 */
complementAll(const UnicodeSet & c)1282 UnicodeSet& UnicodeSet::complementAll(const UnicodeSet& c) {
1283 if (isFrozen()) {
1284 return *this;
1285 }
1286 exclusiveOr(c.list, c.len, 0);
1287
1288 for (int32_t i=0; i<c.strings->size(); ++i) {
1289 void* e = c.strings->elementAt(i);
1290 if (!strings->removeElement(e)) {
1291 _add(*(const UnicodeString*)e);
1292 }
1293 }
1294 return *this;
1295 }
1296
1297 /**
1298 * Removes all of the elements from this set. This set will be
1299 * empty after this call returns.
1300 */
clear(void)1301 UnicodeSet& UnicodeSet::clear(void) {
1302 if (isFrozen()) {
1303 return *this;
1304 }
1305 list[0] = UNICODESET_HIGH;
1306 len = 1;
1307 releasePattern();
1308 strings->removeAllElements();
1309 return *this;
1310 }
1311
1312 /**
1313 * Iteration method that returns the number of ranges contained in
1314 * this set.
1315 * @see #getRangeStart
1316 * @see #getRangeEnd
1317 */
getRangeCount() const1318 int32_t UnicodeSet::getRangeCount() const {
1319 return len/2;
1320 }
1321
1322 /**
1323 * Iteration method that returns the first character in the
1324 * specified range of this set.
1325 * @see #getRangeCount
1326 * @see #getRangeEnd
1327 */
getRangeStart(int32_t index) const1328 UChar32 UnicodeSet::getRangeStart(int32_t index) const {
1329 return list[index*2];
1330 }
1331
1332 /**
1333 * Iteration method that returns the last character in the
1334 * specified range of this set.
1335 * @see #getRangeStart
1336 * @see #getRangeEnd
1337 */
getRangeEnd(int32_t index) const1338 UChar32 UnicodeSet::getRangeEnd(int32_t index) const {
1339 return list[index*2 + 1] - 1;
1340 }
1341
getStringCount() const1342 int32_t UnicodeSet::getStringCount() const {
1343 return strings->size();
1344 }
1345
getString(int32_t index) const1346 const UnicodeString* UnicodeSet::getString(int32_t index) const {
1347 return (const UnicodeString*) strings->elementAt(index);
1348 }
1349
1350 /**
1351 * Reallocate this objects internal structures to take up the least
1352 * possible space, without changing this object's value.
1353 */
compact()1354 UnicodeSet& UnicodeSet::compact() {
1355 if (isFrozen()) {
1356 return *this;
1357 }
1358 // Delete buffer first to defragment memory less.
1359 if (buffer != NULL) {
1360 uprv_free(buffer);
1361 buffer = NULL;
1362 }
1363 if (len < capacity) {
1364 // Make the capacity equal to len or 1.
1365 // We don't want to realloc of 0 size.
1366 capacity = len + (len == 0);
1367 list = (UChar32*) uprv_realloc(list, sizeof(UChar32) * capacity);
1368 }
1369 return *this;
1370 }
1371
serialize(uint16_t * dest,int32_t destCapacity,UErrorCode & ec) const1372 int32_t UnicodeSet::serialize(uint16_t *dest, int32_t destCapacity, UErrorCode& ec) const {
1373 int32_t bmpLength, length, destLength;
1374
1375 if (U_FAILURE(ec)) {
1376 return 0;
1377 }
1378
1379 if (destCapacity<0 || (destCapacity>0 && dest==NULL)) {
1380 ec=U_ILLEGAL_ARGUMENT_ERROR;
1381 return 0;
1382 }
1383
1384 /* count necessary 16-bit units */
1385 length=this->len-1; // Subtract 1 to ignore final UNICODESET_HIGH
1386 // assert(length>=0);
1387 if (length==0) {
1388 /* empty set */
1389 if (destCapacity>0) {
1390 *dest=0;
1391 } else {
1392 ec=U_BUFFER_OVERFLOW_ERROR;
1393 }
1394 return 1;
1395 }
1396 /* now length>0 */
1397
1398 if (this->list[length-1]<=0xffff) {
1399 /* all BMP */
1400 bmpLength=length;
1401 } else if (this->list[0]>=0x10000) {
1402 /* all supplementary */
1403 bmpLength=0;
1404 length*=2;
1405 } else {
1406 /* some BMP, some supplementary */
1407 for (bmpLength=0; bmpLength<length && this->list[bmpLength]<=0xffff; ++bmpLength) {}
1408 length=bmpLength+2*(length-bmpLength);
1409 }
1410
1411 /* length: number of 16-bit array units */
1412 if (length>0x7fff) {
1413 /* there are only 15 bits for the length in the first serialized word */
1414 ec=U_INDEX_OUTOFBOUNDS_ERROR;
1415 return 0;
1416 }
1417
1418 /*
1419 * total serialized length:
1420 * number of 16-bit array units (length) +
1421 * 1 length unit (always) +
1422 * 1 bmpLength unit (if there are supplementary values)
1423 */
1424 destLength=length+((length>bmpLength)?2:1);
1425 if (destLength<=destCapacity) {
1426 const UChar32 *p;
1427 int32_t i;
1428
1429 *dest=(uint16_t)length;
1430 if (length>bmpLength) {
1431 *dest|=0x8000;
1432 *++dest=(uint16_t)bmpLength;
1433 }
1434 ++dest;
1435
1436 /* write the BMP part of the array */
1437 p=this->list;
1438 for (i=0; i<bmpLength; ++i) {
1439 *dest++=(uint16_t)*p++;
1440 }
1441
1442 /* write the supplementary part of the array */
1443 for (; i<length; i+=2) {
1444 *dest++=(uint16_t)(*p>>16);
1445 *dest++=(uint16_t)*p++;
1446 }
1447 } else {
1448 ec=U_BUFFER_OVERFLOW_ERROR;
1449 }
1450 return destLength;
1451 }
1452
1453 //----------------------------------------------------------------
1454 // Implementation: Utility methods
1455 //----------------------------------------------------------------
1456
1457 /**
1458 * Allocate our strings vector and return TRUE if successful.
1459 */
allocateStrings(UErrorCode & status)1460 UBool UnicodeSet::allocateStrings(UErrorCode &status) {
1461 if (U_FAILURE(status)) {
1462 return FALSE;
1463 }
1464 strings = new UVector(uhash_deleteUnicodeString,
1465 uhash_compareUnicodeString, 1, status);
1466 if (U_FAILURE(status)) {
1467 delete strings;
1468 strings = NULL;
1469 return FALSE;
1470 }
1471 return TRUE;
1472 }
1473
ensureCapacity(int32_t newLen)1474 void UnicodeSet::ensureCapacity(int32_t newLen) {
1475 if (newLen <= capacity)
1476 return;
1477 capacity = newLen + GROW_EXTRA;
1478 UChar32* temp = (UChar32*) uprv_malloc(sizeof(UChar32) * capacity);
1479 uprv_memcpy(temp, list, len*sizeof(UChar32));
1480 uprv_free(list);
1481 list = temp;
1482 }
1483
ensureBufferCapacity(int32_t newLen)1484 void UnicodeSet::ensureBufferCapacity(int32_t newLen) {
1485 if (buffer != NULL && newLen <= bufferCapacity)
1486 return;
1487 if (buffer) {
1488 uprv_free(buffer);
1489 }
1490 bufferCapacity = newLen + GROW_EXTRA;
1491 buffer = (UChar32*) uprv_malloc(sizeof(UChar32) * bufferCapacity);
1492 }
1493
1494 /**
1495 * Swap list and buffer.
1496 */
swapBuffers(void)1497 void UnicodeSet::swapBuffers(void) {
1498 // swap list and buffer
1499 UChar32* temp = list;
1500 list = buffer;
1501 buffer = temp;
1502
1503 int32_t c = capacity;
1504 capacity = bufferCapacity;
1505 bufferCapacity = c;
1506 }
1507
1508 //----------------------------------------------------------------
1509 // Implementation: Fundamental operators
1510 //----------------------------------------------------------------
1511
max(UChar32 a,UChar32 b)1512 static inline UChar32 max(UChar32 a, UChar32 b) {
1513 return (a > b) ? a : b;
1514 }
1515
1516 // polarity = 0, 3 is normal: x xor y
1517 // polarity = 1, 2: x xor ~y == x === y
1518
exclusiveOr(const UChar32 * other,int32_t otherLen,int8_t polarity)1519 void UnicodeSet::exclusiveOr(const UChar32* other, int32_t otherLen, int8_t polarity) {
1520 if (isFrozen()) {
1521 return;
1522 }
1523 ensureBufferCapacity(len + otherLen);
1524 int32_t i = 0, j = 0, k = 0;
1525 UChar32 a = list[i++];
1526 UChar32 b;
1527 if (polarity == 1 || polarity == 2) {
1528 b = UNICODESET_LOW;
1529 if (other[j] == UNICODESET_LOW) { // skip base if already LOW
1530 ++j;
1531 b = other[j];
1532 }
1533 } else {
1534 b = other[j++];
1535 }
1536 // simplest of all the routines
1537 // sort the values, discarding identicals!
1538 for (;;) {
1539 if (a < b) {
1540 buffer[k++] = a;
1541 a = list[i++];
1542 } else if (b < a) {
1543 buffer[k++] = b;
1544 b = other[j++];
1545 } else if (a != UNICODESET_HIGH) { // at this point, a == b
1546 // discard both values!
1547 a = list[i++];
1548 b = other[j++];
1549 } else { // DONE!
1550 buffer[k++] = UNICODESET_HIGH;
1551 len = k;
1552 break;
1553 }
1554 }
1555 swapBuffers();
1556 releasePattern();
1557 }
1558
1559 // polarity = 0 is normal: x union y
1560 // polarity = 2: x union ~y
1561 // polarity = 1: ~x union y
1562 // polarity = 3: ~x union ~y
1563
add(const UChar32 * other,int32_t otherLen,int8_t polarity)1564 void UnicodeSet::add(const UChar32* other, int32_t otherLen, int8_t polarity) {
1565 if (isFrozen()) {
1566 return;
1567 }
1568 ensureBufferCapacity(len + otherLen);
1569 int32_t i = 0, j = 0, k = 0;
1570 UChar32 a = list[i++];
1571 UChar32 b = other[j++];
1572 // change from xor is that we have to check overlapping pairs
1573 // polarity bit 1 means a is second, bit 2 means b is.
1574 for (;;) {
1575 switch (polarity) {
1576 case 0: // both first; take lower if unequal
1577 if (a < b) { // take a
1578 // Back up over overlapping ranges in buffer[]
1579 if (k > 0 && a <= buffer[k-1]) {
1580 // Pick latter end value in buffer[] vs. list[]
1581 a = max(list[i], buffer[--k]);
1582 } else {
1583 // No overlap
1584 buffer[k++] = a;
1585 a = list[i];
1586 }
1587 i++; // Common if/else code factored out
1588 polarity ^= 1;
1589 } else if (b < a) { // take b
1590 if (k > 0 && b <= buffer[k-1]) {
1591 b = max(other[j], buffer[--k]);
1592 } else {
1593 buffer[k++] = b;
1594 b = other[j];
1595 }
1596 j++;
1597 polarity ^= 2;
1598 } else { // a == b, take a, drop b
1599 if (a == UNICODESET_HIGH) goto loop_end;
1600 // This is symmetrical; it doesn't matter if
1601 // we backtrack with a or b. - liu
1602 if (k > 0 && a <= buffer[k-1]) {
1603 a = max(list[i], buffer[--k]);
1604 } else {
1605 // No overlap
1606 buffer[k++] = a;
1607 a = list[i];
1608 }
1609 i++;
1610 polarity ^= 1;
1611 b = other[j++];
1612 polarity ^= 2;
1613 }
1614 break;
1615 case 3: // both second; take higher if unequal, and drop other
1616 if (b <= a) { // take a
1617 if (a == UNICODESET_HIGH) goto loop_end;
1618 buffer[k++] = a;
1619 } else { // take b
1620 if (b == UNICODESET_HIGH) goto loop_end;
1621 buffer[k++] = b;
1622 }
1623 a = list[i++];
1624 polarity ^= 1; // factored common code
1625 b = other[j++];
1626 polarity ^= 2;
1627 break;
1628 case 1: // a second, b first; if b < a, overlap
1629 if (a < b) { // no overlap, take a
1630 buffer[k++] = a; a = list[i++]; polarity ^= 1;
1631 } else if (b < a) { // OVERLAP, drop b
1632 b = other[j++];
1633 polarity ^= 2;
1634 } else { // a == b, drop both!
1635 if (a == UNICODESET_HIGH) goto loop_end;
1636 a = list[i++];
1637 polarity ^= 1;
1638 b = other[j++];
1639 polarity ^= 2;
1640 }
1641 break;
1642 case 2: // a first, b second; if a < b, overlap
1643 if (b < a) { // no overlap, take b
1644 buffer[k++] = b;
1645 b = other[j++];
1646 polarity ^= 2;
1647 } else if (a < b) { // OVERLAP, drop a
1648 a = list[i++];
1649 polarity ^= 1;
1650 } else { // a == b, drop both!
1651 if (a == UNICODESET_HIGH) goto loop_end;
1652 a = list[i++];
1653 polarity ^= 1;
1654 b = other[j++];
1655 polarity ^= 2;
1656 }
1657 break;
1658 }
1659 }
1660 loop_end:
1661 buffer[k++] = UNICODESET_HIGH; // terminate
1662 len = k;
1663 swapBuffers();
1664 releasePattern();
1665 }
1666
1667 // polarity = 0 is normal: x intersect y
1668 // polarity = 2: x intersect ~y == set-minus
1669 // polarity = 1: ~x intersect y
1670 // polarity = 3: ~x intersect ~y
1671
retain(const UChar32 * other,int32_t otherLen,int8_t polarity)1672 void UnicodeSet::retain(const UChar32* other, int32_t otherLen, int8_t polarity) {
1673 if (isFrozen()) {
1674 return;
1675 }
1676 ensureBufferCapacity(len + otherLen);
1677 int32_t i = 0, j = 0, k = 0;
1678 UChar32 a = list[i++];
1679 UChar32 b = other[j++];
1680 // change from xor is that we have to check overlapping pairs
1681 // polarity bit 1 means a is second, bit 2 means b is.
1682 for (;;) {
1683 switch (polarity) {
1684 case 0: // both first; drop the smaller
1685 if (a < b) { // drop a
1686 a = list[i++];
1687 polarity ^= 1;
1688 } else if (b < a) { // drop b
1689 b = other[j++];
1690 polarity ^= 2;
1691 } else { // a == b, take one, drop other
1692 if (a == UNICODESET_HIGH) goto loop_end;
1693 buffer[k++] = a;
1694 a = list[i++];
1695 polarity ^= 1;
1696 b = other[j++];
1697 polarity ^= 2;
1698 }
1699 break;
1700 case 3: // both second; take lower if unequal
1701 if (a < b) { // take a
1702 buffer[k++] = a;
1703 a = list[i++];
1704 polarity ^= 1;
1705 } else if (b < a) { // take b
1706 buffer[k++] = b;
1707 b = other[j++];
1708 polarity ^= 2;
1709 } else { // a == b, take one, drop other
1710 if (a == UNICODESET_HIGH) goto loop_end;
1711 buffer[k++] = a;
1712 a = list[i++];
1713 polarity ^= 1;
1714 b = other[j++];
1715 polarity ^= 2;
1716 }
1717 break;
1718 case 1: // a second, b first;
1719 if (a < b) { // NO OVERLAP, drop a
1720 a = list[i++];
1721 polarity ^= 1;
1722 } else if (b < a) { // OVERLAP, take b
1723 buffer[k++] = b;
1724 b = other[j++];
1725 polarity ^= 2;
1726 } else { // a == b, drop both!
1727 if (a == UNICODESET_HIGH) goto loop_end;
1728 a = list[i++];
1729 polarity ^= 1;
1730 b = other[j++];
1731 polarity ^= 2;
1732 }
1733 break;
1734 case 2: // a first, b second; if a < b, overlap
1735 if (b < a) { // no overlap, drop b
1736 b = other[j++];
1737 polarity ^= 2;
1738 } else if (a < b) { // OVERLAP, take a
1739 buffer[k++] = a;
1740 a = list[i++];
1741 polarity ^= 1;
1742 } else { // a == b, drop both!
1743 if (a == UNICODESET_HIGH) goto loop_end;
1744 a = list[i++];
1745 polarity ^= 1;
1746 b = other[j++];
1747 polarity ^= 2;
1748 }
1749 break;
1750 }
1751 }
1752 loop_end:
1753 buffer[k++] = UNICODESET_HIGH; // terminate
1754 len = k;
1755 swapBuffers();
1756 releasePattern();
1757 }
1758
1759 /**
1760 * Append the <code>toPattern()</code> representation of a
1761 * string to the given <code>StringBuffer</code>.
1762 */
_appendToPat(UnicodeString & buf,const UnicodeString & s,UBool escapeUnprintable)1763 void UnicodeSet::_appendToPat(UnicodeString& buf, const UnicodeString& s, UBool
1764 escapeUnprintable) {
1765 UChar32 cp;
1766 for (int32_t i = 0; i < s.length(); i += UTF_CHAR_LENGTH(cp)) {
1767 _appendToPat(buf, cp = s.char32At(i), escapeUnprintable);
1768 }
1769 }
1770
1771 /**
1772 * Append the <code>toPattern()</code> representation of a
1773 * character to the given <code>StringBuffer</code>.
1774 */
_appendToPat(UnicodeString & buf,UChar32 c,UBool escapeUnprintable)1775 void UnicodeSet::_appendToPat(UnicodeString& buf, UChar32 c, UBool
1776 escapeUnprintable) {
1777 if (escapeUnprintable && ICU_Utility::isUnprintable(c)) {
1778 // Use hex escape notation (\uxxxx or \Uxxxxxxxx) for anything
1779 // unprintable
1780 if (ICU_Utility::escapeUnprintable(buf, c)) {
1781 return;
1782 }
1783 }
1784 // Okay to let ':' pass through
1785 switch (c) {
1786 case SET_OPEN:
1787 case SET_CLOSE:
1788 case HYPHEN:
1789 case COMPLEMENT:
1790 case INTERSECTION:
1791 case BACKSLASH:
1792 case OPEN_BRACE:
1793 case CLOSE_BRACE:
1794 case COLON:
1795 case SymbolTable::SYMBOL_REF:
1796 buf.append(BACKSLASH);
1797 break;
1798 default:
1799 // Escape whitespace
1800 if (uprv_isRuleWhiteSpace(c)) {
1801 buf.append(BACKSLASH);
1802 }
1803 break;
1804 }
1805 buf.append(c);
1806 }
1807
1808 /**
1809 * Append a string representation of this set to result. This will be
1810 * a cleaned version of the string passed to applyPattern(), if there
1811 * is one. Otherwise it will be generated.
1812 */
_toPattern(UnicodeString & result,UBool escapeUnprintable) const1813 UnicodeString& UnicodeSet::_toPattern(UnicodeString& result,
1814 UBool escapeUnprintable) const
1815 {
1816 if (pat != NULL) {
1817 int32_t i;
1818 int32_t backslashCount = 0;
1819 for (i=0; i<patLen; ) {
1820 UChar32 c;
1821 U16_NEXT(pat, i, patLen, c);
1822 if (escapeUnprintable && ICU_Utility::isUnprintable(c)) {
1823 // If the unprintable character is preceded by an odd
1824 // number of backslashes, then it has been escaped.
1825 // Before unescaping it, we delete the final
1826 // backslash.
1827 if ((backslashCount % 2) == 1) {
1828 result.truncate(result.length() - 1);
1829 }
1830 ICU_Utility::escapeUnprintable(result, c);
1831 backslashCount = 0;
1832 } else {
1833 result.append(c);
1834 if (c == BACKSLASH) {
1835 ++backslashCount;
1836 } else {
1837 backslashCount = 0;
1838 }
1839 }
1840 }
1841 return result;
1842 }
1843
1844 return _generatePattern(result, escapeUnprintable);
1845 }
1846
1847 /**
1848 * Returns a string representation of this set. If the result of
1849 * calling this function is passed to a UnicodeSet constructor, it
1850 * will produce another set that is equal to this one.
1851 */
toPattern(UnicodeString & result,UBool escapeUnprintable) const1852 UnicodeString& UnicodeSet::toPattern(UnicodeString& result,
1853 UBool escapeUnprintable) const
1854 {
1855 result.truncate(0);
1856 return _toPattern(result, escapeUnprintable);
1857 }
1858
1859 /**
1860 * Generate and append a string representation of this set to result.
1861 * This does not use this.pat, the cleaned up copy of the string
1862 * passed to applyPattern().
1863 */
_generatePattern(UnicodeString & result,UBool escapeUnprintable) const1864 UnicodeString& UnicodeSet::_generatePattern(UnicodeString& result,
1865 UBool escapeUnprintable) const
1866 {
1867 result.append(SET_OPEN);
1868
1869 // // Check against the predefined categories. We implicitly build
1870 // // up ALL category sets the first time toPattern() is called.
1871 // for (int8_t cat=0; cat<Unicode::GENERAL_TYPES_COUNT; ++cat) {
1872 // if (*this == getCategorySet(cat)) {
1873 // result.append(COLON);
1874 // result.append(CATEGORY_NAMES, cat*2, 2);
1875 // return result.append(CATEGORY_CLOSE);
1876 // }
1877 // }
1878
1879 int32_t count = getRangeCount();
1880
1881 // If the set contains at least 2 intervals and includes both
1882 // MIN_VALUE and MAX_VALUE, then the inverse representation will
1883 // be more economical.
1884 if (count > 1 &&
1885 getRangeStart(0) == MIN_VALUE &&
1886 getRangeEnd(count-1) == MAX_VALUE) {
1887
1888 // Emit the inverse
1889 result.append(COMPLEMENT);
1890
1891 for (int32_t i = 1; i < count; ++i) {
1892 UChar32 start = getRangeEnd(i-1)+1;
1893 UChar32 end = getRangeStart(i)-1;
1894 _appendToPat(result, start, escapeUnprintable);
1895 if (start != end) {
1896 if ((start+1) != end) {
1897 result.append(HYPHEN);
1898 }
1899 _appendToPat(result, end, escapeUnprintable);
1900 }
1901 }
1902 }
1903
1904 // Default; emit the ranges as pairs
1905 else {
1906 for (int32_t i = 0; i < count; ++i) {
1907 UChar32 start = getRangeStart(i);
1908 UChar32 end = getRangeEnd(i);
1909 _appendToPat(result, start, escapeUnprintable);
1910 if (start != end) {
1911 if ((start+1) != end) {
1912 result.append(HYPHEN);
1913 }
1914 _appendToPat(result, end, escapeUnprintable);
1915 }
1916 }
1917 }
1918
1919 for (int32_t i = 0; i<strings->size(); ++i) {
1920 result.append(OPEN_BRACE);
1921 _appendToPat(result,
1922 *(const UnicodeString*) strings->elementAt(i),
1923 escapeUnprintable);
1924 result.append(CLOSE_BRACE);
1925 }
1926 return result.append(SET_CLOSE);
1927 }
1928
1929 /**
1930 * Release existing cached pattern
1931 */
releasePattern()1932 void UnicodeSet::releasePattern() {
1933 if (pat) {
1934 uprv_free(pat);
1935 pat = NULL;
1936 patLen = 0;
1937 }
1938 }
1939
1940 /**
1941 * Set the new pattern to cache.
1942 */
setPattern(const UnicodeString & newPat)1943 void UnicodeSet::setPattern(const UnicodeString& newPat) {
1944 releasePattern();
1945 int32_t newPatLen = newPat.length();
1946 pat = (UChar *)uprv_malloc((newPatLen + 1) * sizeof(UChar));
1947 if (pat) {
1948 patLen = newPatLen;
1949 newPat.extractBetween(0, patLen, pat);
1950 pat[patLen] = 0;
1951 }
1952 // else we don't care if malloc failed. This was just a nice cache.
1953 // We can regenerate an equivalent pattern later when requested.
1954 }
1955
freeze()1956 UnicodeFunctor *UnicodeSet::freeze() {
1957 if(!isFrozen()) {
1958 // Do most of what compact() does before freezing because
1959 // compact() will not work when the set is frozen.
1960 // Small modification: Don't shrink if the savings would be tiny (<=GROW_EXTRA).
1961
1962 // Delete buffer first to defragment memory less.
1963 if (buffer != NULL) {
1964 uprv_free(buffer);
1965 buffer = NULL;
1966 }
1967 if (capacity > (len + GROW_EXTRA)) {
1968 // Make the capacity equal to len or 1.
1969 // We don't want to realloc of 0 size.
1970 capacity = len + (len == 0);
1971 list = (UChar32*) uprv_realloc(list, sizeof(UChar32) * capacity);
1972 }
1973
1974 // Optimize contains() and span() and similar functions.
1975 if (!strings->isEmpty()) {
1976 stringSpan = new UnicodeSetStringSpan(*this, *strings, UnicodeSetStringSpan::ALL);
1977 if (stringSpan != NULL && !stringSpan->needsStringSpanUTF16()) {
1978 // All strings are irrelevant for span() etc. because
1979 // all of each string's code points are contained in this set.
1980 // Do not check needsStringSpanUTF8() because UTF-8 has at most as
1981 // many relevant strings as UTF-16.
1982 // (Thus needsStringSpanUTF8() implies needsStringSpanUTF16().)
1983 delete stringSpan;
1984 stringSpan = NULL;
1985 }
1986 }
1987 if (stringSpan == NULL) {
1988 // No span-relevant strings: Optimize for code point spans.
1989 bmpSet=new BMPSet(list, len);
1990 }
1991 }
1992 return this;
1993 }
1994
span(const UChar * s,int32_t length,USetSpanCondition spanCondition) const1995 int32_t UnicodeSet::span(const UChar *s, int32_t length, USetSpanCondition spanCondition) const {
1996 if(length>0 && bmpSet!=NULL) {
1997 return (int32_t)(bmpSet->span(s, s+length, spanCondition)-s);
1998 }
1999 if(length<0) {
2000 length=u_strlen(s);
2001 }
2002 if(length==0) {
2003 return 0;
2004 }
2005 if(stringSpan!=NULL) {
2006 return stringSpan->span(s, length, spanCondition);
2007 } else if(!strings->isEmpty()) {
2008 uint32_t which= spanCondition==USET_SPAN_NOT_CONTAINED ?
2009 UnicodeSetStringSpan::FWD_UTF16_NOT_CONTAINED :
2010 UnicodeSetStringSpan::FWD_UTF16_CONTAINED;
2011 UnicodeSetStringSpan strSpan(*this, *strings, which);
2012 if(strSpan.needsStringSpanUTF16()) {
2013 return strSpan.span(s, length, spanCondition);
2014 }
2015 }
2016
2017 if(spanCondition!=USET_SPAN_NOT_CONTAINED) {
2018 spanCondition=USET_SPAN_CONTAINED; // Pin to 0/1 values.
2019 }
2020
2021 UChar32 c;
2022 int32_t start=0, prev=0;
2023 do {
2024 U16_NEXT(s, start, length, c);
2025 if(spanCondition!=contains(c)) {
2026 break;
2027 }
2028 } while((prev=start)<length);
2029 return prev;
2030 }
2031
spanBack(const UChar * s,int32_t length,USetSpanCondition spanCondition) const2032 int32_t UnicodeSet::spanBack(const UChar *s, int32_t length, USetSpanCondition spanCondition) const {
2033 if(length>0 && bmpSet!=NULL) {
2034 return (int32_t)(bmpSet->spanBack(s, s+length, spanCondition)-s);
2035 }
2036 if(length<0) {
2037 length=u_strlen(s);
2038 }
2039 if(length==0) {
2040 return 0;
2041 }
2042 if(stringSpan!=NULL) {
2043 return stringSpan->spanBack(s, length, spanCondition);
2044 } else if(!strings->isEmpty()) {
2045 uint32_t which= spanCondition==USET_SPAN_NOT_CONTAINED ?
2046 UnicodeSetStringSpan::BACK_UTF16_NOT_CONTAINED :
2047 UnicodeSetStringSpan::BACK_UTF16_CONTAINED;
2048 UnicodeSetStringSpan strSpan(*this, *strings, which);
2049 if(strSpan.needsStringSpanUTF16()) {
2050 return strSpan.spanBack(s, length, spanCondition);
2051 }
2052 }
2053
2054 if(spanCondition!=USET_SPAN_NOT_CONTAINED) {
2055 spanCondition=USET_SPAN_CONTAINED; // Pin to 0/1 values.
2056 }
2057
2058 UChar32 c;
2059 int32_t prev=length;
2060 do {
2061 U16_PREV(s, 0, length, c);
2062 if(spanCondition!=contains(c)) {
2063 break;
2064 }
2065 } while((prev=length)>0);
2066 return prev;
2067 }
2068
spanUTF8(const char * s,int32_t length,USetSpanCondition spanCondition) const2069 int32_t UnicodeSet::spanUTF8(const char *s, int32_t length, USetSpanCondition spanCondition) const {
2070 if(length>0 && bmpSet!=NULL) {
2071 const uint8_t *s0=(const uint8_t *)s;
2072 return (int32_t)(bmpSet->spanUTF8(s0, length, spanCondition)-s0);
2073 }
2074 if(length<0) {
2075 length=uprv_strlen(s);
2076 }
2077 if(length==0) {
2078 return 0;
2079 }
2080 if(stringSpan!=NULL) {
2081 return stringSpan->spanUTF8((const uint8_t *)s, length, spanCondition);
2082 } else if(!strings->isEmpty()) {
2083 uint32_t which= spanCondition==USET_SPAN_NOT_CONTAINED ?
2084 UnicodeSetStringSpan::FWD_UTF8_NOT_CONTAINED :
2085 UnicodeSetStringSpan::FWD_UTF8_CONTAINED;
2086 UnicodeSetStringSpan strSpan(*this, *strings, which);
2087 if(strSpan.needsStringSpanUTF8()) {
2088 return strSpan.spanUTF8((const uint8_t *)s, length, spanCondition);
2089 }
2090 }
2091
2092 if(spanCondition!=USET_SPAN_NOT_CONTAINED) {
2093 spanCondition=USET_SPAN_CONTAINED; // Pin to 0/1 values.
2094 }
2095
2096 UChar32 c;
2097 int32_t start=0, prev=0;
2098 do {
2099 U8_NEXT(s, start, length, c);
2100 if(c<0) {
2101 c=0xfffd;
2102 }
2103 if(spanCondition!=contains(c)) {
2104 break;
2105 }
2106 } while((prev=start)<length);
2107 return prev;
2108 }
2109
spanBackUTF8(const char * s,int32_t length,USetSpanCondition spanCondition) const2110 int32_t UnicodeSet::spanBackUTF8(const char *s, int32_t length, USetSpanCondition spanCondition) const {
2111 if(length>0 && bmpSet!=NULL) {
2112 const uint8_t *s0=(const uint8_t *)s;
2113 return bmpSet->spanBackUTF8(s0, length, spanCondition);
2114 }
2115 if(length<0) {
2116 length=uprv_strlen(s);
2117 }
2118 if(length==0) {
2119 return 0;
2120 }
2121 if(stringSpan!=NULL) {
2122 return stringSpan->spanBackUTF8((const uint8_t *)s, length, spanCondition);
2123 } else if(!strings->isEmpty()) {
2124 uint32_t which= spanCondition==USET_SPAN_NOT_CONTAINED ?
2125 UnicodeSetStringSpan::BACK_UTF8_NOT_CONTAINED :
2126 UnicodeSetStringSpan::BACK_UTF8_CONTAINED;
2127 UnicodeSetStringSpan strSpan(*this, *strings, which);
2128 if(strSpan.needsStringSpanUTF8()) {
2129 return strSpan.spanBackUTF8((const uint8_t *)s, length, spanCondition);
2130 }
2131 }
2132
2133 if(spanCondition!=USET_SPAN_NOT_CONTAINED) {
2134 spanCondition=USET_SPAN_CONTAINED; // Pin to 0/1 values.
2135 }
2136
2137 UChar32 c;
2138 int32_t prev=length;
2139 do {
2140 U8_PREV(s, 0, length, c);
2141 if(c<0) {
2142 c=0xfffd;
2143 }
2144 if(spanCondition!=contains(c)) {
2145 break;
2146 }
2147 } while((prev=length)>0);
2148 return prev;
2149 }
2150
2151 U_NAMESPACE_END
2152