fune/xpcom/string/nsTSubstring.h
Henri Sivonen 3edc601325 Bug 1402247 - Use encoding_rs for XPCOM string encoding conversions. r=Nika,erahm,froydnj.
Correctness improvements:

 * UTF errors are handled safely per spec instead of dangerously truncating
   strings.

 * There are fewer converter implementations.

Performance improvements:

 * The old code did exact buffer length math, which meant doing UTF math twice
   on each input string (once for length calculation and another time for
   conversion). Exact length math is more complicated when handling errors
   properly, which the old code didn't do. The new code does UTF math on the
   string content only once (when converting) but risks allocating more than
   once. There are heuristics in place to lower the probability of
   reallocation in cases where the double math avoidance isn't enough of a
   saving to absorb an allocation and memcpy.

 * Previously, in UTF-16 <-> UTF-8 conversions, an ASCII prefix was optimized
   but a single non-ASCII code point pessimized the rest of the string. The
   new code tries to get back on the fast ASCII path.

 * UTF-16 to Latin1 conversion guarantees less about handling of out-of-range
   input to eliminate an operation from the inner loop on x86/x86_64.

 * When assigning to a pre-existing string, the new code tries to reuse the
   old buffer instead of first releasing the old buffer and then allocating a
   new one.

 * When reallocating from the new code, the memcpy covers only the data that
   is part of the logical length of the old string instead of memcpying the
   whole capacity. (For old callers old excess memcpy behavior is preserved
   due to bogus callers. See bug 1472113.)

 * UTF-8 strings in XPConnect that are in the Latin1 range are passed to
   SpiderMonkey as Latin1.

New features:

 * Conversion between UTF-8 and Latin1 is added in order to enable faster
   future interop between Rust code (or otherwise UTF-8-using code) and text
   node and SpiderMonkey code that uses Latin1.

MozReview-Commit-ID: JaJuExfILM9
2018-08-14 14:43:42 +03:00

