- if (!buffer.size())
- m_rep = &Rep::empty();
- else
- m_rep = Rep::createCopying(buffer.data(), buffer.size());
-}
-
-static ALWAYS_INLINE int newCapacityWithOverflowCheck(const int currentCapacity, const int extendLength, const bool plusOne = false)
-{
- ASSERT_WITH_MESSAGE(extendLength >= 0, "extendedLength = %d", extendLength);
-
- const int plusLength = plusOne ? 1 : 0;
- if (currentCapacity > std::numeric_limits<int>::max() - extendLength - plusLength)
- CRASH();
-
- return currentCapacity + extendLength + plusLength;
-}
-
-static ALWAYS_INLINE PassRefPtr<UString::Rep> concatenate(PassRefPtr<UString::Rep> r, const UChar* tData, int tSize)
-{
- RefPtr<UString::Rep> rep = r;
-
- 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(), newCapacityWithOverflowCheck(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(), newCapacityWithOverflowCheck(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(), newCapacityWithOverflowCheck(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(), newCapacityWithOverflowCheck(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(newCapacityWithOverflowCheck(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;