michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* vim:set ts=2 sw=2 sts=2 et cindent: */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: // IWYU pragma: private, include "nsString.h" michael@0: michael@0: #include "mozilla/Casting.h" michael@0: #include "mozilla/MemoryReporting.h" michael@0: michael@0: #ifndef MOZILLA_INTERNAL_API michael@0: #error Cannot use internal string classes without MOZILLA_INTERNAL_API defined. Use the frozen header nsStringAPI.h instead. michael@0: #endif michael@0: michael@0: /** michael@0: * The base for string comparators michael@0: */ michael@0: class nsTStringComparator_CharT michael@0: { michael@0: public: michael@0: typedef CharT char_type; michael@0: michael@0: nsTStringComparator_CharT() {} michael@0: michael@0: virtual int operator()( const char_type*, const char_type*, uint32_t, uint32_t ) const = 0; michael@0: }; michael@0: michael@0: michael@0: /** michael@0: * The default string comparator (case-sensitive comparision) michael@0: */ michael@0: class nsTDefaultStringComparator_CharT michael@0: : public nsTStringComparator_CharT michael@0: { michael@0: public: michael@0: typedef CharT char_type; michael@0: michael@0: nsTDefaultStringComparator_CharT() {} michael@0: michael@0: virtual int operator()( const char_type*, const char_type*, uint32_t, uint32_t ) const; michael@0: }; michael@0: michael@0: /** michael@0: * nsTSubstring is the most abstract class in the string hierarchy. It michael@0: * represents a single contiguous array of characters, which may or may not michael@0: * be null-terminated. This type is not instantiated directly. A sub-class michael@0: * is instantiated instead. For example, see nsTString. michael@0: * michael@0: * NAMES: michael@0: * nsAString for wide characters michael@0: * nsACString for narrow characters michael@0: * michael@0: * Many of the accessors on nsTSubstring are inlined as an optimization. michael@0: */ michael@0: class nsTSubstring_CharT michael@0: { michael@0: public: michael@0: typedef mozilla::fallible_t fallible_t; michael@0: michael@0: typedef CharT char_type; michael@0: michael@0: typedef nsCharTraits char_traits; michael@0: typedef char_traits::incompatible_char_type incompatible_char_type; michael@0: michael@0: typedef nsTSubstring_CharT self_type; michael@0: typedef self_type abstract_string_type; michael@0: typedef self_type base_string_type; michael@0: michael@0: typedef self_type substring_type; michael@0: typedef nsTSubstringTuple_CharT substring_tuple_type; michael@0: typedef nsTString_CharT string_type; michael@0: michael@0: typedef nsReadingIterator const_iterator; michael@0: typedef nsWritingIterator iterator; michael@0: michael@0: typedef nsTStringComparator_CharT comparator_type; michael@0: michael@0: typedef char_type* char_iterator; michael@0: typedef const char_type* const_char_iterator; michael@0: michael@0: typedef uint32_t size_type; michael@0: typedef uint32_t index_type; michael@0: michael@0: public: michael@0: michael@0: // this acts like a virtual destructor michael@0: ~nsTSubstring_CharT() { Finalize(); } michael@0: michael@0: /** michael@0: * reading iterators michael@0: */ michael@0: michael@0: const_char_iterator BeginReading() const { return mData; } michael@0: const_char_iterator EndReading() const { return mData + mLength; } michael@0: michael@0: /** michael@0: * deprecated reading iterators michael@0: */ michael@0: michael@0: const_iterator& BeginReading( const_iterator& iter ) const michael@0: { michael@0: iter.mStart = mData; michael@0: iter.mEnd = mData + mLength; michael@0: iter.mPosition = iter.mStart; michael@0: return iter; michael@0: } michael@0: michael@0: const_iterator& EndReading( const_iterator& iter ) const michael@0: { michael@0: iter.mStart = mData; michael@0: iter.mEnd = mData + mLength; michael@0: iter.mPosition = iter.mEnd; michael@0: return iter; michael@0: } michael@0: michael@0: const_char_iterator& BeginReading( const_char_iterator& iter ) const michael@0: { michael@0: return iter = mData; michael@0: } michael@0: michael@0: const_char_iterator& EndReading( const_char_iterator& iter ) const michael@0: { michael@0: return iter = mData + mLength; michael@0: } michael@0: michael@0: michael@0: /** michael@0: * writing iterators michael@0: */ michael@0: michael@0: char_iterator BeginWriting() michael@0: { michael@0: if (!EnsureMutable()) michael@0: NS_ABORT_OOM(mLength); michael@0: michael@0: return mData; michael@0: } michael@0: michael@0: char_iterator BeginWriting( const fallible_t& ) michael@0: { michael@0: return EnsureMutable() ? mData : char_iterator(0); michael@0: } michael@0: michael@0: char_iterator EndWriting() michael@0: { michael@0: if (!EnsureMutable()) michael@0: NS_ABORT_OOM(mLength); michael@0: michael@0: return mData + mLength; michael@0: } michael@0: michael@0: char_iterator EndWriting( const fallible_t& ) michael@0: { michael@0: return EnsureMutable() ? (mData + mLength) : char_iterator(0); michael@0: } michael@0: michael@0: char_iterator& BeginWriting( char_iterator& iter ) michael@0: { michael@0: return iter = BeginWriting(); michael@0: } michael@0: michael@0: char_iterator& BeginWriting( char_iterator& iter, const fallible_t& ) michael@0: { michael@0: return iter = BeginWriting(fallible_t()); michael@0: } michael@0: michael@0: char_iterator& EndWriting( char_iterator& iter ) michael@0: { michael@0: return iter = EndWriting(); michael@0: } michael@0: michael@0: char_iterator& EndWriting( char_iterator& iter, const fallible_t& ) michael@0: { michael@0: return iter = EndWriting(fallible_t()); michael@0: } michael@0: michael@0: /** michael@0: * deprecated writing iterators michael@0: */ michael@0: michael@0: iterator& BeginWriting( iterator& iter ) michael@0: { michael@0: char_type *data = BeginWriting(); michael@0: iter.mStart = data; michael@0: iter.mEnd = data + mLength; michael@0: iter.mPosition = iter.mStart; michael@0: return iter; michael@0: } michael@0: michael@0: iterator& EndWriting( iterator& iter ) michael@0: { michael@0: char_type *data = BeginWriting(); michael@0: iter.mStart = data; michael@0: iter.mEnd = data + mLength; michael@0: iter.mPosition = iter.mEnd; michael@0: return iter; michael@0: } michael@0: michael@0: /** michael@0: * accessors michael@0: */ michael@0: michael@0: // returns pointer to string data (not necessarily null-terminated) michael@0: #if defined(CharT_is_PRUnichar) && defined(MOZ_USE_CHAR16_WRAPPER) michael@0: char16ptr_t Data() const michael@0: #else michael@0: const char_type *Data() const michael@0: #endif michael@0: { michael@0: return mData; michael@0: } michael@0: michael@0: size_type Length() const michael@0: { michael@0: return mLength; michael@0: } michael@0: michael@0: uint32_t Flags() const michael@0: { michael@0: return mFlags; michael@0: } michael@0: michael@0: bool IsEmpty() const michael@0: { michael@0: return mLength == 0; michael@0: } michael@0: michael@0: bool IsLiteral() const michael@0: { michael@0: return (mFlags & F_LITERAL) != 0; michael@0: } michael@0: michael@0: bool IsVoid() const michael@0: { michael@0: return (mFlags & F_VOIDED) != 0; michael@0: } michael@0: michael@0: bool IsTerminated() const michael@0: { michael@0: return (mFlags & F_TERMINATED) != 0; michael@0: } michael@0: michael@0: char_type CharAt( index_type i ) const michael@0: { michael@0: NS_ASSERTION(i < mLength, "index exceeds allowable range"); michael@0: return mData[i]; michael@0: } michael@0: michael@0: char_type operator[]( index_type i ) const michael@0: { michael@0: return CharAt(i); michael@0: } michael@0: michael@0: char_type First() const michael@0: { michael@0: NS_ASSERTION(mLength > 0, "|First()| called on an empty string"); michael@0: return mData[0]; michael@0: } michael@0: michael@0: inline michael@0: char_type Last() const michael@0: { michael@0: NS_ASSERTION(mLength > 0, "|Last()| called on an empty string"); michael@0: return mData[mLength - 1]; michael@0: } michael@0: michael@0: size_type NS_FASTCALL CountChar( char_type ) const; michael@0: int32_t NS_FASTCALL FindChar( char_type, index_type offset = 0 ) const; michael@0: michael@0: michael@0: /** michael@0: * equality michael@0: */ michael@0: michael@0: bool NS_FASTCALL Equals( const self_type& ) const; michael@0: bool NS_FASTCALL Equals( const self_type&, const comparator_type& ) const; michael@0: michael@0: bool NS_FASTCALL Equals( const char_type* data ) const; michael@0: bool NS_FASTCALL Equals( const char_type* data, const comparator_type& comp ) const; michael@0: michael@0: #if defined(CharT_is_PRUnichar) && defined(MOZ_USE_CHAR16_WRAPPER) michael@0: bool NS_FASTCALL Equals( char16ptr_t data ) const michael@0: { michael@0: return Equals(static_cast(data)); michael@0: } michael@0: bool NS_FASTCALL Equals( char16ptr_t data, const comparator_type& comp ) const michael@0: { michael@0: return Equals(static_cast(data), comp); michael@0: } michael@0: #endif michael@0: michael@0: /** michael@0: * An efficient comparison with ASCII that can be used even michael@0: * for wide strings. Call this version when you know the michael@0: * length of 'data'. michael@0: */ michael@0: bool NS_FASTCALL EqualsASCII( const char* data, size_type len ) const; michael@0: /** michael@0: * An efficient comparison with ASCII that can be used even michael@0: * for wide strings. Call this version when 'data' is michael@0: * null-terminated. michael@0: */ michael@0: bool NS_FASTCALL EqualsASCII( const char* data ) const; michael@0: michael@0: // EqualsLiteral must ONLY be applied to an actual literal string, or michael@0: // a char array *constant* declared without an explicit size. michael@0: // Do not attempt to use it with a regular char* pointer, or with a michael@0: // non-constant char array variable. Use EqualsASCII for them. michael@0: // The template trick to acquire the array length at compile time without michael@0: // using a macro is due to Corey Kosak, with much thanks. michael@0: template michael@0: inline bool EqualsLiteral( const char (&str)[N] ) const michael@0: { michael@0: return EqualsASCII(str, N-1); michael@0: } michael@0: michael@0: // The LowerCaseEquals methods compare the ASCII-lowercase version of michael@0: // this string (lowercasing only ASCII uppercase characters) to some michael@0: // ASCII/Literal string. The ASCII string is *not* lowercased for michael@0: // you. If you compare to an ASCII or literal string that contains an michael@0: // uppercase character, it is guaranteed to return false. We will michael@0: // throw assertions too. michael@0: bool NS_FASTCALL LowerCaseEqualsASCII( const char* data, size_type len ) const; michael@0: bool NS_FASTCALL LowerCaseEqualsASCII( const char* data ) const; michael@0: michael@0: // LowerCaseEqualsLiteral must ONLY be applied to an actual michael@0: // literal string, or a char array *constant* declared without an michael@0: // explicit size. Do not attempt to use it with a regular char* michael@0: // pointer, or with a non-constant char array variable. Use michael@0: // LowerCaseEqualsASCII for them. michael@0: template michael@0: inline bool LowerCaseEqualsLiteral( const char (&str)[N] ) const michael@0: { michael@0: return LowerCaseEqualsASCII(str, N-1); michael@0: } michael@0: michael@0: /** michael@0: * assignment michael@0: */ michael@0: michael@0: void NS_FASTCALL Assign( char_type c ); michael@0: bool NS_FASTCALL Assign( char_type c, const fallible_t& ) NS_WARN_UNUSED_RESULT; michael@0: michael@0: void NS_FASTCALL Assign( const char_type* data ); michael@0: void NS_FASTCALL Assign( const char_type* data, size_type length ); michael@0: bool NS_FASTCALL Assign( const char_type* data, size_type length, const fallible_t& ) NS_WARN_UNUSED_RESULT; michael@0: michael@0: void NS_FASTCALL Assign( const self_type& ); michael@0: bool NS_FASTCALL Assign( const self_type&, const fallible_t& ) NS_WARN_UNUSED_RESULT; michael@0: michael@0: void NS_FASTCALL Assign( const substring_tuple_type& ); michael@0: bool NS_FASTCALL Assign( const substring_tuple_type&, const fallible_t& ) NS_WARN_UNUSED_RESULT; michael@0: michael@0: #if defined(CharT_is_PRUnichar) && defined(MOZ_USE_CHAR16_WRAPPER) michael@0: void Assign (char16ptr_t data) michael@0: { michael@0: Assign(static_cast(data)); michael@0: } michael@0: michael@0: bool Assign(char16ptr_t data, const fallible_t&) NS_WARN_UNUSED_RESULT michael@0: { michael@0: return Assign(static_cast(data), fallible_t()); michael@0: } michael@0: michael@0: void Assign (char16ptr_t data, size_type length) michael@0: { michael@0: Assign(static_cast(data), length); michael@0: } michael@0: michael@0: bool Assign(char16ptr_t data, size_type length, const fallible_t&) NS_WARN_UNUSED_RESULT michael@0: { michael@0: return Assign(static_cast(data), length, fallible_t()); michael@0: } michael@0: #endif michael@0: michael@0: void NS_FASTCALL AssignASCII( const char* data, size_type length ); michael@0: bool NS_FASTCALL AssignASCII( const char* data, size_type length, const fallible_t& ) NS_WARN_UNUSED_RESULT; michael@0: michael@0: void NS_FASTCALL AssignASCII( const char* data ) michael@0: { michael@0: AssignASCII(data, mozilla::SafeCast(strlen(data))); michael@0: } michael@0: bool NS_FASTCALL AssignASCII( const char* data, const fallible_t& ) NS_WARN_UNUSED_RESULT michael@0: { michael@0: return AssignASCII(data, mozilla::SafeCast(strlen(data)), fallible_t()); michael@0: } michael@0: michael@0: // AssignLiteral must ONLY be applied to an actual literal string, or michael@0: // a char array *constant* declared without an explicit size. michael@0: // Do not attempt to use it with a regular char* pointer, or with a michael@0: // non-constant char array variable. Use AssignASCII for those. michael@0: // There are not fallible version of these methods because they only really michael@0: // apply to small allocations that we wouldn't want to check anyway. michael@0: template michael@0: void AssignLiteral( const char_type (&str)[N] ) michael@0: { AssignLiteral(str, N - 1); } michael@0: #ifdef CharT_is_PRUnichar michael@0: template michael@0: void AssignLiteral( const char (&str)[N] ) michael@0: { AssignASCII(str, N-1); } michael@0: #endif michael@0: michael@0: self_type& operator=( char_type c ) { Assign(c); return *this; } michael@0: self_type& operator=( const char_type* data ) { Assign(data); return *this; } michael@0: #if defined(CharT_is_PRUnichar) && defined(MOZ_USE_CHAR16_WRAPPER) michael@0: self_type& operator=( char16ptr_t data ) { Assign(data); return *this; } michael@0: #endif michael@0: self_type& operator=( const self_type& str ) { Assign(str); return *this; } michael@0: self_type& operator=( const substring_tuple_type& tuple ) { Assign(tuple); return *this; } michael@0: michael@0: void NS_FASTCALL Adopt( char_type* data, size_type length = size_type(-1) ); michael@0: michael@0: michael@0: /** michael@0: * buffer manipulation michael@0: */ michael@0: michael@0: void NS_FASTCALL Replace( index_type cutStart, size_type cutLength, char_type c ); michael@0: bool NS_FASTCALL Replace( index_type cutStart, size_type cutLength, char_type c, const mozilla::fallible_t&) NS_WARN_UNUSED_RESULT; michael@0: void NS_FASTCALL Replace( index_type cutStart, size_type cutLength, const char_type* data, size_type length = size_type(-1) ); michael@0: bool NS_FASTCALL Replace( index_type cutStart, size_type cutLength, const char_type* data, size_type length, const mozilla::fallible_t&) NS_WARN_UNUSED_RESULT; michael@0: void Replace( index_type cutStart, size_type cutLength, const self_type& str ) { Replace(cutStart, cutLength, str.Data(), str.Length()); } michael@0: bool Replace( index_type cutStart, size_type cutLength, const self_type& str, const mozilla::fallible_t&) NS_WARN_UNUSED_RESULT michael@0: { return Replace(cutStart, cutLength, str.Data(), str.Length(), mozilla::fallible_t()); } michael@0: void NS_FASTCALL Replace( index_type cutStart, size_type cutLength, const substring_tuple_type& tuple ); michael@0: michael@0: void NS_FASTCALL ReplaceASCII( index_type cutStart, size_type cutLength, const char* data, size_type length = size_type(-1) ); michael@0: michael@0: // ReplaceLiteral must ONLY be applied to an actual literal string. michael@0: // Do not attempt to use it with a regular char* pointer, or with a char michael@0: // array variable. Use Replace or ReplaceASCII for those. michael@0: template michael@0: void ReplaceLiteral( index_type cutStart, size_type cutLength, const char_type (&str)[N] ) { ReplaceLiteral(cutStart, cutLength, str, N - 1); } michael@0: michael@0: void Append( char_type c ) { Replace(mLength, 0, c); } michael@0: bool Append( char_type c, const mozilla::fallible_t&) NS_WARN_UNUSED_RESULT { return Replace(mLength, 0, c, mozilla::fallible_t()); } michael@0: void Append( const char_type* data, size_type length = size_type(-1) ) { Replace(mLength, 0, data, length); } michael@0: bool Append( const char_type* data, size_type length, const mozilla::fallible_t&) NS_WARN_UNUSED_RESULT michael@0: { return Replace(mLength, 0, data, length, mozilla::fallible_t()); } michael@0: michael@0: #if defined(CharT_is_PRUnichar) && defined(MOZ_USE_CHAR16_WRAPPER) michael@0: void Append( char16ptr_t data, size_type length = size_type(-1) ) { Append(static_cast(data), length); } michael@0: #endif michael@0: michael@0: void Append( const self_type& str ) { Replace(mLength, 0, str); } michael@0: void Append( const substring_tuple_type& tuple ) { Replace(mLength, 0, tuple); } michael@0: michael@0: void AppendASCII( const char* data, size_type length = size_type(-1) ) { ReplaceASCII(mLength, 0, data, length); } michael@0: michael@0: /** michael@0: * Append a formatted string to the current string. Uses the format michael@0: * codes documented in prprf.h michael@0: */ michael@0: void AppendPrintf( const char* format, ... ); michael@0: void AppendPrintf( const char* format, va_list ap ); michael@0: void AppendInt( int32_t aInteger ) michael@0: { AppendPrintf( "%d", aInteger ); } michael@0: void AppendInt( int32_t aInteger, int aRadix ) michael@0: { michael@0: const char *fmt = aRadix == 10 ? "%d" : aRadix == 8 ? "%o" : "%x"; michael@0: AppendPrintf( fmt, aInteger ); michael@0: } michael@0: void AppendInt( uint32_t aInteger ) michael@0: { AppendPrintf( "%u", aInteger ); } michael@0: void AppendInt( uint32_t aInteger, int aRadix ) michael@0: { michael@0: const char *fmt = aRadix == 10 ? "%u" : aRadix == 8 ? "%o" : "%x"; michael@0: AppendPrintf( fmt, aInteger ); michael@0: } michael@0: void AppendInt( int64_t aInteger ) michael@0: { AppendPrintf( "%lld", aInteger ); } michael@0: void AppendInt( int64_t aInteger, int aRadix ) michael@0: { michael@0: const char *fmt = aRadix == 10 ? "%lld" : aRadix == 8 ? "%llo" : "%llx"; michael@0: AppendPrintf( fmt, aInteger ); michael@0: } michael@0: void AppendInt( uint64_t aInteger ) michael@0: { AppendPrintf( "%llu", aInteger ); } michael@0: void AppendInt( uint64_t aInteger, int aRadix ) michael@0: { michael@0: const char *fmt = aRadix == 10 ? "%llu" : aRadix == 8 ? "%llo" : "%llx"; michael@0: AppendPrintf( fmt, aInteger ); michael@0: } michael@0: michael@0: /** michael@0: * Append the given float to this string michael@0: */ michael@0: void NS_FASTCALL AppendFloat( float aFloat ); michael@0: void NS_FASTCALL AppendFloat( double aFloat ); michael@0: public: michael@0: michael@0: // AppendLiteral must ONLY be applied to an actual literal string. michael@0: // Do not attempt to use it with a regular char* pointer, or with a char michael@0: // array variable. Use Append or AppendASCII for those. michael@0: template michael@0: void AppendLiteral( const char_type (&str)[N] ) { ReplaceLiteral(mLength, 0, str, N - 1); } michael@0: #ifdef CharT_is_PRUnichar michael@0: template michael@0: void AppendLiteral( const char (&str)[N] ) michael@0: { AppendASCII(str, N-1); } michael@0: #endif michael@0: michael@0: self_type& operator+=( char_type c ) { Append(c); return *this; } michael@0: self_type& operator+=( const char_type* data ) { Append(data); return *this; } michael@0: #if defined(CharT_is_PRUnichar) && defined(MOZ_USE_CHAR16_WRAPPER) michael@0: self_type& operator+=( char16ptr_t data ) { Append(data); return *this; } michael@0: #endif michael@0: self_type& operator+=( const self_type& str ) { Append(str); return *this; } michael@0: self_type& operator+=( const substring_tuple_type& tuple ) { Append(tuple); return *this; } michael@0: michael@0: void Insert( char_type c, index_type pos ) { Replace(pos, 0, c); } michael@0: void Insert( const char_type* data, index_type pos, size_type length = size_type(-1) ) { Replace(pos, 0, data, length); } michael@0: #if defined(CharT_is_PRUnichar) && defined(MOZ_USE_CHAR16_WRAPPER) michael@0: void Insert( char16ptr_t data, index_type pos, size_type length = size_type(-1) ) michael@0: { Insert(static_cast(data), pos, length); } michael@0: #endif michael@0: void Insert( const self_type& str, index_type pos ) { Replace(pos, 0, str); } michael@0: void Insert( const substring_tuple_type& tuple, index_type pos ) { Replace(pos, 0, tuple); } michael@0: michael@0: // InsertLiteral must ONLY be applied to an actual literal string. michael@0: // Do not attempt to use it with a regular char* pointer, or with a char michael@0: // array variable. Use Insert for those. michael@0: template michael@0: void InsertLiteral( const char_type (&str)[N], index_type pos ) { ReplaceLiteral(pos, 0, str, N - 1); } michael@0: michael@0: void Cut( index_type cutStart, size_type cutLength ) { Replace(cutStart, cutLength, char_traits::sEmptyBuffer, 0); } michael@0: michael@0: michael@0: /** michael@0: * buffer sizing michael@0: */ michael@0: michael@0: /** michael@0: * Attempts to set the capacity to the given size in number of michael@0: * characters, without affecting the length of the string. michael@0: * There is no need to include room for the null terminator: it is michael@0: * the job of the string class. michael@0: * Also ensures that the buffer is mutable. michael@0: */ michael@0: void NS_FASTCALL SetCapacity( size_type newCapacity ); michael@0: bool NS_FASTCALL SetCapacity( size_type newCapacity, const fallible_t& ) NS_WARN_UNUSED_RESULT; michael@0: michael@0: void NS_FASTCALL SetLength( size_type newLength ); michael@0: bool NS_FASTCALL SetLength( size_type newLength, const fallible_t& ) NS_WARN_UNUSED_RESULT; michael@0: michael@0: void Truncate( size_type newLength = 0 ) michael@0: { michael@0: NS_ASSERTION(newLength <= mLength, "Truncate cannot make string longer"); michael@0: SetLength(newLength); michael@0: } michael@0: michael@0: michael@0: /** michael@0: * buffer access michael@0: */ michael@0: michael@0: michael@0: /** michael@0: * Get a const pointer to the string's internal buffer. The caller michael@0: * MUST NOT modify the characters at the returned address. michael@0: * michael@0: * @returns The length of the buffer in characters. michael@0: */ michael@0: inline size_type GetData( const char_type** data ) const michael@0: { michael@0: *data = mData; michael@0: return mLength; michael@0: } michael@0: michael@0: /** michael@0: * Get a pointer to the string's internal buffer, optionally resizing michael@0: * the buffer first. If size_type(-1) is passed for newLen, then the michael@0: * current length of the string is used. The caller MAY modify the michael@0: * characters at the returned address (up to but not exceeding the michael@0: * length of the string). michael@0: * michael@0: * @returns The length of the buffer in characters or 0 if unable to michael@0: * satisfy the request due to low-memory conditions. michael@0: */ michael@0: size_type GetMutableData( char_type** data, size_type newLen = size_type(-1) ) michael@0: { michael@0: if (!EnsureMutable(newLen)) michael@0: NS_ABORT_OOM(newLen == size_type(-1) ? mLength : newLen); michael@0: michael@0: *data = mData; michael@0: return mLength; michael@0: } michael@0: michael@0: size_type GetMutableData( char_type** data, size_type newLen, const fallible_t& ) michael@0: { michael@0: if (!EnsureMutable(newLen)) michael@0: { michael@0: *data = nullptr; michael@0: return 0; michael@0: } michael@0: michael@0: *data = mData; michael@0: return mLength; michael@0: } michael@0: michael@0: #if defined(CharT_is_PRUnichar) && defined(MOZ_USE_CHAR16_WRAPPER) michael@0: size_type GetMutableData( wchar_t** data, size_type newLen = size_type(-1) ) michael@0: { michael@0: return GetMutableData(reinterpret_cast(data), newLen); michael@0: } michael@0: michael@0: size_type GetMutableData( wchar_t** data, size_type newLen, const fallible_t& ) michael@0: { michael@0: return GetMutableData(reinterpret_cast(data), newLen, fallible_t()); michael@0: } michael@0: #endif michael@0: michael@0: michael@0: /** michael@0: * string data is never null, but can be marked void. if true, the michael@0: * string will be truncated. @see nsTSubstring::IsVoid michael@0: */ michael@0: michael@0: void NS_FASTCALL SetIsVoid( bool ); michael@0: michael@0: /** michael@0: * This method is used to remove all occurrences of aChar from this michael@0: * string. michael@0: * michael@0: * @param aChar -- char to be stripped michael@0: * @param aOffset -- where in this string to start stripping chars michael@0: */ michael@0: michael@0: void StripChar( char_type aChar, int32_t aOffset=0 ); michael@0: michael@0: /** michael@0: * This method is used to remove all occurrences of aChars from this michael@0: * string. michael@0: * michael@0: * @param aChars -- chars to be stripped michael@0: * @param aOffset -- where in this string to start stripping chars michael@0: */ michael@0: michael@0: void StripChars( const char_type* aChars, uint32_t aOffset=0 ); michael@0: michael@0: /** michael@0: * If the string uses a shared buffer, this method michael@0: * clears the pointer without releasing the buffer. michael@0: */ michael@0: void ForgetSharedBuffer() michael@0: { michael@0: if (mFlags & nsSubstring::F_SHARED) michael@0: { michael@0: mData = char_traits::sEmptyBuffer; michael@0: mLength = 0; michael@0: mFlags = F_TERMINATED; michael@0: } michael@0: } michael@0: michael@0: public: michael@0: michael@0: /** michael@0: * this is public to support automatic conversion of tuple to string michael@0: * base type, which helps avoid converting to nsTAString. michael@0: */ michael@0: nsTSubstring_CharT(const substring_tuple_type& tuple) michael@0: : mData(nullptr), michael@0: mLength(0), michael@0: mFlags(F_NONE) michael@0: { michael@0: Assign(tuple); michael@0: } michael@0: michael@0: /** michael@0: * allows for direct initialization of a nsTSubstring object. michael@0: * michael@0: * NOTE: this constructor is declared public _only_ for convenience michael@0: * inside the string implementation. michael@0: */ michael@0: // XXXbz or can I just include nscore.h and use NS_BUILD_REFCNT_LOGGING? michael@0: #if defined(DEBUG) || defined(FORCE_BUILD_REFCNT_LOGGING) michael@0: #define XPCOM_STRING_CONSTRUCTOR_OUT_OF_LINE michael@0: nsTSubstring_CharT( char_type *data, size_type length, uint32_t flags ); michael@0: #else michael@0: #undef XPCOM_STRING_CONSTRUCTOR_OUT_OF_LINE michael@0: nsTSubstring_CharT( char_type *data, size_type length, uint32_t flags ) michael@0: : mData(data), michael@0: mLength(length), michael@0: mFlags(flags) {} michael@0: #endif /* DEBUG || FORCE_BUILD_REFCNT_LOGGING */ michael@0: michael@0: size_t SizeOfExcludingThisMustBeUnshared(mozilla::MallocSizeOf mallocSizeOf) michael@0: const; michael@0: size_t SizeOfIncludingThisMustBeUnshared(mozilla::MallocSizeOf mallocSizeOf) michael@0: const; michael@0: michael@0: size_t SizeOfExcludingThisIfUnshared(mozilla::MallocSizeOf mallocSizeOf) michael@0: const; michael@0: size_t SizeOfIncludingThisIfUnshared(mozilla::MallocSizeOf mallocSizeOf) michael@0: const; michael@0: michael@0: /** michael@0: * WARNING: Only use these functions if you really know what you are michael@0: * doing, because they can easily lead to double-counting strings. If michael@0: * you do use them, please explain clearly in a comment why it's safe michael@0: * and won't lead to double-counting. michael@0: */ michael@0: size_t SizeOfExcludingThisEvenIfShared(mozilla::MallocSizeOf mallocSizeOf) michael@0: const; michael@0: size_t SizeOfIncludingThisEvenIfShared(mozilla::MallocSizeOf mallocSizeOf) michael@0: const; michael@0: michael@0: protected: michael@0: michael@0: friend class nsTObsoleteAStringThunk_CharT; michael@0: friend class nsTSubstringTuple_CharT; michael@0: michael@0: // XXX GCC 3.4 needs this :-( michael@0: friend class nsTPromiseFlatString_CharT; michael@0: michael@0: char_type* mData; michael@0: size_type mLength; michael@0: uint32_t mFlags; michael@0: michael@0: // default initialization michael@0: nsTSubstring_CharT() michael@0: : mData(char_traits::sEmptyBuffer), michael@0: mLength(0), michael@0: mFlags(F_TERMINATED) {} michael@0: michael@0: // version of constructor that leaves mData and mLength uninitialized michael@0: explicit michael@0: nsTSubstring_CharT( uint32_t flags ) michael@0: : mFlags(flags) {} michael@0: michael@0: // copy-constructor, constructs as dependent on given object michael@0: // (NOTE: this is for internal use only) michael@0: nsTSubstring_CharT( const self_type& str ) michael@0: : mData(str.mData), michael@0: mLength(str.mLength), michael@0: mFlags(str.mFlags & (F_TERMINATED | F_VOIDED)) {} michael@0: michael@0: /** michael@0: * this function releases mData and does not change the value of michael@0: * any of its member variables. in other words, this function acts michael@0: * like a destructor. michael@0: */ michael@0: void NS_FASTCALL Finalize(); michael@0: michael@0: /** michael@0: * this function prepares mData to be mutated. michael@0: * michael@0: * @param capacity specifies the required capacity of mData michael@0: * @param old_data returns null or the old value of mData michael@0: * @param old_flags returns 0 or the old value of mFlags michael@0: * michael@0: * if mData is already mutable and of sufficient capacity, then this michael@0: * function will return immediately. otherwise, it will either resize michael@0: * mData or allocate a new shared buffer. if it needs to allocate a michael@0: * new buffer, then it will return the old buffer and the corresponding michael@0: * flags. this allows the caller to decide when to free the old data. michael@0: * michael@0: * this function returns false if is unable to allocate sufficient michael@0: * memory. michael@0: * michael@0: * XXX we should expose a way for subclasses to free old_data. michael@0: */ michael@0: bool NS_FASTCALL MutatePrep( size_type capacity, char_type** old_data, uint32_t* old_flags ); michael@0: michael@0: /** michael@0: * this function prepares a section of mData to be modified. if michael@0: * necessary, this function will reallocate mData and possibly move michael@0: * existing data to open up the specified section. michael@0: * michael@0: * @param cutStart specifies the starting offset of the section michael@0: * @param cutLength specifies the length of the section to be replaced michael@0: * @param newLength specifies the length of the new section michael@0: * michael@0: * for example, suppose mData contains the string "abcdef" then michael@0: * michael@0: * ReplacePrep(2, 3, 4); michael@0: * michael@0: * would cause mData to look like "ab____f" where the characters michael@0: * indicated by '_' have an unspecified value and can be freely michael@0: * modified. this function will null-terminate mData upon return. michael@0: * michael@0: * this function returns false if is unable to allocate sufficient michael@0: * memory. michael@0: */ michael@0: bool ReplacePrep(index_type cutStart, size_type cutLength, michael@0: size_type newLength) NS_WARN_UNUSED_RESULT michael@0: { michael@0: cutLength = XPCOM_MIN(cutLength, mLength - cutStart); michael@0: uint32_t newTotalLen = mLength - cutLength + newLength; michael@0: if (cutStart == mLength && Capacity() > newTotalLen) { michael@0: mFlags &= ~F_VOIDED; michael@0: mData[newTotalLen] = char_type(0); michael@0: mLength = newTotalLen; michael@0: return true; michael@0: } michael@0: return ReplacePrepInternal(cutStart, cutLength, newLength, newTotalLen); michael@0: } michael@0: michael@0: bool NS_FASTCALL ReplacePrepInternal(index_type cutStart, michael@0: size_type cutLength, michael@0: size_type newFragLength, michael@0: size_type newTotalLength) michael@0: NS_WARN_UNUSED_RESULT; michael@0: michael@0: /** michael@0: * returns the number of writable storage units starting at mData. michael@0: * the value does not include space for the null-terminator character. michael@0: * michael@0: * NOTE: this function returns 0 if mData is immutable (or the buffer michael@0: * is 0-sized). michael@0: */ michael@0: size_type NS_FASTCALL Capacity() const; michael@0: michael@0: /** michael@0: * this helper function can be called prior to directly manipulating michael@0: * the contents of mData. see, for example, BeginWriting. michael@0: */ michael@0: bool NS_FASTCALL EnsureMutable( size_type newLen = size_type(-1) ) NS_WARN_UNUSED_RESULT; michael@0: michael@0: /** michael@0: * returns true if this string overlaps with the given string fragment. michael@0: */ michael@0: bool IsDependentOn( const char_type *start, const char_type *end ) const michael@0: { michael@0: /** michael@0: * if it _isn't_ the case that one fragment starts after the other ends, michael@0: * or ends before the other starts, then, they conflict: michael@0: * michael@0: * !(f2.begin >= f1.end || f2.end <= f1.begin) michael@0: * michael@0: * Simplified, that gives us: michael@0: */ michael@0: return ( start < (mData + mLength) && end > mData ); michael@0: } michael@0: michael@0: /** michael@0: * this helper function stores the specified dataFlags in mFlags michael@0: */ michael@0: void SetDataFlags(uint32_t dataFlags) michael@0: { michael@0: NS_ASSERTION((dataFlags & 0xFFFF0000) == 0, "bad flags"); michael@0: mFlags = dataFlags | (mFlags & 0xFFFF0000); michael@0: } michael@0: michael@0: void NS_FASTCALL ReplaceLiteral( index_type cutStart, size_type cutLength, const char_type* data, size_type length ); michael@0: michael@0: static int AppendFunc( void* arg, const char* s, uint32_t len); michael@0: michael@0: public: michael@0: michael@0: // NOTE: this method is declared public _only_ for convenience for michael@0: // callers who don't have access to the original nsLiteralString_CharT. michael@0: void NS_FASTCALL AssignLiteral( const char_type* data, size_type length ); michael@0: michael@0: // mFlags is a bitwise combination of the following flags. the meaning michael@0: // and interpretation of these flags is an implementation detail. michael@0: // michael@0: // NOTE: these flags are declared public _only_ for convenience inside michael@0: // the string implementation. michael@0: michael@0: enum michael@0: { michael@0: F_NONE = 0, // no flags michael@0: michael@0: // data flags are in the lower 16-bits michael@0: F_TERMINATED = 1 << 0, // IsTerminated returns true michael@0: F_VOIDED = 1 << 1, // IsVoid returns true michael@0: F_SHARED = 1 << 2, // mData points to a heap-allocated, shared buffer michael@0: F_OWNED = 1 << 3, // mData points to a heap-allocated, raw buffer michael@0: F_FIXED = 1 << 4, // mData points to a fixed-size writable, dependent buffer michael@0: F_LITERAL = 1 << 5, // mData points to a string literal; F_TERMINATED will also be set michael@0: michael@0: // class flags are in the upper 16-bits michael@0: F_CLASS_FIXED = 1 << 16 // indicates that |this| is of type nsTFixedString michael@0: }; michael@0: michael@0: // michael@0: // Some terminology: michael@0: // michael@0: // "dependent buffer" A dependent buffer is one that the string class michael@0: // does not own. The string class relies on some michael@0: // external code to ensure the lifetime of the michael@0: // dependent buffer. michael@0: // michael@0: // "shared buffer" A shared buffer is one that the string class michael@0: // allocates. When it allocates a shared string michael@0: // buffer, it allocates some additional space at michael@0: // the beginning of the buffer for additional michael@0: // fields, including a reference count and a michael@0: // buffer length. See nsStringHeader. michael@0: // michael@0: // "adopted buffer" An adopted buffer is a raw string buffer michael@0: // allocated on the heap (using nsMemory::Alloc) michael@0: // of which the string class subsumes ownership. michael@0: // michael@0: // Some comments about the string flags: michael@0: // michael@0: // F_SHARED, F_OWNED, and F_FIXED are all mutually exlusive. They michael@0: // indicate the allocation type of mData. If none of these flags michael@0: // are set, then the string buffer is dependent. michael@0: // michael@0: // F_SHARED, F_OWNED, or F_FIXED imply F_TERMINATED. This is because michael@0: // the string classes always allocate null-terminated buffers, and michael@0: // non-terminated substrings are always dependent. michael@0: // michael@0: // F_VOIDED implies F_TERMINATED, and moreover it implies that mData michael@0: // points to char_traits::sEmptyBuffer. Therefore, F_VOIDED is michael@0: // mutually exclusive with F_SHARED, F_OWNED, and F_FIXED. michael@0: // michael@0: }; michael@0: michael@0: int NS_FASTCALL Compare( const nsTSubstring_CharT::base_string_type& lhs, const nsTSubstring_CharT::base_string_type& rhs, const nsTStringComparator_CharT& = nsTDefaultStringComparator_CharT() ); michael@0: michael@0: michael@0: inline michael@0: bool operator!=( const nsTSubstring_CharT::base_string_type& lhs, const nsTSubstring_CharT::base_string_type& rhs ) michael@0: { michael@0: return !lhs.Equals(rhs); michael@0: } michael@0: michael@0: inline michael@0: bool operator< ( const nsTSubstring_CharT::base_string_type& lhs, const nsTSubstring_CharT::base_string_type& rhs ) michael@0: { michael@0: return Compare(lhs, rhs)< 0; michael@0: } michael@0: michael@0: inline michael@0: bool operator<=( const nsTSubstring_CharT::base_string_type& lhs, const nsTSubstring_CharT::base_string_type& rhs ) michael@0: { michael@0: return Compare(lhs, rhs)<=0; michael@0: } michael@0: michael@0: inline michael@0: bool operator==( const nsTSubstring_CharT::base_string_type& lhs, const nsTSubstring_CharT::base_string_type& rhs ) michael@0: { michael@0: return lhs.Equals(rhs); michael@0: } michael@0: michael@0: inline michael@0: bool operator==( const nsTSubstring_CharT::base_string_type& lhs, const nsTSubstring_CharT::char_type* rhs ) michael@0: { michael@0: return lhs.Equals(rhs); michael@0: } michael@0: michael@0: michael@0: inline michael@0: bool operator>=( const nsTSubstring_CharT::base_string_type& lhs, const nsTSubstring_CharT::base_string_type& rhs ) michael@0: { michael@0: return Compare(lhs, rhs)>=0; michael@0: } michael@0: michael@0: inline michael@0: bool operator> ( const nsTSubstring_CharT::base_string_type& lhs, const nsTSubstring_CharT::base_string_type& rhs ) michael@0: { michael@0: return Compare(lhs, rhs)> 0; michael@0: }