/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // IWYU pragma: private, include "nsString.h"
#ifndef MOZILLA_INTERNAL_API # error "Using XPCOM strings is limited to code linked into libxul." #endif
// The max number of logically uninitialized code units to // fill with a marker byte or to mark as unintialized for // memory checking. (Limited to avoid quadratic behavior.) const size_t kNsStringBufferMaxPoison = 16;
template <typename T> class nsTSubstringSplitter; template <typename T> class nsTString; template <typename T> class nsTSubstring;
template <typename T> struct type_identity { using type = T;
}; template <typename T> using type_identity_t = typename type_identity<T>::type;
namespace mozilla {
/** * This handle represents permission to perform low-level writes * the storage buffer of a string in a manner that's aware of the * actual capacity of the storage buffer allocation and that's * cache-friendly in the sense that the writing of zero terminator * for C compatibility can happen in linear memory access order * (i.e. the zero terminator write takes place after writing * new content to the string as opposed to the zero terminator * write happening first causing a non-linear memory write for * cache purposes). * * If you requested a prefix to be preserved when starting * or restarting the bulk write, the prefix is present at the * start of the buffer exposed by this handle as Span or * as a raw pointer, and it's your responsibility to start * writing after after the preserved prefix (which you * presumably wanted not to overwrite since you asked for * it to be preserved). * * In a success case, you must call Finish() with the new * length of the string. In failure cases, it's OK to return * early from the function whose local variable this handle is. * The destructor of this class takes care of putting the * string in a valid and mostly harmless state in that case * by setting the value of a non-empty string to a single * REPLACEMENT CHARACTER or in the case of nsACString that's * too short for a REPLACEMENT CHARACTER to fit, an ASCII * SUBSTITUTE. * * You must not allow this handle to outlive the string you * obtained it from. * * You must not access the string you obtained this handle * from in any way other than through this handle until * you call Finish() on the handle or the handle goes out * of scope. * * Once you've called Finish(), you must not call any * methods on this handle and must not use values previously * obtained. * * Once you call RestartBulkWrite(), you must not use * values previously obtained from this handle and must * reobtain the new corresponding values.
*/ template <typename T> class BulkWriteHandle final { friendclass nsTSubstring<T>;
/** * Pointer to the start of the writable buffer. Never nullptr. * * This pointer is valid until whichever of these happens first: * 1) Finish() is called * 2) RestartBulkWrite() is called * 3) BulkWriteHandle goes out of scope
*/
T* Elements() const {
MOZ_ASSERT(mString); return mString->mData;
}
/** * How many code units can be written to the buffer. * (Note: This is not the same as the string's Length().) * * This value is valid until whichever of these happens first: * 1) Finish() is called * 2) RestartBulkWrite() is called * 3) BulkWriteHandle goes out of scope
*/
size_type Length() const {
MOZ_ASSERT(mString); return mCapacity;
}
/** * Pointer past the end of the buffer. * * This pointer is valid until whichever of these happens first: * 1) Finish() is called * 2) RestartBulkWrite() is called * 3) BulkWriteHandle goes out of scope
*/
T* End() const { return Elements() + Length(); }
/** * The writable buffer as Span. * * This Span is valid until whichever of these happens first: * 1) Finish() is called * 2) RestartBulkWrite() is called * 3) BulkWriteHandle goes out of scope
*/ auto AsSpan() const { return mozilla::Span<T>{Elements(), Length()}; }
/** * Autoconvert to the buffer as writable Span. * * This Span is valid until whichever of these happens first: * 1) Finish() is called * 2) RestartBulkWrite() is called * 3) BulkWriteHandle goes out of scope
*/ operator mozilla::Span<T>() const { return AsSpan(); }
/** * Restart the bulk write with a different capacity. * * This method invalidates previous return values * of the other methods above. * * Can fail if out of memory leaving the buffer * in the state before this call. * * @param aCapacity the new requested capacity * @param aPrefixToPreserve the number of code units at * the start of the string to * copy over to the new buffer * @param aAllowShrinking whether the string is * allowed to attempt to * allocate a smaller buffer * for its content and copy * the data over.
*/
mozilla::Result<mozilla::Ok, nsresult> RestartBulkWrite(
size_type aCapacity, size_type aPrefixToPreserve, bool aAllowShrinking) {
MOZ_ASSERT(mString);
MOZ_TRY_VAR(mCapacity, mString->StartBulkWriteImpl(
aCapacity, aPrefixToPreserve, aAllowShrinking)); return mozilla::Ok();
}
/** * Indicate that the bulk write finished successfully. * * @param aLength the number of code units written; * must not exceed Length() * @param aAllowShrinking whether the string is * allowed to attempt to * allocate a smaller buffer * for its content and copy * the data over.
*/ void Finish(size_type aLength, bool aAllowShrinking) {
MOZ_ASSERT(mString);
MOZ_ASSERT(aLength <= mCapacity); if (!aLength) { // Truncate is safe even when the string is in an invalid state
mString->Truncate();
mString = nullptr; return;
} if (aAllowShrinking) {
mozilla::Unused << mString->StartBulkWriteImpl(aLength, aLength, true);
}
mString->FinishBulkWriteImpl(aLength);
mString = nullptr;
}
~BulkWriteHandle() { if (!mString || !mCapacity) { return;
} // The old zero terminator may be gone by now, so we need // to write a new one somewhere and make length match. // We can use a length between 1 and self.capacity. // The contents of the string can be partially uninitialized // or partially initialized in a way that would be dangerous // if parsed by some recipient. It's prudent to write something // same as the contents of the string. U+FFFD is the safest // placeholder, but when it doesn't fit, let's use ASCII // substitute. Merely truncating the string to a zero-length // string might be dangerous in some scenarios. See // https://www.unicode.org/reports/tr36/#Substituting_for_Ill_Formed_Subsequences // for closely related scenario. auto ptr = Elements(); // Cast the pointer below to silence warnings if (sizeof(T) == 1) { unsignedchar* charPtr = reinterpret_cast<unsignedchar*>(ptr); if (mCapacity >= 3) {
*charPtr++ = 0xEF;
*charPtr++ = 0xBF;
*charPtr++ = 0xBD;
mString->mLength = 3;
} else {
*charPtr++ = 0x1A;
mString->mLength = 1;
}
*charPtr = 0;
} elseif (sizeof(T) == 2) {
char16_t* charPtr = reinterpret_cast<char16_t*>(ptr);
*charPtr++ = 0xFFFD;
*charPtr = 0;
mString->mLength = 1;
} else {
MOZ_ASSERT_UNREACHABLE("Only 8-bit and 16-bit code units supported.");
}
}
nsTSubstring<T>* mString; // nullptr upon finish
size_type mCapacity;
};
} // namespace mozilla
/** * nsTSubstring is an abstract string class. From an API perspective, this * class is the root of the string class hierarchy. It represents a single * contiguous array of characters, which may or may not be null-terminated. * This type is not instantiated directly. A sub-class is instantiated * instead. For example, see nsTString. * * NAMES: * nsAString for wide characters * nsACString for narrow characters *
*/ template <typename T> class nsTSubstring : public mozilla::detail::nsTStringRepr<T> { friendclass mozilla::BulkWriteHandle<T>; friendclass mozilla::StringBuffer;
// These are only for internal use within the string classes: typedeftypename base_string_type::DataFlags DataFlags; typedeftypename base_string_type::ClassFlags ClassFlags; typedeftypename base_string_type::LengthStorage LengthStorage;
// this acts like a virtual destructor
~nsTSubstring() { Finalize(); }
/** * writing iterators * * BeginWriting() makes the string mutable (if it isn't * already) and returns (or writes into an outparam) a * pointer that provides write access to the string's buffer. * * Note: Consider if BulkWrite() suits your use case better * than BeginWriting() combined with SetLength(). * * Note: Strings autoconvert into writable mozilla::Span, * which may suit your use case better than calling * BeginWriting() directly. * * When writing via the pointer obtained from BeginWriting(), * you are allowed to write at most the number of code units * indicated by Length() or, alternatively, write up to, but * not including, the position indicated by EndWriting(). * * In particular, calling SetCapacity() does not affect what * the above paragraph says.
*/
iterator BeginWriting() { if (!EnsureMutable()) {
AllocFailed(base_string_type::mLength);
}
/** * Perform string to int conversion. * @param aErrorCode will contain error if one occurs * @param aRadix is the radix to use. Only 10 and 16 are supported. * @return int rep of string value, and possible (out) error code
*/
int32_t ToInteger(nsresult* aErrorCode, uint32_t aRadix = 10) const;
/** * Perform string to uint conversion. * @param aErrorCode will contain error if one occurs * @param aRadix is the radix to use. Only 10 and 16 are supported. * @return int rep of string value, and possible (out) error code
*/
uint32_t ToUnsignedInteger(nsresult* aErrorCode, uint32_t aRadix = 10) const;
/** * Perform string to 64-bit int conversion. * @param aErrorCode will contain error if one occurs * @param aRadix is the radix to use. Only 10 and 16 are supported. * @return 64-bit int rep of string value, and possible (out) error code
*/
int64_t ToInteger64(nsresult* aErrorCode, uint32_t aRadix = 10) const;
// AssignLiteral must ONLY be called with an actual literal string, or // a character array *constant* of static storage duration declared // without an explicit size and with an initializer that is a string // literal or is otherwise null-terminated. // Use Assign or AssignASCII for other character array variables. // // This method does not need a fallible version, because it uses the // POD buffer of the literal as the string's buffer without allocating. // The literal does not need to be ASCII. If this a 16-bit string, this // method takes a u"" literal. (The overload on 16-bit strings that takes // a "" literal takes only ASCII.) template <int N> void AssignLiteral(const char_type (&aStr)[N]) {
AssignLiteral(aStr, N - 1);
}
// AssignLiteral must ONLY be called with an actual literal string, or // a char array *constant* declared without an explicit size and with an // initializer that is a string literal or is otherwise null-terminated. // Use AssignASCII for other char array variables. // // This method takes an 8-bit (ASCII-only!) string that is expanded // into a 16-bit string at run time causing a run-time allocation. // To avoid the run-time allocation (at the cost of the literal // taking twice the size in the binary), use the above overload that // takes a u"" string instead. Using the overload that takes a u"" // literal is generally preferred when working with 16-bit strings. // // There is not a fallible version of this method because it only really // applies to small allocations that we wouldn't want to check anyway. template <int N, typename Q = T, typename EnableIfChar16 = typename mozilla::Char16OnlyT<Q>> void AssignLiteral(const incompatible_char_type (&aStr)[N]) {
AssignASCII(aStr, N - 1);
}
// Adopt a heap-allocated char sequence for this string; is Voided if aData // is null. Useful for e.g. converting an strdup'd C string into an // nsCString. See also getter_Copies(), which is a useful wrapper. void NS_FASTCALL Adopt(char_type* aData, size_type aLength = size_type(-1));
// ReplaceLiteral must ONLY be called with an actual literal string, or // a character array *constant* of static storage duration declared // without an explicit size and with an initializer that is a string // literal or is otherwise null-terminated. // Use Replace for other character array variables. template <int N> void ReplaceLiteral(index_type aCutStart, size_type aCutLength, const char_type (&aStr)[N]) {
ReplaceLiteral(aCutStart, aCutLength, aStr, N - 1);
}
/** * |Left|, |Mid|, and |Right| are annoying signatures that seem better almost * any _other_ way than they are now. Consider these alternatives * * // ...a member function that returns a |Substring| * aWritable = aReadable.Left(17); * // ...a global function that returns a |Substring| * aWritable = Left(aReadable, 17); * // ...a global function that does the assignment * Left(aReadable, 17, aWritable); * * as opposed to the current signature * * // ...a member function that does the assignment * aReadable.Left(aWritable, 17); * * or maybe just stamping them out in favor of |Substring|, they are just * duplicate functionality * * aWritable = Substring(aReadable, 0, 17);
*/
size_type Mid(self_type& aResult, index_type aStartPos,
size_type aCount) const;
/** * This method strips whitespace throughout the string.
*/ void StripWhitespace(); bool StripWhitespace(const fallible_t&);
/** * This method is used to remove all occurrences of aChar from this * string. * * @param aChar -- char to be stripped
*/ void StripChar(char_type aChar);
/** * This method is used to remove all occurrences of aChars from this * string. * * @param aChars -- chars to be stripped
*/ void StripChars(const char_type* aChars);
/** * This method is used to remove all occurrences of some characters this * from this string. The characters removed have the corresponding * entries in the bool array set to true; we retain all characters * with code beyond 127. * THE CALLER IS RESPONSIBLE for making sure the complete boolean * array, 128 entries, is properly initialized. * * See also: ASCIIMask class. * * @param aToStrip -- Array where each entry is true if the * corresponding ASCII character is to be stripped. All * characters beyond code 127 are retained. Note that this * parameter is of ASCIIMaskArray type, but we expand the typedef * to avoid having to include nsASCIIMask.h in this include file * as it brings other includes.
*/ void StripTaggedASCII(const std::array<bool, 128>& aToStrip);
/** * A shortcut to strip \r and \n.
*/ void StripCRLF();
/** * swaps occurence of 1 string for another
*/ void ReplaceChar(char_type aOldChar, char_type aNewChar); void ReplaceChar(const string_view& aSet, char_type aNewChar);
/** * Replace all occurrences of aTarget with aNewValue. * The complexity of this function is O(n+m), n being the length of the string * and m being the length of aNewValue.
*/ void ReplaceSubstring(const self_type& aTarget, const self_type& aNewValue); void ReplaceSubstring(const char_type* aTarget, const char_type* aNewValue);
[[nodiscard]] bool ReplaceSubstring(const self_type& aTarget, const self_type& aNewValue, const fallible_t&);
[[nodiscard]] bool ReplaceSubstring(const char_type* aTarget, const char_type* aNewValue, const fallible_t&);
/** * This method trims characters found in aSet from either end of the * underlying string. * * @param aSet -- contains chars to be trimmed from both ends * @param aTrimLeading * @param aTrimTrailing * @param aIgnoreQuotes -- if true, causes surrounding quotes to be ignored * @return this
*/ void Trim(const std::string_view& aSet, bool aTrimLeading = true, bool aTrimTrailing = true, bool aIgnoreQuotes = false);
/** * This method strips whitespace from string. * You can control whether whitespace is yanked from start and end of * string as well. * * @param aTrimLeading controls stripping of leading ws * @param aTrimTrailing controls stripping of trailing ws
*/ void CompressWhitespace(bool aTrimLeading = true, bool aTrimTrailing = true);
// Appends a literal string ("" literal in the 8-bit case and u"" literal // in the 16-bit case) to the string. // // AppendLiteral must ONLY be called with an actual literal string, or // a character array *constant* of static storage duration declared // without an explicit size and with an initializer that is a string // literal or is otherwise null-terminated. // Use Append or AppendASCII for other character array variables. template <int N> void AppendLiteral(const char_type (&aStr)[N]) { // The case where base_string_type::mLength is zero is intentionally // left unoptimized (could be optimized as call to AssignLiteral), // because it's rare/nonexistent. If you add that optimization, // please be sure to also check that // !(base_string_type::mDataFlags & DataFlags::REFCOUNTED) // to avoid undoing the effects of SetCapacity().
Append(aStr, N - 1);
}
template <int N> void AppendLiteral(const char_type (&aStr)[N], const fallible_t& aFallible) { // The case where base_string_type::mLength is zero is intentionally // left unoptimized (could be optimized as call to AssignLiteral), // because it's rare/nonexistent. If you add that optimization, // please be sure to also check that // !(base_string_type::mDataFlags & DataFlags::REFCOUNTED) // to avoid undoing the effects of SetCapacity(). return Append(aStr, N - 1, aFallible);
}
// Only enable for T = char16_t // // Appends an 8-bit literal string ("" literal) to a 16-bit string by // expanding it. The literal must only contain ASCII. // // Using u"" literals with 16-bit strings is generally preferred. template <int N, typename Q = T, typename EnableIfChar16 = mozilla::Char16OnlyT<Q>> void AppendLiteral(const incompatible_char_type (&aStr)[N]) {
AppendASCII(aStr, N - 1);
}
// Only enable for T = char16_t template <int N, typename Q = T, typename EnableIfChar16 = mozilla::Char16OnlyT<Q>>
[[nodiscard]] bool AppendLiteral(const incompatible_char_type (&aStr)[N], const fallible_t& aFallible) { return AppendASCII(aStr, N - 1, aFallible);
}
/** * Append a formatted string to the current string. Uses the * standard printf format codes. This uses NSPR formatting, which will be * locale-aware for floating-point values. You probably don't want to use * this with floating-point values as a result.
*/ void AppendPrintf(constchar* aFormat, ...) MOZ_FORMAT_PRINTF(2, 3); void AppendVprintf(constchar* aFormat, va_list aAp) MOZ_FORMAT_PRINTF(2, 0); void AppendInt(int32_t aInteger) { AppendIntDec(aInteger); } void AppendInt(int32_t aInteger, int aRadix) { if (aRadix == 10) {
AppendIntDec(aInteger);
} elseif (aRadix == 8) {
AppendIntOct(static_cast<uint32_t>(aInteger));
} else {
AppendIntHex(static_cast<uint32_t>(aInteger));
}
} void AppendInt(uint32_t aInteger) { AppendIntDec(aInteger); } void AppendInt(uint32_t aInteger, int aRadix) { if (aRadix == 10) {
AppendIntDec(aInteger);
} elseif (aRadix == 8) {
AppendIntOct(aInteger);
} else {
AppendIntHex(aInteger);
}
} void AppendInt(int64_t aInteger) { AppendIntDec(aInteger); } void AppendInt(int64_t aInteger, int aRadix) { if (aRadix == 10) {
AppendIntDec(aInteger);
} elseif (aRadix == 8) {
AppendIntOct(static_cast<uint64_t>(aInteger));
} else {
AppendIntHex(static_cast<uint64_t>(aInteger));
}
} void AppendInt(uint64_t aInteger) { AppendIntDec(aInteger); } void AppendInt(uint64_t aInteger, int aRadix) { if (aRadix == 10) {
AppendIntDec(aInteger);
} elseif (aRadix == 8) {
AppendIntOct(aInteger);
} else {
AppendIntHex(aInteger);
}
}
// InsertLiteral must ONLY be called with an actual literal string, or // a character array *constant* of static storage duration declared // without an explicit size and with an initializer that is a string // literal or is otherwise null-terminated. // Use Insert for other character array variables. template <int N> void InsertLiteral(const char_type (&aStr)[N], index_type aPos) {
ReplaceLiteral(aPos, 0, aStr, N - 1);
}
/** * Attempts to set the capacity to the given size in number of * code units without affecting the length of the string in * order to avoid reallocation during a subsequent sequence of * appends. * * This method is appropriate to use before a sequence of multiple * operations from the following list (without operations that are * not on the list between the SetCapacity() call and operations * from the list): * * Append() * AppendASCII() * AppendLiteral() * AppendPrintf() * AppendInt() * AppendFloat() * LossyAppendUTF16toASCII() * AppendASCIItoUTF16() * * DO NOT call SetCapacity() if the subsequent operations on the * string do not meet the criteria above. Operations that undo * the benefits of SetCapacity() include but are not limited to: * * SetLength() * Truncate() * Assign() * AssignLiteral() * Adopt() * CopyASCIItoUTF16() * LossyCopyUTF16toASCII() * AppendUTF16toUTF8() * AppendUTF8toUTF16() * CopyUTF16toUTF8() * CopyUTF8toUTF16() * * If your string is an nsAuto[C]String and you are calling * SetCapacity() with a constant N, please instead declare the * string as nsAuto[C]StringN<N+1> without calling SetCapacity(). * * There is no need to include room for the null terminator: it is * the job of the string class. * * Note: Calling SetCapacity() does not give you permission to * use the pointer obtained from BeginWriting() to write * past the current length (as returned by Length()) of the * string. Please use either BulkWrite() or SetLength() * instead. * * Note: SetCapacity() won't make the string shorter if * called with an argument smaller than the length of the * string. * * Note: You must not use previously obtained iterators * or spans after calling SetCapacity().
*/ void NS_FASTCALL SetCapacity(size_type aNewCapacity);
[[nodiscard]] bool NS_FASTCALL SetCapacity(size_type aNewCapacity, const fallible_t&);
/** * Changes the logical length of the string, potentially * allocating a differently-sized buffer for the string. * * When making the string shorter, this method never * reports allocation failure. * * Exposes uninitialized memory if the string got longer. * * If called with the argument 0, releases the * heap-allocated buffer, if any. (But the no-argument * overload of Truncate() is a more idiomatic and efficient * option than SetLength(0).) * * Note: You must not use previously obtained iterators * or spans after calling SetLength().
*/ void NS_FASTCALL SetLength(size_type aNewLength);
[[nodiscard]] bool NS_FASTCALL SetLength(size_type aNewLength, const fallible_t&);
/** * Like SetLength() but asserts in that the string * doesn't become longer. Never fails, so doesn't need a * fallible variant. * * Note: You must not use previously obtained iterators * or spans after calling Truncate().
*/ void Truncate(size_type aNewLength) {
MOZ_RELEASE_ASSERT(aNewLength <= base_string_type::mLength, "Truncate cannot make string longer");
mozilla::DebugOnly<bool> success = SetLength(aNewLength, mozilla::fallible);
MOZ_ASSERT(success);
}
/** * A more efficient overload for Truncate(0). Releases the * heap-allocated buffer if any.
*/ void Truncate();
/** * buffer access
*/
/** * Get a const pointer to the string's internal buffer. The caller * MUST NOT modify the characters at the returned address. * * @returns The length of the buffer in characters.
*/ inline size_type GetData(const char_type** aData) const {
*aData = base_string_type::mData; return base_string_type::mLength;
}
/** * Get a pointer to the string's internal buffer, optionally resizing * the buffer first. If size_type(-1) is passed for newLen, then the * current length of the string is used. The caller MAY modify the * characters at the returned address (up to but not exceeding the * length of the string). * * @returns The length of the buffer in characters or 0 if unable to * satisfy the request due to low-memory conditions.
*/
size_type GetMutableData(char_type** aData,
size_type aNewLen = size_type(-1)) { if (!EnsureMutable(aNewLen)) {
AllocFailed(aNewLen == size_type(-1) ? base_string_type::Length()
: aNewLen);
}
/** * string data is never null, but can be marked void. if true, the * string will be truncated. @see nsTSubstring::IsVoid
*/
void NS_FASTCALL SetIsVoid(bool);
/** * If the string uses a reference-counted buffer, this method returns a * pointer to it without incrementing the buffer's refcount.
*/
mozilla::StringBuffer* GetStringBuffer() const { if (this->mDataFlags & DataFlags::REFCOUNTED) { return mozilla::StringBuffer::FromData(this->mData);
} return nullptr;
}
protected:
constexpr void AssertValid() {
MOZ_DIAGNOSTIC_ASSERT(!(this->mClassFlags & ClassFlags::INVALID_MASK));
MOZ_DIAGNOSTIC_ASSERT(!(this->mDataFlags & DataFlags::INVALID_MASK));
MOZ_ASSERT(!(this->mClassFlags & ClassFlags::NULL_TERMINATED) ||
(this->mDataFlags & DataFlags::TERMINATED), "String classes whose static type guarantees a null-terminated " "buffer must not be assigned a non-null-terminated buffer.");
}
public: /** * this is public to support automatic conversion of tuple to string * base type, which helps avoid converting to nsTAString.
*/
MOZ_IMPLICIT nsTSubstring(const substring_tuple_type& aTuple)
: base_string_type(nullptr, 0, DataFlags(0), ClassFlags(0)) {
AssertValid();
Assign(aTuple);
}
/** * WARNING: Only use these functions if you really know what you are * doing, because they can easily lead to double-counting strings. If * you do use them, please explain clearly in a comment why it's safe * and won't lead to double-counting.
*/
size_t SizeOfExcludingThisEvenIfShared(
mozilla::MallocSizeOf aMallocSizeOf) const;
size_t SizeOfIncludingThisEvenIfShared(
mozilla::MallocSizeOf aMallocSizeOf) const;
template <class N> void NS_ABORT_OOM(T) { struct never {}; // a compiler-friendly way to do static_assert(false)
static_assert(
std::is_same_v<N, never>, "In string classes, use AllocFailed to account for sizeof(char_type). " "Use the global ::NS_ABORT_OOM if you really have a count of bytes.");
}
// copy-constructor, constructs as dependent on given object // (NOTE: this is for internal use only)
nsTSubstring(const self_type& aStr)
: base_string_type(aStr.base_string_type::mData,
aStr.base_string_type::mLength,
aStr.base_string_type::mDataFlags &
(DataFlags::TERMINATED | DataFlags::VOIDED),
ClassFlags(0)) {
AssertValid();
}
/** * this function releases mData and does not change the value of * any of its member variables. in other words, this function acts * like a destructor.
*/ void NS_FASTCALL Finalize();
public: /** * Starts a low-level write transaction to the string. * * Prepares the string for mutation such that the capacity * of the string is at least aCapacity. The returned handle * exposes the actual, potentially larger, capacity. * * If meeting the capacity or mutability requirement requires * reallocation, aPrefixToPreserve code units are copied from the * start of the old buffer to the start of the new buffer. * aPrefixToPreserve must not be greater than the string's current * length or greater than aCapacity. * * aAllowShrinking indicates whether an allocation may be * performed when the string is already mutable and the requested * capacity is smaller than the current capacity. * * If this method returns successfully, you must not access * the string except through the returned BulkWriteHandle * until either the BulkWriteHandle goes out of scope or * you call Finish() on the BulkWriteHandle. * * Compared to SetLength() and BeginWriting(), this more * complex API accomplishes two things: * 1) It exposes the actual capacity which may be larger * than the requested capacity, which is useful in some * multi-step write operations that don't allocate for * the worst case up front. * 2) It writes the zero terminator after the string * content has been written, which results in a * cache-friendly linear write pattern.
*/
mozilla::Result<mozilla::BulkWriteHandle<T>, nsresult> NS_FASTCALL BulkWrite(
size_type aCapacity, size_type aPrefixToPreserve, bool aAllowShrinking);
/** * THIS IS NOT REALLY A PUBLIC METHOD! DO NOT CALL FROM OUTSIDE * THE STRING IMPLEMENTATION. (It's public only because friend * declarations don't allow extern or static and this needs to * be called from Rust FFI glue.) * * Prepares mData to be mutated such that the capacity of the string * (not counting the zero-terminator) is at least aCapacity. * Returns the actual capacity, which may be larger than what was * requested or Err(NS_ERROR_OUT_OF_MEMORY) on allocation failure. * * mLength is ignored by this method. If the buffer is reallocated, * aUnitsToPreserve specifies how many code units to copy over to * the new buffer. The old buffer is freed if applicable. * * Unless the return value is Err(NS_ERROR_OUT_OF_MEMORY) to signal * failure or 0 to signal that the string has been set to * the special empty state, this method leaves the string in an * invalid state! The caller is responsible for calling * FinishBulkWrite() (or in Rust calling * nsA[C]StringBulkWriteHandle::finish()), which put the string * into a valid state by setting mLength and zero-terminating. * This method sets the flag to claim that the string is * zero-terminated before it actually is. * * Once this method has been called and before FinishBulkWrite() * has been called, only accessing mData or calling this method * again are valid operations. Do not call any other methods or * access other fields between calling this method and * FinishBulkWrite(). * * @param aCapacity The requested capacity. The return value * will be greater than or equal to this value. * @param aPrefixToPreserve The number of code units at the start * of the old buffer to copy into the * new buffer. * @parem aAllowShrinking If true, an allocation may be performed * if the requested capacity is smaller * than the current capacity. * @param aSuffixLength The length, in code units, of a suffix * to move. * @param aOldSuffixStart The old start index of the suffix to * move. * @param aNewSuffixStart The new start index of the suffix to * move. *
*/
mozilla::Result<size_type, nsresult> NS_FASTCALL StartBulkWriteImpl(
size_type aCapacity, size_type aPrefixToPreserve = 0, bool aAllowShrinking = true, size_type aSuffixLength = 0,
size_type aOldSuffixStart = 0, size_type aNewSuffixStart = 0);
/** * Do not call this except from within FinishBulkWriteImpl() and * SetCapacity().
*/
MOZ_ALWAYS_INLINE void NS_FASTCALL
FinishBulkWriteImplImpl(LengthStorage aLength) {
base_string_type::mData[aLength] = char_type(0);
base_string_type::mLength = aLength; #ifdef DEBUG // ifdefed in order to avoid the call to Capacity() in non-debug // builds. // // Our string is mutable, so Capacity() doesn't return zero. // Capacity() doesn't include the space for the zero terminator, // but we want to unitialize that slot, too. Since we start // counting after the zero terminator the we just wrote above, // we end up overwriting the space for terminator not reflected // in the capacity number.
char_traits::uninitialize(
base_string_type::mData + aLength + 1,
XPCOM_MIN(size_t(Capacity() - aLength), kNsStringBufferMaxPoison)); #endif
}
protected: /** * Restores the string to a valid state after a call to StartBulkWrite() * that returned a non-error result. The argument to this method * must be less than or equal to the value returned by the most recent * StartBulkWrite() call.
*/ void NS_FASTCALL FinishBulkWriteImpl(size_type aLength);
/** * this function prepares a section of mData to be modified. if * necessary, this function will reallocate mData and possibly move * existing data to open up the specified section. * * @param aCutStart specifies the starting offset of the section * @param aCutLength specifies the length of the section to be replaced * @param aNewLength specifies the length of the new section * * for example, suppose mData contains the string "abcdef" then * * ReplacePrep(2, 3, 4); * * would cause mData to look like "ab____f" where the characters * indicated by '_' have an unspecified value and can be freely * modified. this function will null-terminate mData upon return. * * this function returns false if is unable to allocate sufficient * memory.
*/
[[nodiscard]] bool ReplacePrep(index_type aCutStart, size_type aCutLength,
size_type aNewLength);
/** * returns the number of writable storage units starting at mData. * the value does not include space for the null-terminator character. * * NOTE: this function returns 0 if mData is immutable (or the buffer * is 0-sized).
*/
size_type NS_FASTCALL Capacity() const;
/** * this helper function can be called prior to directly manipulating * the contents of mData. see, for example, BeginWriting.
*/
[[nodiscard]] bool NS_FASTCALL
EnsureMutable(size_type aNewLen = size_type(-1));
public: // NOTE: this method is declared public _only_ for convenience for // callers who don't have access to the original nsLiteralString_CharT. void NS_FASTCALL AssignLiteral(const char_type* aData, size_type aLength);
};
static_assert(sizeof(nsTSubstring<char>) == sizeof(mozilla::detail::nsTStringRepr<char>), "Don't add new data fields to nsTSubstring_CharT. " "Add to nsTStringRepr instead.");
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.