1132 lines
35 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 "mozilla/Casting.h"
#include "mozilla/IntegerPrintfMacros.h"
#include "mozilla/UniquePtr.h"
#include "mozilla/MemoryReporting.h"
#include "mozilla/IntegerTypeTraits.h"
#include "mozilla/Result.h"
#include "mozilla/Span.h"
#include "nsTStringRepr.h"
#ifndef MOZILLA_INTERNAL_API
#error "Using XPCOM strings is limited to code linked into libxul."
#endif
template <typename T> class nsTSubstringSplitter;
template <typename T> class nsTString;
/**
* 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>
{
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::char_iterator char_iterator;
typedef typename base_string_type::const_char_iterator const_char_iterator;
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;
// this acts like a virtual destructor
~nsTSubstring()
{
Finalize();
}
/**
* writing iterators
*/
char_iterator BeginWriting()
{
if (!EnsureMutable()) {
AllocFailed(base_string_type::mLength);
}
return base_string_type::mData;
}
char_iterator BeginWriting(const fallible_t&)
{
return EnsureMutable() ? base_string_type::mData : char_iterator(0);
}
char_iterator EndWriting()
{
if (!EnsureMutable()) {
AllocFailed(base_string_type::mLength);
}
return base_string_type::mData + base_string_type::mLength;
}
char_iterator EndWriting(const fallible_t&)
{
return EnsureMutable() ? (base_string_type::mData + base_string_type::mLength) : char_iterator(0);
}
char_iterator& BeginWriting(char_iterator& aIter)
{
return aIter = BeginWriting();
}
char_iterator& BeginWriting(char_iterator& aIter, const fallible_t& aFallible)
{
return aIter = BeginWriting(aFallible);
}
char_iterator& EndWriting(char_iterator& aIter)
{
return aIter = EndWriting();
}
char_iterator& EndWriting(char_iterator& aIter, const fallible_t& aFallible)
{
return aIter = EndWriting(aFallible);
}
/**
* 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;
/**
* deprecated writing iterators
*/
iterator& BeginWriting(iterator& aIter)
{
char_type* data = BeginWriting();
aIter.mStart = data;
aIter.mEnd = data + base_string_type::mLength;
aIter.mPosition = aIter.mStart;
return aIter;
}
iterator& EndWriting(iterator& aIter)
{
char_type* data = BeginWriting();
aIter.mStart = data;
aIter.mEnd = data + base_string_type::mLength;
aIter.mPosition = aIter.mEnd;
return aIter;
}
/**
* assignment
*/
void NS_FASTCALL Assign(char_type aChar);
MOZ_MUST_USE bool NS_FASTCALL Assign(char_type aChar, const fallible_t&);
void NS_FASTCALL Assign(const char_type* aData);
MOZ_MUST_USE bool NS_FASTCALL Assign(const char_type* aData,
const fallible_t&);
void NS_FASTCALL Assign(const char_type* aData, size_type aLength);
MOZ_MUST_USE bool NS_FASTCALL Assign(const char_type* aData,
size_type aLength, const fallible_t&);
void NS_FASTCALL Assign(const self_type&);
MOZ_MUST_USE bool NS_FASTCALL Assign(const self_type&, const fallible_t&);
void NS_FASTCALL Assign(self_type&&);
MOZ_MUST_USE bool NS_FASTCALL Assign(self_type&&, const fallible_t&);
void NS_FASTCALL Assign(const substring_tuple_type&);
MOZ_MUST_USE 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>>
MOZ_MUST_USE 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);
MOZ_MUST_USE bool NS_FASTCALL AssignASCII(const char* aData,
size_type aLength,
const fallible_t&);
void NS_FASTCALL AssignASCII(const char* aData)
{
AssignASCII(aData, mozilla::AssertedCast<size_type, size_t>(strlen(aData)));
}
MOZ_MUST_USE bool NS_FASTCALL AssignASCII(const char* aData,
const fallible_t& aFallible)
{
return AssignASCII(aData,
mozilla::AssertedCast<size_type, size_t>(strlen(aData)),
aFallible);
}
// AssignLiteral must ONLY be applied to an actual literal string, or
// a char array *constant* declared without an explicit size.
// Do not attempt to use it with a regular char* pointer, or with a
// non-constant char array variable. Use AssignASCII for those.
// There are not fallible version of these methods because they only really
// apply to small allocations that we wouldn't want to check anyway.
template<int N>
void AssignLiteral(const char_type (&aStr)[N])
{
AssignLiteral(aStr, N - 1);
}
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);
MOZ_MUST_USE 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));
MOZ_MUST_USE 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());
}
MOZ_MUST_USE 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);
void NS_FASTCALL ReplaceASCII(index_type aCutStart, size_type aCutLength,
const char* aData,
size_type aLength = size_type(-1));
MOZ_MUST_USE bool NS_FASTCALL ReplaceASCII(index_type aCutStart, size_type aCutLength,
const char* aData,
size_type aLength,
const fallible_t&);
// ReplaceLiteral must ONLY be applied to an actual literal string.
// Do not attempt to use it with a regular char* pointer, or with a char
// array variable. Use Replace or ReplaceASCII for those.
template<int N>
void ReplaceLiteral(index_type aCutStart, size_type aCutLength,
const char_type (&aStr)[N])
{
ReplaceLiteral(aCutStart, aCutLength, aStr, N - 1);
}
void Append(char_type aChar)
{
Replace(base_string_type::mLength, 0, aChar);
}
MOZ_MUST_USE bool Append(char_type aChar, const fallible_t& aFallible)
{
return Replace(base_string_type::mLength, 0, aChar, aFallible);
}
void Append(const char_type* aData, size_type aLength = size_type(-1))
{
Replace(base_string_type::mLength, 0, aData, aLength);
}
MOZ_MUST_USE bool Append(const char_type* aData, size_type aLength,
const fallible_t& aFallible)
{
return Replace(base_string_type::mLength, 0, aData, aLength, 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)
{
Replace(base_string_type::mLength, 0, aStr);
}
MOZ_MUST_USE bool Append(const self_type& aStr, const fallible_t& aFallible)
{
return Replace(base_string_type::mLength, 0, aStr, aFallible);
}
void Append(const substring_tuple_type& aTuple)
{
Replace(base_string_type::mLength, 0, aTuple);
}
void AppendASCII(const char* aData, size_type aLength = size_type(-1))
{
ReplaceASCII(base_string_type::mLength, 0, aData, aLength);
}
MOZ_MUST_USE bool AppendASCII(const char* aData, const fallible_t& aFallible)
{
return ReplaceASCII(base_string_type::mLength, 0, aData, size_type(-1), aFallible);
}
MOZ_MUST_USE bool AppendASCII(const char* aData, size_type aLength, const fallible_t& aFallible)
{
return ReplaceASCII(base_string_type::mLength, 0, aData, aLength, 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 AppendPrintf(const char* aFormat, va_list aAp) MOZ_FORMAT_PRINTF(2, 0);
void AppendInt(int32_t aInteger)
{
AppendPrintf("%" PRId32, aInteger);
}
void AppendInt(int32_t aInteger, int aRadix)
{
if (aRadix == 10) {
AppendPrintf("%" PRId32, aInteger);
} else {
AppendPrintf(aRadix == 8 ? "%" PRIo32 : "%" PRIx32,
static_cast<uint32_t>(aInteger));
}
}
void AppendInt(uint32_t aInteger)
{
AppendPrintf("%" PRIu32, aInteger);
}
void AppendInt(uint32_t aInteger, int aRadix)
{
AppendPrintf(aRadix == 10 ? "%" PRIu32 : aRadix == 8 ? "%" PRIo32 : "%" PRIx32,
aInteger);
}
void AppendInt(int64_t aInteger)
{
AppendPrintf("%" PRId64, aInteger);
}
void AppendInt(int64_t aInteger, int aRadix)
{
if (aRadix == 10) {
AppendPrintf("%" PRId64, aInteger);
} else {
AppendPrintf(aRadix == 8 ? "%" PRIo64 : "%" PRIx64,
static_cast<uint64_t>(aInteger));
}
}
void AppendInt(uint64_t aInteger)
{
AppendPrintf("%" PRIu64, aInteger);
}
void AppendInt(uint64_t aInteger, int aRadix)
{
AppendPrintf(aRadix == 10 ? "%" PRIu64 : aRadix == 8 ? "%" PRIo64 : "%" PRIx64,
aInteger);
}
/**
* Append the given float to this string
*/
void NS_FASTCALL AppendFloat(float aFloat);
void NS_FASTCALL AppendFloat(double aFloat);
public:
// AppendLiteral must ONLY be applied to an actual literal string.
// Do not attempt to use it with a regular char* pointer, or with a char
// array variable. Use Append or AppendASCII for those.
template<int N>
void AppendLiteral(const char_type (&aStr)[N])
{
ReplaceLiteral(base_string_type::mLength, 0, aStr, N - 1);
}
// Only enable for T = char16_t
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>>
MOZ_MUST_USE bool
AppendLiteral(const incompatible_char_type (&aStr)[N], const fallible_t& aFallible)
{
return AppendASCII(aStr, N - 1, aFallible);
}
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 applied to an actual literal string.
// Do not attempt to use it with a regular char* pointer, or with a char
// array variable. Use Insert for those.
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
* characters, without affecting the length of the string.
* There is no need to include room for the null terminator: it is
* the job of the string class.
* Also ensures that the buffer is mutable.
*/
void NS_FASTCALL SetCapacity(size_type aNewCapacity);
MOZ_MUST_USE bool NS_FASTCALL SetCapacity(size_type aNewCapacity,
const fallible_t&);
void NS_FASTCALL SetLength(size_type aNewLength);
MOZ_MUST_USE bool NS_FASTCALL SetLength(size_type aNewLength,
const fallible_t&);
void Truncate(size_type aNewLength = 0)
{
NS_ASSERTION(aNewLength <= base_string_type::mLength, "Truncate cannot make string longer");
SetLength(aNewLength);
}
/**
* 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::mLength : aNewLen);
}
*aData = base_string_type::mData;
return base_string_type::mLength;
}
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
/**
* Span integration
*/
operator mozilla::Span<char_type>()
{
return mozilla::MakeSpan(BeginWriting(), base_string_type::Length());
}
operator mozilla::Span<const char_type>() const
{
return mozilla::MakeSpan(base_string_type::BeginReading(), base_string_type::Length());
}
void Append(mozilla::Span<const char_type> aSpan)
{
auto len = aSpan.Length();
MOZ_RELEASE_ASSERT(len <= mozilla::MaxValue<size_type>::value);
Append(aSpan.Elements(), len);
}
MOZ_MUST_USE bool Append(mozilla::Span<const char_type> aSpan,
const fallible_t& aFallible)
{
auto len = aSpan.Length();
if (len > mozilla::MaxValue<size_type>::value) {
return false;
}
return Append(aSpan.Elements(), len, aFallible);
}
template <typename Q = T, typename EnableIfChar = mozilla::CharOnlyT<Q>>
operator mozilla::Span<uint8_t>()
{
return mozilla::MakeSpan(reinterpret_cast<uint8_t*>(BeginWriting()),
base_string_type::Length());
}
template <typename Q = T, typename EnableIfChar = mozilla::CharOnlyT<Q>>
operator mozilla::Span<const uint8_t>() const
{
return mozilla::MakeSpan(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)
{
auto len = aSpan.Length();
MOZ_RELEASE_ASSERT(len <= mozilla::MaxValue<size_type>::value);
Append(reinterpret_cast<const char*>(aSpan.Elements()), len);
}
template <typename Q = T, typename EnableIfChar = mozilla::CharOnlyT<Q>>
MOZ_MUST_USE bool Append(mozilla::Span<const uint8_t> aSpan,
const fallible_t& aFallible)
{
auto len = aSpan.Length();
if (len > mozilla::MaxValue<size_type>::value) {
return false;
}
return Append(
reinterpret_cast<const char*>(aSpan.Elements()), len, aFallible);
}
/**
* 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);
/**
* 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();
/**
* 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_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(mozilla::IsSame<N, never>::value,
"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)
// XXXbz or can I just include nscore.h and use NS_BUILD_REFCNT_LOGGING?
#if defined(DEBUG) || defined(FORCE_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();
MOZ_RELEASE_ASSERT(CheckCapacity(aLength), "String is too large.");
}
#endif /* DEBUG || FORCE_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, size_type 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:
/**
* 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<uint32_t, nsresult>
NS_FASTCALL StartBulkWrite(size_type aCapacity,
size_type aPrefixToPreserve = 0,
bool aAllowShrinking = true,
size_type aSuffixLength = 0,
size_type aOldSuffixStart = 0,
size_type aNewSuffixStart = 0);
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 FinishBulkWrite(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.
*/
MOZ_MUST_USE bool ReplacePrep(index_type aCutStart,
size_type aCutLength,
size_type aNewLength);
MOZ_MUST_USE 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.
*/
MOZ_MUST_USE bool NS_FASTCALL EnsureMutable(
size_type aNewLen = size_type(-1));
/**
* Checks if the given capacity is valid for this string type.
*/
static MOZ_MUST_USE bool CheckCapacity(size_type aCapacity) {
if (aCapacity > kMaxCapacity) {
// Also assert for |aCapacity| equal to |size_type(-1)|, since we used to
// use that value to flag immutability.
NS_ASSERTION(aCapacity != size_type(-1), "Bogus capacity");
return false;
}
return true;
}
void NS_FASTCALL ReplaceLiteral(index_type aCutStart, size_type aCutLength,
const char_type* aData, size_type aLength);
static const size_type kMaxCapacity;
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.");
// You should not need to instantiate this class directly.
// Use nsTSubstring::Split instead.
template <typename T>
class nsTSubstringSplitter
{
typedef typename nsTSubstring<T>::size_type size_type;
typedef typename nsTSubstring<T>::char_type char_type;
class nsTSubstringSplit_Iter
{
public:
nsTSubstringSplit_Iter(const nsTSubstringSplitter<T>& aObj,
size_type aPos)
: mObj(aObj)
, mPos(aPos)
{
}
bool operator!=(const nsTSubstringSplit_Iter& other) const
{
return mPos != other.mPos;
}
const nsTDependentSubstring<T>& operator*() const;
const nsTSubstringSplit_Iter& operator++()
{
++mPos;
return *this;
}
private:
const nsTSubstringSplitter<T>& mObj;
size_type mPos;
};
private:
const nsTSubstring<T>* const mStr;
mozilla::UniquePtr<nsTDependentSubstring<T>[]> mArray;
size_type mArraySize;
const char_type mDelim;
public:
nsTSubstringSplitter(const nsTSubstring<T>* aStr, char_type aDelim);
nsTSubstringSplit_Iter begin() const
{
return nsTSubstringSplit_Iter(*this, 0);
}
nsTSubstringSplit_Iter end() const
{
return nsTSubstringSplit_Iter(*this, mArraySize);
}
const nsTDependentSubstring<T>& Get(const size_type index) const
{
MOZ_ASSERT(index < mArraySize);
return mArray[index];
}
};
extern template class nsTSubstringSplitter<char>;
extern template class nsTSubstringSplitter<char16_t>;
/**
* Span integration
*/
namespace mozilla {
inline Span<char>
MakeSpan(nsTSubstring<char>& aString)
{
return aString;
}
inline Span<const char>
MakeSpan(const nsTSubstring<char>& aString)
{
return aString;
}
inline Span<char16_t>
MakeSpan(nsTSubstring<char16_t>& aString)
{
return aString;
}
inline Span<const char16_t>
MakeSpan(const nsTSubstring<char16_t>& aString)
{
return aString;
}
} // namespace mozilla
#endif