gecko-dev/xpcom/string/public/nsTSubstring.h

472 lines
18 KiB
C++

/* -*- 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):
* Darin Fisher <darin@meer.net>
*
* 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 ***** */
/**
* nsTSubstring
*
* The base string type. This type is not instantiated directly. A sub-
* class is instantiated instead. For example, see nsTString.
*
* This type works like nsTAString except that it does not have the ABI
* requirements of that interface. Like nsTAString, nsTSubstring
* represents a single contiguous array of characters that may or may not
* be null-terminated.
*
* Many of the accessors on nsTSubstring are inlined as an optimization.
*
* This class is also known as "nsASingleFragmentC?String".
*/
class nsTSubstring_CharT : public nsTAString_CharT
{
public:
typedef nsTSubstring_CharT self_type;
typedef nsTString_CharT string_type;
typedef char_type* char_iterator;
typedef const char_type* const_char_iterator;
public:
/**
* 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& iter ) const
{
iter.mStart = mData;
iter.mEnd = mData + mLength;
iter.mPosition = iter.mStart;
return iter;
}
const_iterator& EndReading( const_iterator& iter ) const
{
iter.mStart = mData;
iter.mEnd = mData + mLength;
iter.mPosition = iter.mEnd;
return iter;
}
const_char_iterator& BeginReading( const_char_iterator& iter ) const
{
return iter = mData;
}
const_char_iterator& EndReading( const_char_iterator& iter ) const
{
return iter = mData + mLength;
}
/**
* writing iterators
*/
char_iterator BeginWriting() { EnsureMutable(); return mData; }
char_iterator EndWriting() { EnsureMutable(); return mData + mLength; }
/**
* deprecated writing iterators
*/
iterator& BeginWriting( iterator& iter )
{
EnsureMutable();
iter.mStart = mData;
iter.mEnd = mData + mLength;
iter.mPosition = iter.mStart;
return iter;
}
iterator& EndWriting( iterator& iter )
{
EnsureMutable();
iter.mStart = mData;
iter.mEnd = mData + mLength;
iter.mPosition = iter.mEnd;
return iter;
}
char_iterator& BeginWriting( char_iterator& iter )
{
EnsureMutable();
return iter = mData;
}
char_iterator& EndWriting( char_iterator& iter )
{
EnsureMutable();
return iter = mData + mLength;
}
/**
* accessors
*/
// returns pointer to string data (not necessarily null-terminated)
const char_type *Data() const
{
return mData;
}
size_type Length() const
{
return mLength;
}
PRBool IsEmpty() const
{
return mLength == 0;
}
PRBool IsVoid() const
{
return mFlags & F_VOIDED;
}
PRBool IsTerminated() const
{
return mFlags & F_TERMINATED;
}
char_type CharAt( index_type i ) const
{
NS_ASSERTION(i < mLength, "index exceeds allowable range");
return mData[i];
}
char_type operator[]( index_type i ) const
{
return CharAt(i);
}
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];
}
NS_COM size_type CountChar( char_type ) const;
NS_COM PRInt32 FindChar( char_type, index_type offset = 0 ) const;
/**
* equality
*/
NS_COM PRBool Equals( const self_type& ) const;
NS_COM PRBool Equals( const self_type&, const comparator_type& ) const;
NS_COM PRBool Equals( const abstract_string_type& readable ) const;
NS_COM PRBool Equals( const abstract_string_type& readable, const comparator_type& comp ) const;
NS_COM PRBool Equals( const char_type* data ) const;
NS_COM PRBool Equals( const char_type* data, const comparator_type& comp ) const;
/**
* assignment
*/
void Assign( char_type c ) { Assign(&c, 1); }
NS_COM void Assign( const char_type* data, size_type length = size_type(-1) );
NS_COM void Assign( const self_type& );
NS_COM void Assign( const substring_tuple_type& );
NS_COM void Assign( const abstract_string_type& );
self_type& operator=( char_type c ) { Assign(c); return *this; }
self_type& operator=( const char_type* data ) { Assign(data); return *this; }
self_type& operator=( const self_type& str ) { Assign(str); return *this; }
self_type& operator=( const substring_tuple_type& tuple ) { Assign(tuple); return *this; }
self_type& operator=( const abstract_string_type& readable ) { Assign(readable); return *this; }
NS_COM void Adopt( char_type* data, size_type length = size_type(-1) );
/**
* buffer manipulation
*/
void Replace( index_type cutStart, size_type cutLength, char_type c ) { Replace(cutStart, cutLength, &c, 1); }
NS_COM void Replace( index_type cutStart, size_type cutLength, const char_type* data, size_type length = size_type(-1) );
void Replace( index_type cutStart, size_type cutLength, const self_type& str ) { Replace(cutStart, cutLength, str.Data(), str.Length()); }
NS_COM void Replace( index_type cutStart, size_type cutLength, const substring_tuple_type& tuple );
NS_COM void Replace( index_type cutStart, size_type cutLength, const abstract_string_type& readable );
void Append( char_type c ) { Replace(mLength, 0, c); }
void Append( const char_type* data, size_type length = size_type(-1) ) { Replace(mLength, 0, data, length); }
void Append( const self_type& str ) { Replace(mLength, 0, str); }
void Append( const substring_tuple_type& tuple ) { Replace(mLength, 0, tuple); }
void Append( const abstract_string_type& readable ) { Replace(mLength, 0, readable); }
self_type& operator+=( char_type c ) { Append(c); return *this; }
self_type& operator+=( const char_type* data ) { Append(data); return *this; }
self_type& operator+=( const self_type& str ) { Append(str); return *this; }
self_type& operator+=( const substring_tuple_type& tuple ) { Append(tuple); return *this; }
self_type& operator+=( const abstract_string_type& readable ) { Append(readable); return *this; }
void Insert( char_type c, index_type pos ) { Replace(pos, 0, c); }
void Insert( const char_type* data, index_type pos, size_type length = size_type(-1) ) { Replace(pos, 0, data, length); }
void Insert( const self_type& str, index_type pos ) { Replace(pos, 0, str); }
void Insert( const substring_tuple_type& tuple, index_type pos ) { Replace(pos, 0, tuple); }
void Insert( const abstract_string_type& readable, index_type pos ) { Replace(pos, 0, readable); }
void Cut( index_type cutStart, size_type cutLength ) { Replace(cutStart, cutLength, char_traits::sEmptyBuffer, 0); }
/**
* buffer sizing
*/
NS_COM void SetCapacity( size_type capacity );
NS_COM void SetLength( size_type );
void Truncate( size_type newLength = 0 )
{
NS_ASSERTION(newLength <= mLength, "Truncate cannot make string longer");
SetLength(newLength);
}
/**
* string data is never null, but can be marked void. if true, the
* string will be truncated. @see nsTSubstring::IsVoid
*/
NS_COM void SetIsVoid( PRBool );
public:
/**
* this is public to support automatic conversion of tuple to string
* base type, which helps avoid converting to nsTAString.
*/
nsTSubstring_CharT(const substring_tuple_type& tuple)
: abstract_string_type(nsnull, 0, F_NONE)
{
Assign(tuple);
}
protected:
friend class nsTObsoleteAStringThunk_CharT;
friend class nsTAString_CharT;
friend class nsTSubstringTuple_CharT;
// XXX GCC 3.4 needs this :-(
friend class nsTPromiseFlatString_CharT;
// default initialization
nsTSubstring_CharT()
: abstract_string_type(
NS_CONST_CAST(char_type*, char_traits::sEmptyBuffer), 0, F_TERMINATED) {}
// allow subclasses to initialize fields directly
nsTSubstring_CharT( char_type *data, size_type length, PRUint32 flags )
: abstract_string_type(data, length, flags) {}
// version of constructor that leaves mData and mLength uninitialized
explicit
nsTSubstring_CharT( PRUint32 flags )
: abstract_string_type(flags) {}
// copy-constructor, constructs as dependent on given object
// (NOTE: this is for internal use only)
nsTSubstring_CharT( const self_type& str )
: abstract_string_type(
str.mData, str.mLength, str.mFlags & (F_TERMINATED | F_VOIDED)) {}
/**
* this function releases mData and does not change the value of
* any of its member variables. inotherwords, this function acts
* like a destructor.
*/
void Finalize();
/**
* this function prepares mData to be mutated.
*
* @param capacity specifies the required capacity of mData
* @param old_data returns null or the old value of mData
* @param old_flags 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.
*
* XXX we should expose a way for subclasses to free old_data.
*/
PRBool MutatePrep( size_type capacity, char_type** old_data, PRUint32* old_flags );
/**
* 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 cutStart specifies the starting offset of the section
* @param cutLength specifies the length of the section to be replaced
* @param newLength 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.
*/
void ReplacePrep( index_type cutStart, size_type cutLength, size_type newLength );
/**
* 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 size_type(-1) if mData is immutable.
*/
size_type Capacity() const;
/**
* this helper function can be called prior to directly manipulating
* the contents of mData. see, for example, BeginWriting.
*/
NS_COM void EnsureMutable();
/**
* returns true if this string overlaps with the given string fragment.
*/
PRBool IsDependentOn( const char_type *start, const char_type *end ) 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.end || f2.end <= f1.begin)
*
* Simplified, that gives us:
*/
return ( start < (mData + mLength) && end > mData );
}
/**
* this helper function stores the specified dataFlags in mFlags
*/
void SetDataFlags(PRUint32 dataFlags)
{
NS_ASSERTION((dataFlags & 0xFFFF0000) == 0, "bad flags");
mFlags = dataFlags | (mFlags & 0xFFFF0000);
}
public:
// 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
// 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 nsMemory::Alloc)
// 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.
//
};