diff options
Diffstat (limited to 'xpcom/string/nsTSubstring.h')
-rw-r--r-- | xpcom/string/nsTSubstring.h | 1186 |
1 files changed, 1186 insertions, 0 deletions
diff --git a/xpcom/string/nsTSubstring.h b/xpcom/string/nsTSubstring.h new file mode 100644 index 0000000000..a08036b1f0 --- /dev/null +++ b/xpcom/string/nsTSubstring.h @@ -0,0 +1,1186 @@ +/* -*- 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" + +#include "mozilla/Casting.h" +#include "mozilla/MemoryReporting.h" + +#ifndef MOZILLA_INTERNAL_API +#error Cannot use internal string classes without MOZILLA_INTERNAL_API defined. Use the frozen header nsStringAPI.h instead. +#endif + +/** + * The base for string comparators + */ +class nsTStringComparator_CharT +{ +public: + typedef CharT char_type; + + nsTStringComparator_CharT() + { + } + + virtual int operator()(const char_type*, const char_type*, + uint32_t, uint32_t) const = 0; +}; + + +/** + * The default string comparator (case-sensitive comparision) + */ +class nsTDefaultStringComparator_CharT + : public nsTStringComparator_CharT +{ +public: + typedef CharT char_type; + + nsTDefaultStringComparator_CharT() + { + } + + virtual int operator()(const char_type*, const char_type*, + uint32_t, uint32_t) const override; +}; + +/** + * nsTSubstring is the most abstract class in the string 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 + * + * Many of the accessors on nsTSubstring are inlined as an optimization. + */ +class nsTSubstring_CharT +{ +public: + typedef mozilla::fallible_t fallible_t; + + typedef CharT char_type; + + typedef nsCharTraits<char_type> char_traits; + typedef char_traits::incompatible_char_type incompatible_char_type; + + typedef nsTSubstring_CharT self_type; + typedef self_type abstract_string_type; + typedef self_type base_string_type; + + typedef self_type substring_type; + typedef nsTSubstringTuple_CharT substring_tuple_type; + typedef nsTString_CharT string_type; + + typedef nsReadingIterator<char_type> const_iterator; + typedef nsWritingIterator<char_type> iterator; + + typedef nsTStringComparator_CharT comparator_type; + + typedef char_type* char_iterator; + typedef const char_type* const_char_iterator; + + typedef uint32_t size_type; + typedef uint32_t index_type; + +public: + + // this acts like a virtual destructor + ~nsTSubstring_CharT() + { + Finalize(); + } + + /** + * reading iterators + */ + + const_char_iterator BeginReading() const + { + return mData; + } + const_char_iterator EndReading() const + { + return mData + mLength; + } + + /** + * deprecated reading iterators + */ + + const_iterator& BeginReading(const_iterator& aIter) const + { + aIter.mStart = mData; + aIter.mEnd = mData + mLength; + aIter.mPosition = aIter.mStart; + return aIter; + } + + const_iterator& EndReading(const_iterator& aIter) const + { + aIter.mStart = mData; + aIter.mEnd = mData + mLength; + aIter.mPosition = aIter.mEnd; + return aIter; + } + + const_char_iterator& BeginReading(const_char_iterator& aIter) const + { + return aIter = mData; + } + + const_char_iterator& EndReading(const_char_iterator& aIter) const + { + return aIter = mData + mLength; + } + + + /** + * writing iterators + */ + + char_iterator BeginWriting() + { + if (!EnsureMutable()) { + AllocFailed(mLength); + } + + return mData; + } + + char_iterator BeginWriting(const fallible_t&) + { + return EnsureMutable() ? mData : char_iterator(0); + } + + char_iterator EndWriting() + { + if (!EnsureMutable()) { + AllocFailed(mLength); + } + + return mData + mLength; + } + + char_iterator EndWriting(const fallible_t&) + { + return EnsureMutable() ? (mData + 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); + } + + /** + * deprecated writing iterators + */ + + iterator& BeginWriting(iterator& aIter) + { + char_type* data = BeginWriting(); + aIter.mStart = data; + aIter.mEnd = data + mLength; + aIter.mPosition = aIter.mStart; + return aIter; + } + + iterator& EndWriting(iterator& aIter) + { + char_type* data = BeginWriting(); + aIter.mStart = data; + aIter.mEnd = data + mLength; + aIter.mPosition = aIter.mEnd; + return aIter; + } + + /** + * accessors + */ + + // returns pointer to string data (not necessarily null-terminated) +#if defined(CharT_is_PRUnichar) && defined(MOZ_USE_CHAR16_WRAPPER) + char16ptr_t Data() const +#else + const char_type* Data() const +#endif + { + return mData; + } + + size_type Length() const + { + return mLength; + } + + uint32_t Flags() const + { + return mFlags; + } + + bool IsEmpty() const + { + return mLength == 0; + } + + bool IsLiteral() const + { + return (mFlags & F_LITERAL) != 0; + } + + bool IsVoid() const + { + return (mFlags & F_VOIDED) != 0; + } + + bool IsTerminated() const + { + return (mFlags & F_TERMINATED) != 0; + } + + char_type CharAt(index_type aIndex) const + { + NS_ASSERTION(aIndex < mLength, "index exceeds allowable range"); + return mData[aIndex]; + } + + char_type operator[](index_type aIndex) const + { + return CharAt(aIndex); + } + + char_type First() const + { + NS_ASSERTION(mLength > 0, "|First()| called on an empty string"); + return mData[0]; + } + + inline char_type Last() const + { + NS_ASSERTION(mLength > 0, "|Last()| called on an empty string"); + return mData[mLength - 1]; + } + + size_type NS_FASTCALL CountChar(char_type) const; + int32_t NS_FASTCALL FindChar(char_type, index_type aOffset = 0) const; + + inline bool Contains(char_type aChar) const + { + return FindChar(aChar) != kNotFound; + } + + /** + * equality + */ + + bool NS_FASTCALL Equals(const self_type&) const; + bool NS_FASTCALL Equals(const self_type&, const comparator_type&) const; + + bool NS_FASTCALL Equals(const char_type* aData) const; + bool NS_FASTCALL Equals(const char_type* aData, + const comparator_type& aComp) const; + +#if defined(CharT_is_PRUnichar) && defined(MOZ_USE_CHAR16_WRAPPER) + bool NS_FASTCALL Equals(char16ptr_t aData) const + { + return Equals(static_cast<const char16_t*>(aData)); + } + bool NS_FASTCALL Equals(char16ptr_t aData, const comparator_type& aComp) const + { + return Equals(static_cast<const char16_t*>(aData), aComp); + } +#endif + + /** + * An efficient comparison with ASCII that can be used even + * for wide strings. Call this version when you know the + * length of 'data'. + */ + bool NS_FASTCALL EqualsASCII(const char* aData, size_type aLen) const; + /** + * An efficient comparison with ASCII that can be used even + * for wide strings. Call this version when 'data' is + * null-terminated. + */ + bool NS_FASTCALL EqualsASCII(const char* aData) const; + + // EqualsLiteral 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 EqualsASCII for them. + // The template trick to acquire the array length at compile time without + // using a macro is due to Corey Kosak, with much thanks. + template<int N> + inline bool EqualsLiteral(const char (&aStr)[N]) const + { + return EqualsASCII(aStr, N - 1); + } + + // The LowerCaseEquals methods compare the ASCII-lowercase version of + // this string (lowercasing only ASCII uppercase characters) to some + // ASCII/Literal string. The ASCII string is *not* lowercased for + // you. If you compare to an ASCII or literal string that contains an + // uppercase character, it is guaranteed to return false. We will + // throw assertions too. + bool NS_FASTCALL LowerCaseEqualsASCII(const char* aData, + size_type aLen) const; + bool NS_FASTCALL LowerCaseEqualsASCII(const char* aData) const; + + // LowerCaseEqualsLiteral 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 + // LowerCaseEqualsASCII for them. + template<int N> + inline bool LowerCaseEqualsLiteral(const char (&aStr)[N]) const + { + return LowerCaseEqualsASCII(aStr, N - 1); + } + + /** + * 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(const substring_tuple_type&); + MOZ_MUST_USE bool NS_FASTCALL Assign(const substring_tuple_type&, + const fallible_t&); + +#if defined(CharT_is_PRUnichar) && defined(MOZ_USE_CHAR16_WRAPPER) + void Assign(char16ptr_t aData) + { + Assign(static_cast<const char16_t*>(aData)); + } + + void Assign(char16ptr_t aData, size_type aLength) + { + Assign(static_cast<const char16_t*>(aData), aLength); + } + + 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); + } +#ifdef CharT_is_PRUnichar + template<int N> + void AssignLiteral(const char (&aStr)[N]) + { + AssignASCII(aStr, N - 1); + } +#endif + + self_type& operator=(char_type aChar) + { + Assign(aChar); + return *this; + } + self_type& operator=(const char_type* aData) + { + Assign(aData); + return *this; + } +#if defined(CharT_is_PRUnichar) && defined(MOZ_USE_CHAR16_WRAPPER) + 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=(const substring_tuple_type& aTuple) + { + Assign(aTuple); + return *this; + } + + 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(mLength, 0, aChar); + } + MOZ_MUST_USE bool Append(char_type aChar, const fallible_t& aFallible) + { + return Replace(mLength, 0, aChar, aFallible); + } + void Append(const char_type* aData, size_type aLength = size_type(-1)) + { + Replace(mLength, 0, aData, aLength); + } + MOZ_MUST_USE bool Append(const char_type* aData, size_type aLength, + const fallible_t& aFallible) + { + return Replace(mLength, 0, aData, aLength, aFallible); + } + +#if defined(CharT_is_PRUnichar) && defined(MOZ_USE_CHAR16_WRAPPER) + 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(mLength, 0, aStr); + } + MOZ_MUST_USE bool Append(const self_type& aStr, const fallible_t& aFallible) + { + return Replace(mLength, 0, aStr, aFallible); + } + void Append(const substring_tuple_type& aTuple) + { + Replace(mLength, 0, aTuple); + } + + void AppendASCII(const char* aData, size_type aLength = size_type(-1)) + { + ReplaceASCII(mLength, 0, aData, aLength); + } + + MOZ_MUST_USE bool AppendASCII(const char* aData, const fallible_t& aFallible) + { + return ReplaceASCII(mLength, 0, aData, size_type(-1), aFallible); + } + + MOZ_MUST_USE bool AppendASCII(const char* aData, size_type aLength, const fallible_t& aFallible) + { + return ReplaceASCII(mLength, 0, aData, aLength, aFallible); + } + + /** + * Append a formatted string to the current string. Uses the format + * codes documented in prprf.h + */ + void AppendPrintf(const char* aFormat, ...); + void AppendPrintf(const char* aFormat, va_list aAp); + void AppendInt(int32_t aInteger) + { + AppendPrintf("%d", aInteger); + } + void AppendInt(int32_t aInteger, int aRadix) + { + const char* fmt = aRadix == 10 ? "%d" : aRadix == 8 ? "%o" : "%x"; + AppendPrintf(fmt, aInteger); + } + void AppendInt(uint32_t aInteger) + { + AppendPrintf("%u", aInteger); + } + void AppendInt(uint32_t aInteger, int aRadix) + { + const char* fmt = aRadix == 10 ? "%u" : aRadix == 8 ? "%o" : "%x"; + AppendPrintf(fmt, aInteger); + } + void AppendInt(int64_t aInteger) + { + AppendPrintf("%lld", aInteger); + } + void AppendInt(int64_t aInteger, int aRadix) + { + const char* fmt = aRadix == 10 ? "%lld" : aRadix == 8 ? "%llo" : "%llx"; + AppendPrintf(fmt, aInteger); + } + void AppendInt(uint64_t aInteger) + { + AppendPrintf("%llu", aInteger); + } + void AppendInt(uint64_t aInteger, int aRadix) + { + const char* fmt = aRadix == 10 ? "%llu" : aRadix == 8 ? "%llo" : "%llx"; + AppendPrintf(fmt, 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(mLength, 0, aStr, N - 1); + } +#ifdef CharT_is_PRUnichar + template<int N> + void AppendLiteral(const char (&aStr)[N]) + { + AppendASCII(aStr, N - 1); + } + + template<int N> + MOZ_MUST_USE bool AppendLiteral(const char (&aStr)[N], const fallible_t& aFallible) + { + return AppendASCII(aStr, N - 1, aFallible); + } +#endif + + self_type& operator+=(char_type aChar) + { + Append(aChar); + return *this; + } + self_type& operator+=(const char_type* aData) + { + Append(aData); + return *this; + } +#if defined(CharT_is_PRUnichar) && defined(MOZ_USE_CHAR16_WRAPPER) + 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(CharT_is_PRUnichar) && defined(MOZ_USE_CHAR16_WRAPPER) + 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); + } + + + /** + * 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 <= 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 = mData; + return 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) ? mLength : aNewLen); + } + + *aData = mData; + return mLength; + } + + size_type GetMutableData(char_type** aData, size_type aNewLen, const fallible_t&) + { + if (!EnsureMutable(aNewLen)) { + *aData = nullptr; + return 0; + } + + *aData = mData; + return mLength; + } + +#if defined(CharT_is_PRUnichar) && defined(MOZ_USE_CHAR16_WRAPPER) + size_type GetMutableData(wchar_t** aData, size_type aNewLen = size_type(-1)) + { + return GetMutableData(reinterpret_cast<char16_t**>(aData), aNewLen); + } + + size_type GetMutableData(wchar_t** aData, size_type aNewLen, + const fallible_t& aFallible) + { + return GetMutableData(reinterpret_cast<char16_t**>(aData), aNewLen, + aFallible); + } +#endif + + + /** + * 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 + * @param aOffset -- where in this string to start stripping chars + */ + + void StripChar(char_type aChar, int32_t aOffset = 0); + + /** + * This method is used to remove all occurrences of aChars from this + * string. + * + * @param aChars -- chars to be stripped + * @param aOffset -- where in this string to start stripping chars + */ + + void StripChars(const char_type* aChars, uint32_t aOffset = 0); + + /** + * If the string uses a shared buffer, this method + * clears the pointer without releasing the buffer. + */ + void ForgetSharedBuffer() + { + if (mFlags & nsSubstring::F_SHARED) { + mData = char_traits::sEmptyBuffer; + mLength = 0; + mFlags = F_TERMINATED; + } + } + +public: + + /** + * this is public to support automatic conversion of tuple to string + * base type, which helps avoid converting to nsTAString. + */ + MOZ_IMPLICIT nsTSubstring_CharT(const substring_tuple_type& aTuple) + : mData(nullptr) + , mLength(0) + , mFlags(F_NONE) + { + Assign(aTuple); + } + + /** + * allows for direct initialization of a nsTSubstring object. + * + * NOTE: this constructor is declared public _only_ for convenience + * inside the string implementation. + */ + // 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 + nsTSubstring_CharT(char_type* aData, size_type aLength, uint32_t aFlags); +#else +#undef XPCOM_STRING_CONSTRUCTOR_OUT_OF_LINE + nsTSubstring_CharT(char_type* aData, size_type aLength, uint32_t aFlags) + : mData(aData) + , mLength(aLength) + , mFlags(aFlags) + { + MOZ_RELEASE_ASSERT(CheckCapacity(aLength), "String is too large."); + } +#endif /* DEBUG || FORCE_BUILD_REFCNT_LOGGING */ + + 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 T> + void NS_ABORT_OOM(T) + { + struct never {}; // a compiler-friendly way to do static_assert(false) + static_assert(mozilla::IsSame<T, 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: + + friend class nsTObsoleteAStringThunk_CharT; + friend class nsTSubstringTuple_CharT; + + // XXX GCC 3.4 needs this :-( + friend class nsTPromiseFlatString_CharT; + + char_type* mData; + size_type mLength; + uint32_t mFlags; + + // default initialization + nsTSubstring_CharT() + : mData(char_traits::sEmptyBuffer) + , mLength(0) + , mFlags(F_TERMINATED) + { + } + + // version of constructor that leaves mData and mLength uninitialized + explicit + nsTSubstring_CharT(uint32_t aFlags) + : mFlags(aFlags) + { + } + + // copy-constructor, constructs as dependent on given object + // (NOTE: this is for internal use only) + nsTSubstring_CharT(const self_type& aStr) + : mData(aStr.mData) + , mLength(aStr.mLength) + , mFlags(aStr.mFlags & (F_TERMINATED | F_VOIDED)) + { + } + + /** + * 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(); + + /** + * this function prepares mData to be mutated. + * + * @param aCapacity specifies the required capacity of mData + * @param aOldData returns null or the old value of mData + * @param aOldFlags returns 0 or the old value of mFlags + * + * if mData is already mutable and of sufficient capacity, then this + * function will return immediately. otherwise, it will either resize + * mData or allocate a new shared buffer. if it needs to allocate a + * new buffer, then it will return the old buffer and the corresponding + * flags. this allows the caller to decide when to free the old data. + * + * this function returns false if is unable to allocate sufficient + * memory. + * + * XXX we should expose a way for subclasses to free old_data. + */ + bool NS_FASTCALL MutatePrep(size_type aCapacity, + char_type** aOldData, uint32_t* aOldFlags); + + /** + * 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)); + + /** + * returns true if this string overlaps with the given string fragment. + */ + bool IsDependentOn(const char_type* aStart, const char_type* aEnd) const + { + /** + * if it _isn't_ the case that one fragment starts after the other ends, + * or ends before the other starts, then, they conflict: + * + * !(f2.begin >= f1.aEnd || f2.aEnd <= f1.begin) + * + * Simplified, that gives us: + */ + return (aStart < (mData + mLength) && aEnd > mData); + } + + /** + * 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; + } + + /** + * this helper function stores the specified dataFlags in mFlags + */ + void SetDataFlags(uint32_t aDataFlags) + { + NS_ASSERTION((aDataFlags & 0xFFFF0000) == 0, "bad flags"); + mFlags = aDataFlags | (mFlags & 0xFFFF0000); + } + + void NS_FASTCALL ReplaceLiteral(index_type aCutStart, size_type aCutLength, + const char_type* aData, size_type aLength); + + static int AppendFunc(void* aArg, const char* aStr, uint32_t aLen); + + 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); + + // mFlags is a bitwise combination of the following flags. the meaning + // and interpretation of these flags is an implementation detail. + // + // NOTE: these flags are declared public _only_ for convenience inside + // the string implementation. + + enum + { + F_NONE = 0, // no flags + + // data flags are in the lower 16-bits + F_TERMINATED = 1 << 0, // IsTerminated returns true + F_VOIDED = 1 << 1, // IsVoid returns true + F_SHARED = 1 << 2, // mData points to a heap-allocated, shared buffer + F_OWNED = 1 << 3, // mData points to a heap-allocated, raw buffer + F_FIXED = 1 << 4, // mData points to a fixed-size writable, dependent buffer + F_LITERAL = 1 << 5, // mData points to a string literal; F_TERMINATED will also be set + + // class flags are in the upper 16-bits + F_CLASS_FIXED = 1 << 16 // indicates that |this| is of type nsTFixedString + }; + + // + // Some terminology: + // + // "dependent buffer" A dependent buffer is one that the string class + // does not own. The string class relies on some + // external code to ensure the lifetime of the + // dependent buffer. + // + // "shared buffer" A shared buffer is one that the string class + // allocates. When it allocates a shared string + // buffer, it allocates some additional space at + // the beginning of the buffer for additional + // fields, including a reference count and a + // buffer length. See nsStringHeader. + // + // "adopted buffer" An adopted buffer is a raw string buffer + // allocated on the heap (using moz_xmalloc) + // of which the string class subsumes ownership. + // + // Some comments about the string flags: + // + // F_SHARED, F_OWNED, and F_FIXED are all mutually exlusive. They + // indicate the allocation type of mData. If none of these flags + // are set, then the string buffer is dependent. + // + // F_SHARED, F_OWNED, or F_FIXED imply F_TERMINATED. This is because + // the string classes always allocate null-terminated buffers, and + // non-terminated substrings are always dependent. + // + // F_VOIDED implies F_TERMINATED, and moreover it implies that mData + // points to char_traits::sEmptyBuffer. Therefore, F_VOIDED is + // mutually exclusive with F_SHARED, F_OWNED, and F_FIXED. + // +}; + +int NS_FASTCALL +Compare(const nsTSubstring_CharT::base_string_type& aLhs, + const nsTSubstring_CharT::base_string_type& aRhs, + const nsTStringComparator_CharT& = nsTDefaultStringComparator_CharT()); + + +inline bool +operator!=(const nsTSubstring_CharT::base_string_type& aLhs, + const nsTSubstring_CharT::base_string_type& aRhs) +{ + return !aLhs.Equals(aRhs); +} + +inline bool +operator!=(const nsTSubstring_CharT::base_string_type& aLhs, + const nsTSubstring_CharT::char_type* aRhs) +{ + return !aLhs.Equals(aRhs); +} + +inline bool +operator<(const nsTSubstring_CharT::base_string_type& aLhs, + const nsTSubstring_CharT::base_string_type& aRhs) +{ + return Compare(aLhs, aRhs) < 0; +} + +inline bool +operator<=(const nsTSubstring_CharT::base_string_type& aLhs, + const nsTSubstring_CharT::base_string_type& aRhs) +{ + return Compare(aLhs, aRhs) <= 0; +} + +inline bool +operator==(const nsTSubstring_CharT::base_string_type& aLhs, + const nsTSubstring_CharT::base_string_type& aRhs) +{ + return aLhs.Equals(aRhs); +} + +inline bool +operator==(const nsTSubstring_CharT::base_string_type& aLhs, + const nsTSubstring_CharT::char_type* aRhs) +{ + return aLhs.Equals(aRhs); +} + + +inline bool +operator>=(const nsTSubstring_CharT::base_string_type& aLhs, + const nsTSubstring_CharT::base_string_type& aRhs) +{ + return Compare(aLhs, aRhs) >= 0; +} + +inline bool +operator>(const nsTSubstring_CharT::base_string_type& aLhs, + const nsTSubstring_CharT::base_string_type& aRhs) +{ + return Compare(aLhs, aRhs) > 0; +} |