📄 ustring.cpp
字号:
rep->checkConsistency(); int thisSize = rep->size(); int thisOffset = rep->offset; int length = thisSize + tSize; UString::BaseString* base = rep->baseString(); // possible cases: if (tSize == 0) { // t is empty } else if (thisSize == 0) { // this is empty rep = UString::Rep::createCopying(tData, tSize); } else if (rep == base && rep->rc == 1) { // this is direct and has refcount of 1 (so we can just alter it directly) if (!expandCapacity(rep.get(), thisOffset + length)) rep = &UString::Rep::null(); if (rep->data()) { copyChars(rep->data() + thisSize, tData, tSize); rep->len = length; rep->_hash = 0; } } else if (thisOffset + thisSize == base->usedCapacity && thisSize >= minShareSize) { // this reaches the end of the buffer - extend it if it's long enough to append to if (!expandCapacity(rep.get(), thisOffset + length)) rep = &UString::Rep::null(); if (rep->data()) { copyChars(rep->data() + thisSize, tData, tSize); rep = UString::Rep::create(rep, 0, length); } } else { // this is shared with someone using more capacity, gotta make a whole new string size_t newCapacity = expandedSize(length, 0); UChar* d = allocChars(newCapacity); if (!d) rep = &UString::Rep::null(); else { copyChars(d, rep->data(), thisSize); copyChars(d + thisSize, tData, tSize); rep = UString::Rep::create(d, length); rep->baseString()->capacity = newCapacity; } } rep->checkConsistency(); return rep.release();}static ALWAYS_INLINE PassRefPtr<UString::Rep> concatenate(PassRefPtr<UString::Rep> r, const char* t){ RefPtr<UString::Rep> rep = r; rep->checkConsistency(); int thisSize = rep->size(); int thisOffset = rep->offset; int tSize = static_cast<int>(strlen(t)); int length = thisSize + tSize; UString::BaseString* base = rep->baseString(); // possible cases: if (thisSize == 0) { // this is empty rep = createRep(t); } else if (tSize == 0) { // t is empty, we'll just return *this below. } else if (rep == base && rep->rc == 1) { // this is direct and has refcount of 1 (so we can just alter it directly) expandCapacity(rep.get(), thisOffset + length); UChar* d = rep->data(); if (d) { for (int i = 0; i < tSize; ++i) d[thisSize + i] = static_cast<unsigned char>(t[i]); // use unsigned char to zero-extend instead of sign-extend rep->len = length; rep->_hash = 0; } } else if (thisOffset + thisSize == base->usedCapacity && thisSize >= minShareSize) { // this string reaches the end of the buffer - extend it expandCapacity(rep.get(), thisOffset + length); UChar* d = rep->data(); if (d) { for (int i = 0; i < tSize; ++i) d[thisSize + i] = static_cast<unsigned char>(t[i]); // use unsigned char to zero-extend instead of sign-extend rep = UString::Rep::create(rep, 0, length); } } else { // this is shared with someone using more capacity, gotta make a whole new string size_t newCapacity = expandedSize(length, 0); UChar* d = allocChars(newCapacity); if (!d) rep = &UString::Rep::null(); else { copyChars(d, rep->data(), thisSize); for (int i = 0; i < tSize; ++i) d[thisSize + i] = static_cast<unsigned char>(t[i]); // use unsigned char to zero-extend instead of sign-extend rep = UString::Rep::create(d, length); rep->baseString()->capacity = newCapacity; } } rep->checkConsistency(); return rep.release();}PassRefPtr<UString::Rep> concatenate(UString::Rep* a, UString::Rep* b){ a->checkConsistency(); b->checkConsistency(); int aSize = a->size(); int aOffset = a->offset; int bSize = b->size(); int bOffset = b->offset; int length = aSize + bSize; // possible cases: // a is empty if (aSize == 0) return b; // b is empty if (bSize == 0) return a; UString::BaseString* aBase = a->baseString(); if (bSize == 1 && aOffset + aSize == aBase->usedCapacity && aOffset + length <= aBase->capacity) { // b is a single character (common fast case) aBase->usedCapacity = aOffset + length; a->data()[aSize] = b->data()[0]; return UString::Rep::create(a, 0, length); } UString::BaseString* bBase = b->baseString(); if (aOffset + aSize == aBase->usedCapacity && aSize >= minShareSize && 4 * aSize >= bSize && (-bOffset != bBase->usedPreCapacity || aSize >= bSize)) { // - a reaches the end of its buffer so it qualifies for shared append // - also, it's at least a quarter the length of b - appending to a much shorter // string does more harm than good // - however, if b qualifies for prepend and is longer than a, we'd rather prepend UString x(a); x.expandCapacity(aOffset + length); if (!a->data() || !x.data()) return 0; copyChars(a->data() + aSize, b->data(), bSize); PassRefPtr<UString::Rep> result = UString::Rep::create(a, 0, length); a->checkConsistency(); b->checkConsistency(); result->checkConsistency(); return result; } if (-bOffset == bBase->usedPreCapacity && bSize >= minShareSize && 4 * bSize >= aSize) { // - b reaches the beginning of its buffer so it qualifies for shared prepend // - also, it's at least a quarter the length of a - prepending to a much shorter // string does more harm than good UString y(b); y.expandPreCapacity(-bOffset + aSize); if (!b->data() || !y.data()) return 0; copyChars(b->data() - aSize, a->data(), aSize); PassRefPtr<UString::Rep> result = UString::Rep::create(b, -aSize, length); a->checkConsistency(); b->checkConsistency(); result->checkConsistency(); return result; } // a does not qualify for append, and b does not qualify for prepend, gotta make a whole new string size_t newCapacity = expandedSize(length, 0); UChar* d = allocChars(newCapacity); if (!d) return 0; copyChars(d, a->data(), aSize); copyChars(d + aSize, b->data(), bSize); PassRefPtr<UString::Rep> result = UString::Rep::create(d, length); result->baseString()->capacity = newCapacity; a->checkConsistency(); b->checkConsistency(); result->checkConsistency(); return result;}PassRefPtr<UString::Rep> concatenate(UString::Rep* rep, int i){ UChar buf[1 + sizeof(i) * 3]; UChar* end = buf + sizeof(buf) / sizeof(UChar); UChar* p = end; if (i == 0) *--p = '0'; else if (i == INT_MIN) { char minBuf[1 + sizeof(i) * 3]; sprintf(minBuf, "%d", INT_MIN); return concatenate(rep, minBuf); } else { bool negative = false; if (i < 0) { negative = true; i = -i; } while (i) { *--p = static_cast<unsigned short>((i % 10) + '0'); i /= 10; } if (negative) *--p = '-'; } return concatenate(rep, p, static_cast<int>(end - p));}PassRefPtr<UString::Rep> concatenate(UString::Rep* rep, double d){ // avoid ever printing -NaN, in JS conceptually there is only one NaN value if (isnan(d)) return concatenate(rep, "NaN"); if (d == 0.0) // stringify -0 as 0 d = 0.0; char buf[80]; int decimalPoint; int sign; char* result = WTF::dtoa(d, 0, &decimalPoint, &sign, NULL); int length = static_cast<int>(strlen(result)); int i = 0; if (sign) buf[i++] = '-'; if (decimalPoint <= 0 && decimalPoint > -6) { buf[i++] = '0'; buf[i++] = '.'; for (int j = decimalPoint; j < 0; j++) buf[i++] = '0'; strcpy(buf + i, result); } else if (decimalPoint <= 21 && decimalPoint > 0) { if (length <= decimalPoint) { strcpy(buf + i, result); i += length; for (int j = 0; j < decimalPoint - length; j++) buf[i++] = '0'; buf[i] = '\0'; } else { strncpy(buf + i, result, decimalPoint); i += decimalPoint; buf[i++] = '.'; strcpy(buf + i, result + decimalPoint); } } else if (result[0] < '0' || result[0] > '9') strcpy(buf + i, result); else { buf[i++] = result[0]; if (length > 1) { buf[i++] = '.'; strcpy(buf + i, result + 1); i += length - 1; } buf[i++] = 'e'; buf[i++] = (decimalPoint >= 0) ? '+' : '-'; // decimalPoint can't be more than 3 digits decimal given the // nature of float representation int exponential = decimalPoint - 1; if (exponential < 0) exponential = -exponential; if (exponential >= 100) buf[i++] = static_cast<char>('0' + exponential / 100); if (exponential >= 10) buf[i++] = static_cast<char>('0' + (exponential % 100) / 10); buf[i++] = static_cast<char>('0' + exponential % 10); buf[i++] = '\0'; } WTF::freedtoa(result); return concatenate(rep, buf);}UString UString::from(int i){ UChar buf[1 + sizeof(i) * 3]; UChar* end = buf + sizeof(buf) / sizeof(UChar); UChar* p = end; if (i == 0) *--p = '0'; else if (i == INT_MIN) { char minBuf[1 + sizeof(i) * 3]; sprintf(minBuf, "%d", INT_MIN); return UString(minBuf); } else { bool negative = false; if (i < 0) { negative = true; i = -i; } while (i) { *--p = static_cast<unsigned short>((i % 10) + '0'); i /= 10; } if (negative) *--p = '-'; } return UString(p, static_cast<int>(end - p));}UString UString::from(unsigned int u){ UChar buf[sizeof(u) * 3]; UChar* end = buf + sizeof(buf) / sizeof(UChar); UChar* p = end; if (u == 0) *--p = '0'; else { while (u) { *--p = static_cast<unsigned short>((u % 10) + '0'); u /= 10; } } return UString(p, static_cast<int>(end - p));}UString UString::from(long l){ UChar buf[1 + sizeof(l) * 3]; UChar* end = buf + sizeof(buf) / sizeof(UChar); UChar* p = end; if (l == 0) *--p = '0'; else if (l == LONG_MIN) { char minBuf[1 + sizeof(l) * 3]; sprintf(minBuf, "%ld", LONG_MIN); return UString(minBuf); } else { bool negative = false; if (l < 0) { negative = true; l = -l; } while (l) { *--p = static_cast<unsigned short>((l % 10) + '0'); l /= 10; } if (negative) *--p = '-'; } return UString(p, static_cast<int>(end - p));}UString UString::from(double d){ // avoid ever printing -NaN, in JS conceptually there is only one NaN value if (isnan(d)) return "NaN"; char buf[80]; int decimalPoint; int sign; char* result = WTF::dtoa(d, 0, &decimalPoint, &sign, NULL); int length = static_cast<int>(strlen(result)); int i = 0; if (sign) buf[i++] = '-'; if (decimalPoint <= 0 && decimalPoint > -6) { buf[i++] = '0'; buf[i++] = '.'; for (int j = decimalPoint; j < 0; j++) buf[i++] = '0'; strcpy(buf + i, result); } else if (decimalPoint <= 21 && decimalPoint > 0) { if (length <= decimalPoint) { strcpy(buf + i, result); i += length; for (int j = 0; j < decimalPoint - length; j++) buf[i++] = '0'; buf[i] = '\0'; } else { strncpy(buf + i, result, decimalPoint); i += decimalPoint; buf[i++] = '.'; strcpy(buf + i, result + decimalPoint); } } else if (result[0] < '0' || result[0] > '9') strcpy(buf + i, result); else { buf[i++] = result[0]; if (length > 1) { buf[i++] = '.'; strcpy(buf + i, result + 1); i += length - 1; } buf[i++] = 'e'; buf[i++] = (decimalPoint >= 0) ? '+' : '-'; // decimalPoint can't be more than 3 digits decimal given the // nature of float representation int exponential = decimalPoint - 1; if (exponential < 0) exponential = -exponential; if (exponential >= 100) buf[i++] = static_cast<char>('0' + exponential / 100); if (exponential >= 10) buf[i++] = static_cast<char>('0' + (exponential % 100) / 10); buf[i++] = static_cast<char>('0' + exponential % 10); buf[i++] = '\0'; } WTF::freedtoa(result); return UString(buf);}UString UString::spliceSubstringsWithSeparators(const Range* substringRanges, int rangeCount, const UString* separators, int separatorCount) const{ m_rep->checkConsistency(); if (rangeCount == 1 && separatorCount == 0) { int thisSize = size(); int position = substringRanges[0].position; int length = substringRanges[0].length; if (position <= 0 && length >= thisSize) return *this; return UString::Rep::create(m_rep, max(0, position), min(thisSize, length)); } int totalLength = 0; for (int i = 0; i < rangeCount; i++) totalLength += substringRanges[i].length; for (int i = 0; i < separatorCount; i++) totalLength += separators[i].size(); if (totalLength == 0) return ""; UChar* buffer = allocChars(totalLength); if (!buffer) return null(); int maxCount = max(rangeCount, separatorCount); int bufferPos = 0; for (int i = 0; i < maxCount; i++) { if (i < rangeCount) { copyChars(buffer + bufferPos, data() + substringRanges[i].position, substringRanges[i].length); bufferPos += substringRanges[i].length; } if (i < separatorCount) { copyChars(buffer + bufferPos, separators[i].data(), separators[i].size()); bufferPos += separators[i].size(); } } return UString::Rep::create(buffer, totalLength);}UString& UString::append(const UString &t){ m_rep->checkConsistency(); t.rep()->checkConsistency(); int thisSize = size(); int thisOffset = m_rep->offset; int tSize = t.size(); int length = thisSize + tSize; BaseString* base = m_rep->baseString(); // possible cases: if (thisSize == 0) { // this is empty *this = t; } else if (tSize == 0) { // t is empty } else if (m_rep == base && m_rep->rc == 1) { // this is direct and has refcount of 1 (so we can just alter it directly) expandCapacity(thisOffset + length); if (data()) { copyChars(m_rep->data() + thisSize, t.data(), tSize); m_rep->len = length; m_rep->_hash = 0; } } else if (thisOffset + thisSize == base->usedCapacity && thisSize >= minShareSize) { // this reaches the end of the buffer - extend it if it's long enough to append to expandCapacity(thisOffset + length); if (data()) { copyChars(m_rep->data() + thisSize, t.data(), tSize); m_rep = Rep::create(m_rep, 0, length); } } else { // this is shared with someone using more capacity, gotta make a whole new string size_t newCapacity = expandedSize(length, 0); UChar* d = allocChars(newCapacity); if (!d) makeNull(); else { copyChars(d, data(), thisSize); copyChars(d + thisSize, t.data(), tSize); m_rep = Rep::create(d, length); m_rep->baseString()->capacity = newCapacity; } } m_rep->checkConsistency(); t.rep()->checkConsistency(); return *this;}UString& UString::append(const UChar* tData, int tSize){ m_rep = concatenate(m_rep.release(), tData, tSize); return *this;}UString& UString::append(const char* t){ m_rep = concatenate(m_rep.release(), t); return *this;}UString& UString::append(UChar c){ m_rep->checkConsistency(); int thisOffset = m_rep->offset; int length = size(); BaseString* base = m_rep->baseString(); // possible cases: if (length == 0) { // this is empty - must make a new m_rep because we don't want to pollute the shared empty one size_t newCapacity = expandedSize(1, 0); UChar* d = allocChars(newCapacity); if (!d) makeNull(); else {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -