// DO NOT DELETE THIS CODE. This code is used to debug memory leaks. // To enable the debugging, define the symbol DEBUG_MEM in the line // below. This will result in text being sent to stdout that looks // like this: // DEBUG UnicodeSet: ct 0x00A39B20; 397 [\u0A81-\u0A83\u0A85- // DEBUG UnicodeSet: dt 0x00A39B20; 396 [\u0A81-\u0A83\u0A85- // Each line lists a construction (ct) or destruction (dt) event, the // object address, the number of outstanding objects after the event, // and the pattern of the object in question.
//---------------------------------------------------------------- // UnicodeString in UVector support //----------------------------------------------------------------
/** *Returnstrueifthissetcontainsthegivencharacter. *@paramccharactertobecheckedforcontainment *@returntrueifthetestconditionismet
*/
UBool UnicodeSet::contains(UChar32 c) const { // Set i to the index of the start item greater than ch // We know we will terminate without length test! // LATER: for large sets, add binary search //int32_t i = -1; //for (;;) { // if (c < list[++i]) break; //} if (bmpSet != nullptr) { return bmpSet->contains(c);
} if (stringSpan != nullptr) { return stringSpan->contains(c);
} if (c >= UNICODESET_HIGH) { // Don't need to check LOW bound returnfalse;
}
int32_t i = findCodePoint(c); return i & 1; // return true if odd
}
// Return the smallest i such that c < list[i]. Assume // list[len - 1] == HIGH and that c is legal (0..HIGH-1). if (c < list[0]) return0; // High runner test. c is often after the last range, so an // initial check for this condition pays off.
int32_t lo = 0;
int32_t hi = len - 1; if (lo >= hi || c >= list[hi-1]) return hi; // invariant: c >= list[lo] // invariant: c < list[hi] for (;;) {
int32_t i = (lo + hi) >> 1; if (i == lo) { break; // Found!
} elseif (c < list[i]) {
hi = i;
} else {
lo = i;
}
} return hi;
}
/** *Returnstrueifthissetcontainsallthecharactersandstrings *ofthegivenset. *@paramcsettobecheckedforcontainment *@returntrueifthetestconditionismet
*/
UBool UnicodeSet::containsAll(const UnicodeSet& c) const { // The specified set is a subset if all of its pairs are contained in // this set. It's possible to code this more efficiently in terms of // direct manipulation of the inversion lists if the need arises.
int32_t n = c.getRangeCount(); for (int i=0; i<n; ++i) { if (!contains(c.getRangeStart(i), c.getRangeEnd(i))) { returnfalse;
}
} return !c.hasStrings() || (strings_ != nullptr && strings_->containsAll(*c.strings_));
}
/** *Returnstrueifthissetcontainsnoneofthecharactersandstrings *ofthegivenset. *@paramcsettobecheckedforcontainment *@returntrueifthetestconditionismet
*/
UBool UnicodeSet::containsNone(const UnicodeSet& c) const { // The specified set is a subset if all of its pairs are contained in // this set. It's possible to code this more efficiently in terms of // direct manipulation of the inversion lists if the need arises.
int32_t n = c.getRangeCount(); for (int32_t i=0; i<n; ++i) { if (!containsNone(c.getRangeStart(i), c.getRangeEnd(i))) { returnfalse;
}
} return strings_ == nullptr || !c.hasStrings() || strings_->containsNone(*c.strings_);
}
// might separate forward and backward loops later // for now they are combined
// TODO Improve efficiency of this, at least in the forward // direction, if not in both. In the forward direction we // can assume the strings are sorted.
int32_t i;
UBool forward = offset < limit;
// firstChar is the leftmost char to match in the // forward direction or the rightmost char to match in // the reverse direction.
char16_t firstChar = text.charAt(offset);
// If there are multiple strings that can match we // return the longest match.
int32_t highWaterLength = 0;
for (i=0; i<strings_->size(); ++i) { const UnicodeString& trial = *static_cast<const UnicodeString*>(strings_->elementAt(i)); if (trial.isEmpty()) { continue; // skip the empty string
}
char16_t c = trial.charAt(forward ? 0 : trial.length() - 1);
// Strings are sorted, so we can optimize in the // forward direction. if (forward && c > firstChar) break; if (c != firstChar) continue;
if (incremental) {
int32_t maxLen = forward ? limit-offset : offset-limit; if (matchLen == maxLen) { // We have successfully matched but only up to limit. return U_PARTIAL_MATCH;
}
}
if (matchLen == trial.length()) { // We have successfully matched the whole string. if (matchLen > highWaterLength) {
highWaterLength = matchLen;
} // In the forward direction we know strings // are sorted so we can bail early. if (forward && matchLen < highWaterLength) { break;
} continue;
}
}
// We've checked all strings without a partial match. // If we have full matches, return the longest one. if (highWaterLength != 0) {
offset += forward ? highWaterLength : -highWaterLength; return U_MATCH;
}
} return UnicodeFilter::matches(text, offset, limit, incremental);
}
}
/** *Returnstheindexofthegivencharacterwithinthisset,where *thesetisorderedbyascendingcodepoint.Ifthecharacter *isnotinthisset,return-1.Theinverseofthismethodis *<code>charAt()</code>. *@returnanindexfrom0..size()-1,or-1
*/
int32_t UnicodeSet::indexOf(UChar32 c) const { if (c < MIN_VALUE || c > MAX_VALUE) { return -1;
}
int32_t i = 0;
int32_t n = 0; for (;;) {
UChar32 start = list[i++]; if (c < start) { return -1;
}
UChar32 limit = list[i++]; if (c < limit) { return n + c - start;
}
n += limit - start;
}
}
/** *Returnsthecharacteratthegivenindexwithinthisset,where *thesetisorderedbyascendingcodepoint.Iftheindexis *outofrange,return(UChar32)-1.Theinverseofthismethodis *<code>indexOf()</code>. *@paramindexanindexfrom0..size()-1 *@returnthecharacteratthegivenindex,or(UChar32)-1.
*/
UChar32 UnicodeSet::charAt(int32_t index) const { if (index >= 0) { // len2 is the largest even integer <= len, that is, it is len // for even values and len-1 for odd values. With odd values // the last entry is UNICODESET_HIGH.
int32_t len2 = len & ~1; for (int32_t i=0; i < len2;) {
UChar32 start = list[i++];
int32_t count = list[i++] - start; if (index < count) { return static_cast<UChar32>(start + index);
}
index -= count;
}
} return static_cast<UChar32>(-1);
}
/** *Addsthespecifiedrangetothissetifitisnotalready *present.Ifthissetalreadycontainsthespecifiedrange, *thecallleavesthissetunchanged.If<code>end>start</code> *thenanemptyrangeisadded,leavingthesetunchanged. * *@paramstartfirstcharacter,inclusive,ofrangetobeadded *tothisset. *@paramendlastcharacter,inclusive,ofrangetobeadded *tothisset.
*/
UnicodeSet& UnicodeSet::add(UChar32 start, UChar32 end) { if (pinCodePoint(start) < pinCodePoint(end)) {
UChar32 limit = end + 1; // Fast path for adding a new range after the last one. // Odd list length: [..., lastStart, lastLimit, HIGH] if ((len & 1) != 0) { // If the list is empty, set lastLimit low enough to not be adjacent to 0.
UChar32 lastLimit = len == 1 ? -2 : list[len - 2]; if (lastLimit <= start && !isFrozen() && !isBogus()) { if (lastLimit == start) { // Extend the last range.
list[len - 2] = limit; if (limit == UNICODESET_HIGH) {
--len;
}
} else {
list[len - 1] = start; if (limit < UNICODESET_HIGH) { if (ensureCapacity(len + 2)) {
list[len++] = limit;
list[len++] = UNICODESET_HIGH;
}
} else { // limit == UNICODESET_HIGH if (ensureCapacity(len + 1)) {
list[len++] = UNICODESET_HIGH;
}
}
}
releasePattern(); return *this;
}
} // This is slow. Could be much faster using findCodePoint(start) // and modifying the list, dealing with adjacent & overlapping ranges.
UChar32 range[3] = { start, limit, UNICODESET_HIGH };
add(range, 2, 0);
} elseif (start == end) {
add(start);
} return *this;
}
// #define DEBUG_US_ADD
#ifdef DEBUG_US_ADD #include <stdio.h> void dump(UChar32 c) { if (c <= 0xFF) {
printf("%c", (char)c);
} else {
printf("U+%04X", c);
}
} void dump(const UChar32* list, int32_t len) {
printf("["); for (int32_t i=0; i<len; ++i) { if (i != 0) printf(", ");
dump(list[i]);
}
printf("]");
} #endif
/** *Addsthespecifiedcharactertothissetifitisnotalready *present.Ifthissetalreadycontainsthespecifiedcharacter, *thecallleavesthissetunchanged.
*/
UnicodeSet& UnicodeSet::add(UChar32 c) { // find smallest i such that c < list[i] // if odd, then it is IN the set // if even, then it is OUT of the set
int32_t i = findCodePoint(pinCodePoint(c));
// already in set? if ((i & 1) != 0 || isFrozen() || isBogus()) return *this;
// HIGH is 0x110000 // assert(list[len-1] == HIGH);
#ifdef DEBUG_US_ADD
printf("Add of ");
dump(c);
printf(" found at %d", i);
printf(": ");
dump(list, len);
printf(" => "); #endif
if (c == list[i]-1) { // c is before start of next range
list[i] = c; // if we touched the HIGH mark, then add a new one if (c == (UNICODESET_HIGH - 1)) { if (!ensureCapacity(len+1)) { // ensureCapacity will mark the object as Bogus if OOM failure happens. return *this;
}
list[len++] = UNICODESET_HIGH;
} if (i > 0 && c == list[i-1]) { // collapse adjacent ranges
if (destCapacity<0 || (destCapacity>0 && dest==nullptr)) {
ec=U_ILLEGAL_ARGUMENT_ERROR; return0;
}
/* count necessary 16-bit units */
length=this->len-1; // Subtract 1 to ignore final UNICODESET_HIGH // assert(length>=0); if (length==0) { /* empty set */ if (destCapacity>0) {
*dest=0;
} else {
ec=U_BUFFER_OVERFLOW_ERROR;
} return1;
} /* now length>0 */
if (this->list[length-1]<=0xffff) { /* all BMP */
bmpLength=length;
} elseif (this->list[0]>=0x10000) { /* all supplementary */
bmpLength=0;
length*=2;
} else { /* some BMP, some supplementary */ for (bmpLength=0; bmpLength<length && this->list[bmpLength]<=0xffff; ++bmpLength) {}
length=bmpLength+2*(length-bmpLength);
} #ifdef DEBUG_SERIALIZE
printf(">> bmpLength%d length%d len%d\n", bmpLength, length, len); #endif /* length: number of 16-bit array units */ if (length>0x7fff) { /* there are only 15 bits for the length in the first serialized word */
ec=U_INDEX_OUTOFBOUNDS_ERROR; return0;
}
/* write the BMP part of the array */
p=this->list; for (i=0; i<bmpLength; ++i) { #ifdef DEBUG_SERIALIZE
printf("writebmp: %x\n", (int)*p); #endif
*dest++ = static_cast<uint16_t>(*p++);
}
/* write the supplementary part of the array */ for (; i<length; i+=2) { #ifdef DEBUG_SERIALIZE
printf("write32: %x\n", (int)*p); #endif
*dest++ = static_cast<uint16_t>(*p >> 16);
*dest++ = static_cast<uint16_t>(*p++);
}
} else {
ec=U_BUFFER_OVERFLOW_ERROR;
} return destLength;
}
int32_t i = 0, j = 0, k = 0;
UChar32 a = list[i++];
UChar32 b; if (polarity == 1 || polarity == 2) {
b = UNICODESET_LOW; if (other[j] == UNICODESET_LOW) { // skip base if already LOW
++j;
b = other[j];
}
} else {
b = other[j++];
} // simplest of all the routines // sort the values, discarding identicals! for (;;) { if (a < b) {
buffer[k++] = a;
a = list[i++];
} elseif (b < a) {
buffer[k++] = b;
b = other[j++];
} elseif (a != UNICODESET_HIGH) { // at this point, a == b // discard both values!
a = list[i++];
b = other[j++];
} else { // DONE!
buffer[k++] = UNICODESET_HIGH;
len = k; break;
}
}
swapBuffers();
releasePattern();
}
// polarity = 0 is normal: x union y // polarity = 2: x union ~y // polarity = 1: ~x union y // polarity = 3: ~x union ~y
int32_t i = 0, j = 0, k = 0;
UChar32 a = list[i++];
UChar32 b = other[j++]; // change from xor is that we have to check overlapping pairs // polarity bit 1 means a is second, bit 2 means b is. for (;;) { switch (polarity) { case0: // both first; take lower if unequal if (a < b) { // take a // Back up over overlapping ranges in buffer[] if (k > 0 && a <= buffer[k-1]) { // Pick latter end value in buffer[] vs. list[]
a = max(list[i], buffer[--k]);
} else { // No overlap
buffer[k++] = a;
a = list[i];
}
i++; // Common if/else code factored out
polarity ^= 1;
} elseif (b < a) { // take b if (k > 0 && b <= buffer[k-1]) {
b = max(other[j], buffer[--k]);
} else {
buffer[k++] = b;
b = other[j];
}
j++;
polarity ^= 2;
} else { // a == b, take a, drop b if (a == UNICODESET_HIGH) goto loop_end; // This is symmetrical; it doesn't matter if // we backtrack with a or b. - liu if (k > 0 && a <= buffer[k-1]) {
a = max(list[i], buffer[--k]);
} else { // No overlap
buffer[k++] = a;
a = list[i];
}
i++;
polarity ^= 1;
b = other[j++];
polarity ^= 2;
} break; case3: // both second; take higher if unequal, and drop other if (b <= a) { // take a if (a == UNICODESET_HIGH) goto loop_end;
buffer[k++] = a;
} else { // take b if (b == UNICODESET_HIGH) goto loop_end;
buffer[k++] = b;
}
a = list[i++];
polarity ^= 1; // factored common code
b = other[j++];
polarity ^= 2; break; case1: // a second, b first; if b < a, overlap if (a < b) { // no overlap, take a
buffer[k++] = a; a = list[i++]; polarity ^= 1;
} elseif (b < a) { // OVERLAP, drop b
b = other[j++];
polarity ^= 2;
} else { // a == b, drop both! if (a == UNICODESET_HIGH) goto loop_end;
a = list[i++];
polarity ^= 1;
b = other[j++];
polarity ^= 2;
} break; case2: // a first, b second; if a < b, overlap if (b < a) { // no overlap, take b
buffer[k++] = b;
b = other[j++];
polarity ^= 2;
} elseif (a < b) { // OVERLAP, drop a
a = list[i++];
polarity ^= 1;
} else { // a == b, drop both! if (a == UNICODESET_HIGH) goto loop_end;
a = list[i++];
polarity ^= 1;
b = other[j++];
polarity ^= 2;
} break;
}
}
loop_end:
buffer[k++] = UNICODESET_HIGH; // terminate
len = k;
swapBuffers();
releasePattern();
}
// polarity = 0 is normal: x intersect y // polarity = 2: x intersect ~y == set-minus // polarity = 1: ~x intersect y // polarity = 3: ~x intersect ~y
int32_t i = 0, j = 0, k = 0;
UChar32 a = list[i++];
UChar32 b = other[j++]; // change from xor is that we have to check overlapping pairs // polarity bit 1 means a is second, bit 2 means b is. for (;;) { switch (polarity) { case0: // both first; drop the smaller if (a < b) { // drop a
a = list[i++];
polarity ^= 1;
} elseif (b < a) { // drop b
b = other[j++];
polarity ^= 2;
} else { // a == b, take one, drop other if (a == UNICODESET_HIGH) goto loop_end;
buffer[k++] = a;
a = list[i++];
polarity ^= 1;
b = other[j++];
polarity ^= 2;
} break; case3: // both second; take lower if unequal if (a < b) { // take a
buffer[k++] = a;
a = list[i++];
polarity ^= 1;
} elseif (b < a) { // take b
buffer[k++] = b;
b = other[j++];
polarity ^= 2;
} else { // a == b, take one, drop other if (a == UNICODESET_HIGH) goto loop_end;
buffer[k++] = a;
a = list[i++];
polarity ^= 1;
b = other[j++];
polarity ^= 2;
} break; case1: // a second, b first; if (a < b) { // NO OVERLAP, drop a
a = list[i++];
polarity ^= 1;
} elseif (b < a) { // OVERLAP, take b
buffer[k++] = b;
b = other[j++];
polarity ^= 2;
} else { // a == b, drop both! if (a == UNICODESET_HIGH) goto loop_end;
a = list[i++];
polarity ^= 1;
b = other[j++];
polarity ^= 2;
} break; case2: // a first, b second; if a < b, overlap if (b < a) { // no overlap, drop b
b = other[j++];
polarity ^= 2;
} elseif (a < b) { // OVERLAP, take a
buffer[k++] = a;
a = list[i++];
polarity ^= 1;
} else { // a == b, drop both! if (a == UNICODESET_HIGH) goto loop_end;
a = list[i++];
polarity ^= 1;
b = other[j++];
polarity ^= 2;
} break;
}
}
loop_end:
buffer[k++] = UNICODESET_HIGH; // terminate
len = k;
swapBuffers();
releasePattern();
}
/** *Appendthe<code>toPattern()</code>representationofa *stringtothegiven<code>StringBuffer</code>.
*/ void UnicodeSet::_appendToPat(UnicodeString& buf, const UnicodeString& s, UBool escapeUnprintable) {
UChar32 cp; for (int32_t i = 0; i < s.length(); i += U16_LENGTH(cp)) {
_appendToPat(buf, cp = s.char32At(i), escapeUnprintable);
}
}
/** *Appendthe<code>toPattern()</code>representationofa *charactertothegiven<code>StringBuffer</code>.
*/ void UnicodeSet::_appendToPat(UnicodeString& buf, UChar32 c, UBool escapeUnprintable) { if (escapeUnprintable ? ICU_Utility::isUnprintable(c) : ICU_Utility::shouldAlwaysBeEscaped(c)) { // Use hex escape notation (\uxxxx or \Uxxxxxxxx) for anything // unprintable
ICU_Utility::escape(buf, c); return;
} // Okay to let ':' pass through switch (c) { case u'[': case u']': case u'-': case u'^': case u'&': case u'\\': case u'{': case u'}': case u':': case SymbolTable::SYMBOL_REF:
buf.append(u'\\'); break; default: // Escape whitespace if (PatternProps::isWhiteSpace(c)) {
buf.append(u'\\');
} break;
}
buf.append(c);
}
void UnicodeSet::_appendToPat(UnicodeString &result, UChar32 start, UChar32 end,
UBool escapeUnprintable) {
_appendToPat(result, start, escapeUnprintable); if (start != end) { if ((start+1) != end || // Avoid writing what looks like a lead+trail surrogate pair.
start == 0xdbff) {
result.append(u'-');
}
_appendToPat(result, end, escapeUnprintable);
}
}
/** *Appendastringrepresentationofthissettoresult.Thiswillbe *acleanedversionofthestringpassedtoapplyPattern(),ifthere *isone.Otherwiseitwillbegenerated.
*/
UnicodeString& UnicodeSet::_toPattern(UnicodeString& result,
UBool escapeUnprintable) const
{ if (pat != nullptr) {
int32_t i;
int32_t backslashCount = 0; for (i=0; i<patLen; ) {
UChar32 c;
U16_NEXT(pat, i, patLen, c); if (escapeUnprintable ?
ICU_Utility::isUnprintable(c) : ICU_Utility::shouldAlwaysBeEscaped(c)) { // If the unprintable character is preceded by an odd // number of backslashes, then it has been escaped. // Before unescaping it, we delete the final // backslash. if ((backslashCount % 2) == 1) {
result.truncate(result.length() - 1);
}
ICU_Utility::escape(result, c);
backslashCount = 0;
} else {
result.append(c); if (c == u'\\') {
++backslashCount;
} else {
backslashCount = 0;
}
}
} return result;
}
int32_t i = 0;
int32_t limit = len & ~1; // = 2 * getRangeCount()
// If the set contains at least 2 intervals and includes both // MIN_VALUE and MAX_VALUE, then the inverse representation will // be more economical. // if (getRangeCount() >= 2 && // getRangeStart(0) == MIN_VALUE && // getRangeEnd(last) == MAX_VALUE) // Invariant: list[len-1] == HIGH == MAX_VALUE + 1 // If limit == len then len is even and the last range ends with MAX_VALUE. // // *But* do not write the inverse (complement) if there are strings. // Since ICU 70, the '^' performs a code point complement which removes all strings. if (len >= 4 && list[0] == 0 && limit == len && !hasStrings()) { // Emit the inverse
result.append(u'^'); // Offsetting the inversion list index by one lets us // iterate over the ranges of the set complement.
i = 1;
--limit;
}
// Emit the ranges as pairs. while (i < limit) {
UChar32 start = list[i]; // getRangeStart()
UChar32 end = list[i + 1] - 1; // getRangeEnd() = range limit minus one if (!(0xd800 <= end && end <= 0xdbff)) {
_appendToPat(result, start, end, escapeUnprintable);
i += 2;
} else { // The range ends with a lead surrogate. // Avoid writing what looks like a lead+trail surrogate pair. // 1. Postpone ranges that start with a lead surrogate code point.
int32_t firstLead = i; while ((i += 2) < limit && list[i] <= 0xdbff) {}
int32_t firstAfterLead = i; // 2. Write following ranges that start with a trail surrogate code point. while (i < limit && (start = list[i]) <= 0xdfff) {
_appendToPat(result, start, list[i + 1] - 1, escapeUnprintable);
i += 2;
} // 3. Now write the postponed ranges. for (int j = firstLead; j < firstAfterLead; j += 2) {
_appendToPat(result, list[j], list[j + 1] - 1, escapeUnprintable);
}
}
}
if (strings_ != nullptr) { for (int32_t i = 0; i<strings_->size(); ++i) {
result.append(u'{');
_appendToPat(result,
*static_cast<const UnicodeString*>(strings_->elementAt(i)),
escapeUnprintable);
result.append(u'}');
}
} return result.append(u']');
}
/** *Releaseexistingcachedpattern
*/ void UnicodeSet::releasePattern() { if (pat) {
uprv_free(pat);
pat = nullptr;
patLen = 0;
}
}
/** *Setthenewpatterntocache.
*/ void UnicodeSet::setPattern(const char16_t *newPat, int32_t newPatLen) {
releasePattern();
pat = static_cast<char16_t*>(uprv_malloc((newPatLen + 1) * sizeof(char16_t))); if (pat) {
patLen = newPatLen;
u_memcpy(pat, newPat, patLen);
pat[patLen] = 0;
} // else we don't care if malloc failed. This was just a nice cache. // We can regenerate an equivalent pattern later when requested.
}
// Optimize contains() and span() and similar functions. if (hasStrings()) {
stringSpan = new UnicodeSetStringSpan(*this, *strings_, UnicodeSetStringSpan::ALL); if (stringSpan == nullptr) {
setToBogus(); return this;
} elseif (!stringSpan->needsStringSpanUTF16()) { // All strings are irrelevant for span() etc. because // all of each string's code points are contained in this set. // Do not check needsStringSpanUTF8() because UTF-8 has at most as // many relevant strings as UTF-16. // (Thus needsStringSpanUTF8() implies needsStringSpanUTF16().) delete stringSpan;
stringSpan = nullptr;
}
} if (stringSpan == nullptr) { // No span-relevant strings: Optimize for code point spans.
bmpSet=new BMPSet(list, len); if (bmpSet == nullptr) { // Check for memory allocation error.
setToBogus();
}
}
} return this;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.