bool nsTSubstring_CharT::Assign( const substring_tuple_type& tuple, const fallible_t& ) { if (tuple.IsDependentOn(mData, mData + mLength)) { // take advantage of sharing here... return Assign(string_type(tuple), fallible_t()); } size_type length = tuple.Length(); // don't use ReplacePrep here because it changes the length char_type* oldData; uint32_t oldFlags; if (!MutatePrep(length, &oldData, &oldFlags)) return false; if (oldData) ::ReleaseData(oldData, oldFlags); tuple.WriteTo(mData, length); mData[length] = 0; mLength = length; return true; }
bool nsTSubstring_CharT::ReplacePrepInternal(index_type cutStart, size_type cutLen, size_type fragLen, size_type newLen) { char_type* oldData; uint32_t oldFlags; if (!MutatePrep(newLen, &oldData, &oldFlags)) return false; // out-of-memory if (oldData) { // determine whether or not we need to copy part of the old string // over to the new string. if (cutStart > 0) { // copy prefix from old string char_traits::copy(mData, oldData, cutStart); } if (cutStart + cutLen < mLength) { // copy suffix from old string to new offset size_type from = cutStart + cutLen; size_type fromLen = mLength - from; uint32_t to = cutStart + fragLen; char_traits::copy(mData + to, oldData + from, fromLen); } ::ReleaseData(oldData, oldFlags); } else { // original data remains intact // determine whether or not we need to move part of the existing string // to make room for the requested hole. if (fragLen != cutLen && cutStart + cutLen < mLength) { uint32_t from = cutStart + cutLen; uint32_t fromLen = mLength - from; uint32_t to = cutStart + fragLen; char_traits::move(mData + to, mData + from, fromLen); } } // add null terminator (mutable mData always has room for the null- // terminator). mData[newLen] = char_type(0); mLength = newLen; return true; }
PRBool nsTSubstring_CharT::SetCapacity( size_type capacity ) { // capacity does not include room for the terminating null char // if our capacity is reduced to zero, then free our buffer. if (capacity == 0) { ::ReleaseData(mData, mFlags); mData = char_traits::sEmptyBuffer; mLength = 0; SetDataFlags(F_TERMINATED); } else { char_type* oldData; PRUint32 oldFlags; if (!MutatePrep(capacity, &oldData, &oldFlags)) return PR_FALSE; // out-of-memory // compute new string length size_type newLen = NS_MIN(mLength, capacity); if (oldData) { // preserve old data if (mLength > 0) char_traits::copy(mData, oldData, newLen); ::ReleaseData(oldData, oldFlags); } // adjust mLength if our buffer shrunk down in size if (newLen < mLength) mLength = newLen; // always null-terminate here, even if the buffer got longer. this is // for backwards compat with the old string implementation. mData[capacity] = char_type(0); } return PR_TRUE; }
void nsTSubstring_CharT::Assign( const substring_tuple_type& tuple ) { if (tuple.IsDependentOn(mData, mData + mLength)) { // take advantage of sharing here... Assign(string_type(tuple)); return; } size_type length = tuple.Length(); // don't use ReplacePrep here because it changes the length char_type* oldData; PRUint32 oldFlags; if (MutatePrep(length, &oldData, &oldFlags)) { if (oldData) ::ReleaseData(oldData, oldFlags); tuple.WriteTo(mData, length); mData[length] = 0; mLength = length; } }
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; }