void
print(const char16_t *s,
int32_t len, constchar *name)
{
char16_t c;
cout << name << ":|"; for(int i = 0; i < len; ++i) {
c = s[i]; if(c>= 0x007E || c < 0x0020)
cout << "[0x" << hex << s[i] << "]"; else
cout << (char) s[i];
}
cout << '|' << endl;
} // END DEBUGGING #endif
// Local function definitions for now
// need to copy areas that may overlap static inlinevoid
us_arrayCopy(const char16_t *src, int32_t srcStart,
char16_t *dst, int32_t dstStart, int32_t count)
{ if(count>0) {
uprv_memmove(dst+dstStart, src+srcStart, (size_t)count*sizeof(*src));
}
}
// u_unescapeAt() callback to get a char16_t from a UnicodeString
U_CDECL_BEGIN static char16_t U_CALLCONV
UnicodeString_charAt(int32_t offset, void *context) { return ((icu::UnicodeString*) context)->charAt(offset);
}
U_CDECL_END
U_NAMESPACE_BEGIN
/* The Replaceable virtual destructor can't be defined in the header due to how AIX works with multiple definitions of virtual functions.
*/
Replaceable::~Replaceable() {}
UOBJECT_DEFINE_RTTI_IMPLEMENTATION(UnicodeString)
UnicodeString U_EXPORT2 operator+ (const UnicodeString &s1, const UnicodeString &s2) {
int32_t sumLengths; if (uprv_add32_overflow(s1.length(), s2.length(), &sumLengths)) {
UnicodeString bogus;
bogus.setToBogus(); return bogus;
} if (sumLengths != INT32_MAX) {
++sumLengths; // space for a terminating NUL if we need one
} return UnicodeString(sumLengths, static_cast<UChar32>(0), 0).append(s1).append(s2);
}
U_COMMON_API UnicodeString U_EXPORT2
unistr_internalConcat(const UnicodeString &s1, std::u16string_view s2) {
int32_t sumLengths; if (s2.length() > INT32_MAX ||
uprv_add32_overflow(s1.length(), static_cast<int32_t>(s2.length()), &sumLengths)) {
UnicodeString bogus;
bogus.setToBogus(); return bogus;
} if (sumLengths != INT32_MAX) {
++sumLengths; // space for a terminating NUL if we need one
} return UnicodeString(sumLengths, static_cast<UChar32>(0), 0).append(s1).append(s2);
}
//======================================== // Reference Counting functions, put at top of file so that optimizing compilers // have a chance to automatically inline. //========================================
UnicodeString::UnicodeString(UChar32 ch) {
fUnion.fFields.fLengthAndFlags = kShortString;
int32_t i = 0;
UBool isError = false;
U16_APPEND(fUnion.fStackFields.fBuffer, i, US_STACKBUF_SIZE, ch, isError); // We test isError so that the compiler does not complain that we don't. // If isError then i==0 which is what we want anyway. if(!isError) {
setShortLength(i);
}
}
// The number of bytes for one int32_t reference counter and capacity UChars // must fit into a 32-bit size_t (at least when on a 32-bit platform). // We also add one for the NUL terminator, to avoid reallocation in getTerminatedBuffer(), // and round up to a multiple of 16 bytes. // This means that capacity must be at most (0xfffffff0 - 4) / 2 - 1 = 0x7ffffff5. // (With more complicated checks we could go up to 0x7ffffffd without rounding up, // but that does not seem worth it.) const int32_t kMaxCapacity = 0x7ffffff5;
UBool
UnicodeString::allocate(int32_t capacity) { if(capacity <= US_STACKBUF_SIZE) {
fUnion.fFields.fLengthAndFlags = kShortString; returntrue;
} if(capacity <= kMaxCapacity) {
++capacity; // for the NUL // Switch to size_t which is unsigned so that we can allocate up to 4GB. // Reference counter + UChars.
size_t numBytes = sizeof(int32_t) + static_cast<size_t>(capacity) * U_SIZEOF_UCHAR; // Round up to a multiple of 16.
numBytes = (numBytes + 15) & ~15;
int32_t* array = static_cast<int32_t*>(uprv_malloc(numBytes)); if(array != nullptr) { // set initial refCount and point behind the refCount
*array++ = 1;
numBytes -= sizeof(int32_t);
// have fArray point to the first char16_t
fUnion.fFields.fArray = reinterpret_cast<char16_t*>(array);
fUnion.fFields.fCapacity = static_cast<int32_t>(numBytes / U_SIZEOF_UCHAR);
fUnion.fFields.fLengthAndFlags = kLongString; returntrue;
}
}
fUnion.fFields.fLengthAndFlags = kIsBogus;
fUnion.fFields.fArray = nullptr;
fUnion.fFields.fCapacity = 0; returnfalse;
}
UnicodeString::~UnicodeString()
{ #ifdef UNISTR_COUNT_FINAL_STRING_LENGTHS // Count lengths of strings at the end of their lifetime. // Useful for discussion of a desirable stack buffer size. // Count the contents length, not the optional NUL terminator nor further capacity. // Ignore open-buffer strings and strings which alias external storage. if((fUnion.fFields.fLengthAndFlags&(kOpenGetBuffer|kReadonlyAlias|kWritableAlias)) == 0) { if(hasShortLength()) {
umtx_atomic_inc(finalLengthCounts + getShortLength());
} else {
umtx_atomic_inc(&beyondCount);
}
} #endif
UnicodeString UnicodeString::fromUTF32(const UChar32 *utf32, int32_t length) {
UnicodeString result;
int32_t capacity; // Most UTF-32 strings will be BMP-only and result in a same-length // UTF-16 string. We overestimate the capacity just slightly, // just in case there are a few supplementary characters. if(length <= US_STACKBUF_SIZE) {
capacity = US_STACKBUF_SIZE;
} else {
capacity = length + (length >> 4) + 4;
} do {
char16_t *utf16 = result.getBuffer(capacity);
int32_t length16;
UErrorCode errorCode = U_ZERO_ERROR;
u_strFromUTF32WithSub(utf16, result.getCapacity(), &length16,
utf32, length,
0xfffd, // Substitution character.
nullptr, // Don't care about number of substitutions.
&errorCode);
result.releaseBuffer(length16); if(errorCode == U_BUFFER_OVERFLOW_ERROR) {
capacity = length16 + 1; // +1 for the terminating NUL. continue;
} elseif(U_FAILURE(errorCode)) {
result.setToBogus();
} break;
} while(true); return result;
}
UnicodeString &
UnicodeString::copyFrom(const UnicodeString &src, UBool fastCopy) { // if assigning to ourselves, do nothing if(this == &src) { return *this;
}
// is the right side bogus? if(src.isBogus()) {
setToBogus(); return *this;
}
// delete the current contents
releaseArray();
if(src.isEmpty()) { // empty string - use the stack buffer
setToEmpty(); return *this;
}
// fLength>0 and not an "open" src.getBuffer(minCapacity)
fUnion.fFields.fLengthAndFlags = src.fUnion.fFields.fLengthAndFlags; switch(src.fUnion.fFields.fLengthAndFlags & kAllStorageFlags) { case kShortString: // short string using the stack buffer, do the same
uprv_memcpy(fUnion.fStackFields.fBuffer, src.fUnion.fStackFields.fBuffer,
getShortLength() * U_SIZEOF_UCHAR); break; case kLongString: // src uses a refCounted string buffer, use that buffer with refCount // src is const, use a cast - we don't actually change it const_cast<UnicodeString &>(src).addRef(); // copy all fields, share the reference-counted buffer
fUnion.fFields.fArray = src.fUnion.fFields.fArray;
fUnion.fFields.fCapacity = src.fUnion.fFields.fCapacity; if(!hasShortLength()) {
fUnion.fFields.fLength = src.fUnion.fFields.fLength;
} break; case kReadonlyAlias: if(fastCopy) { // src is a readonly alias, do the same // -> maintain the readonly alias as such
fUnion.fFields.fArray = src.fUnion.fFields.fArray;
fUnion.fFields.fCapacity = src.fUnion.fFields.fCapacity; if(!hasShortLength()) {
fUnion.fFields.fLength = src.fUnion.fFields.fLength;
} break;
} // else if(!fastCopy) fall through to case kWritableAlias // -> allocate a new buffer and copy the contents
U_FALLTHROUGH; case kWritableAlias: { // src is a writable alias; we make a copy of that instead
int32_t srcLength = src.length(); if(allocate(srcLength)) {
u_memcpy(getArrayStart(), src.getArrayStart(), srcLength);
setLength(srcLength); break;
} // if there is not enough memory, then fall through to setting to bogus
U_FALLTHROUGH;
} default: // if src is bogus, set ourselves to bogus // do not call setToBogus() here because fArray and flags are not consistent here
fUnion.fFields.fLengthAndFlags = kIsBogus;
fUnion.fFields.fArray = nullptr;
fUnion.fFields.fCapacity = 0; break;
}
return *this;
}
UnicodeString &UnicodeString::operator=(UnicodeString &&src) noexcept { // No explicit check for self move assignment, consistent with standard library. // Self move assignment causes no crash nor leak but might make the object bogus.
releaseArray();
copyFieldsFrom(src, true); return *this;
}
// Same as move assignment except without memory management. void UnicodeString::copyFieldsFrom(UnicodeString &src, UBool setSrcToBogus) noexcept {
int16_t lengthAndFlags = fUnion.fFields.fLengthAndFlags = src.fUnion.fFields.fLengthAndFlags; if(lengthAndFlags & kUsingStackBuffer) { // Short string using the stack buffer, copy the contents. // Check for self assignment to prevent "overlap in memcpy" warnings, // although it should be harmless to copy a buffer to itself exactly. if(this != &src) {
uprv_memcpy(fUnion.fStackFields.fBuffer, src.fUnion.fStackFields.fBuffer,
getShortLength() * U_SIZEOF_UCHAR);
}
} else { // In all other cases, copy all fields.
fUnion.fFields.fArray = src.fUnion.fFields.fArray;
fUnion.fFields.fCapacity = src.fUnion.fFields.fCapacity; if(!hasShortLength()) {
fUnion.fFields.fLength = src.fUnion.fFields.fLength;
} if(setSrcToBogus) { // Set src to bogus without releasing any memory.
src.fUnion.fFields.fLengthAndFlags = kIsBogus;
src.fUnion.fFields.fArray = nullptr;
src.fUnion.fFields.fCapacity = 0;
}
}
}
void UnicodeString::swap(UnicodeString &other) noexcept {
UnicodeString temp; // Empty short string: Known not to need releaseArray(). // Copy fields without resetting source values in between.
temp.copyFieldsFrom(*this, false);
this->copyFieldsFrom(other, false);
other.copyFieldsFrom(temp, false); // Set temp to an empty string so that other's memory is not released twice.
temp.fUnion.fFields.fLengthAndFlags = kShortString;
}
//======================================== // Read-only implementation //========================================
UBool
UnicodeString::doEquals(const char16_t *text, int32_t len) const { // Requires: this not bogus and have same lengths. // Byte-wise comparison works for equality regardless of endianness. return uprv_memcmp(getArrayStart(), text, len * U_SIZEOF_UCHAR) == 0;
}
/* * note that uprv_memcmp() returns an int but we return an int8_t; * we need to take care not to truncate the result - * one way to do this is to right-shift the value to * move the sign bit into the lower 8 bits and making sure that this * does not become 0 itself
*/
// turn a bogus string into an empty one void
UnicodeString::unBogus() { if(fUnion.fFields.fLengthAndFlags & kIsBogus) {
setToEmpty();
}
}
const char16_t *
UnicodeString::getTerminatedBuffer() { if(!isWritable()) { return nullptr;
}
char16_t *array = getArrayStart();
int32_t len = length(); if(len < getCapacity()) { if(fUnion.fFields.fLengthAndFlags & kBufferIsReadonly) { // If len<capacity on a read-only alias, then array[len] is // either the original NUL (if constructed with (true, s, length)) // or one of the original string contents characters (if later truncated), // therefore we can assume that array[len] is initialized memory. if(array[len] == 0) { return array;
}
} elseif(((fUnion.fFields.fLengthAndFlags & kRefCounted) == 0 || refCount() == 1)) { // kRefCounted: Do not write the NUL if the buffer is shared. // That is mostly safe, except when the length of one copy was modified // without copy-on-write, e.g., via truncate(newLength) or remove(). // Then the NUL would be written into the middle of another copy's string.
// Otherwise, the buffer is fully writable and it is anyway safe to write the NUL. // Do not test if there is a NUL already because it might be uninitialized memory. // (That would be safe, but tools like valgrind & Purify would complain.)
array[len] = 0; return array;
}
} if(len<INT32_MAX && cloneArrayIfNeeded(len+1)) {
array = getArrayStart();
array[len] = 0; return array;
} else { return nullptr;
}
}
// setTo() analogous to the readonly-aliasing constructor with the same signature
UnicodeString &
UnicodeString::setTo(UBool isTerminated,
ConstChar16Ptr textPtr,
int32_t textLength)
{ if(fUnion.fFields.fLengthAndFlags & kOpenGetBuffer) { // do not modify a string that has an "open" getBuffer(minCapacity) return *this;
}
const char16_t *text = textPtr; if(text == nullptr) { // treat as an empty string, do not alias
releaseArray();
setToEmpty(); return *this;
}
if(textLength == -1) { // text is terminated, or else it would have failed the above test
textLength = u_strlen(text);
}
fUnion.fFields.fLengthAndFlags = kReadonlyAlias;
setArray(const_cast<char16_t*>(text), textLength, isTerminated ? textLength + 1 : textLength); return *this;
}
// setTo() analogous to the writable-aliasing constructor with the same signature
UnicodeString &
UnicodeString::setTo(char16_t *buffer,
int32_t buffLength,
int32_t buffCapacity) { if(fUnion.fFields.fLengthAndFlags & kOpenGetBuffer) { // do not modify a string that has an "open" getBuffer(minCapacity) return *this;
}
if(buffer == nullptr) { // treat as an empty string, do not alias
releaseArray();
setToEmpty(); return *this;
}
UnicodeString &UnicodeString::setToUTF8(StringPiece utf8) {
unBogus();
int32_t length = utf8.length();
int32_t capacity; // The UTF-16 string will be at most as long as the UTF-8 string. if(length <= US_STACKBUF_SIZE) {
capacity = US_STACKBUF_SIZE;
} else {
capacity = length + 1; // +1 for the terminating NUL.
}
char16_t *utf16 = getBuffer(capacity);
int32_t length16;
UErrorCode errorCode = U_ZERO_ERROR;
u_strFromUTF8WithSub(utf16, getCapacity(), &length16,
utf8.data(), length,
0xfffd, // Substitution character.
nullptr, // Don't care about number of substitutions.
&errorCode);
releaseBuffer(length16); if(U_FAILURE(errorCode)) {
setToBogus();
} return *this;
}
UnicodeString&
UnicodeString::setCharAt(int32_t offset,
char16_t c)
{
int32_t len = length(); if(cloneArrayIfNeeded() && len > 0) { if(offset < 0) {
offset = 0;
} elseif(offset >= len) {
offset = len - 1;
}
getArrayStart()[offset] = c;
} return *this;
}
UnicodeString&
UnicodeString::replace(int32_t start,
int32_t _length,
UChar32 srcChar) {
char16_t buffer[U16_MAX_LENGTH];
int32_t count = 0;
UBool isError = false;
U16_APPEND(buffer, count, U16_MAX_LENGTH, srcChar, isError); // We test isError so that the compiler does not complain that we don't. // If isError (srcChar is not a valid code point) then count==0 which means // we remove the source segment rather than replacing it with srcChar. return doReplace(start, _length, buffer, 0, isError ? 0 : count);
}
UnicodeString&
UnicodeString::append(UChar32 srcChar) {
char16_t buffer[U16_MAX_LENGTH];
int32_t _length = 0;
UBool isError = false;
U16_APPEND(buffer, _length, U16_MAX_LENGTH, srcChar, isError); // We test isError so that the compiler does not complain that we don't. // If isError then _length==0 which turns the doAppend() into a no-op anyway. return isError ? *this : doAppend(buffer, 0, _length);
}
UnicodeString&
UnicodeString::doReplace( int32_t start,
int32_t length, const UnicodeString& src,
int32_t srcStart,
int32_t srcLength)
{ // pin the indices to legal values
src.pinIndices(srcStart, srcLength);
// get the characters from src // and replace the range in ourselves with them return doReplace(start, length, src.getArrayStart(), srcStart, srcLength);
}
if (srcChars == nullptr) {
srcLength = 0;
} else { // Perform all remaining operations relative to srcChars + srcStart. // From this point forward, do not use srcStart.
srcChars += srcStart; if (srcLength < 0) { // get the srcLength if necessary
srcLength = u_strlen(srcChars);
}
}
// pin the indices to legal values
pinIndices(start, length);
// Calculate the size of the string after the replace. // Avoid int32_t overflow.
int32_t newLength = oldLength - length; if(srcLength > (INT32_MAX - newLength)) {
setToBogus(); return *this;
}
newLength += srcLength;
// Check for insertion into ourself const char16_t *oldArray = getArrayStart(); if (isBufferWritable() &&
oldArray < srcChars + srcLength &&
srcChars < oldArray + oldLength) { // Copy into a new UnicodeString and start over
UnicodeString copy(srcChars, srcLength); if (copy.isBogus()) {
setToBogus(); return *this;
} return doReplace(start, length, copy.getArrayStart(), 0, srcLength);
}
// cloneArrayIfNeeded(doCopyArray=false) may change fArray but will not copy the current contents; // therefore we need to keep the current fArray
char16_t oldStackBuffer[US_STACKBUF_SIZE]; if((fUnion.fFields.fLengthAndFlags&kUsingStackBuffer) && (newLength > US_STACKBUF_SIZE)) { // copy the stack buffer contents because it will be overwritten with // fUnion.fFields values
u_memcpy(oldStackBuffer, oldArray, oldLength);
oldArray = oldStackBuffer;
}
// clone our array and allocate a bigger array if needed
int32_t *bufferToDelete = nullptr; if(!cloneArrayIfNeeded(newLength, getGrowCapacity(newLength), false, &bufferToDelete)
) { return *this;
}
// now do the replace
char16_t *newArray = getArrayStart(); if(newArray != oldArray) { // if fArray changed, then we need to copy everything except what will change
us_arrayCopy(oldArray, 0, newArray, 0, start);
us_arrayCopy(oldArray, start + length,
newArray, start + srcLength,
oldLength - (start + length));
} elseif(length != srcLength) { // fArray did not change; copy only the portion that isn't changing, leaving a hole
us_arrayCopy(oldArray, start + length,
newArray, start + srcLength,
oldLength - (start + length));
}
// now fill in the hole with the new string
us_arrayCopy(srcChars, 0, newArray, start, srcLength);
setLength(newLength);
// delayed delete in case srcChars == fArray when we started, and // to keep oldArray alive for the above operations if (bufferToDelete) {
uprv_free(bufferToDelete);
}
/** * Replaceable API
*/ void
UnicodeString::copy(int32_t start, int32_t limit, int32_t dest) { if (limit <= start) { return; // Nothing to do; avoid bogus malloc call
}
char16_t* text = static_cast<char16_t*>(uprv_malloc(sizeof(char16_t) * (limit - start))); // Check to make sure text is not null. if (text != nullptr) {
extractBetween(start, limit, text, 0);
insert(dest, text, 0, limit - start);
uprv_free(text);
}
}
/** * Replaceable API * * NOTE: This is for the Replaceable class. There is no rep.cpp, * so we implement this function here.
*/
UBool Replaceable::hasMetaData() const { returntrue;
}
// Before the loop we know left<right because length>=2. do {
hasSupplementary |= static_cast<UBool>(U16_IS_LEAD(swap = *left));
hasSupplementary |= static_cast<UBool>(U16_IS_LEAD(*left++ = *right));
*right-- = swap;
} while(left < right); // Make sure to test the middle code unit of an odd-length string. // Redundant if the length is even.
hasSupplementary |= static_cast<UBool>(U16_IS_LEAD(*left));
/* if there are supplementary code points in the reversed range, then re-swap their surrogates */ if(hasSupplementary) {
char16_t swap2;
left = getArrayStart() + start;
right = left + length - 1; // -1 so that we can look at *(left+1) if left<right while(left < right) { if(U16_IS_TRAIL(swap = *left) && U16_IS_LEAD(swap2 = *(left + 1))) {
*left++ = swap2;
*left++ = swap;
} else {
++left;
}
}
}
void
UnicodeString::releaseBuffer(int32_t newLength) { if(fUnion.fFields.fLengthAndFlags&kOpenGetBuffer && newLength>=-1) { // set the new fLength
int32_t capacity=getCapacity(); if(newLength==-1) { // the new length is the string length, capped by fCapacity const char16_t *array=getArrayStart(), *p=array, *limit=array+capacity; while(p<limit && *p!=0) {
++p;
}
newLength = static_cast<int32_t>(p - array);
} elseif(newLength>capacity) {
newLength=capacity;
}
setLength(newLength);
fUnion.fFields.fLengthAndFlags&=~kOpenGetBuffer;
}
}
//======================================== // Miscellaneous //========================================
UBool
UnicodeString::cloneArrayIfNeeded(int32_t newCapacity,
int32_t growCapacity,
UBool doCopyArray,
int32_t **pBufferToDelete,
UBool forceClone) { // default parameters need to be static, therefore // the defaults are -1 to have convenience defaults if(newCapacity == -1) {
newCapacity = getCapacity();
}
// while a getBuffer(minCapacity) is "open", // prevent any modifications of the string by returning false here // if the string is bogus, then only an assignment or similar can revive it if(!isWritable()) { returnfalse;
}
/* * We need to make a copy of the array if * the buffer is read-only, or * the buffer is refCounted (shared), and refCount>1, or * the buffer is too small. * Return false if memory could not be allocated.
*/ if(forceClone ||
fUnion.fFields.fLengthAndFlags & kBufferIsReadonly ||
(fUnion.fFields.fLengthAndFlags & kRefCounted && refCount() > 1) ||
newCapacity > getCapacity()
) { // check growCapacity for default value and use of the stack buffer if(growCapacity < 0) {
growCapacity = newCapacity;
} elseif(newCapacity <= US_STACKBUF_SIZE && growCapacity > US_STACKBUF_SIZE) {
growCapacity = US_STACKBUF_SIZE;
}
// save old values
char16_t oldStackBuffer[US_STACKBUF_SIZE];
char16_t *oldArray;
int32_t oldLength = length();
int16_t flags = fUnion.fFields.fLengthAndFlags;
if(flags&kUsingStackBuffer) {
U_ASSERT(!(flags&kRefCounted)); /* kRefCounted and kUsingStackBuffer are mutally exclusive */ if(doCopyArray && growCapacity > US_STACKBUF_SIZE) { // copy the stack buffer contents because it will be overwritten with // fUnion.fFields values
us_arrayCopy(fUnion.fStackFields.fBuffer, 0, oldStackBuffer, 0, oldLength);
oldArray = oldStackBuffer;
} else {
oldArray = nullptr; // no need to copy from the stack buffer to itself
}
} else {
oldArray = fUnion.fFields.fArray;
U_ASSERT(oldArray!=nullptr); /* when stack buffer is not used, oldArray must have a non-nullptr reference */
}
// allocate a new array if(allocate(growCapacity) ||
(newCapacity < growCapacity && allocate(newCapacity))
) { if(doCopyArray) { // copy the contents // do not copy more than what fits - it may be smaller than before
int32_t minLength = oldLength;
newCapacity = getCapacity(); if(newCapacity < minLength) {
minLength = newCapacity;
} if(oldArray != nullptr) {
us_arrayCopy(oldArray, 0, getArrayStart(), 0, minLength);
}
setLength(minLength);
} else {
setZeroLength();
}
// release the old array if(flags & kRefCounted) { // the array is refCounted; decrement and release if 0
u_atomic_int32_t* pRefCount = reinterpret_cast<u_atomic_int32_t*>(oldArray) - 1; if(umtx_atomic_dec(pRefCount) == 0) { if (pBufferToDelete == nullptr) { // Note: cast to (void *) is needed with MSVC, where u_atomic_int32_t // is defined as volatile. (Volatile has useful non-standard behavior // with this compiler.)
uprv_free((void *)pRefCount);
} else { // the caller requested to delete it himself
*pBufferToDelete = reinterpret_cast<int32_t*>(pRefCount);
}
}
}
} else { // not enough memory for growCapacity and not even for the smaller newCapacity // reset the old values for setToBogus() to release the array if(!(flags&kUsingStackBuffer)) {
fUnion.fFields.fArray = oldArray;
}
fUnion.fFields.fLengthAndFlags = flags;
setToBogus(); returnfalse;
}
} returntrue;
}
// Moved here from uhash_us.cpp so that using a UVector of UnicodeString* // does not depend on hashtable code.
U_CAPI UBool U_EXPORT2
uhash_compareUnicodeString(const UElement key1, const UElement key2) { const UnicodeString *str1 = (const UnicodeString*) key1.pointer; const UnicodeString *str2 = (const UnicodeString*) key2.pointer; if (str1 == str2) { returntrue;
} if (str1 == nullptr || str2 == nullptr) { returnfalse;
} return *str1 == *str2;
}
#ifdef U_STATIC_IMPLEMENTATION /* This should never be called. It is defined here to make sure that the virtual vector deleting destructor is defined within unistr.cpp. The vector deleting destructor is already a part of UObject, but defining it here makes sure that it is included with this object file. This makes sure that static library dependencies are kept to a minimum.
*/ #ifdefined(__clang__) || U_GCC_MAJOR_MINOR >= 1100 #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wunused-function" staticvoid uprv_UnicodeStringDummy() { delete [] (new UnicodeString[2]);
} #pragma GCC diagnostic pop #endif #endif
Messung V0.5
¤ Dauer der Verarbeitung: 0.23 Sekunden
(vorverarbeitet)
¤
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.