diff --git a/xpcom/string/nsTSubstring.cpp b/xpcom/string/nsTSubstring.cpp index d7e1b14e2f92..402fb5483dde 100644 --- a/xpcom/string/nsTSubstring.cpp +++ b/xpcom/string/nsTSubstring.cpp @@ -507,6 +507,24 @@ void nsTSubstring::Assign(self_type&& aStr) { } } +template +void nsTSubstring::AssignOwned(self_type&& aStr) { + NS_ASSERTION(aStr.mDataFlags & (DataFlags::REFCOUNTED | DataFlags::OWNED), + "neither shared nor owned"); + + // If they have a REFCOUNTED or OWNED buffer, we can avoid a copy - so steal + // their buffer and reset them to the empty string. + + // |aStr| should be null-terminated + NS_ASSERTION(aStr.mDataFlags & DataFlags::TERMINATED, + "shared or owned, but not terminated"); + + ::ReleaseData(this->mData, this->mDataFlags); + + SetData(aStr.mData, aStr.mLength, aStr.mDataFlags); + aStr.SetToEmptyBuffer(); +} + template bool nsTSubstring::Assign(self_type&& aStr, const fallible_t& aFallible) { // We're moving |aStr| in this method, so we need to try to steal the data, @@ -519,17 +537,7 @@ bool nsTSubstring::Assign(self_type&& aStr, const fallible_t& aFallible) { } if (aStr.mDataFlags & (DataFlags::REFCOUNTED | DataFlags::OWNED)) { - // If they have a REFCOUNTED or OWNED buffer, we can avoid a copy - so steal - // their buffer and reset them to the empty string. - - // |aStr| should be null-terminated - NS_ASSERTION(aStr.mDataFlags & DataFlags::TERMINATED, - "shared or owned, but not terminated"); - - ::ReleaseData(this->mData, this->mDataFlags); - - SetData(aStr.mData, aStr.mLength, aStr.mDataFlags); - aStr.SetToEmptyBuffer(); + AssignOwned(std::move(aStr)); return true; } @@ -550,26 +558,40 @@ void nsTSubstring::Assign(const substring_tuple_type& aTuple) { } template -bool nsTSubstring::Assign(const substring_tuple_type& aTuple, - const fallible_t& aFallible) { - if (aTuple.IsDependentOn(this->mData, this->mData + this->mLength)) { - // take advantage of sharing here... - return Assign(string_type(aTuple), aFallible); - } +bool nsTSubstring::AssignNonDependent(const substring_tuple_type& aTuple, + size_type aTupleLength, + const mozilla::fallible_t& aFallible) { + NS_ASSERTION(aTuple.Length() == aTupleLength, "wrong length passed"); - size_type length = aTuple.Length(); - - mozilla::Result r = StartBulkWriteImpl(length); + mozilla::Result r = StartBulkWriteImpl(aTupleLength); if (r.isErr()) { return false; } - aTuple.WriteTo(this->mData, length); + aTuple.WriteTo(this->mData, aTupleLength); - FinishBulkWriteImpl(length); + FinishBulkWriteImpl(aTupleLength); return true; } +template +bool nsTSubstring::Assign(const substring_tuple_type& aTuple, + const fallible_t& aFallible) { + const auto [isDependentOnThis, tupleLength] = + aTuple.IsDependentOnWithLength(this->mData, this->mData + this->mLength); + if (isDependentOnThis) { + string_type temp; + self_type& tempSubstring = temp; + if (!tempSubstring.AssignNonDependent(aTuple, tupleLength, aFallible)) { + return false; + } + AssignOwned(std::move(temp)); + return true; + } + + return AssignNonDependent(aTuple, tupleLength, aFallible); +} + template void nsTSubstring::Adopt(char_type* aData, size_type aLength) { if (aData) { diff --git a/xpcom/string/nsTSubstring.h b/xpcom/string/nsTSubstring.h index cad96e39bc15..fa48a63fd108 100644 --- a/xpcom/string/nsTSubstring.h +++ b/xpcom/string/nsTSubstring.h @@ -1271,6 +1271,11 @@ class nsTSubstring : public mozilla::detail::nsTStringRepr { size_type aOldSuffixStart = 0, size_type aNewSuffixStart = 0); private: + void AssignOwned(self_type&& aStr); + bool AssignNonDependent(const substring_tuple_type& aTuple, + size_type aTupleLength, + const mozilla::fallible_t& aFallible); + /** * Do not call this except from within FinishBulkWriteImpl() and * SetCapacity().