summaryrefslogtreecommitdiff
path: root/xpcom/string/nsTSubstring.h
diff options
context:
space:
mode:
Diffstat (limited to 'xpcom/string/nsTSubstring.h')
-rw-r--r--xpcom/string/nsTSubstring.h1186
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;
+}