/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim:set ts=2 sw=2 sts=2 et cindent: */ /* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is Mozilla. * * The Initial Developer of the Original Code is IBM Corporation. * Portions created by IBM Corporation are Copyright (C) 2003 * IBM Corporation. All Rights Reserved. * * Contributor(s): * Scott Collins (original author) * Darin Fisher * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ /** * The base for string comparators */ class NS_COM nsTStringComparator_CharT { public: typedef CharT char_type; nsTStringComparator_CharT() {} virtual int operator()( const char_type*, const char_type*, PRUint32 length ) const = 0; virtual int operator()( char_type, char_type ) const = 0; }; /** * The default string comparator (case-sensitive comparision) */ class NS_COM nsTDefaultStringComparator_CharT : public nsTStringComparator_CharT { public: typedef CharT char_type; nsTDefaultStringComparator_CharT() {} virtual int operator()( const char_type*, const char_type*, PRUint32 length ) const; virtual int operator()( char_type, char_type ) const; }; /** * nsTAString is the most abstract class in the string hierarchy. * * In its original inception, nsTAString was designed to allow the data * storage for a string to be separated into multiple fragments. This was * intended to enable lazy string flattening or avoid string flattening * altogether in some cases. This abstraction, however, meant that every * single string operation (including simple operations such as IsEmpty() and * BeginReading()) required virtual function calls. A virtual destructor was * also required. This not only meant additional overhead for invoking * string methods but also added to additional codesize at every callsite (to * load the virtual function address). * * Today nsTAString exists mainly for backwards compatibility of the string * API. It is restricted to representing a contiguous array of characters, * where the character array is not necessarily null-terminated. Moreover, * since nsTAString's virtual function table was frozen for Mozilla 1.0, * nsTAString necessarily maintains ABI compatibility with older versions of * Gecko. (nsTObsoleteAString provides that frozen ABI. See * nsObsoleteAString.h for a description of how we solve the ABI * compatibility requirement while eliminating virtual function calls on * nsTAString.) * * XPIDL still generates C++ header files with references to nsTAStrings, so * nsTAString will still be heavily used in real code. * * If the opportunity to break ABI compatibility with Mozilla 1.0 were to * ever arise, our first move should be to make nsTAString equate to * nsTSubstring. This may in fact be an option today for some Gecko-based * products. */ class nsTAString_CharT { public: typedef CharT char_type; typedef nsCharTraits char_traits; typedef char_traits::incompatible_char_type incompatible_char_type; typedef nsTAString_CharT self_type; typedef nsTAString_CharT abstract_string_type; typedef nsTObsoleteAString_CharT obsolete_string_type; typedef nsTSubstring_CharT substring_type; typedef nsTSubstringTuple_CharT substring_tuple_type; typedef nsReadingIterator const_iterator; typedef nsWritingIterator iterator; typedef nsTStringComparator_CharT comparator_type; typedef PRUint32 size_type; typedef PRUint32 index_type; public: // this acts like a virtual destructor NS_COM NS_FASTCALL ~nsTAString_CharT(); /** * BeginReading/EndReading can be used to get immutable access to the * string's underlying buffer. EndReading returns a pointer to the * end of the string's buffer. nsReadableUtils.h provides a collection * of utility functions that work with these iterators. */ inline const_iterator& BeginReading( const_iterator& iter ) const { size_type len = GetReadableBuffer(&iter.mStart); iter.mEnd = iter.mStart + len; iter.mPosition = iter.mStart; return iter; } inline const_iterator& EndReading( const_iterator& iter ) const { size_type len = GetReadableBuffer(&iter.mStart); iter.mEnd = iter.mStart + len; iter.mPosition = iter.mEnd; return iter; } /** * BeginWriting/EndWriting can be used to get mutable access to the * string's underlying buffer. EndWriting returns a pointer to the * end of the string's buffer. This iterator API cannot be used to * grow a buffer. Use SetLength to resize the string's buffer. */ inline iterator& BeginWriting( iterator& iter ) { size_type len = GetWritableBuffer(&iter.mStart); iter.mEnd = iter.mStart + len; iter.mPosition = iter.mStart; return iter; } inline iterator& EndWriting( iterator& iter ) { size_type len = GetWritableBuffer(&iter.mStart); iter.mEnd = iter.mStart + len; iter.mPosition = iter.mEnd; return iter; } /** * Length checking functions. IsEmpty is a helper function to avoid * writing code like: |if (str.Length() == 0)| */ NS_COM size_type NS_FASTCALL Length() const; PRBool IsEmpty() const { return Length() == 0; } /** * String equality tests. Pass a string comparator if you want to * control how the strings are compared. By default, a binary * "case-sensitive" comparision is performed. */ NS_COM PRBool NS_FASTCALL Equals( const self_type& ) const; NS_COM PRBool NS_FASTCALL Equals( const self_type&, const comparator_type& ) const; NS_COM PRBool NS_FASTCALL Equals( const char_type* ) const; NS_COM PRBool NS_FASTCALL Equals( const char_type*, const comparator_type& ) const; /** * An efficient comparison with ASCII that can be used even * for wide strings. Call this version when you know the * length of 'data'. */ NS_COM PRBool NS_FASTCALL EqualsASCII( const char* data, size_type len ) const; /** * An efficient comparison with ASCII that can be used even * for wide strings. Call this version when 'data' is * null-terminated. */ NS_COM PRBool NS_FASTCALL EqualsASCII( const char* data ) const; // EqualsLiteral 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. // The template trick to acquire the array length at compile time without // using a macro is due to Corey Kosak, with much thanks. #ifdef NS_DISABLE_LITERAL_TEMPLATE inline PRBool EqualsLiteral( const char* str ) const { return EqualsASCII(str); } #else template inline PRBool EqualsLiteral( const char (&str)[N] ) const { return EqualsASCII(str, N-1); } template inline PRBool EqualsLiteral( char (&str)[N] ) const { const char* s = str; return EqualsASCII(s, N-1); } #endif // The LowerCaseEquals methods compare the lower case version of // this string 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. NS_COM PRBool NS_FASTCALL LowerCaseEqualsASCII( const char* data, size_type len ) const; NS_COM PRBool NS_FASTCALL LowerCaseEqualsASCII( const char* data ) const; // LowerCaseEqualsLiteral 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 // LowerCaseEqualsASCII for them. #ifdef NS_DISABLE_LITERAL_TEMPLATE inline PRBool LowerCaseEqualsLiteral( const char* str ) const { return LowerCaseEqualsASCII(str); } #else template inline PRBool LowerCaseEqualsLiteral( const char (&str)[N] ) const { return LowerCaseEqualsASCII(str, N-1); } template inline PRBool LowerCaseEqualsLiteral( char (&str)[N] ) const { const char* s = str; return LowerCaseEqualsASCII(s, N-1); } #endif /** * A string always references a non-null data pointer. In some * applications (e.g., the DOM) it is necessary for a string class * to have some way to distinguish an empty string from a null (or * void) string. These methods enable support for the concept of * a void string. */ NS_COM PRBool NS_FASTCALL IsVoid() const; NS_COM void NS_FASTCALL SetIsVoid( PRBool ); /** * This method returns true if the string's underlying buffer is * null-terminated. This should rarely be needed by applications. * The PromiseFlatTString method should be used to ensure that a * string's underlying buffer is null-terminated. */ NS_COM PRBool NS_FASTCALL IsTerminated() const; /** * These are contant time since nsTAString uses flat storage */ NS_COM char_type NS_FASTCALL First() const; NS_COM char_type NS_FASTCALL Last() const; /** * Returns the number of occurances of the given character. */ NS_COM size_type NS_FASTCALL CountChar( char_type ) const; /** * Locates the offset of the first occurance of the character. Pass a * non-zero offset to control where the search begins. */ NS_COM PRInt32 NS_FASTCALL FindChar( char_type, index_type offset = 0 ) const; /** * SetCapacity is not required to do anything; however, it can be used * as a hint to the implementation to reduce allocations. * * SetCapacity(0) is a suggestion to discard all associated storage. */ NS_COM void NS_FASTCALL SetCapacity( size_type ); /** * XXX talk to dbaron about this comment. we do need a method that * XXX allows someone to resize a string's buffer so that it can be * XXX populated using writing iterators. SetLength seems to be the * XXX right method for the job, and we do use it in this capacity * XXX in certain places. * * SetLength is used in two ways: * 1) to |Cut| a suffix of the string; * 2) to prepare to |Append| or move characters around. * * External callers are not allowed to use |SetLength| in this * latter capacity, and should prefer |Truncate| for the former. * In other words, |SetLength| is deprecated for all use outside * of the string library and the internal use may at some point * be replaced as well. * * This distinction makes me think the two different uses should * be split into two distinct functions. */ NS_COM void NS_FASTCALL SetLength( size_type ); /** * Can't use |Truncate| to make a string longer! */ void Truncate( size_type aNewLength=0 ) { NS_ASSERTION(aNewLength <= Length(), "Truncate cannot make string longer"); SetLength(aNewLength); } /** * |Assign| and |operator=| make |this| equivalent to the string or * buffer given as an argument. If possible, they do this by sharing * a reference counted buffer (see |nsTSubstring|). If not, they copy * the buffer into their own buffer. */ NS_COM void NS_FASTCALL Assign( const self_type& readable ); NS_COM void NS_FASTCALL Assign( const substring_tuple_type& tuple ); NS_COM void NS_FASTCALL Assign( const char_type* data ); NS_COM void NS_FASTCALL Assign( const char_type* data, size_type length ); NS_COM void NS_FASTCALL Assign( char_type c ); NS_COM void NS_FASTCALL AssignASCII( const char* data, size_type length ); NS_COM void NS_FASTCALL AssignASCII( const char* data ); // AssignLiteral 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 AssignASCII for those. #ifdef NS_DISABLE_LITERAL_TEMPLATE void AssignLiteral( const char* str ) { AssignASCII(str); } #else template void AssignLiteral( const char (&str)[N] ) { AssignASCII(str, N-1); } template void AssignLiteral( char (&str)[N] ) { AssignASCII(str, N-1); } #endif // copy-assignment operator. I must define my own if I don't want the compiler to make me one self_type& operator=( const self_type& readable ) { Assign(readable); return *this; } self_type& operator=( const substring_tuple_type& tuple ) { Assign(tuple); return *this; } self_type& operator=( const char_type* data ) { Assign(data); return *this; } self_type& operator=( char_type c ) { Assign(c); return *this; } /** * |Append|, |operator+=| are used to add characters to the end of this string. */ NS_COM void NS_FASTCALL Append( const self_type& readable ); NS_COM void NS_FASTCALL Append( const substring_tuple_type& tuple ); NS_COM void NS_FASTCALL Append( const char_type* data ); NS_COM void NS_FASTCALL Append( const char_type* data, size_type length ); NS_COM void NS_FASTCALL Append( char_type c ); NS_COM void NS_FASTCALL AppendASCII( const char* data, size_type length ); NS_COM void NS_FASTCALL AppendASCII( const char* data ); // 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 AppendASCII for those. #ifdef NS_DISABLE_LITERAL_TEMPLATE void AppendLiteral( const char* str ) { AppendASCII(str); } #else template void AppendLiteral( const char (&str)[N] ) { AppendASCII(str, N-1); } template void AppendLiteral( char (&str)[N] ) { AppendASCII(str, N-1); } #endif self_type& operator+=( const self_type& readable ) { Append(readable); return *this; } self_type& operator+=( const substring_tuple_type& tuple ) { Append(tuple); return *this; } self_type& operator+=( const char_type* data ) { Append(data); return *this; } self_type& operator+=( char_type c ) { Append(c); return *this; } /** * |Insert| is used to add characters into this string at a given position. * NOTE: It's a shame the |pos| parameter isn't at the front of the arg list. */ NS_COM void NS_FASTCALL Insert( const self_type& readable, index_type pos ); NS_COM void NS_FASTCALL Insert( const substring_tuple_type& tuple, index_type pos ); NS_COM void NS_FASTCALL Insert( const char_type* data, index_type pos ); NS_COM void NS_FASTCALL Insert( const char_type* data, index_type pos, size_type length ); NS_COM void NS_FASTCALL Insert( char_type c, index_type pos ); /** * |Cut| is used to remove a range of characters from this string. */ NS_COM void NS_FASTCALL Cut( index_type cutStart, size_type cutLength ); /** * |Replace| is used overwrite a range of characters from this string. */ NS_COM void NS_FASTCALL Replace( index_type cutStart, size_type cutLength, const self_type& readable ); NS_COM void NS_FASTCALL Replace( index_type cutStart, size_type cutLength, const substring_tuple_type& readable ); /** * this is public to support automatic conversion of tuple to abstract * string, which is necessary to support our API. */ nsTAString_CharT(const substring_tuple_type& tuple) : mVTable(obsolete_string_type::sCanonicalVTable) , mData(nsnull) , mLength(0) , mFlags(0) { Assign(tuple); } protected: friend class nsTSubstringTuple_CharT; // GCC 3.2 erroneously needs these (even though they are subclasses!) friend class nsTSubstring_CharT; friend class nsTDependentSubstring_CharT; friend class nsTPromiseFlatString_CharT; /** * the address of our virtual function table. required for backwards * compatibility with Mozilla 1.0 frozen nsAC?String interface. */ const void* mVTable; /** * these fields are "here" only when mVTable == sCanonicalVTable. * * they exist to support automatic construction of a nsTAString * from a nsTSubstringTuple. */ char_type* mData; size_type mLength; PRUint32 mFlags; /** * nsTAString must be subclassed before it can be instantiated. */ nsTAString_CharT(char_type* data, size_type length, PRUint32 flags) : mVTable(obsolete_string_type::sCanonicalVTable) , mData(data) , mLength(length) , mFlags(flags) {} /** * optional ctor for use by subclasses. * * NOTE: mData and mLength are intentionally left uninitialized. */ explicit nsTAString_CharT(PRUint32 flags) : mVTable(obsolete_string_type::sCanonicalVTable) , mFlags(flags) {} /** * get pointer to internal string buffer (may not be null terminated). * return length of buffer. */ NS_COM size_type NS_FASTCALL GetReadableBuffer( const char_type **data ) const; NS_COM size_type NS_FASTCALL GetWritableBuffer( char_type **data ); /** * returns true if this tuple is dependent on (i.e., overlapping with) * the given char sequence. */ PRBool NS_FASTCALL IsDependentOn(const char_type *start, const char_type *end) const; /** * we can be converted to a const nsTSubstring (dependent on this) */ const substring_type NS_FASTCALL ToSubstring() const; /** * type cast helpers */ const obsolete_string_type* AsObsoleteString() const { return NS_REINTERPRET_CAST(const obsolete_string_type*, this); } obsolete_string_type* AsObsoleteString() { return NS_REINTERPRET_CAST(obsolete_string_type*, this); } const substring_type* AsSubstring() const { return NS_REINTERPRET_CAST(const substring_type*, this); } substring_type* AsSubstring() { return NS_REINTERPRET_CAST(substring_type*, this); } private: // GCC 2.95.3, EGCS-2.91.66, Sun Workshop/Forte, and IBM VisualAge C++ // require a public copy-constructor in order to support automatic // construction of a nsTAString from a nsTSubstringTuple. I believe // enabling the default copy-constructor is harmless, but I do not want // it to be enabled by default because that might tempt people into // using it (where it would be invalid). #if !defined(__SUNPRO_CC) && \ !(defined(_AIX) && defined(__IBMCPP__)) && \ (!defined(__GNUC__) || __GNUC__ > 2 || __GNUC_MINOR__ > 95) // NOT TO BE IMPLEMENTED nsTAString_CharT( const self_type& ); #endif // NOT TO BE IMPLEMENTED void operator= ( incompatible_char_type ); void Assign ( incompatible_char_type ); void operator+= ( incompatible_char_type ); void Append ( incompatible_char_type ); void Insert ( incompatible_char_type, index_type ); }; NS_COM int NS_FASTCALL Compare( const nsTAString_CharT& lhs, const nsTAString_CharT& rhs, const nsTStringComparator_CharT& = nsTDefaultStringComparator_CharT() ); inline PRBool operator!=( const nsTAString_CharT& lhs, const nsTAString_CharT& rhs ) { return !lhs.Equals(rhs); } inline PRBool operator< ( const nsTAString_CharT& lhs, const nsTAString_CharT& rhs ) { return Compare(lhs, rhs)< 0; } inline PRBool operator<=( const nsTAString_CharT& lhs, const nsTAString_CharT& rhs ) { return Compare(lhs, rhs)<=0; } inline PRBool operator==( const nsTAString_CharT& lhs, const nsTAString_CharT& rhs ) { return lhs.Equals(rhs); } inline PRBool operator>=( const nsTAString_CharT& lhs, const nsTAString_CharT& rhs ) { return Compare(lhs, rhs)>=0; } inline PRBool operator> ( const nsTAString_CharT& lhs, const nsTAString_CharT& rhs ) { return Compare(lhs, rhs)> 0; }