зеркало из https://github.com/mozilla/gecko-dev.git
1455 строки
52 KiB
C++
1455 строки
52 KiB
C++
/* -*- 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 nsTSubstring_h
|
|
#define nsTSubstring_h
|
|
|
|
#include <iterator>
|
|
#include <type_traits>
|
|
|
|
#include "mozilla/Casting.h"
|
|
#include "mozilla/DebugOnly.h"
|
|
#include "mozilla/IntegerPrintfMacros.h"
|
|
#include "mozilla/UniquePtr.h"
|
|
#include "mozilla/Maybe.h"
|
|
#include "mozilla/MemoryReporting.h"
|
|
#include "mozilla/IntegerTypeTraits.h"
|
|
#include "mozilla/ResultExtensions.h"
|
|
#include "mozilla/Span.h"
|
|
#include "mozilla/Try.h"
|
|
#include "mozilla/Unused.h"
|
|
|
|
#include "nsTStringRepr.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;
|
|
|
|
class nsStringBuffer;
|
|
template <typename T>
|
|
class nsTSubstringSplitter;
|
|
template <typename T>
|
|
class nsTString;
|
|
template <typename T>
|
|
class nsTSubstring;
|
|
|
|
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 {
|
|
friend class nsTSubstring<T>;
|
|
|
|
public:
|
|
typedef typename mozilla::detail::nsTStringRepr<T> base_string_type;
|
|
typedef typename base_string_type::size_type size_type;
|
|
|
|
/**
|
|
* 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(BulkWriteHandle&& aOther)
|
|
: mString(aOther.Forget()), mCapacity(aOther.mCapacity) {}
|
|
|
|
~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) {
|
|
unsigned char* charPtr = reinterpret_cast<unsigned char*>(ptr);
|
|
if (mCapacity >= 3) {
|
|
*charPtr++ = 0xEF;
|
|
*charPtr++ = 0xBF;
|
|
*charPtr++ = 0xBD;
|
|
mString->mLength = 3;
|
|
} else {
|
|
*charPtr++ = 0x1A;
|
|
mString->mLength = 1;
|
|
}
|
|
*charPtr = 0;
|
|
} else if (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.");
|
|
}
|
|
}
|
|
|
|
BulkWriteHandle() = delete;
|
|
BulkWriteHandle(const BulkWriteHandle&) = delete;
|
|
BulkWriteHandle& operator=(const BulkWriteHandle&) = delete;
|
|
|
|
private:
|
|
BulkWriteHandle(nsTSubstring<T>* aString, size_type aCapacity)
|
|
: mString(aString), mCapacity(aCapacity) {}
|
|
|
|
nsTSubstring<T>* Forget() {
|
|
auto string = mString;
|
|
mString = nullptr;
|
|
return string;
|
|
}
|
|
|
|
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> {
|
|
friend class mozilla::BulkWriteHandle<T>;
|
|
friend class nsStringBuffer;
|
|
|
|
public:
|
|
typedef nsTSubstring<T> self_type;
|
|
|
|
typedef nsTString<T> string_type;
|
|
|
|
typedef typename mozilla::detail::nsTStringRepr<T> base_string_type;
|
|
typedef typename base_string_type::substring_type substring_type;
|
|
|
|
typedef typename base_string_type::fallible_t fallible_t;
|
|
|
|
typedef typename base_string_type::char_type char_type;
|
|
typedef typename base_string_type::char_traits char_traits;
|
|
typedef
|
|
typename base_string_type::incompatible_char_type incompatible_char_type;
|
|
|
|
typedef typename base_string_type::substring_tuple_type substring_tuple_type;
|
|
|
|
typedef typename base_string_type::const_iterator const_iterator;
|
|
typedef typename base_string_type::iterator iterator;
|
|
|
|
typedef typename base_string_type::comparator_type comparator_type;
|
|
|
|
typedef typename base_string_type::const_char_iterator const_char_iterator;
|
|
|
|
typedef typename base_string_type::string_view string_view;
|
|
|
|
typedef typename base_string_type::index_type index_type;
|
|
typedef typename base_string_type::size_type size_type;
|
|
|
|
// These are only for internal use within the string classes:
|
|
typedef typename base_string_type::DataFlags DataFlags;
|
|
typedef typename base_string_type::ClassFlags ClassFlags;
|
|
typedef typename 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);
|
|
}
|
|
|
|
return base_string_type::mData;
|
|
}
|
|
|
|
iterator BeginWriting(const fallible_t&) {
|
|
return EnsureMutable() ? base_string_type::mData : iterator(0);
|
|
}
|
|
|
|
iterator EndWriting() {
|
|
if (!EnsureMutable()) {
|
|
AllocFailed(base_string_type::mLength);
|
|
}
|
|
|
|
return base_string_type::mData + base_string_type::mLength;
|
|
}
|
|
|
|
iterator EndWriting(const fallible_t&) {
|
|
return EnsureMutable()
|
|
? (base_string_type::mData + base_string_type::mLength)
|
|
: iterator(0);
|
|
}
|
|
|
|
/**
|
|
* 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 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;
|
|
|
|
/**
|
|
* assignment
|
|
*/
|
|
|
|
void NS_FASTCALL Assign(char_type aChar);
|
|
[[nodiscard]] bool NS_FASTCALL Assign(char_type aChar, const fallible_t&);
|
|
|
|
void NS_FASTCALL Assign(const char_type* aData,
|
|
size_type aLength = size_type(-1));
|
|
[[nodiscard]] bool NS_FASTCALL Assign(const char_type* aData,
|
|
const fallible_t&);
|
|
[[nodiscard]] bool NS_FASTCALL Assign(const char_type* aData,
|
|
size_type aLength, const fallible_t&);
|
|
|
|
void NS_FASTCALL Assign(const self_type&);
|
|
[[nodiscard]] bool NS_FASTCALL Assign(const self_type&, const fallible_t&);
|
|
|
|
void NS_FASTCALL Assign(self_type&&);
|
|
[[nodiscard]] bool NS_FASTCALL Assign(self_type&&, const fallible_t&);
|
|
|
|
void NS_FASTCALL Assign(const substring_tuple_type&);
|
|
[[nodiscard]] bool NS_FASTCALL Assign(const substring_tuple_type&,
|
|
const fallible_t&);
|
|
|
|
#if defined(MOZ_USE_CHAR16_WRAPPER)
|
|
template <typename Q = T, typename EnableIfChar16 = mozilla::Char16OnlyT<Q>>
|
|
void Assign(char16ptr_t aData) {
|
|
Assign(static_cast<const char16_t*>(aData));
|
|
}
|
|
|
|
template <typename Q = T, typename EnableIfChar16 = mozilla::Char16OnlyT<Q>>
|
|
void Assign(char16ptr_t aData, size_type aLength) {
|
|
Assign(static_cast<const char16_t*>(aData), aLength);
|
|
}
|
|
|
|
template <typename Q = T, typename EnableIfChar16 = mozilla::Char16OnlyT<Q>>
|
|
[[nodiscard]] bool Assign(char16ptr_t aData, size_type aLength,
|
|
const fallible_t& aFallible) {
|
|
return Assign(static_cast<const char16_t*>(aData), aLength, aFallible);
|
|
}
|
|
#endif
|
|
|
|
void NS_FASTCALL AssignASCII(const char* aData, size_type aLength);
|
|
[[nodiscard]] bool NS_FASTCALL AssignASCII(const char* aData,
|
|
size_type aLength,
|
|
const fallible_t&);
|
|
|
|
void NS_FASTCALL AssignASCII(const char* aData) {
|
|
AssignASCII(aData, strlen(aData));
|
|
}
|
|
[[nodiscard]] bool NS_FASTCALL AssignASCII(const char* aData,
|
|
const fallible_t& aFallible) {
|
|
return AssignASCII(aData, strlen(aData), aFallible);
|
|
}
|
|
|
|
// 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);
|
|
}
|
|
|
|
self_type& operator=(char_type aChar) {
|
|
Assign(aChar);
|
|
return *this;
|
|
}
|
|
self_type& operator=(const char_type* aData) {
|
|
Assign(aData);
|
|
return *this;
|
|
}
|
|
#if defined(MOZ_USE_CHAR16_WRAPPER)
|
|
template <typename Q = T, typename EnableIfChar16 = mozilla::Char16OnlyT<Q>>
|
|
self_type& operator=(char16ptr_t aData) {
|
|
Assign(aData);
|
|
return *this;
|
|
}
|
|
#endif
|
|
self_type& operator=(const self_type& aStr) {
|
|
Assign(aStr);
|
|
return *this;
|
|
}
|
|
self_type& operator=(self_type&& aStr) {
|
|
Assign(std::move(aStr));
|
|
return *this;
|
|
}
|
|
self_type& operator=(const substring_tuple_type& aTuple) {
|
|
Assign(aTuple);
|
|
return *this;
|
|
}
|
|
|
|
// 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));
|
|
|
|
/**
|
|
* buffer manipulation
|
|
*/
|
|
|
|
void NS_FASTCALL Replace(index_type aCutStart, size_type aCutLength,
|
|
char_type aChar);
|
|
[[nodiscard]] bool NS_FASTCALL Replace(index_type aCutStart,
|
|
size_type aCutLength, char_type aChar,
|
|
const fallible_t&);
|
|
void NS_FASTCALL Replace(index_type aCutStart, size_type aCutLength,
|
|
const char_type* aData,
|
|
size_type aLength = size_type(-1));
|
|
[[nodiscard]] bool NS_FASTCALL Replace(index_type aCutStart,
|
|
size_type aCutLength,
|
|
const char_type* aData,
|
|
size_type aLength, const fallible_t&);
|
|
void Replace(index_type aCutStart, size_type aCutLength,
|
|
const self_type& aStr) {
|
|
Replace(aCutStart, aCutLength, aStr.Data(), aStr.Length());
|
|
}
|
|
[[nodiscard]] bool Replace(index_type aCutStart, size_type aCutLength,
|
|
const self_type& aStr,
|
|
const fallible_t& aFallible) {
|
|
return Replace(aCutStart, aCutLength, aStr.Data(), aStr.Length(),
|
|
aFallible);
|
|
}
|
|
void NS_FASTCALL Replace(index_type aCutStart, size_type aCutLength,
|
|
const substring_tuple_type& aTuple);
|
|
|
|
// 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;
|
|
|
|
size_type Left(self_type& aResult, size_type aCount) const {
|
|
return Mid(aResult, 0, aCount);
|
|
}
|
|
|
|
size_type Right(self_type& aResult, size_type aCount) const {
|
|
aCount = XPCOM_MIN(this->Length(), aCount);
|
|
return Mid(aResult, this->mLength - aCount, aCount);
|
|
}
|
|
|
|
/**
|
|
* 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);
|
|
|
|
void Append(char_type aChar);
|
|
|
|
[[nodiscard]] bool Append(char_type aChar, const fallible_t& aFallible);
|
|
|
|
void Append(const char_type* aData, size_type aLength = size_type(-1));
|
|
|
|
[[nodiscard]] bool Append(const char_type* aData, size_type aLength,
|
|
const fallible_t& aFallible);
|
|
|
|
#if defined(MOZ_USE_CHAR16_WRAPPER)
|
|
template <typename Q = T, typename EnableIfChar16 = mozilla::Char16OnlyT<Q>>
|
|
void Append(char16ptr_t aData, size_type aLength = size_type(-1)) {
|
|
Append(static_cast<const char16_t*>(aData), aLength);
|
|
}
|
|
#endif
|
|
|
|
void Append(const self_type& aStr);
|
|
|
|
[[nodiscard]] bool Append(const self_type& aStr, const fallible_t& aFallible);
|
|
|
|
void Append(const substring_tuple_type& aTuple);
|
|
|
|
[[nodiscard]] bool Append(const substring_tuple_type& aTuple,
|
|
const fallible_t& aFallible);
|
|
|
|
void AppendASCII(const char* aData, size_type aLength = size_type(-1));
|
|
|
|
[[nodiscard]] bool AppendASCII(const char* aData,
|
|
const fallible_t& aFallible);
|
|
|
|
[[nodiscard]] bool AppendASCII(const char* aData, size_type aLength,
|
|
const fallible_t& aFallible);
|
|
|
|
// 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(const char* aFormat, ...) MOZ_FORMAT_PRINTF(2, 3);
|
|
void AppendVprintf(const char* 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);
|
|
} else if (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);
|
|
} else if (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);
|
|
} else if (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);
|
|
} else if (aRadix == 8) {
|
|
AppendIntOct(aInteger);
|
|
} else {
|
|
AppendIntHex(aInteger);
|
|
}
|
|
}
|
|
|
|
private:
|
|
void AppendIntDec(int32_t);
|
|
void AppendIntDec(uint32_t);
|
|
void AppendIntOct(uint32_t);
|
|
void AppendIntHex(uint32_t);
|
|
void AppendIntDec(int64_t);
|
|
void AppendIntDec(uint64_t);
|
|
void AppendIntOct(uint64_t);
|
|
void AppendIntHex(uint64_t);
|
|
|
|
public:
|
|
/**
|
|
* Append the given float to this string
|
|
*/
|
|
void NS_FASTCALL AppendFloat(float aFloat);
|
|
void NS_FASTCALL AppendFloat(double aFloat);
|
|
|
|
self_type& operator+=(char_type aChar) {
|
|
Append(aChar);
|
|
return *this;
|
|
}
|
|
self_type& operator+=(const char_type* aData) {
|
|
Append(aData);
|
|
return *this;
|
|
}
|
|
#if defined(MOZ_USE_CHAR16_WRAPPER)
|
|
template <typename Q = T, typename EnableIfChar16 = mozilla::Char16OnlyT<Q>>
|
|
self_type& operator+=(char16ptr_t aData) {
|
|
Append(aData);
|
|
return *this;
|
|
}
|
|
#endif
|
|
self_type& operator+=(const self_type& aStr) {
|
|
Append(aStr);
|
|
return *this;
|
|
}
|
|
self_type& operator+=(const substring_tuple_type& aTuple) {
|
|
Append(aTuple);
|
|
return *this;
|
|
}
|
|
|
|
void Insert(char_type aChar, index_type aPos) { Replace(aPos, 0, aChar); }
|
|
void Insert(const char_type* aData, index_type aPos,
|
|
size_type aLength = size_type(-1)) {
|
|
Replace(aPos, 0, aData, aLength);
|
|
}
|
|
#if defined(MOZ_USE_CHAR16_WRAPPER)
|
|
template <typename Q = T, typename EnableIfChar16 = mozilla::Char16OnlyT<Q>>
|
|
void Insert(char16ptr_t aData, index_type aPos,
|
|
size_type aLength = size_type(-1)) {
|
|
Insert(static_cast<const char16_t*>(aData), aPos, aLength);
|
|
}
|
|
#endif
|
|
void Insert(const self_type& aStr, index_type aPos) {
|
|
Replace(aPos, 0, aStr);
|
|
}
|
|
void Insert(const substring_tuple_type& aTuple, index_type aPos) {
|
|
Replace(aPos, 0, aTuple);
|
|
}
|
|
|
|
// 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);
|
|
}
|
|
|
|
void Cut(index_type aCutStart, size_type aCutLength) {
|
|
Replace(aCutStart, aCutLength, char_traits::sEmptyBuffer, 0);
|
|
}
|
|
|
|
nsTSubstringSplitter<T> Split(const char_type aChar) const;
|
|
|
|
/**
|
|
* buffer sizing
|
|
*/
|
|
|
|
/**
|
|
* 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() (except if the string is empty: bug 1487606)
|
|
* 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);
|
|
}
|
|
|
|
*aData = base_string_type::mData;
|
|
return base_string_type::Length();
|
|
}
|
|
|
|
size_type GetMutableData(char_type** aData, size_type aNewLen,
|
|
const fallible_t&) {
|
|
if (!EnsureMutable(aNewLen)) {
|
|
*aData = nullptr;
|
|
return 0;
|
|
}
|
|
|
|
*aData = base_string_type::mData;
|
|
return base_string_type::mLength;
|
|
}
|
|
|
|
#if defined(MOZ_USE_CHAR16_WRAPPER)
|
|
template <typename Q = T, typename EnableIfChar16 = mozilla::Char16OnlyT<Q>>
|
|
size_type GetMutableData(wchar_t** aData, size_type aNewLen = size_type(-1)) {
|
|
return GetMutableData(reinterpret_cast<char16_t**>(aData), aNewLen);
|
|
}
|
|
|
|
template <typename Q = T, typename EnableIfChar16 = mozilla::Char16OnlyT<Q>>
|
|
size_type GetMutableData(wchar_t** aData, size_type aNewLen,
|
|
const fallible_t& aFallible) {
|
|
return GetMutableData(reinterpret_cast<char16_t**>(aData), aNewLen,
|
|
aFallible);
|
|
}
|
|
#endif
|
|
|
|
mozilla::Span<char_type> GetMutableData(size_type aNewLen = size_type(-1)) {
|
|
if (!EnsureMutable(aNewLen)) {
|
|
AllocFailed(aNewLen == size_type(-1) ? base_string_type::Length()
|
|
: aNewLen);
|
|
}
|
|
|
|
return mozilla::Span{base_string_type::mData, base_string_type::Length()};
|
|
}
|
|
|
|
mozilla::Maybe<mozilla::Span<char_type>> GetMutableData(size_type aNewLen,
|
|
const fallible_t&) {
|
|
if (!EnsureMutable(aNewLen)) {
|
|
return mozilla::Nothing();
|
|
}
|
|
return Some(
|
|
mozilla::Span{base_string_type::mData, base_string_type::Length()});
|
|
}
|
|
|
|
/**
|
|
* Span integration
|
|
*/
|
|
|
|
operator mozilla::Span<const char_type>() const {
|
|
return mozilla::Span{base_string_type::BeginReading(),
|
|
base_string_type::Length()};
|
|
}
|
|
|
|
void Append(mozilla::Span<const char_type> aSpan) {
|
|
Append(aSpan.Elements(), aSpan.Length());
|
|
}
|
|
|
|
[[nodiscard]] bool Append(mozilla::Span<const char_type> aSpan,
|
|
const fallible_t& aFallible) {
|
|
return Append(aSpan.Elements(), aSpan.Length(), aFallible);
|
|
}
|
|
|
|
void NS_FASTCALL AssignASCII(mozilla::Span<const char> aData) {
|
|
AssignASCII(aData.Elements(), aData.Length());
|
|
}
|
|
[[nodiscard]] bool NS_FASTCALL AssignASCII(mozilla::Span<const char> aData,
|
|
const fallible_t& aFallible) {
|
|
return AssignASCII(aData.Elements(), aData.Length(), aFallible);
|
|
}
|
|
|
|
void AppendASCII(mozilla::Span<const char> aData) {
|
|
AppendASCII(aData.Elements(), aData.Length());
|
|
}
|
|
|
|
template <typename Q = T, typename EnableIfChar = mozilla::CharOnlyT<Q>>
|
|
operator mozilla::Span<const uint8_t>() const {
|
|
return mozilla::Span{
|
|
reinterpret_cast<const uint8_t*>(base_string_type::BeginReading()),
|
|
base_string_type::Length()};
|
|
}
|
|
|
|
template <typename Q = T, typename EnableIfChar = mozilla::CharOnlyT<Q>>
|
|
void Append(mozilla::Span<const uint8_t> aSpan) {
|
|
Append(reinterpret_cast<const char*>(aSpan.Elements()), aSpan.Length());
|
|
}
|
|
|
|
template <typename Q = T, typename EnableIfChar = mozilla::CharOnlyT<Q>>
|
|
[[nodiscard]] bool Append(mozilla::Span<const uint8_t> aSpan,
|
|
const fallible_t& aFallible) {
|
|
return Append(reinterpret_cast<const char*>(aSpan.Elements()),
|
|
aSpan.Length(), aFallible);
|
|
}
|
|
|
|
void Insert(mozilla::Span<const char_type> aSpan, index_type aPos) {
|
|
Insert(aSpan.Elements(), aPos, aSpan.Length());
|
|
}
|
|
|
|
/**
|
|
* 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 shared buffer, this method
|
|
* clears the pointer without releasing the buffer.
|
|
*/
|
|
void ForgetSharedBuffer() {
|
|
if (base_string_type::mDataFlags & DataFlags::REFCOUNTED) {
|
|
SetToEmptyBuffer();
|
|
}
|
|
}
|
|
|
|
protected:
|
|
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);
|
|
}
|
|
|
|
size_t SizeOfExcludingThisIfUnshared(
|
|
mozilla::MallocSizeOf aMallocSizeOf) const;
|
|
size_t SizeOfIncludingThisIfUnshared(
|
|
mozilla::MallocSizeOf aMallocSizeOf) const;
|
|
|
|
/**
|
|
* 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.");
|
|
}
|
|
|
|
MOZ_ALWAYS_INLINE void AllocFailed(size_t aLength) {
|
|
::NS_ABORT_OOM(aLength * sizeof(char_type));
|
|
}
|
|
|
|
protected:
|
|
// default initialization
|
|
nsTSubstring()
|
|
: base_string_type(char_traits::sEmptyBuffer, 0, DataFlags::TERMINATED,
|
|
ClassFlags(0)) {
|
|
AssertValid();
|
|
}
|
|
|
|
// 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();
|
|
}
|
|
|
|
// initialization with ClassFlags
|
|
explicit nsTSubstring(ClassFlags aClassFlags)
|
|
: base_string_type(char_traits::sEmptyBuffer, 0, DataFlags::TERMINATED,
|
|
aClassFlags) {
|
|
AssertValid();
|
|
}
|
|
|
|
/**
|
|
* allows for direct initialization of a nsTSubstring object.
|
|
*/
|
|
nsTSubstring(char_type* aData, size_type aLength, DataFlags aDataFlags,
|
|
ClassFlags aClassFlags)
|
|
#if defined(NS_BUILD_REFCNT_LOGGING)
|
|
# define XPCOM_STRING_CONSTRUCTOR_OUT_OF_LINE
|
|
;
|
|
#else
|
|
# undef XPCOM_STRING_CONSTRUCTOR_OUT_OF_LINE
|
|
: base_string_type(aData, aLength, aDataFlags, aClassFlags) {
|
|
AssertValid();
|
|
}
|
|
#endif /* NS_BUILD_REFCNT_LOGGING */
|
|
|
|
void SetToEmptyBuffer() {
|
|
base_string_type::mData = char_traits::sEmptyBuffer;
|
|
base_string_type::mLength = 0;
|
|
base_string_type::mDataFlags = DataFlags::TERMINATED;
|
|
AssertValid();
|
|
}
|
|
|
|
void SetData(char_type* aData, LengthStorage aLength, DataFlags aDataFlags) {
|
|
base_string_type::mData = aData;
|
|
base_string_type::mLength = aLength;
|
|
base_string_type::mDataFlags = aDataFlags;
|
|
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);
|
|
|
|
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().
|
|
*/
|
|
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);
|
|
|
|
[[nodiscard]] bool NS_FASTCALL ReplacePrepInternal(index_type aCutStart,
|
|
size_type aCutLength,
|
|
size_type aNewFragLength,
|
|
size_type aNewTotalLength);
|
|
|
|
/**
|
|
* 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));
|
|
|
|
void NS_FASTCALL ReplaceLiteral(index_type aCutStart, size_type aCutLength,
|
|
const char_type* aData, size_type aLength);
|
|
|
|
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);
|
|
};
|
|
|
|
extern template class nsTSubstring<char>;
|
|
extern template class nsTSubstring<char16_t>;
|
|
|
|
static_assert(sizeof(nsTSubstring<char>) ==
|
|
sizeof(mozilla::detail::nsTStringRepr<char>),
|
|
"Don't add new data fields to nsTSubstring_CharT. "
|
|
"Add to nsTStringRepr<T> instead.");
|
|
|
|
#include "nsCharSeparatedTokenizer.h"
|
|
#include "nsTDependentSubstring.h"
|
|
|
|
/**
|
|
* Span integration
|
|
*/
|
|
namespace mozilla {
|
|
Span(const nsTSubstring<char>&) -> Span<const char>;
|
|
Span(const nsTSubstring<char16_t>&) -> Span<const char16_t>;
|
|
|
|
} // namespace mozilla
|
|
|
|
#endif
|