bool nsVoidArray::GrowArrayBy(int32_t aGrowBy) { // We have to grow the array. Grow by kMinGrowArrayBy slots if we're // smaller than kLinearThreshold bytes, or a power of two if we're // larger. This is much more efficient with most memory allocators, // especially if it's very large, or of the allocator is binned. if (aGrowBy < kMinGrowArrayBy) aGrowBy = kMinGrowArrayBy; uint32_t newCapacity = GetArraySize() + aGrowBy; // Minimum increase uint32_t newSize = SIZEOF_IMPL(newCapacity); if (newSize >= (uint32_t) kLinearThreshold) { // newCount includes enough space for at least kMinGrowArrayBy new // slots. Select the next power-of-two size in bytes above or // equal to that. // Also, limit the increase in size to about a VM page or two. if (GetArraySize() >= kMaxGrowArrayBy) { newCapacity = GetArraySize() + XPCOM_MAX(kMaxGrowArrayBy,aGrowBy); newSize = SIZEOF_IMPL(newCapacity); } else { PR_CEILING_LOG2(newSize, newSize); newCapacity = CAPACITYOF_IMPL(1u << newSize); } } // frees old mImpl IF this succeeds if (!SizeTo(newCapacity)) return false; return true; }
bool nsTString_CharT::ReplaceSubstring(const self_type& aTarget, const self_type& aNewValue, const fallible_t&) { if (aTarget.Length() == 0) return true; // Remember all of the non-matching parts. AutoTArray<Segment, 16> nonMatching; uint32_t i = 0; uint32_t newLength = 0; while (true) { int32_t r = FindSubstring(mData + i, mLength - i, static_cast<const char_type*>(aTarget.Data()), aTarget.Length(), false); int32_t until = (r == kNotFound) ? mLength - i : r; nonMatching.AppendElement(Segment(i, until)); newLength += until; if (r == kNotFound) { break; } newLength += aNewValue.Length(); i += r + aTarget.Length(); if (i >= mLength) { // Add an auxiliary entry at the end of the list to help as an edge case // for the algorithms below. nonMatching.AppendElement(Segment(mLength, 0)); break; } } // If there's only one non-matching segment, then the target string was not // found, and there's nothing to do. if (nonMatching.Length() == 1) { MOZ_ASSERT(nonMatching[0].mBegin == 0 && nonMatching[0].mLength == mLength, "We should have the correct non-matching segment."); return true; } // Make sure that we can mutate our buffer. // Note that we always allocate at least an mLength sized buffer, because the // rest of the algorithm relies on having access to all of the original // string. In other words, we over-allocate in the shrinking case. char_type* oldData; uint32_t oldFlags; if (!MutatePrep(XPCOM_MAX(mLength, newLength), &oldData, &oldFlags)) return false; if (oldData) { // Copy all of the old data to the new buffer. char_traits::copy(mData, oldData, mLength); ::ReleaseData(oldData, oldFlags); } if (aTarget.Length() >= aNewValue.Length()) { // In the shrinking case, start filling the buffer from the beginning. const uint32_t delta = (aTarget.Length() - aNewValue.Length()); for (i = 1; i < nonMatching.Length(); ++i) { // When we move the i'th non-matching segment into position, we need to // account for the characters deleted by the previous |i| replacements by // subtracting |i * delta|. const char_type* sourceSegmentPtr = mData + nonMatching[i].mBegin; char_type* destinationSegmentPtr = mData + nonMatching[i].mBegin - i * delta; // Write the i'th replacement immediately before the new i'th non-matching // segment. char_traits::copy(destinationSegmentPtr - aNewValue.Length(), aNewValue.Data(), aNewValue.Length()); char_traits::move(destinationSegmentPtr, sourceSegmentPtr, nonMatching[i].mLength); } } else { // In the growing case, start filling the buffer from the end. const uint32_t delta = (aNewValue.Length() - aTarget.Length()); for (i = nonMatching.Length() - 1; i > 0; --i) { // When we move the i'th non-matching segment into position, we need to // account for the characters added by the previous |i| replacements by // adding |i * delta|. const char_type* sourceSegmentPtr = mData + nonMatching[i].mBegin; char_type* destinationSegmentPtr = mData + nonMatching[i].mBegin + i * delta; char_traits::move(destinationSegmentPtr, sourceSegmentPtr, nonMatching[i].mLength); // Write the i'th replacement immediately before the new i'th non-matching // segment. char_traits::copy(destinationSegmentPtr - aNewValue.Length(), aNewValue.Data(), aNewValue.Length()); } } // Adjust the length and make sure the string is null terminated. mLength = newLength; mData[mLength] = char_type(0); return true; }