gecko-dev/xpcom/string/nsTString.h
Emilio Cobos Álvarez 38fce4f9a3 Bug 1815558 - Downgrade nsDependentString assert. r=smaug
I saw this in the nightly profile. This makes us go into the string
which in most cases is not necessary because the lengths are different.

Depends on D169143

Differential Revision: https://phabricator.services.mozilla.com/D169144
2023-02-08 00:55:19 +00:00

448 lines
13 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 nsTString_h
#define nsTString_h
#include "nsTSubstring.h"
/**
* This is the canonical null-terminated string class. All subclasses
* promise null-terminated storage. Instances of this class allocate
* strings on the heap.
*
* NAMES:
* nsString for wide characters
* nsCString for narrow characters
*
* This class is also known as nsAFlat[C]String, where "flat" is used
* to denote a null-terminated string.
*/
template <typename T>
class nsTString : public nsTSubstring<T> {
public:
typedef nsTString<T> self_type;
using repr_type = mozilla::detail::nsTStringRepr<T>;
#ifdef __clang__
// bindgen w/ clang 3.9 at least chokes on a typedef, but using is okay.
using typename nsTSubstring<T>::substring_type;
#else
// On the other hand msvc chokes on the using statement. It seems others
// don't care either way so we lump them in here.
typedef typename nsTSubstring<T>::substring_type substring_type;
#endif
typedef typename substring_type::fallible_t fallible_t;
typedef typename substring_type::char_type char_type;
typedef typename substring_type::char_traits char_traits;
typedef
typename substring_type::incompatible_char_type incompatible_char_type;
typedef typename substring_type::substring_tuple_type substring_tuple_type;
typedef typename substring_type::const_iterator const_iterator;
typedef typename substring_type::iterator iterator;
typedef typename substring_type::comparator_type comparator_type;
typedef typename substring_type::const_char_iterator const_char_iterator;
typedef typename substring_type::string_view string_view;
typedef typename substring_type::index_type index_type;
typedef typename substring_type::size_type size_type;
// These are only for internal use within the string classes:
typedef typename substring_type::DataFlags DataFlags;
typedef typename substring_type::ClassFlags ClassFlags;
public:
/**
* constructors
*/
nsTString() : substring_type(ClassFlags::NULL_TERMINATED) {}
explicit nsTString(const char_type* aData, size_type aLength = size_type(-1))
: substring_type(ClassFlags::NULL_TERMINATED) {
this->Assign(aData, aLength);
}
explicit nsTString(mozilla::Span<const char_type> aData)
: nsTString(aData.Elements(), aData.Length()) {}
#if defined(MOZ_USE_CHAR16_WRAPPER)
template <typename Q = T, typename EnableIfChar16 = mozilla::Char16OnlyT<Q>>
explicit nsTString(char16ptr_t aStr, size_type aLength = size_type(-1))
: substring_type(ClassFlags::NULL_TERMINATED) {
this->Assign(static_cast<const char16_t*>(aStr), aLength);
}
#endif
nsTString(const self_type& aStr)
: substring_type(ClassFlags::NULL_TERMINATED) {
this->Assign(aStr);
}
nsTString(self_type&& aStr) : substring_type(ClassFlags::NULL_TERMINATED) {
this->Assign(std::move(aStr));
}
MOZ_IMPLICIT nsTString(const substring_tuple_type& aTuple)
: substring_type(ClassFlags::NULL_TERMINATED) {
this->Assign(aTuple);
}
explicit nsTString(const substring_type& aReadable)
: substring_type(ClassFlags::NULL_TERMINATED) {
this->Assign(aReadable);
}
explicit nsTString(substring_type&& aReadable)
: substring_type(ClassFlags::NULL_TERMINATED) {
this->Assign(std::move(aReadable));
}
// |operator=| does not inherit, so we must define our own
self_type& operator=(char_type aChar) {
this->Assign(aChar);
return *this;
}
self_type& operator=(const char_type* aData) {
this->Assign(aData);
return *this;
}
self_type& operator=(const self_type& aStr) {
this->Assign(aStr);
return *this;
}
self_type& operator=(self_type&& aStr) {
this->Assign(std::move(aStr));
return *this;
}
#if defined(MOZ_USE_CHAR16_WRAPPER)
template <typename Q = T, typename EnableIfChar16 = mozilla::Char16OnlyT<Q>>
self_type& operator=(const char16ptr_t aStr) {
this->Assign(static_cast<const char16_t*>(aStr));
return *this;
}
#endif
self_type& operator=(const substring_type& aStr) {
this->Assign(aStr);
return *this;
}
self_type& operator=(substring_type&& aStr) {
this->Assign(std::move(aStr));
return *this;
}
self_type& operator=(const substring_tuple_type& aTuple) {
this->Assign(aTuple);
return *this;
}
/**
* returns the null-terminated string
*/
template <typename U, typename Dummy>
struct raw_type {
typedef const U* type;
};
#if defined(MOZ_USE_CHAR16_WRAPPER)
template <typename Dummy>
struct raw_type<char16_t, Dummy> {
typedef char16ptr_t type;
};
#endif
MOZ_NO_DANGLING_ON_TEMPORARIES typename raw_type<T, int>::type get() const {
return this->mData;
}
/**
* returns character at specified index.
*
* NOTE: unlike nsTSubstring::CharAt, this function allows you to index
* the null terminator character.
*/
char_type CharAt(index_type aIndex) const {
MOZ_ASSERT(aIndex <= this->Length(), "index exceeds allowable range");
return this->mData[aIndex];
}
char_type operator[](index_type aIndex) const { return CharAt(aIndex); }
/**
* Set a char inside this string at given index
*
* @param aChar is the char you want to write into this string
* @param anIndex is the ofs where you want to write the given char
* @return TRUE if successful
*/
bool SetCharAt(char16_t aChar, index_type aIndex);
/**
* Allow this string to be bound to a character buffer
* until the string is rebound or mutated; the caller
* must ensure that the buffer outlives the string.
*/
void Rebind(const char_type* aData, size_type aLength);
/**
* verify restrictions for dependent strings
*/
void AssertValidDependentString() {
MOZ_ASSERT(this->mData, "nsTDependentString must wrap a non-NULL buffer");
MOZ_ASSERT(this->mData[substring_type::mLength] == 0,
"nsTDependentString must wrap only null-terminated strings. "
"You are probably looking for nsTDependentSubstring.");
}
protected:
// allow subclasses to initialize fields directly
nsTString(char_type* aData, size_type aLength, DataFlags aDataFlags,
ClassFlags aClassFlags)
: substring_type(aData, aLength, aDataFlags,
aClassFlags | ClassFlags::NULL_TERMINATED) {}
friend const nsTString<char>& VoidCString();
friend const nsTString<char16_t>& VoidString();
// Used by Null[C]String.
explicit nsTString(DataFlags aDataFlags)
: substring_type(char_traits::sEmptyBuffer, 0,
aDataFlags | DataFlags::TERMINATED,
ClassFlags::NULL_TERMINATED) {}
};
extern template class nsTString<char>;
extern template class nsTString<char16_t>;
/**
* nsTAutoStringN
*
* Subclass of nsTString that adds support for stack-based string
* allocation. It is normally not a good idea to use this class on the
* heap, because it will allocate space which may be wasted if the string
* it contains is significantly smaller or any larger than 64 characters.
*
* NAMES:
* nsAutoStringN / nsTAutoString for wide characters
* nsAutoCStringN / nsTAutoCString for narrow characters
*/
template <typename T, size_t N>
class MOZ_NON_MEMMOVABLE nsTAutoStringN : public nsTString<T> {
public:
typedef nsTAutoStringN<T, N> self_type;
typedef nsTString<T> base_string_type;
typedef typename base_string_type::string_type string_type;
typedef typename base_string_type::char_type char_type;
typedef typename base_string_type::char_traits char_traits;
typedef typename base_string_type::substring_type substring_type;
typedef typename base_string_type::size_type size_type;
typedef typename base_string_type::substring_tuple_type substring_tuple_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;
public:
/**
* constructors
*/
nsTAutoStringN()
: string_type(mStorage, 0, DataFlags::TERMINATED | DataFlags::INLINE,
ClassFlags::INLINE),
mInlineCapacity(N - 1) {
// null-terminate
mStorage[0] = char_type(0);
}
explicit nsTAutoStringN(char_type aChar) : self_type() {
this->Assign(aChar);
}
explicit nsTAutoStringN(const char_type* aData,
size_type aLength = size_type(-1))
: self_type() {
this->Assign(aData, aLength);
}
#if defined(MOZ_USE_CHAR16_WRAPPER)
template <typename Q = T, typename EnableIfChar16 = mozilla::Char16OnlyT<Q>>
explicit nsTAutoStringN(char16ptr_t aData, size_type aLength = size_type(-1))
: self_type(static_cast<const char16_t*>(aData), aLength) {}
#endif
nsTAutoStringN(const self_type& aStr) : self_type() { this->Assign(aStr); }
nsTAutoStringN(self_type&& aStr) : self_type() {
this->Assign(std::move(aStr));
}
explicit nsTAutoStringN(const substring_type& aStr) : self_type() {
this->Assign(aStr);
}
explicit nsTAutoStringN(substring_type&& aStr) : self_type() {
this->Assign(std::move(aStr));
}
MOZ_IMPLICIT nsTAutoStringN(const substring_tuple_type& aTuple)
: self_type() {
this->Assign(aTuple);
}
// |operator=| does not inherit, so we must define our own
self_type& operator=(char_type aChar) {
this->Assign(aChar);
return *this;
}
self_type& operator=(const char_type* aData) {
this->Assign(aData);
return *this;
}
#if defined(MOZ_USE_CHAR16_WRAPPER)
template <typename Q = T, typename EnableIfChar16 = mozilla::Char16OnlyT<Q>>
self_type& operator=(char16ptr_t aStr) {
this->Assign(aStr);
return *this;
}
#endif
self_type& operator=(const self_type& aStr) {
this->Assign(aStr);
return *this;
}
self_type& operator=(self_type&& aStr) {
this->Assign(std::move(aStr));
return *this;
}
self_type& operator=(const substring_type& aStr) {
this->Assign(aStr);
return *this;
}
self_type& operator=(substring_type&& aStr) {
this->Assign(std::move(aStr));
return *this;
}
self_type& operator=(const substring_tuple_type& aTuple) {
this->Assign(aTuple);
return *this;
}
static const size_t kStorageSize = N;
protected:
friend class nsTSubstring<T>;
const LengthStorage mInlineCapacity;
private:
char_type mStorage[N];
};
// Externs for the most common nsTAutoStringN variations.
extern template class nsTAutoStringN<char, 64>;
extern template class nsTAutoStringN<char16_t, 64>;
//
// nsAutoString stores pointers into itself which are invalidated when an
// nsTArray is resized, so nsTArray must not be instantiated with nsAutoString
// elements!
//
template <class E>
class nsTArrayElementTraits;
template <typename T>
class nsTArrayElementTraits<nsTAutoString<T>> {
public:
template <class A>
struct Dont_Instantiate_nsTArray_of;
template <class A>
struct Instead_Use_nsTArray_of;
static Dont_Instantiate_nsTArray_of<nsTAutoString<T>>* Construct(
Instead_Use_nsTArray_of<nsTString<T>>* aE) {
return 0;
}
template <class A>
static Dont_Instantiate_nsTArray_of<nsTAutoString<T>>* Construct(
Instead_Use_nsTArray_of<nsTString<T>>* aE, const A& aArg) {
return 0;
}
template <class... Args>
static Dont_Instantiate_nsTArray_of<nsTAutoString<T>>* Construct(
Instead_Use_nsTArray_of<nsTString<T>>* aE, Args&&... aArgs) {
return 0;
}
static Dont_Instantiate_nsTArray_of<nsTAutoString<T>>* Destruct(
Instead_Use_nsTArray_of<nsTString<T>>* aE) {
return 0;
}
};
/**
* getter_Copies support for adopting raw string out params that are
* heap-allocated, e.g.:
*
* char* gStr;
* void GetBlah(char** aStr)
* {
* *aStr = strdup(gStr);
* }
*
* // This works, but is clumsy.
* void Inelegant()
* {
* char* buf;
* GetBlah(&buf);
* nsCString str;
* str.Adopt(buf);
* // ...
* }
*
* // This is nicer.
* void Elegant()
* {
* nsCString str;
* GetBlah(getter_Copies(str));
* // ...
* }
*/
template <typename T>
class MOZ_STACK_CLASS nsTGetterCopies {
public:
typedef T char_type;
explicit nsTGetterCopies(nsTSubstring<T>& aStr)
: mString(aStr), mData(nullptr) {}
~nsTGetterCopies() {
mString.Adopt(mData); // OK if mData is null
}
operator char_type**() { return &mData; }
private:
nsTSubstring<T>& mString;
char_type* mData;
};
// See the comment above nsTGetterCopies_CharT for how to use this.
template <typename T>
inline nsTGetterCopies<T> getter_Copies(nsTSubstring<T>& aString) {
return nsTGetterCopies<T>(aString);
}
#endif