зеркало из https://github.com/mozilla/pjs.git
Incremental changes. Reorganized code; implemented more factored methods. Moved string owner from fragment to iterator. Renamed the |const| version of |GetFragment| to |GetConstFragment| so we didn't mix overloading with overriding; eliminating need for some uses of |using| ... may want to do the same thing with |Begin| and |End|. These files are not part of the build.
This commit is contained in:
Родитель
34b42f2d14
Коммит
7ac3541035
|
@ -54,30 +54,21 @@
|
|||
*/
|
||||
|
||||
|
||||
#define NS_DEF_1_STRING_COMPARISON_OPERATOR(comp, T1, T2) \
|
||||
template <class CharT> \
|
||||
inline \
|
||||
PRBool \
|
||||
operator comp( T1 lhs, T2 rhs ) \
|
||||
{ \
|
||||
return PRBool(Compare(lhs, rhs) comp 0); \
|
||||
}
|
||||
|
||||
#define NS_DEF_STRING_COMPARISON_OPERATORS(T1, T2) \
|
||||
NS_DEF_1_STRING_COMPARISON_OPERATOR(!=, T1, T2) \
|
||||
NS_DEF_1_STRING_COMPARISON_OPERATOR(< , T1, T2) \
|
||||
NS_DEF_1_STRING_COMPARISON_OPERATOR(<=, T1, T2) \
|
||||
NS_DEF_1_STRING_COMPARISON_OPERATOR(==, T1, T2) \
|
||||
NS_DEF_1_STRING_COMPARISON_OPERATOR(>=, T1, T2) \
|
||||
NS_DEF_1_STRING_COMPARISON_OPERATOR(> , T1, T2)
|
||||
|
||||
#define NS_DEF_STRING_COMPARISONS(T) \
|
||||
NS_DEF_STRING_COMPARISON_OPERATORS(const T&, const CharT*) \
|
||||
NS_DEF_STRING_COMPARISON_OPERATORS(const CharT*, const T&)
|
||||
|
||||
template <class CharT> class basic_nsAWritableString;
|
||||
// ...because we sometimes use them as `out' params
|
||||
|
||||
template <class CharT> class basic_nsLiteralString;
|
||||
// ...because we sometimes use them as in params to force the conversion of |CharT*|s
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//
|
||||
// nsAReadable[C]String
|
||||
//
|
||||
|
||||
template <class CharT>
|
||||
class basic_nsAReadableString
|
||||
/*
|
||||
|
@ -86,18 +77,14 @@ class basic_nsAReadableString
|
|||
{
|
||||
protected:
|
||||
|
||||
|
||||
struct ConstFragment
|
||||
{
|
||||
const CharT* mStart;
|
||||
const CharT* mEnd;
|
||||
const CharT* mStart;
|
||||
const CharT* mEnd;
|
||||
PRUint32 mFragmentIdentifier;
|
||||
|
||||
const basic_nsAReadableString<CharT>* mOwningString;
|
||||
PRUint32 mFragmentIdentifier;
|
||||
|
||||
explicit
|
||||
ConstFragment( const basic_nsAReadableString<CharT>* aOwner = 0 )
|
||||
: mStart(0), mEnd(0), mOwningString(aOwner), mFragmentIdentifier(0)
|
||||
ConstFragment()
|
||||
: mStart(0), mEnd(0), mFragmentIdentifier(0)
|
||||
{
|
||||
// nothing else to do here
|
||||
}
|
||||
|
@ -106,23 +93,32 @@ class basic_nsAReadableString
|
|||
public:
|
||||
enum FragmentRequest { kPrevFragment, kFirstFragment, kLastFragment, kNextFragment, kFragmentAt };
|
||||
|
||||
// Damn! Had to make |GetFragment| public because the compilers suck. Should be protected.
|
||||
virtual const CharT* GetFragment( ConstFragment&, FragmentRequest, PRUint32 = 0 ) const = 0;
|
||||
// Damn! Had to make |GetConstFragment| public because the compilers suck. Should be protected.
|
||||
virtual const CharT* GetConstFragment( ConstFragment&, FragmentRequest, PRUint32 = 0 ) const = 0;
|
||||
|
||||
friend class ConstIterator;
|
||||
class ConstIterator
|
||||
: public std::bidirectional_iterator_tag
|
||||
{
|
||||
public:
|
||||
typedef ptrdiff_t difference_type;
|
||||
typedef CharT value_type;
|
||||
typedef const CharT* pointer;
|
||||
typedef const CharT& reference;
|
||||
typedef bidirectional_iterator_tag iterator_category;
|
||||
|
||||
private:
|
||||
friend class basic_nsAReadableString<CharT>;
|
||||
|
||||
ConstFragment mFragment;
|
||||
const CharT* mPosition;
|
||||
const basic_nsAReadableString<CharT>* mOwningString;
|
||||
|
||||
void
|
||||
normalize_forward()
|
||||
{
|
||||
if ( mPosition == mFragment.mEnd )
|
||||
if ( mFragment.mOwningString->GetFragment(mFragment, kNextFragment) )
|
||||
if ( mOwningString->GetConstFragment(mFragment, kNextFragment) )
|
||||
mPosition = mFragment.mStart;
|
||||
}
|
||||
|
||||
|
@ -130,12 +126,16 @@ class basic_nsAReadableString
|
|||
normalize_backward()
|
||||
{
|
||||
if ( mPosition == mFragment.mStart )
|
||||
if ( mFragment.mOwningString->GetFragment(mFragment, kPrevFragment) )
|
||||
if ( mOwningString->GetConstFragment(mFragment, kPrevFragment) )
|
||||
mPosition = mFragment.mEnd;
|
||||
}
|
||||
|
||||
ConstIterator( const ConstFragment& aFragment, const CharT* aStartingPosition )
|
||||
: mFragment(aFragment), mPosition(aStartingPosition)
|
||||
ConstIterator( const ConstFragment& aFragment,
|
||||
const CharT* aStartingPosition,
|
||||
const basic_nsAReadableString<CharT>& aOwningString )
|
||||
: mFragment(aFragment),
|
||||
mPosition(aStartingPosition),
|
||||
mOwningString(&aOwningString)
|
||||
{
|
||||
// nothing else to do here
|
||||
}
|
||||
|
@ -207,29 +207,40 @@ class basic_nsAReadableString
|
|||
ConstIterator
|
||||
Begin( PRUint32 aOffset = 0 ) const
|
||||
{
|
||||
ConstFragment fragment(this);
|
||||
const CharT* startPos = GetFragment(fragment, kFragmentAt, aOffset);
|
||||
return ConstIterator(fragment, startPos);
|
||||
ConstFragment fragment;
|
||||
const CharT* startPos = GetConstFragment(fragment, kFragmentAt, aOffset);
|
||||
return ConstIterator(fragment, startPos, *this);
|
||||
}
|
||||
|
||||
ConstIterator
|
||||
End( PRUint32 aOffset = 0 ) const
|
||||
{
|
||||
ConstFragment fragment(this);
|
||||
const CharT* startPos = GetFragment(fragment, kFragmentAt, max(0U, Length()-aOffset));
|
||||
return ConstIterator(fragment, startPos);
|
||||
ConstFragment fragment;
|
||||
const CharT* startPos = GetConstFragment(fragment, kFragmentAt, max(0U, Length()-aOffset));
|
||||
return ConstIterator(fragment, startPos, *this);
|
||||
}
|
||||
|
||||
public:
|
||||
virtual ~basic_nsAReadableString<CharT>() { }
|
||||
// ...yes, I expect to be sub-classed.
|
||||
|
||||
virtual PRUint32 Length() const = 0;
|
||||
PRBool IsEmpty() const { return Length()==0; }
|
||||
|
||||
// PRBool IsOrdered() const;
|
||||
PRBool
|
||||
IsEmpty() const
|
||||
{
|
||||
return Length() == 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
RickG says the following three routines, |IsUnicode()|, |GetBuffer()|, and |GetUnicode()|
|
||||
shouldn't be implemented because they're wrong access. I agree. Callers who really need
|
||||
this access should use the iterators instead. We'll use these to ease the transition to
|
||||
|nsAReadable...|, and then remove them as soon as possible.
|
||||
*/
|
||||
|
||||
PRBool IsUnicode() const { return PR_FALSE; }
|
||||
// ...but note specialization for |PRUnichar|, below
|
||||
|
||||
|
@ -237,31 +248,19 @@ class basic_nsAReadableString
|
|||
const PRUnichar* GetUnicode() const { return 0; }
|
||||
// ...but note specializations for |char| and |PRUnichar|, below
|
||||
|
||||
// CharT operator[]( PRUint32 ) const;
|
||||
// CharT CharAt( PRUint32 ) const;
|
||||
// CharT First() const;
|
||||
// CharT Last() const;
|
||||
|
||||
// void ToLowerCase( basic_nsAWritableString<CharT>& ) const;
|
||||
// void ToUpperCase( basic_nsAWritableString<CharT>& ) const;
|
||||
|
||||
// PRUint32 CountChar( char_type ) const;
|
||||
CharT CharAt( PRUint32 ) const;
|
||||
CharT operator[]( PRUint32 ) const;
|
||||
CharT First() const;
|
||||
CharT Last() const;
|
||||
|
||||
// nsString* ToNewString() const; NO! The right way to say this is
|
||||
// new nsString( fromAReadableString )
|
||||
|
||||
// char* ToNewCString() const;
|
||||
// char* ToNewUTF8String() const;
|
||||
// PRUnichar* ToNewUnicode() const;
|
||||
// char* ToCString( char*, PRUint32, PRUint32 ) const;
|
||||
// double ToFLoat( PRInt32* aErrorCode ) const;
|
||||
// long ToInteger( PRInt32* aErrorCode, PRUint32 aRadix );
|
||||
PRUint32 CountChar( CharT ) const;
|
||||
|
||||
PRUint32 Left( basic_nsAWritableString<CharT>&, PRUint32 ) const;
|
||||
PRUint32 Mid( basic_nsAWritableString<CharT>&, PRUint32, PRUint32 ) const;
|
||||
PRUint32 Right( basic_nsAWritableString<CharT>&, PRUint32 ) const;
|
||||
|
||||
// PRUint32 BinarySearch( CharT ) const;
|
||||
// Find( ... ) const;
|
||||
// FindChar( ... ) const;
|
||||
// FindCharInSet( ... ) const;
|
||||
|
@ -270,24 +269,66 @@ class basic_nsAReadableString
|
|||
// RFindCharInSet( ... ) const;
|
||||
|
||||
int Compare( const basic_nsAReadableString<CharT>& rhs ) const;
|
||||
// int Compare( const CharT*, const CharT* ) const;
|
||||
int Compare( const basic_nsLiteralString<CharT>& rhs ) const;
|
||||
|
||||
// Equals
|
||||
|
||||
// |Equals()| is a synonym for |Compare()|
|
||||
|
||||
PRBool
|
||||
Equals( const basic_nsAReadableString<CharT>& rhs ) const
|
||||
{
|
||||
return Compare(rhs) == 0;
|
||||
}
|
||||
|
||||
PRBool
|
||||
Equals( const basic_nsLiteralString<CharT>& rhs ) const
|
||||
{
|
||||
return Compare(rhs) == 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Shouldn't be implemented because they're i18n sensitive.
|
||||
Let's leave them in |nsString| for now.
|
||||
*/
|
||||
|
||||
// ToLowerCase
|
||||
// ToUpperCase
|
||||
// EqualsIgnoreCase
|
||||
|
||||
// IsASCII
|
||||
// IsSpace
|
||||
// IsAlpha
|
||||
// IsDigit
|
||||
// ToFloat
|
||||
// ToInteger
|
||||
|
||||
// char* ToNewCString() const;
|
||||
// char* ToNewUTF8String() const;
|
||||
// PRUnichar* ToNewUnicode() const;
|
||||
// char* ToCString( char*, PRUint32, PRUint32 ) const;
|
||||
|
||||
|
||||
/*
|
||||
Normally you wouldn't declare these as members...
|
||||
|
||||
...explanation to come...
|
||||
Shouldn't be implemented because it's wrong duplication.
|
||||
Let's leave it in |nsString| for now.
|
||||
*/
|
||||
|
||||
// nsString* ToNewString() const;
|
||||
// NO! The right way to say this is |new nsString( fromAReadableString )|
|
||||
|
||||
|
||||
/*
|
||||
Shouldn't be implemented because they're not generally applicable.
|
||||
Let's leave them in |nsString| for now.
|
||||
*/
|
||||
|
||||
// IsOrdered
|
||||
// BinarySearch
|
||||
|
||||
|
||||
|
||||
// Comparison operators are all synonyms for |Compare()|
|
||||
|
||||
PRBool operator!=( const basic_nsAReadableString<CharT>& rhs ) const { return Compare(rhs)!=0; }
|
||||
PRBool operator< ( const basic_nsAReadableString<CharT>& rhs ) const { return Compare(rhs)< 0; }
|
||||
PRBool operator<=( const basic_nsAReadableString<CharT>& rhs ) const { return Compare(rhs)<=0; }
|
||||
|
@ -296,6 +337,28 @@ class basic_nsAReadableString
|
|||
PRBool operator> ( const basic_nsAReadableString<CharT>& rhs ) const { return Compare(rhs)> 0; }
|
||||
};
|
||||
|
||||
#define NS_DEF_1_STRING_COMPARISON_OPERATOR(comp, T1, T2) \
|
||||
template <class CharT> \
|
||||
inline \
|
||||
PRBool \
|
||||
operator comp( T1 lhs, T2 rhs ) \
|
||||
{ \
|
||||
return PRBool(Compare(lhs, rhs) comp 0); \
|
||||
}
|
||||
|
||||
#define NS_DEF_STRING_COMPARISON_OPERATORS(T1, T2) \
|
||||
NS_DEF_1_STRING_COMPARISON_OPERATOR(!=, T1, T2) \
|
||||
NS_DEF_1_STRING_COMPARISON_OPERATOR(< , T1, T2) \
|
||||
NS_DEF_1_STRING_COMPARISON_OPERATOR(<=, T1, T2) \
|
||||
NS_DEF_1_STRING_COMPARISON_OPERATOR(==, T1, T2) \
|
||||
NS_DEF_1_STRING_COMPARISON_OPERATOR(>=, T1, T2) \
|
||||
NS_DEF_1_STRING_COMPARISON_OPERATOR(> , T1, T2)
|
||||
|
||||
#define NS_DEF_STRING_COMPARISONS(T) \
|
||||
NS_DEF_STRING_COMPARISON_OPERATORS(const T&, const CharT*) \
|
||||
NS_DEF_STRING_COMPARISON_OPERATORS(const CharT*, const T&)
|
||||
|
||||
|
||||
NS_DEF_STRING_COMPARISONS(basic_nsAReadableString<CharT>)
|
||||
|
||||
|
||||
|
@ -308,17 +371,6 @@ basic_nsAReadableString<PRUnichar>::IsUnicode() const
|
|||
return PR_TRUE;
|
||||
}
|
||||
|
||||
NS_SPECIALIZE_TEMPLATE
|
||||
inline
|
||||
const PRUnichar*
|
||||
basic_nsAReadableString<PRUnichar>::GetUnicode() const
|
||||
// DEPRECATED: use the iterators instead
|
||||
{
|
||||
ConstFragment fragment;
|
||||
GetFragment(fragment, kFirstFragment);
|
||||
return fragment.mStart;
|
||||
}
|
||||
|
||||
NS_SPECIALIZE_TEMPLATE
|
||||
inline
|
||||
const char*
|
||||
|
@ -326,21 +378,163 @@ basic_nsAReadableString<char>::GetBuffer() const
|
|||
// DEPRECATED: use the iterators instead
|
||||
{
|
||||
ConstFragment fragment;
|
||||
GetFragment(fragment, kFirstFragment);
|
||||
GetConstFragment(fragment, kFirstFragment);
|
||||
return fragment.mStart;
|
||||
}
|
||||
|
||||
NS_SPECIALIZE_TEMPLATE
|
||||
inline
|
||||
const PRUnichar*
|
||||
basic_nsAReadableString<PRUnichar>::GetUnicode() const
|
||||
// DEPRECATED: use the iterators instead
|
||||
{
|
||||
ConstFragment fragment;
|
||||
GetConstFragment(fragment, kFirstFragment);
|
||||
return fragment.mStart;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
Note: the following four functions, |CharAt|, |operator[]|, |First|, and |Last|, are implemented
|
||||
in the simplest reasonable scheme; by calling |GetConstFragment| and resolving the pointer it
|
||||
returns. The alternative is to force at least one of these methods to be |virtual|. The ideal
|
||||
candidate for that change would be |CharAt|.
|
||||
|
||||
This is something to measure in the context of how string classes are actually used. In practice,
|
||||
do people extract a character at a time in performance critical places? If so, can they use
|
||||
iterators instead? If they must extract single characters, _and_ they can't use iterators, _and_
|
||||
it happens enough to notice, then we'll take the hit and make |CharAt| virtual.
|
||||
*/
|
||||
|
||||
template <class CharT>
|
||||
inline
|
||||
CharT
|
||||
basic_nsAReadableString<CharT>::CharAt( PRUint32 aIndex ) const
|
||||
{
|
||||
// ??? Is |CharAt()| supposed to be the 'safe' version?
|
||||
ConstFragment fragment;
|
||||
return *GetConstFragment(fragment, kFragmentAt, aIndex);
|
||||
}
|
||||
|
||||
template <class CharT>
|
||||
inline
|
||||
CharT
|
||||
basic_nsAReadableString<CharT>::operator[]( PRUint32 aIndex ) const
|
||||
{
|
||||
return CharAt(aIndex);
|
||||
}
|
||||
|
||||
template <class CharT>
|
||||
inline
|
||||
CharT
|
||||
basic_nsAReadableString<CharT>::First() const
|
||||
{
|
||||
return CharAt(0);
|
||||
}
|
||||
|
||||
template <class CharT>
|
||||
inline
|
||||
CharT
|
||||
basic_nsAReadableString<CharT>::Last() const
|
||||
{
|
||||
return CharAt(Length()-1);
|
||||
}
|
||||
|
||||
template <class CharT>
|
||||
PRUint32
|
||||
basic_nsAReadableString<CharT>::CountChar( CharT c ) const
|
||||
{
|
||||
return count(Begin(), End(), c);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Note: |Left()|, |Mid()|, and |Right()| could be modified to notice when they degenerate into copying the
|
||||
entire string, and call |Assign()| instead. This would be a win when the underlying implementation of
|
||||
both strings could do buffer sharing. This is _definitely_ something that should be measured before
|
||||
being implemented.
|
||||
*/
|
||||
|
||||
template <class CharT>
|
||||
PRUint32
|
||||
basic_nsAReadableString<CharT>::Left( basic_nsAWritableString<CharT>& aResult, PRUint32 aLengthToCopy ) const
|
||||
{
|
||||
aResult = Substring(*this, 0, aLengthToCopy);
|
||||
return aResult.Length();
|
||||
}
|
||||
|
||||
template <class CharT>
|
||||
PRUint32
|
||||
basic_nsAReadableString<CharT>::Mid( basic_nsAWritableString<CharT>& aResult, PRUint32 aStartPos, PRUint32 aLengthToCopy ) const
|
||||
{
|
||||
aResult = Substring(*this, aStartPos, aLengthToCopy);
|
||||
return aResult.Length();
|
||||
}
|
||||
|
||||
template <class CharT>
|
||||
PRUint32
|
||||
basic_nsAReadableString<CharT>::Right( basic_nsAWritableString<CharT>& aResult, PRUint32 aLengthToCopy ) const
|
||||
{
|
||||
PRUint32 myLength = Length();
|
||||
aLengthToCopy = min(myLength, aLengthToCopy);
|
||||
aResult = Substring(*this, myLength-aLengthToCopy, aLengthToCopy);
|
||||
return aResult.Length();
|
||||
}
|
||||
|
||||
|
||||
|
||||
template <class CharT>
|
||||
inline
|
||||
int
|
||||
basic_nsAReadableString<CharT>::Compare( const basic_nsAReadableString<CharT>& rhs ) const
|
||||
{
|
||||
return ::Compare(*this, rhs);
|
||||
}
|
||||
|
||||
template <class CharT>
|
||||
inline
|
||||
int
|
||||
basic_nsAReadableString<CharT>::Compare( const basic_nsLiteralString<CharT>& rhs ) const
|
||||
{
|
||||
return ::Compare(*this, rhs);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//
|
||||
// nsLiteral[C]String
|
||||
//
|
||||
|
||||
template <class CharT>
|
||||
class basic_nsLiteralString
|
||||
: public basic_nsAReadableString<CharT>
|
||||
/*
|
||||
...this class wraps a constant literal string and lets it act like an |nsAReadable...|.
|
||||
|
||||
Use it like this:
|
||||
|
||||
SomeFunctionTakingACString( nsLiteralCString("Hello, World!") );
|
||||
|
||||
With some tweaking, I think I can make this work as well...
|
||||
|
||||
SomeStringFunc( nsLiteralString( L"Hello, World!" ) );
|
||||
|
||||
This class just holds a pointer. If you don't supply the length, it must calculate it.
|
||||
No copying or allocations are performed.
|
||||
|
||||
|const basic_nsLiteralString<CharT>&| appears frequently in interfaces because it
|
||||
allows the automatic conversion of a |CharT*|.
|
||||
*/
|
||||
{
|
||||
typedef typename basic_nsAReadableString<CharT>::FragmentRequest FragmentRequest;
|
||||
typedef typename basic_nsAWritableString<CharT>::ConstFragment ConstFragment;
|
||||
|
||||
protected:
|
||||
virtual const CharT* GetFragment( ConstFragment&, FragmentRequest, PRUint32 ) const;
|
||||
virtual const CharT* GetConstFragment( ConstFragment&, FragmentRequest, PRUint32 ) const;
|
||||
|
||||
public:
|
||||
|
||||
|
@ -368,37 +562,89 @@ class basic_nsLiteralString
|
|||
|
||||
NS_DEF_STRING_COMPARISONS(basic_nsLiteralString<CharT>)
|
||||
|
||||
template <class CharT>
|
||||
const CharT*
|
||||
basic_nsLiteralString<CharT>::GetConstFragment( ConstFragment& aFragment, FragmentRequest aRequest, PRUint32 aOffset ) const
|
||||
{
|
||||
switch ( aRequest )
|
||||
{
|
||||
case kFirstFragment:
|
||||
case kLastFragment:
|
||||
case kFragmentAt:
|
||||
aFragment.mStart = mStart;
|
||||
aFragment.mEnd = mEnd;
|
||||
return mStart + aOffset;
|
||||
|
||||
case kPrevFragment:
|
||||
case kNextFragment:
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
template <class CharT>
|
||||
PRUint32
|
||||
basic_nsLiteralString<CharT>::Length() const
|
||||
{
|
||||
return PRUint32(mEnd - mStart);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//
|
||||
// nsPromiseConcatenation
|
||||
//
|
||||
|
||||
template <class CharT>
|
||||
class nsPromiseConcatenation
|
||||
: public basic_nsAReadableString<CharT>
|
||||
/*
|
||||
...not unlike RickG's original |nsSubsumeString| in _intent_.
|
||||
NOT FOR USE BY HUMANS
|
||||
|
||||
Instances of this class only exist as anonymous temporary results from |operator+()|.
|
||||
This is the machinery that makes string concatenation efficient. No allocations or
|
||||
character copies are required unless and until a final assignment is made. It works
|
||||
its magic by overriding and forwarding calls to |GetConstFragment()|.
|
||||
|
||||
Note: |nsPromiseConcatenation| imposes some limits on string concatenation with |operator+()|.
|
||||
- no more than 33 strings, e.g., |s1 + s2 + s3 + ... s32 + s33|
|
||||
- left to right evaluation is required ... do not use parentheses to override this
|
||||
|
||||
In practice, neither of these is onerous. Parentheses do not change the semantics of the
|
||||
concatenation, only the order in which the result is assembled ... so there's no reason
|
||||
for a user to need to control it. Too many strings summed together can easily be worked
|
||||
around with an intermediate assignment. I wouldn't have the parentheses limitation if I
|
||||
assigned the identifier mask starting at the top, the first time anybody called
|
||||
|GetConstFragment()|.
|
||||
*/
|
||||
{
|
||||
typedef typename basic_nsAReadableString<CharT>::FragmentRequest FragmentRequest;
|
||||
typedef typename basic_nsAWritableString<CharT>::ConstFragment ConstFragment;
|
||||
|
||||
protected:
|
||||
virtual const CharT* GetFragment( ConstFragment&, FragmentRequest, PRUint32 ) const;
|
||||
virtual const CharT* GetConstFragment( ConstFragment&, FragmentRequest, PRUint32 ) const;
|
||||
|
||||
static const int kLeftString = 0;
|
||||
static const int kRightString = 1;
|
||||
|
||||
int
|
||||
current_string( const ConstFragment& aFragment ) const
|
||||
GetCurrentStringFromFragment( const ConstFragment& aFragment ) const
|
||||
{
|
||||
return (aFragment.mFragmentIdentifier & mFragmentIdentifierMask) ? kRightString : kLeftString;
|
||||
}
|
||||
|
||||
int
|
||||
use_left_string( ConstFragment& aFragment ) const
|
||||
SetLeftStringInFragment( ConstFragment& aFragment ) const
|
||||
{
|
||||
aFragment.mFragmentIdentifier &= ~mFragmentIdentifierMask;
|
||||
return kLeftString;
|
||||
}
|
||||
|
||||
int
|
||||
use_right_string( ConstFragment& aFragment ) const
|
||||
SetRightStringInFragment( ConstFragment& aFragment ) const
|
||||
{
|
||||
aFragment.mFragmentIdentifier |= mFragmentIdentifierMask;
|
||||
return kRightString;
|
||||
|
@ -437,35 +683,37 @@ nsPromiseConcatenation<CharT>::Length() const
|
|||
|
||||
template <class CharT>
|
||||
const CharT*
|
||||
nsPromiseConcatenation<CharT>::GetFragment( ConstFragment& aFragment, FragmentRequest aRequest, PRUint32 aPosition ) const
|
||||
nsPromiseConcatenation<CharT>::GetConstFragment( ConstFragment& aFragment, FragmentRequest aRequest, PRUint32 aPosition ) const
|
||||
{
|
||||
const int kLeftString = 0;
|
||||
const int kRightString = 1;
|
||||
|
||||
int whichString;
|
||||
|
||||
// based on the request, pick which string we will forward the |GetConstFragment()| call into
|
||||
|
||||
switch ( aRequest )
|
||||
{
|
||||
case kPrevFragment:
|
||||
case kNextFragment:
|
||||
whichString = current_string(aFragment);
|
||||
whichString = GetCurrentStringFromFragment(aFragment);
|
||||
break;
|
||||
|
||||
case kFirstFragment:
|
||||
whichString = use_left_string(aFragment);
|
||||
whichString = SetLeftStringInFragment(aFragment);
|
||||
break;
|
||||
|
||||
case kLastFragment:
|
||||
whichString = use_right_string(aFragment);
|
||||
whichString = SetRightStringInFragment(aFragment);
|
||||
break;
|
||||
|
||||
case kFragmentAt:
|
||||
PRUint32 leftLength = mStrings[kLeftString]->Length();
|
||||
if ( aPosition < leftLength )
|
||||
whichString = use_left_string(aFragment);
|
||||
whichString = SetLeftStringInFragment(aFragment);
|
||||
else
|
||||
{
|
||||
whichString = use_right_string(aFragment);
|
||||
whichString = SetRightStringInFragment(aFragment);
|
||||
aPosition -= leftLength;
|
||||
}
|
||||
break;
|
||||
|
@ -477,7 +725,7 @@ nsPromiseConcatenation<CharT>::GetFragment( ConstFragment& aFragment, FragmentRe
|
|||
do
|
||||
{
|
||||
done = true;
|
||||
result = mStrings[whichString]->GetFragment(aFragment, aRequest, aPosition);
|
||||
result = mStrings[whichString]->GetConstFragment(aFragment, aRequest, aPosition);
|
||||
|
||||
if ( !result )
|
||||
{
|
||||
|
@ -485,12 +733,12 @@ nsPromiseConcatenation<CharT>::GetFragment( ConstFragment& aFragment, FragmentRe
|
|||
if ( aRequest == kNextFragment && whichString == kLeftString )
|
||||
{
|
||||
aRequest = kFirstFragment;
|
||||
whichString = use_right_string(aFragment);
|
||||
whichString = SetRightStringInFragment(aFragment);
|
||||
}
|
||||
else if ( aRequest == kPrevFragment && whichString == kRightString )
|
||||
{
|
||||
aRequest = kLastFragment;
|
||||
whichString = use_left_string(aFragment);
|
||||
whichString = SetLeftStringInFragment(aFragment);
|
||||
}
|
||||
else
|
||||
done = true;
|
||||
|
@ -508,15 +756,31 @@ nsPromiseConcatenation<CharT>::operator+( const basic_nsAReadableString<CharT>&
|
|||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//
|
||||
// nsPromiseSubstring
|
||||
//
|
||||
|
||||
template <class CharT>
|
||||
class nsPromiseSubstring
|
||||
: public basic_nsAReadableString<CharT>
|
||||
/*
|
||||
NOT FOR USE BY HUMANS (mostly)
|
||||
|
||||
...not unlike |nsPromiseConcatenation|. Instances of this class exist only as anonymous
|
||||
temporary results from |Substring()|. Like |nsPromiseConcatenation|, this class only
|
||||
holds a pointer, no string data of its own. It does its magic by overriding and forwarding
|
||||
calls to |GetConstFragment()|.
|
||||
*/
|
||||
{
|
||||
typedef typename basic_nsAReadableString<CharT>::FragmentRequest FragmentRequest;
|
||||
typedef typename basic_nsAWritableString<CharT>::ConstFragment ConstFragment;
|
||||
|
||||
protected:
|
||||
virtual const CharT* GetFragment( ConstFragment&, FragmentRequest, PRUint32 ) const;
|
||||
virtual const CharT* GetConstFragment( ConstFragment&, FragmentRequest, PRUint32 ) const;
|
||||
|
||||
public:
|
||||
nsPromiseSubstring( const basic_nsAReadableString<CharT>& aString, PRUint32 aStartPos, PRUint32 aLength )
|
||||
|
@ -546,8 +810,11 @@ nsPromiseSubstring<CharT>::Length() const
|
|||
|
||||
template <class CharT>
|
||||
const CharT*
|
||||
nsPromiseSubstring<CharT>::GetFragment( ConstFragment& aFragment, FragmentRequest aRequest, PRUint32 aPosition ) const
|
||||
nsPromiseSubstring<CharT>::GetConstFragment( ConstFragment& aFragment, FragmentRequest aRequest, PRUint32 aPosition ) const
|
||||
{
|
||||
// Offset any request for a specific position (First, Last, At) by our
|
||||
// substrings startpos within the owning string
|
||||
|
||||
if ( aRequest == kFirstFragment )
|
||||
{
|
||||
aPosition = mStartPos;
|
||||
|
@ -555,15 +822,24 @@ nsPromiseSubstring<CharT>::GetFragment( ConstFragment& aFragment, FragmentReques
|
|||
}
|
||||
else if ( aRequest == kLastFragment )
|
||||
{
|
||||
aPosition = mLength + mStartPos;
|
||||
aPosition = mStartPos + mLength;
|
||||
aRequest = kFragmentAt;
|
||||
}
|
||||
else if ( aRequest == kFragmentAt )
|
||||
aPosition += mStartPos;
|
||||
|
||||
return mString.GetFragment(aFragment, aRequest, aPosition);
|
||||
return mString.GetConstFragment(aFragment, aRequest, aPosition);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//
|
||||
// Global functions
|
||||
//
|
||||
|
||||
template <class CharT>
|
||||
nsPromiseSubstring<CharT>
|
||||
Substring( const basic_nsAReadableString<CharT>& aString, PRUint32 aStartPos, PRUint32 aSubstringLength )
|
||||
|
@ -572,61 +848,6 @@ Substring( const basic_nsAReadableString<CharT>& aString, PRUint32 aStartPos, PR
|
|||
}
|
||||
|
||||
|
||||
template <class CharT>
|
||||
const CharT*
|
||||
basic_nsLiteralString<CharT>::GetFragment( ConstFragment& aFragment, FragmentRequest aRequest, PRUint32 aOffset ) const
|
||||
{
|
||||
switch ( aRequest )
|
||||
{
|
||||
case kFirstFragment:
|
||||
case kLastFragment:
|
||||
case kFragmentAt:
|
||||
aFragment.mStart = mStart;
|
||||
aFragment.mEnd = mEnd;
|
||||
return mStart + aOffset;
|
||||
|
||||
case kPrevFragment:
|
||||
case kNextFragment:
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
template <class CharT>
|
||||
PRUint32
|
||||
basic_nsLiteralString<CharT>::Length() const
|
||||
{
|
||||
return PRUint32(mEnd - mStart);
|
||||
}
|
||||
|
||||
|
||||
|
||||
template <class CharT>
|
||||
PRUint32
|
||||
basic_nsAReadableString<CharT>::Left( basic_nsAWritableString<CharT>& aResult, PRUint32 aLengthToCopy ) const
|
||||
{
|
||||
aResult = Substring(*this, 0, aLengthToCopy);
|
||||
return aResult.Length();
|
||||
}
|
||||
|
||||
template <class CharT>
|
||||
PRUint32
|
||||
basic_nsAReadableString<CharT>::Mid( basic_nsAWritableString<CharT>& aResult, PRUint32 aStartPos, PRUint32 aLengthToCopy ) const
|
||||
{
|
||||
aResult = Substring(*this, aStartPos, aLengthToCopy);
|
||||
return aResult.Length();
|
||||
}
|
||||
|
||||
template <class CharT>
|
||||
PRUint32
|
||||
basic_nsAReadableString<CharT>::Right( basic_nsAWritableString<CharT>& aResult, PRUint32 aLengthToCopy ) const
|
||||
{
|
||||
PRUint32 myLength = Length();
|
||||
aLengthToCopy = min(myLength, aLengthToCopy);
|
||||
aResult = Substring(*this, myLength-aLengthToCopy, aLengthToCopy);
|
||||
return aResult.Length();
|
||||
}
|
||||
|
||||
template <class CharT>
|
||||
int
|
||||
Compare( const basic_nsAReadableString<CharT>& lhs, const basic_nsAReadableString<CharT>& rhs )
|
||||
|
@ -634,17 +855,11 @@ Compare( const basic_nsAReadableString<CharT>& lhs, const basic_nsAReadableStrin
|
|||
/*
|
||||
If this turns out to be too slow (after measurement), there are two important modifications
|
||||
1) chunky iterators
|
||||
2) use char_traits<T>::compare
|
||||
2) and then possibly use |char_traits<T>::compare|
|
||||
*/
|
||||
|
||||
PRUint32 lLength = lhs.Length();
|
||||
PRUint32 rLength = rhs.Length();
|
||||
int result = 0;
|
||||
if ( lLength < rLength )
|
||||
result = -1;
|
||||
else if ( lLength > rLength )
|
||||
result = 1;
|
||||
|
||||
PRUint32 lengthToCompare = min(lLength, rLength);
|
||||
|
||||
typedef typename basic_nsAReadableString<CharT>::ConstIterator ConstIterator;
|
||||
|
@ -663,10 +878,16 @@ Compare( const basic_nsAReadableString<CharT>& lhs, const basic_nsAReadableStrin
|
|||
++rPos;
|
||||
}
|
||||
|
||||
return result;
|
||||
if ( lLength < rLength )
|
||||
return -1;
|
||||
else if ( rLength < lLength )
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <class CharT>
|
||||
inline
|
||||
int
|
||||
Compare( const basic_nsAReadableString<CharT>& lhs, const CharT* rhs )
|
||||
{
|
||||
|
@ -674,20 +895,13 @@ Compare( const basic_nsAReadableString<CharT>& lhs, const CharT* rhs )
|
|||
}
|
||||
|
||||
template <class CharT>
|
||||
inline
|
||||
int
|
||||
Compare( const CharT* lhs, const basic_nsAReadableString<CharT>& rhs )
|
||||
{
|
||||
return Compare(basic_nsLiteralString<CharT>(lhs), rhs);
|
||||
}
|
||||
|
||||
template <class CharT>
|
||||
inline
|
||||
int
|
||||
basic_nsAReadableString<CharT>::Compare( const basic_nsAReadableString<CharT>& rhs ) const
|
||||
{
|
||||
return ::Compare(*this, rhs);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
|
|
|
@ -51,38 +51,43 @@ class basic_nsAWritableString
|
|||
|
||||
struct Fragment
|
||||
{
|
||||
CharT* mStart;
|
||||
CharT* mEnd;
|
||||
CharT* mStart;
|
||||
CharT* mEnd;
|
||||
PRUint32 mFragmentIdentifier;
|
||||
|
||||
basic_nsAWritableString<CharT>* mOwningString;
|
||||
PRUint32 mFragmentIdentifier;
|
||||
|
||||
explicit
|
||||
Fragment( basic_nsAWritableString<CharT>* aOwner = 0 )
|
||||
: mStart(0), mEnd(0), mOwningString(aOwner), mFragmentIdentifier(0)
|
||||
Fragment()
|
||||
: mStart(0), mEnd(0), mFragmentIdentifier(0)
|
||||
{
|
||||
// nothing else to do here
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
using basic_nsAReadableString<CharT>::GetFragment;
|
||||
virtual CharT* GetFragment( Fragment&, FragmentRequest, PRUint32 = 0 ) = 0;
|
||||
|
||||
friend class Iterator;
|
||||
class Iterator
|
||||
: public std::bidirectional_iterator_tag
|
||||
{
|
||||
public:
|
||||
typedef ptrdiff_t difference_type;
|
||||
typedef CharT value_type;
|
||||
typedef const CharT* pointer;
|
||||
typedef const CharT& reference;
|
||||
typedef bidirectional_iterator_tag iterator_category;
|
||||
|
||||
private:
|
||||
friend class basic_nsAWritableString<CharT>;
|
||||
|
||||
Fragment mFragment;
|
||||
CharT* mPosition;
|
||||
basic_nsAWritableString<CharT>* mOwningString;
|
||||
|
||||
void
|
||||
normalize_forward()
|
||||
{
|
||||
if ( mPosition == mFragment.mEnd )
|
||||
if ( mFragment.mOwningString->GetFragment(mFragment, kNextFragment) )
|
||||
if ( mOwningString->GetFragment(mFragment, kNextFragment) )
|
||||
mPosition = mFragment.mStart;
|
||||
}
|
||||
|
||||
|
@ -90,12 +95,16 @@ class basic_nsAWritableString
|
|||
normalize_backward()
|
||||
{
|
||||
if ( mPosition == mFragment.mStart )
|
||||
if ( mFragment.mOwningString->GetFragment(mFragment, kPrevFragment) )
|
||||
if ( mOwningString->GetFragment(mFragment, kPrevFragment) )
|
||||
mPosition = mFragment.mEnd;
|
||||
}
|
||||
|
||||
Iterator( Fragment& aFragment, CharT* aStartingPosition )
|
||||
: mFragment(aFragment), mPosition(aStartingPosition)
|
||||
Iterator( Fragment& aFragment,
|
||||
CharT* aStartingPosition,
|
||||
basic_nsAWritableString<CharT>& aOwningString )
|
||||
: mFragment(aFragment),
|
||||
mPosition(aStartingPosition),
|
||||
mOwningString(&aOwningString)
|
||||
{
|
||||
// nothing else to do here
|
||||
}
|
||||
|
@ -146,40 +155,55 @@ class basic_nsAWritableString
|
|||
}
|
||||
|
||||
PRBool
|
||||
operator==( const ConstIterator& rhs )
|
||||
operator==( const Iterator& rhs )
|
||||
{
|
||||
return mPosition == rhs.mPosition;
|
||||
}
|
||||
|
||||
PRBool
|
||||
operator!=( const ConstIterator& rhs )
|
||||
operator!=( const Iterator& rhs )
|
||||
{
|
||||
return mPosition != rhs.mPosition;
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
#ifdef HAVE_CPP_USING
|
||||
using basic_nsAReadableString<CharT>::Begin;
|
||||
using basic_nsAReadableString<CharT>::End;
|
||||
#else
|
||||
basic_nsAReadableString<CharT>::ConstIterator
|
||||
Begin( PRUint32 aOffset = 0 ) const
|
||||
{
|
||||
return basic_nsAReadableString<CharT>::Begin(aOffset);
|
||||
}
|
||||
|
||||
basic_nsAReadableString<CharT>::ConstIterator
|
||||
End( PRUint32 aOffset = 0 ) const
|
||||
{
|
||||
return basic_nsAReadableString<CharT>::End(aOffset);
|
||||
}
|
||||
#endif
|
||||
|
||||
Iterator
|
||||
Begin( PRUint32 aOffset = 0 )
|
||||
{
|
||||
Fragment fragment(this);
|
||||
Fragment fragment;
|
||||
CharT* startPos = GetFragment(fragment, kFragmentAt, aOffset);
|
||||
return Iterator(fragment, startPos);
|
||||
return Iterator(fragment, startPos, *this);
|
||||
}
|
||||
|
||||
using basic_nsAReadableString<CharT>::End;
|
||||
|
||||
Iterator
|
||||
End( PRUint32 aOffset = 0 )
|
||||
{
|
||||
Fragment fragment(this);
|
||||
Fragment fragment;
|
||||
CharT* startPos = GetFragment(fragment, kFragmentAt, max(0U, Length()-aOffset));
|
||||
return Iterator(fragment, startPos);
|
||||
return Iterator(fragment, startPos, *this);
|
||||
}
|
||||
|
||||
// virtual void Splice( ... );
|
||||
virtual void Splice();
|
||||
|
||||
virtual void SetCapacity( PRUint32 ) = 0;
|
||||
virtual void SetLength( PRUint32 ) = 0;
|
||||
|
@ -195,8 +219,8 @@ class basic_nsAWritableString
|
|||
|
||||
// virtual PRBool SetCharAt( char_type, index_type ) = 0;
|
||||
|
||||
void ToLowerCase();
|
||||
void ToUpperCase();
|
||||
// void ToLowerCase();
|
||||
// void ToUpperCase();
|
||||
|
||||
// void StripChars( const CharT* aSet );
|
||||
// void StripChar( ... );
|
||||
|
@ -246,9 +270,16 @@ class basic_nsAWritableString
|
|||
|
||||
NS_DEF_STRING_COMPARISONS(basic_nsAWritableString<CharT>)
|
||||
|
||||
template <class CharT>
|
||||
void
|
||||
basic_nsAWritableString<CharT>::Splice()
|
||||
{
|
||||
}
|
||||
|
||||
template <class CharT>
|
||||
void
|
||||
basic_nsAWritableString<CharT>::Assign( const basic_nsAReadableString<CharT>& rhs )
|
||||
// Default implementation. Derived classes may be able to do something smarter...
|
||||
{
|
||||
SetLength(rhs.Length());
|
||||
std::copy(rhs.Begin(), rhs.End(), Begin());
|
||||
|
|
|
@ -54,30 +54,21 @@
|
|||
*/
|
||||
|
||||
|
||||
#define NS_DEF_1_STRING_COMPARISON_OPERATOR(comp, T1, T2) \
|
||||
template <class CharT> \
|
||||
inline \
|
||||
PRBool \
|
||||
operator comp( T1 lhs, T2 rhs ) \
|
||||
{ \
|
||||
return PRBool(Compare(lhs, rhs) comp 0); \
|
||||
}
|
||||
|
||||
#define NS_DEF_STRING_COMPARISON_OPERATORS(T1, T2) \
|
||||
NS_DEF_1_STRING_COMPARISON_OPERATOR(!=, T1, T2) \
|
||||
NS_DEF_1_STRING_COMPARISON_OPERATOR(< , T1, T2) \
|
||||
NS_DEF_1_STRING_COMPARISON_OPERATOR(<=, T1, T2) \
|
||||
NS_DEF_1_STRING_COMPARISON_OPERATOR(==, T1, T2) \
|
||||
NS_DEF_1_STRING_COMPARISON_OPERATOR(>=, T1, T2) \
|
||||
NS_DEF_1_STRING_COMPARISON_OPERATOR(> , T1, T2)
|
||||
|
||||
#define NS_DEF_STRING_COMPARISONS(T) \
|
||||
NS_DEF_STRING_COMPARISON_OPERATORS(const T&, const CharT*) \
|
||||
NS_DEF_STRING_COMPARISON_OPERATORS(const CharT*, const T&)
|
||||
|
||||
template <class CharT> class basic_nsAWritableString;
|
||||
// ...because we sometimes use them as `out' params
|
||||
|
||||
template <class CharT> class basic_nsLiteralString;
|
||||
// ...because we sometimes use them as in params to force the conversion of |CharT*|s
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//
|
||||
// nsAReadable[C]String
|
||||
//
|
||||
|
||||
template <class CharT>
|
||||
class basic_nsAReadableString
|
||||
/*
|
||||
|
@ -86,18 +77,14 @@ class basic_nsAReadableString
|
|||
{
|
||||
protected:
|
||||
|
||||
|
||||
struct ConstFragment
|
||||
{
|
||||
const CharT* mStart;
|
||||
const CharT* mEnd;
|
||||
const CharT* mStart;
|
||||
const CharT* mEnd;
|
||||
PRUint32 mFragmentIdentifier;
|
||||
|
||||
const basic_nsAReadableString<CharT>* mOwningString;
|
||||
PRUint32 mFragmentIdentifier;
|
||||
|
||||
explicit
|
||||
ConstFragment( const basic_nsAReadableString<CharT>* aOwner = 0 )
|
||||
: mStart(0), mEnd(0), mOwningString(aOwner), mFragmentIdentifier(0)
|
||||
ConstFragment()
|
||||
: mStart(0), mEnd(0), mFragmentIdentifier(0)
|
||||
{
|
||||
// nothing else to do here
|
||||
}
|
||||
|
@ -106,23 +93,32 @@ class basic_nsAReadableString
|
|||
public:
|
||||
enum FragmentRequest { kPrevFragment, kFirstFragment, kLastFragment, kNextFragment, kFragmentAt };
|
||||
|
||||
// Damn! Had to make |GetFragment| public because the compilers suck. Should be protected.
|
||||
virtual const CharT* GetFragment( ConstFragment&, FragmentRequest, PRUint32 = 0 ) const = 0;
|
||||
// Damn! Had to make |GetConstFragment| public because the compilers suck. Should be protected.
|
||||
virtual const CharT* GetConstFragment( ConstFragment&, FragmentRequest, PRUint32 = 0 ) const = 0;
|
||||
|
||||
friend class ConstIterator;
|
||||
class ConstIterator
|
||||
: public std::bidirectional_iterator_tag
|
||||
{
|
||||
public:
|
||||
typedef ptrdiff_t difference_type;
|
||||
typedef CharT value_type;
|
||||
typedef const CharT* pointer;
|
||||
typedef const CharT& reference;
|
||||
typedef bidirectional_iterator_tag iterator_category;
|
||||
|
||||
private:
|
||||
friend class basic_nsAReadableString<CharT>;
|
||||
|
||||
ConstFragment mFragment;
|
||||
const CharT* mPosition;
|
||||
const basic_nsAReadableString<CharT>* mOwningString;
|
||||
|
||||
void
|
||||
normalize_forward()
|
||||
{
|
||||
if ( mPosition == mFragment.mEnd )
|
||||
if ( mFragment.mOwningString->GetFragment(mFragment, kNextFragment) )
|
||||
if ( mOwningString->GetConstFragment(mFragment, kNextFragment) )
|
||||
mPosition = mFragment.mStart;
|
||||
}
|
||||
|
||||
|
@ -130,12 +126,16 @@ class basic_nsAReadableString
|
|||
normalize_backward()
|
||||
{
|
||||
if ( mPosition == mFragment.mStart )
|
||||
if ( mFragment.mOwningString->GetFragment(mFragment, kPrevFragment) )
|
||||
if ( mOwningString->GetConstFragment(mFragment, kPrevFragment) )
|
||||
mPosition = mFragment.mEnd;
|
||||
}
|
||||
|
||||
ConstIterator( const ConstFragment& aFragment, const CharT* aStartingPosition )
|
||||
: mFragment(aFragment), mPosition(aStartingPosition)
|
||||
ConstIterator( const ConstFragment& aFragment,
|
||||
const CharT* aStartingPosition,
|
||||
const basic_nsAReadableString<CharT>& aOwningString )
|
||||
: mFragment(aFragment),
|
||||
mPosition(aStartingPosition),
|
||||
mOwningString(&aOwningString)
|
||||
{
|
||||
// nothing else to do here
|
||||
}
|
||||
|
@ -207,29 +207,40 @@ class basic_nsAReadableString
|
|||
ConstIterator
|
||||
Begin( PRUint32 aOffset = 0 ) const
|
||||
{
|
||||
ConstFragment fragment(this);
|
||||
const CharT* startPos = GetFragment(fragment, kFragmentAt, aOffset);
|
||||
return ConstIterator(fragment, startPos);
|
||||
ConstFragment fragment;
|
||||
const CharT* startPos = GetConstFragment(fragment, kFragmentAt, aOffset);
|
||||
return ConstIterator(fragment, startPos, *this);
|
||||
}
|
||||
|
||||
ConstIterator
|
||||
End( PRUint32 aOffset = 0 ) const
|
||||
{
|
||||
ConstFragment fragment(this);
|
||||
const CharT* startPos = GetFragment(fragment, kFragmentAt, max(0U, Length()-aOffset));
|
||||
return ConstIterator(fragment, startPos);
|
||||
ConstFragment fragment;
|
||||
const CharT* startPos = GetConstFragment(fragment, kFragmentAt, max(0U, Length()-aOffset));
|
||||
return ConstIterator(fragment, startPos, *this);
|
||||
}
|
||||
|
||||
public:
|
||||
virtual ~basic_nsAReadableString<CharT>() { }
|
||||
// ...yes, I expect to be sub-classed.
|
||||
|
||||
virtual PRUint32 Length() const = 0;
|
||||
PRBool IsEmpty() const { return Length()==0; }
|
||||
|
||||
// PRBool IsOrdered() const;
|
||||
PRBool
|
||||
IsEmpty() const
|
||||
{
|
||||
return Length() == 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
RickG says the following three routines, |IsUnicode()|, |GetBuffer()|, and |GetUnicode()|
|
||||
shouldn't be implemented because they're wrong access. I agree. Callers who really need
|
||||
this access should use the iterators instead. We'll use these to ease the transition to
|
||||
|nsAReadable...|, and then remove them as soon as possible.
|
||||
*/
|
||||
|
||||
PRBool IsUnicode() const { return PR_FALSE; }
|
||||
// ...but note specialization for |PRUnichar|, below
|
||||
|
||||
|
@ -237,31 +248,19 @@ class basic_nsAReadableString
|
|||
const PRUnichar* GetUnicode() const { return 0; }
|
||||
// ...but note specializations for |char| and |PRUnichar|, below
|
||||
|
||||
// CharT operator[]( PRUint32 ) const;
|
||||
// CharT CharAt( PRUint32 ) const;
|
||||
// CharT First() const;
|
||||
// CharT Last() const;
|
||||
|
||||
// void ToLowerCase( basic_nsAWritableString<CharT>& ) const;
|
||||
// void ToUpperCase( basic_nsAWritableString<CharT>& ) const;
|
||||
|
||||
// PRUint32 CountChar( char_type ) const;
|
||||
CharT CharAt( PRUint32 ) const;
|
||||
CharT operator[]( PRUint32 ) const;
|
||||
CharT First() const;
|
||||
CharT Last() const;
|
||||
|
||||
// nsString* ToNewString() const; NO! The right way to say this is
|
||||
// new nsString( fromAReadableString )
|
||||
|
||||
// char* ToNewCString() const;
|
||||
// char* ToNewUTF8String() const;
|
||||
// PRUnichar* ToNewUnicode() const;
|
||||
// char* ToCString( char*, PRUint32, PRUint32 ) const;
|
||||
// double ToFLoat( PRInt32* aErrorCode ) const;
|
||||
// long ToInteger( PRInt32* aErrorCode, PRUint32 aRadix );
|
||||
PRUint32 CountChar( CharT ) const;
|
||||
|
||||
PRUint32 Left( basic_nsAWritableString<CharT>&, PRUint32 ) const;
|
||||
PRUint32 Mid( basic_nsAWritableString<CharT>&, PRUint32, PRUint32 ) const;
|
||||
PRUint32 Right( basic_nsAWritableString<CharT>&, PRUint32 ) const;
|
||||
|
||||
// PRUint32 BinarySearch( CharT ) const;
|
||||
// Find( ... ) const;
|
||||
// FindChar( ... ) const;
|
||||
// FindCharInSet( ... ) const;
|
||||
|
@ -270,24 +269,66 @@ class basic_nsAReadableString
|
|||
// RFindCharInSet( ... ) const;
|
||||
|
||||
int Compare( const basic_nsAReadableString<CharT>& rhs ) const;
|
||||
// int Compare( const CharT*, const CharT* ) const;
|
||||
int Compare( const basic_nsLiteralString<CharT>& rhs ) const;
|
||||
|
||||
// Equals
|
||||
|
||||
// |Equals()| is a synonym for |Compare()|
|
||||
|
||||
PRBool
|
||||
Equals( const basic_nsAReadableString<CharT>& rhs ) const
|
||||
{
|
||||
return Compare(rhs) == 0;
|
||||
}
|
||||
|
||||
PRBool
|
||||
Equals( const basic_nsLiteralString<CharT>& rhs ) const
|
||||
{
|
||||
return Compare(rhs) == 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Shouldn't be implemented because they're i18n sensitive.
|
||||
Let's leave them in |nsString| for now.
|
||||
*/
|
||||
|
||||
// ToLowerCase
|
||||
// ToUpperCase
|
||||
// EqualsIgnoreCase
|
||||
|
||||
// IsASCII
|
||||
// IsSpace
|
||||
// IsAlpha
|
||||
// IsDigit
|
||||
// ToFloat
|
||||
// ToInteger
|
||||
|
||||
// char* ToNewCString() const;
|
||||
// char* ToNewUTF8String() const;
|
||||
// PRUnichar* ToNewUnicode() const;
|
||||
// char* ToCString( char*, PRUint32, PRUint32 ) const;
|
||||
|
||||
|
||||
/*
|
||||
Normally you wouldn't declare these as members...
|
||||
|
||||
...explanation to come...
|
||||
Shouldn't be implemented because it's wrong duplication.
|
||||
Let's leave it in |nsString| for now.
|
||||
*/
|
||||
|
||||
// nsString* ToNewString() const;
|
||||
// NO! The right way to say this is |new nsString( fromAReadableString )|
|
||||
|
||||
|
||||
/*
|
||||
Shouldn't be implemented because they're not generally applicable.
|
||||
Let's leave them in |nsString| for now.
|
||||
*/
|
||||
|
||||
// IsOrdered
|
||||
// BinarySearch
|
||||
|
||||
|
||||
|
||||
// Comparison operators are all synonyms for |Compare()|
|
||||
|
||||
PRBool operator!=( const basic_nsAReadableString<CharT>& rhs ) const { return Compare(rhs)!=0; }
|
||||
PRBool operator< ( const basic_nsAReadableString<CharT>& rhs ) const { return Compare(rhs)< 0; }
|
||||
PRBool operator<=( const basic_nsAReadableString<CharT>& rhs ) const { return Compare(rhs)<=0; }
|
||||
|
@ -296,6 +337,28 @@ class basic_nsAReadableString
|
|||
PRBool operator> ( const basic_nsAReadableString<CharT>& rhs ) const { return Compare(rhs)> 0; }
|
||||
};
|
||||
|
||||
#define NS_DEF_1_STRING_COMPARISON_OPERATOR(comp, T1, T2) \
|
||||
template <class CharT> \
|
||||
inline \
|
||||
PRBool \
|
||||
operator comp( T1 lhs, T2 rhs ) \
|
||||
{ \
|
||||
return PRBool(Compare(lhs, rhs) comp 0); \
|
||||
}
|
||||
|
||||
#define NS_DEF_STRING_COMPARISON_OPERATORS(T1, T2) \
|
||||
NS_DEF_1_STRING_COMPARISON_OPERATOR(!=, T1, T2) \
|
||||
NS_DEF_1_STRING_COMPARISON_OPERATOR(< , T1, T2) \
|
||||
NS_DEF_1_STRING_COMPARISON_OPERATOR(<=, T1, T2) \
|
||||
NS_DEF_1_STRING_COMPARISON_OPERATOR(==, T1, T2) \
|
||||
NS_DEF_1_STRING_COMPARISON_OPERATOR(>=, T1, T2) \
|
||||
NS_DEF_1_STRING_COMPARISON_OPERATOR(> , T1, T2)
|
||||
|
||||
#define NS_DEF_STRING_COMPARISONS(T) \
|
||||
NS_DEF_STRING_COMPARISON_OPERATORS(const T&, const CharT*) \
|
||||
NS_DEF_STRING_COMPARISON_OPERATORS(const CharT*, const T&)
|
||||
|
||||
|
||||
NS_DEF_STRING_COMPARISONS(basic_nsAReadableString<CharT>)
|
||||
|
||||
|
||||
|
@ -308,17 +371,6 @@ basic_nsAReadableString<PRUnichar>::IsUnicode() const
|
|||
return PR_TRUE;
|
||||
}
|
||||
|
||||
NS_SPECIALIZE_TEMPLATE
|
||||
inline
|
||||
const PRUnichar*
|
||||
basic_nsAReadableString<PRUnichar>::GetUnicode() const
|
||||
// DEPRECATED: use the iterators instead
|
||||
{
|
||||
ConstFragment fragment;
|
||||
GetFragment(fragment, kFirstFragment);
|
||||
return fragment.mStart;
|
||||
}
|
||||
|
||||
NS_SPECIALIZE_TEMPLATE
|
||||
inline
|
||||
const char*
|
||||
|
@ -326,21 +378,163 @@ basic_nsAReadableString<char>::GetBuffer() const
|
|||
// DEPRECATED: use the iterators instead
|
||||
{
|
||||
ConstFragment fragment;
|
||||
GetFragment(fragment, kFirstFragment);
|
||||
GetConstFragment(fragment, kFirstFragment);
|
||||
return fragment.mStart;
|
||||
}
|
||||
|
||||
NS_SPECIALIZE_TEMPLATE
|
||||
inline
|
||||
const PRUnichar*
|
||||
basic_nsAReadableString<PRUnichar>::GetUnicode() const
|
||||
// DEPRECATED: use the iterators instead
|
||||
{
|
||||
ConstFragment fragment;
|
||||
GetConstFragment(fragment, kFirstFragment);
|
||||
return fragment.mStart;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
Note: the following four functions, |CharAt|, |operator[]|, |First|, and |Last|, are implemented
|
||||
in the simplest reasonable scheme; by calling |GetConstFragment| and resolving the pointer it
|
||||
returns. The alternative is to force at least one of these methods to be |virtual|. The ideal
|
||||
candidate for that change would be |CharAt|.
|
||||
|
||||
This is something to measure in the context of how string classes are actually used. In practice,
|
||||
do people extract a character at a time in performance critical places? If so, can they use
|
||||
iterators instead? If they must extract single characters, _and_ they can't use iterators, _and_
|
||||
it happens enough to notice, then we'll take the hit and make |CharAt| virtual.
|
||||
*/
|
||||
|
||||
template <class CharT>
|
||||
inline
|
||||
CharT
|
||||
basic_nsAReadableString<CharT>::CharAt( PRUint32 aIndex ) const
|
||||
{
|
||||
// ??? Is |CharAt()| supposed to be the 'safe' version?
|
||||
ConstFragment fragment;
|
||||
return *GetConstFragment(fragment, kFragmentAt, aIndex);
|
||||
}
|
||||
|
||||
template <class CharT>
|
||||
inline
|
||||
CharT
|
||||
basic_nsAReadableString<CharT>::operator[]( PRUint32 aIndex ) const
|
||||
{
|
||||
return CharAt(aIndex);
|
||||
}
|
||||
|
||||
template <class CharT>
|
||||
inline
|
||||
CharT
|
||||
basic_nsAReadableString<CharT>::First() const
|
||||
{
|
||||
return CharAt(0);
|
||||
}
|
||||
|
||||
template <class CharT>
|
||||
inline
|
||||
CharT
|
||||
basic_nsAReadableString<CharT>::Last() const
|
||||
{
|
||||
return CharAt(Length()-1);
|
||||
}
|
||||
|
||||
template <class CharT>
|
||||
PRUint32
|
||||
basic_nsAReadableString<CharT>::CountChar( CharT c ) const
|
||||
{
|
||||
return count(Begin(), End(), c);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Note: |Left()|, |Mid()|, and |Right()| could be modified to notice when they degenerate into copying the
|
||||
entire string, and call |Assign()| instead. This would be a win when the underlying implementation of
|
||||
both strings could do buffer sharing. This is _definitely_ something that should be measured before
|
||||
being implemented.
|
||||
*/
|
||||
|
||||
template <class CharT>
|
||||
PRUint32
|
||||
basic_nsAReadableString<CharT>::Left( basic_nsAWritableString<CharT>& aResult, PRUint32 aLengthToCopy ) const
|
||||
{
|
||||
aResult = Substring(*this, 0, aLengthToCopy);
|
||||
return aResult.Length();
|
||||
}
|
||||
|
||||
template <class CharT>
|
||||
PRUint32
|
||||
basic_nsAReadableString<CharT>::Mid( basic_nsAWritableString<CharT>& aResult, PRUint32 aStartPos, PRUint32 aLengthToCopy ) const
|
||||
{
|
||||
aResult = Substring(*this, aStartPos, aLengthToCopy);
|
||||
return aResult.Length();
|
||||
}
|
||||
|
||||
template <class CharT>
|
||||
PRUint32
|
||||
basic_nsAReadableString<CharT>::Right( basic_nsAWritableString<CharT>& aResult, PRUint32 aLengthToCopy ) const
|
||||
{
|
||||
PRUint32 myLength = Length();
|
||||
aLengthToCopy = min(myLength, aLengthToCopy);
|
||||
aResult = Substring(*this, myLength-aLengthToCopy, aLengthToCopy);
|
||||
return aResult.Length();
|
||||
}
|
||||
|
||||
|
||||
|
||||
template <class CharT>
|
||||
inline
|
||||
int
|
||||
basic_nsAReadableString<CharT>::Compare( const basic_nsAReadableString<CharT>& rhs ) const
|
||||
{
|
||||
return ::Compare(*this, rhs);
|
||||
}
|
||||
|
||||
template <class CharT>
|
||||
inline
|
||||
int
|
||||
basic_nsAReadableString<CharT>::Compare( const basic_nsLiteralString<CharT>& rhs ) const
|
||||
{
|
||||
return ::Compare(*this, rhs);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//
|
||||
// nsLiteral[C]String
|
||||
//
|
||||
|
||||
template <class CharT>
|
||||
class basic_nsLiteralString
|
||||
: public basic_nsAReadableString<CharT>
|
||||
/*
|
||||
...this class wraps a constant literal string and lets it act like an |nsAReadable...|.
|
||||
|
||||
Use it like this:
|
||||
|
||||
SomeFunctionTakingACString( nsLiteralCString("Hello, World!") );
|
||||
|
||||
With some tweaking, I think I can make this work as well...
|
||||
|
||||
SomeStringFunc( nsLiteralString( L"Hello, World!" ) );
|
||||
|
||||
This class just holds a pointer. If you don't supply the length, it must calculate it.
|
||||
No copying or allocations are performed.
|
||||
|
||||
|const basic_nsLiteralString<CharT>&| appears frequently in interfaces because it
|
||||
allows the automatic conversion of a |CharT*|.
|
||||
*/
|
||||
{
|
||||
typedef typename basic_nsAReadableString<CharT>::FragmentRequest FragmentRequest;
|
||||
typedef typename basic_nsAWritableString<CharT>::ConstFragment ConstFragment;
|
||||
|
||||
protected:
|
||||
virtual const CharT* GetFragment( ConstFragment&, FragmentRequest, PRUint32 ) const;
|
||||
virtual const CharT* GetConstFragment( ConstFragment&, FragmentRequest, PRUint32 ) const;
|
||||
|
||||
public:
|
||||
|
||||
|
@ -368,37 +562,89 @@ class basic_nsLiteralString
|
|||
|
||||
NS_DEF_STRING_COMPARISONS(basic_nsLiteralString<CharT>)
|
||||
|
||||
template <class CharT>
|
||||
const CharT*
|
||||
basic_nsLiteralString<CharT>::GetConstFragment( ConstFragment& aFragment, FragmentRequest aRequest, PRUint32 aOffset ) const
|
||||
{
|
||||
switch ( aRequest )
|
||||
{
|
||||
case kFirstFragment:
|
||||
case kLastFragment:
|
||||
case kFragmentAt:
|
||||
aFragment.mStart = mStart;
|
||||
aFragment.mEnd = mEnd;
|
||||
return mStart + aOffset;
|
||||
|
||||
case kPrevFragment:
|
||||
case kNextFragment:
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
template <class CharT>
|
||||
PRUint32
|
||||
basic_nsLiteralString<CharT>::Length() const
|
||||
{
|
||||
return PRUint32(mEnd - mStart);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//
|
||||
// nsPromiseConcatenation
|
||||
//
|
||||
|
||||
template <class CharT>
|
||||
class nsPromiseConcatenation
|
||||
: public basic_nsAReadableString<CharT>
|
||||
/*
|
||||
...not unlike RickG's original |nsSubsumeString| in _intent_.
|
||||
NOT FOR USE BY HUMANS
|
||||
|
||||
Instances of this class only exist as anonymous temporary results from |operator+()|.
|
||||
This is the machinery that makes string concatenation efficient. No allocations or
|
||||
character copies are required unless and until a final assignment is made. It works
|
||||
its magic by overriding and forwarding calls to |GetConstFragment()|.
|
||||
|
||||
Note: |nsPromiseConcatenation| imposes some limits on string concatenation with |operator+()|.
|
||||
- no more than 33 strings, e.g., |s1 + s2 + s3 + ... s32 + s33|
|
||||
- left to right evaluation is required ... do not use parentheses to override this
|
||||
|
||||
In practice, neither of these is onerous. Parentheses do not change the semantics of the
|
||||
concatenation, only the order in which the result is assembled ... so there's no reason
|
||||
for a user to need to control it. Too many strings summed together can easily be worked
|
||||
around with an intermediate assignment. I wouldn't have the parentheses limitation if I
|
||||
assigned the identifier mask starting at the top, the first time anybody called
|
||||
|GetConstFragment()|.
|
||||
*/
|
||||
{
|
||||
typedef typename basic_nsAReadableString<CharT>::FragmentRequest FragmentRequest;
|
||||
typedef typename basic_nsAWritableString<CharT>::ConstFragment ConstFragment;
|
||||
|
||||
protected:
|
||||
virtual const CharT* GetFragment( ConstFragment&, FragmentRequest, PRUint32 ) const;
|
||||
virtual const CharT* GetConstFragment( ConstFragment&, FragmentRequest, PRUint32 ) const;
|
||||
|
||||
static const int kLeftString = 0;
|
||||
static const int kRightString = 1;
|
||||
|
||||
int
|
||||
current_string( const ConstFragment& aFragment ) const
|
||||
GetCurrentStringFromFragment( const ConstFragment& aFragment ) const
|
||||
{
|
||||
return (aFragment.mFragmentIdentifier & mFragmentIdentifierMask) ? kRightString : kLeftString;
|
||||
}
|
||||
|
||||
int
|
||||
use_left_string( ConstFragment& aFragment ) const
|
||||
SetLeftStringInFragment( ConstFragment& aFragment ) const
|
||||
{
|
||||
aFragment.mFragmentIdentifier &= ~mFragmentIdentifierMask;
|
||||
return kLeftString;
|
||||
}
|
||||
|
||||
int
|
||||
use_right_string( ConstFragment& aFragment ) const
|
||||
SetRightStringInFragment( ConstFragment& aFragment ) const
|
||||
{
|
||||
aFragment.mFragmentIdentifier |= mFragmentIdentifierMask;
|
||||
return kRightString;
|
||||
|
@ -437,35 +683,37 @@ nsPromiseConcatenation<CharT>::Length() const
|
|||
|
||||
template <class CharT>
|
||||
const CharT*
|
||||
nsPromiseConcatenation<CharT>::GetFragment( ConstFragment& aFragment, FragmentRequest aRequest, PRUint32 aPosition ) const
|
||||
nsPromiseConcatenation<CharT>::GetConstFragment( ConstFragment& aFragment, FragmentRequest aRequest, PRUint32 aPosition ) const
|
||||
{
|
||||
const int kLeftString = 0;
|
||||
const int kRightString = 1;
|
||||
|
||||
int whichString;
|
||||
|
||||
// based on the request, pick which string we will forward the |GetConstFragment()| call into
|
||||
|
||||
switch ( aRequest )
|
||||
{
|
||||
case kPrevFragment:
|
||||
case kNextFragment:
|
||||
whichString = current_string(aFragment);
|
||||
whichString = GetCurrentStringFromFragment(aFragment);
|
||||
break;
|
||||
|
||||
case kFirstFragment:
|
||||
whichString = use_left_string(aFragment);
|
||||
whichString = SetLeftStringInFragment(aFragment);
|
||||
break;
|
||||
|
||||
case kLastFragment:
|
||||
whichString = use_right_string(aFragment);
|
||||
whichString = SetRightStringInFragment(aFragment);
|
||||
break;
|
||||
|
||||
case kFragmentAt:
|
||||
PRUint32 leftLength = mStrings[kLeftString]->Length();
|
||||
if ( aPosition < leftLength )
|
||||
whichString = use_left_string(aFragment);
|
||||
whichString = SetLeftStringInFragment(aFragment);
|
||||
else
|
||||
{
|
||||
whichString = use_right_string(aFragment);
|
||||
whichString = SetRightStringInFragment(aFragment);
|
||||
aPosition -= leftLength;
|
||||
}
|
||||
break;
|
||||
|
@ -477,7 +725,7 @@ nsPromiseConcatenation<CharT>::GetFragment( ConstFragment& aFragment, FragmentRe
|
|||
do
|
||||
{
|
||||
done = true;
|
||||
result = mStrings[whichString]->GetFragment(aFragment, aRequest, aPosition);
|
||||
result = mStrings[whichString]->GetConstFragment(aFragment, aRequest, aPosition);
|
||||
|
||||
if ( !result )
|
||||
{
|
||||
|
@ -485,12 +733,12 @@ nsPromiseConcatenation<CharT>::GetFragment( ConstFragment& aFragment, FragmentRe
|
|||
if ( aRequest == kNextFragment && whichString == kLeftString )
|
||||
{
|
||||
aRequest = kFirstFragment;
|
||||
whichString = use_right_string(aFragment);
|
||||
whichString = SetRightStringInFragment(aFragment);
|
||||
}
|
||||
else if ( aRequest == kPrevFragment && whichString == kRightString )
|
||||
{
|
||||
aRequest = kLastFragment;
|
||||
whichString = use_left_string(aFragment);
|
||||
whichString = SetLeftStringInFragment(aFragment);
|
||||
}
|
||||
else
|
||||
done = true;
|
||||
|
@ -508,15 +756,31 @@ nsPromiseConcatenation<CharT>::operator+( const basic_nsAReadableString<CharT>&
|
|||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//
|
||||
// nsPromiseSubstring
|
||||
//
|
||||
|
||||
template <class CharT>
|
||||
class nsPromiseSubstring
|
||||
: public basic_nsAReadableString<CharT>
|
||||
/*
|
||||
NOT FOR USE BY HUMANS (mostly)
|
||||
|
||||
...not unlike |nsPromiseConcatenation|. Instances of this class exist only as anonymous
|
||||
temporary results from |Substring()|. Like |nsPromiseConcatenation|, this class only
|
||||
holds a pointer, no string data of its own. It does its magic by overriding and forwarding
|
||||
calls to |GetConstFragment()|.
|
||||
*/
|
||||
{
|
||||
typedef typename basic_nsAReadableString<CharT>::FragmentRequest FragmentRequest;
|
||||
typedef typename basic_nsAWritableString<CharT>::ConstFragment ConstFragment;
|
||||
|
||||
protected:
|
||||
virtual const CharT* GetFragment( ConstFragment&, FragmentRequest, PRUint32 ) const;
|
||||
virtual const CharT* GetConstFragment( ConstFragment&, FragmentRequest, PRUint32 ) const;
|
||||
|
||||
public:
|
||||
nsPromiseSubstring( const basic_nsAReadableString<CharT>& aString, PRUint32 aStartPos, PRUint32 aLength )
|
||||
|
@ -546,8 +810,11 @@ nsPromiseSubstring<CharT>::Length() const
|
|||
|
||||
template <class CharT>
|
||||
const CharT*
|
||||
nsPromiseSubstring<CharT>::GetFragment( ConstFragment& aFragment, FragmentRequest aRequest, PRUint32 aPosition ) const
|
||||
nsPromiseSubstring<CharT>::GetConstFragment( ConstFragment& aFragment, FragmentRequest aRequest, PRUint32 aPosition ) const
|
||||
{
|
||||
// Offset any request for a specific position (First, Last, At) by our
|
||||
// substrings startpos within the owning string
|
||||
|
||||
if ( aRequest == kFirstFragment )
|
||||
{
|
||||
aPosition = mStartPos;
|
||||
|
@ -555,15 +822,24 @@ nsPromiseSubstring<CharT>::GetFragment( ConstFragment& aFragment, FragmentReques
|
|||
}
|
||||
else if ( aRequest == kLastFragment )
|
||||
{
|
||||
aPosition = mLength + mStartPos;
|
||||
aPosition = mStartPos + mLength;
|
||||
aRequest = kFragmentAt;
|
||||
}
|
||||
else if ( aRequest == kFragmentAt )
|
||||
aPosition += mStartPos;
|
||||
|
||||
return mString.GetFragment(aFragment, aRequest, aPosition);
|
||||
return mString.GetConstFragment(aFragment, aRequest, aPosition);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//
|
||||
// Global functions
|
||||
//
|
||||
|
||||
template <class CharT>
|
||||
nsPromiseSubstring<CharT>
|
||||
Substring( const basic_nsAReadableString<CharT>& aString, PRUint32 aStartPos, PRUint32 aSubstringLength )
|
||||
|
@ -572,61 +848,6 @@ Substring( const basic_nsAReadableString<CharT>& aString, PRUint32 aStartPos, PR
|
|||
}
|
||||
|
||||
|
||||
template <class CharT>
|
||||
const CharT*
|
||||
basic_nsLiteralString<CharT>::GetFragment( ConstFragment& aFragment, FragmentRequest aRequest, PRUint32 aOffset ) const
|
||||
{
|
||||
switch ( aRequest )
|
||||
{
|
||||
case kFirstFragment:
|
||||
case kLastFragment:
|
||||
case kFragmentAt:
|
||||
aFragment.mStart = mStart;
|
||||
aFragment.mEnd = mEnd;
|
||||
return mStart + aOffset;
|
||||
|
||||
case kPrevFragment:
|
||||
case kNextFragment:
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
template <class CharT>
|
||||
PRUint32
|
||||
basic_nsLiteralString<CharT>::Length() const
|
||||
{
|
||||
return PRUint32(mEnd - mStart);
|
||||
}
|
||||
|
||||
|
||||
|
||||
template <class CharT>
|
||||
PRUint32
|
||||
basic_nsAReadableString<CharT>::Left( basic_nsAWritableString<CharT>& aResult, PRUint32 aLengthToCopy ) const
|
||||
{
|
||||
aResult = Substring(*this, 0, aLengthToCopy);
|
||||
return aResult.Length();
|
||||
}
|
||||
|
||||
template <class CharT>
|
||||
PRUint32
|
||||
basic_nsAReadableString<CharT>::Mid( basic_nsAWritableString<CharT>& aResult, PRUint32 aStartPos, PRUint32 aLengthToCopy ) const
|
||||
{
|
||||
aResult = Substring(*this, aStartPos, aLengthToCopy);
|
||||
return aResult.Length();
|
||||
}
|
||||
|
||||
template <class CharT>
|
||||
PRUint32
|
||||
basic_nsAReadableString<CharT>::Right( basic_nsAWritableString<CharT>& aResult, PRUint32 aLengthToCopy ) const
|
||||
{
|
||||
PRUint32 myLength = Length();
|
||||
aLengthToCopy = min(myLength, aLengthToCopy);
|
||||
aResult = Substring(*this, myLength-aLengthToCopy, aLengthToCopy);
|
||||
return aResult.Length();
|
||||
}
|
||||
|
||||
template <class CharT>
|
||||
int
|
||||
Compare( const basic_nsAReadableString<CharT>& lhs, const basic_nsAReadableString<CharT>& rhs )
|
||||
|
@ -634,17 +855,11 @@ Compare( const basic_nsAReadableString<CharT>& lhs, const basic_nsAReadableStrin
|
|||
/*
|
||||
If this turns out to be too slow (after measurement), there are two important modifications
|
||||
1) chunky iterators
|
||||
2) use char_traits<T>::compare
|
||||
2) and then possibly use |char_traits<T>::compare|
|
||||
*/
|
||||
|
||||
PRUint32 lLength = lhs.Length();
|
||||
PRUint32 rLength = rhs.Length();
|
||||
int result = 0;
|
||||
if ( lLength < rLength )
|
||||
result = -1;
|
||||
else if ( lLength > rLength )
|
||||
result = 1;
|
||||
|
||||
PRUint32 lengthToCompare = min(lLength, rLength);
|
||||
|
||||
typedef typename basic_nsAReadableString<CharT>::ConstIterator ConstIterator;
|
||||
|
@ -663,10 +878,16 @@ Compare( const basic_nsAReadableString<CharT>& lhs, const basic_nsAReadableStrin
|
|||
++rPos;
|
||||
}
|
||||
|
||||
return result;
|
||||
if ( lLength < rLength )
|
||||
return -1;
|
||||
else if ( rLength < lLength )
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <class CharT>
|
||||
inline
|
||||
int
|
||||
Compare( const basic_nsAReadableString<CharT>& lhs, const CharT* rhs )
|
||||
{
|
||||
|
@ -674,20 +895,13 @@ Compare( const basic_nsAReadableString<CharT>& lhs, const CharT* rhs )
|
|||
}
|
||||
|
||||
template <class CharT>
|
||||
inline
|
||||
int
|
||||
Compare( const CharT* lhs, const basic_nsAReadableString<CharT>& rhs )
|
||||
{
|
||||
return Compare(basic_nsLiteralString<CharT>(lhs), rhs);
|
||||
}
|
||||
|
||||
template <class CharT>
|
||||
inline
|
||||
int
|
||||
basic_nsAReadableString<CharT>::Compare( const basic_nsAReadableString<CharT>& rhs ) const
|
||||
{
|
||||
return ::Compare(*this, rhs);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
|
|
|
@ -51,38 +51,43 @@ class basic_nsAWritableString
|
|||
|
||||
struct Fragment
|
||||
{
|
||||
CharT* mStart;
|
||||
CharT* mEnd;
|
||||
CharT* mStart;
|
||||
CharT* mEnd;
|
||||
PRUint32 mFragmentIdentifier;
|
||||
|
||||
basic_nsAWritableString<CharT>* mOwningString;
|
||||
PRUint32 mFragmentIdentifier;
|
||||
|
||||
explicit
|
||||
Fragment( basic_nsAWritableString<CharT>* aOwner = 0 )
|
||||
: mStart(0), mEnd(0), mOwningString(aOwner), mFragmentIdentifier(0)
|
||||
Fragment()
|
||||
: mStart(0), mEnd(0), mFragmentIdentifier(0)
|
||||
{
|
||||
// nothing else to do here
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
using basic_nsAReadableString<CharT>::GetFragment;
|
||||
virtual CharT* GetFragment( Fragment&, FragmentRequest, PRUint32 = 0 ) = 0;
|
||||
|
||||
friend class Iterator;
|
||||
class Iterator
|
||||
: public std::bidirectional_iterator_tag
|
||||
{
|
||||
public:
|
||||
typedef ptrdiff_t difference_type;
|
||||
typedef CharT value_type;
|
||||
typedef const CharT* pointer;
|
||||
typedef const CharT& reference;
|
||||
typedef bidirectional_iterator_tag iterator_category;
|
||||
|
||||
private:
|
||||
friend class basic_nsAWritableString<CharT>;
|
||||
|
||||
Fragment mFragment;
|
||||
CharT* mPosition;
|
||||
basic_nsAWritableString<CharT>* mOwningString;
|
||||
|
||||
void
|
||||
normalize_forward()
|
||||
{
|
||||
if ( mPosition == mFragment.mEnd )
|
||||
if ( mFragment.mOwningString->GetFragment(mFragment, kNextFragment) )
|
||||
if ( mOwningString->GetFragment(mFragment, kNextFragment) )
|
||||
mPosition = mFragment.mStart;
|
||||
}
|
||||
|
||||
|
@ -90,12 +95,16 @@ class basic_nsAWritableString
|
|||
normalize_backward()
|
||||
{
|
||||
if ( mPosition == mFragment.mStart )
|
||||
if ( mFragment.mOwningString->GetFragment(mFragment, kPrevFragment) )
|
||||
if ( mOwningString->GetFragment(mFragment, kPrevFragment) )
|
||||
mPosition = mFragment.mEnd;
|
||||
}
|
||||
|
||||
Iterator( Fragment& aFragment, CharT* aStartingPosition )
|
||||
: mFragment(aFragment), mPosition(aStartingPosition)
|
||||
Iterator( Fragment& aFragment,
|
||||
CharT* aStartingPosition,
|
||||
basic_nsAWritableString<CharT>& aOwningString )
|
||||
: mFragment(aFragment),
|
||||
mPosition(aStartingPosition),
|
||||
mOwningString(&aOwningString)
|
||||
{
|
||||
// nothing else to do here
|
||||
}
|
||||
|
@ -146,40 +155,55 @@ class basic_nsAWritableString
|
|||
}
|
||||
|
||||
PRBool
|
||||
operator==( const ConstIterator& rhs )
|
||||
operator==( const Iterator& rhs )
|
||||
{
|
||||
return mPosition == rhs.mPosition;
|
||||
}
|
||||
|
||||
PRBool
|
||||
operator!=( const ConstIterator& rhs )
|
||||
operator!=( const Iterator& rhs )
|
||||
{
|
||||
return mPosition != rhs.mPosition;
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
#ifdef HAVE_CPP_USING
|
||||
using basic_nsAReadableString<CharT>::Begin;
|
||||
using basic_nsAReadableString<CharT>::End;
|
||||
#else
|
||||
basic_nsAReadableString<CharT>::ConstIterator
|
||||
Begin( PRUint32 aOffset = 0 ) const
|
||||
{
|
||||
return basic_nsAReadableString<CharT>::Begin(aOffset);
|
||||
}
|
||||
|
||||
basic_nsAReadableString<CharT>::ConstIterator
|
||||
End( PRUint32 aOffset = 0 ) const
|
||||
{
|
||||
return basic_nsAReadableString<CharT>::End(aOffset);
|
||||
}
|
||||
#endif
|
||||
|
||||
Iterator
|
||||
Begin( PRUint32 aOffset = 0 )
|
||||
{
|
||||
Fragment fragment(this);
|
||||
Fragment fragment;
|
||||
CharT* startPos = GetFragment(fragment, kFragmentAt, aOffset);
|
||||
return Iterator(fragment, startPos);
|
||||
return Iterator(fragment, startPos, *this);
|
||||
}
|
||||
|
||||
using basic_nsAReadableString<CharT>::End;
|
||||
|
||||
Iterator
|
||||
End( PRUint32 aOffset = 0 )
|
||||
{
|
||||
Fragment fragment(this);
|
||||
Fragment fragment;
|
||||
CharT* startPos = GetFragment(fragment, kFragmentAt, max(0U, Length()-aOffset));
|
||||
return Iterator(fragment, startPos);
|
||||
return Iterator(fragment, startPos, *this);
|
||||
}
|
||||
|
||||
// virtual void Splice( ... );
|
||||
virtual void Splice();
|
||||
|
||||
virtual void SetCapacity( PRUint32 ) = 0;
|
||||
virtual void SetLength( PRUint32 ) = 0;
|
||||
|
@ -195,8 +219,8 @@ class basic_nsAWritableString
|
|||
|
||||
// virtual PRBool SetCharAt( char_type, index_type ) = 0;
|
||||
|
||||
void ToLowerCase();
|
||||
void ToUpperCase();
|
||||
// void ToLowerCase();
|
||||
// void ToUpperCase();
|
||||
|
||||
// void StripChars( const CharT* aSet );
|
||||
// void StripChar( ... );
|
||||
|
@ -246,9 +270,16 @@ class basic_nsAWritableString
|
|||
|
||||
NS_DEF_STRING_COMPARISONS(basic_nsAWritableString<CharT>)
|
||||
|
||||
template <class CharT>
|
||||
void
|
||||
basic_nsAWritableString<CharT>::Splice()
|
||||
{
|
||||
}
|
||||
|
||||
template <class CharT>
|
||||
void
|
||||
basic_nsAWritableString<CharT>::Assign( const basic_nsAReadableString<CharT>& rhs )
|
||||
// Default implementation. Derived classes may be able to do something smarter...
|
||||
{
|
||||
SetLength(rhs.Length());
|
||||
std::copy(rhs.Begin(), rhs.End(), Begin());
|
||||
|
|
|
@ -54,30 +54,21 @@
|
|||
*/
|
||||
|
||||
|
||||
#define NS_DEF_1_STRING_COMPARISON_OPERATOR(comp, T1, T2) \
|
||||
template <class CharT> \
|
||||
inline \
|
||||
PRBool \
|
||||
operator comp( T1 lhs, T2 rhs ) \
|
||||
{ \
|
||||
return PRBool(Compare(lhs, rhs) comp 0); \
|
||||
}
|
||||
|
||||
#define NS_DEF_STRING_COMPARISON_OPERATORS(T1, T2) \
|
||||
NS_DEF_1_STRING_COMPARISON_OPERATOR(!=, T1, T2) \
|
||||
NS_DEF_1_STRING_COMPARISON_OPERATOR(< , T1, T2) \
|
||||
NS_DEF_1_STRING_COMPARISON_OPERATOR(<=, T1, T2) \
|
||||
NS_DEF_1_STRING_COMPARISON_OPERATOR(==, T1, T2) \
|
||||
NS_DEF_1_STRING_COMPARISON_OPERATOR(>=, T1, T2) \
|
||||
NS_DEF_1_STRING_COMPARISON_OPERATOR(> , T1, T2)
|
||||
|
||||
#define NS_DEF_STRING_COMPARISONS(T) \
|
||||
NS_DEF_STRING_COMPARISON_OPERATORS(const T&, const CharT*) \
|
||||
NS_DEF_STRING_COMPARISON_OPERATORS(const CharT*, const T&)
|
||||
|
||||
template <class CharT> class basic_nsAWritableString;
|
||||
// ...because we sometimes use them as `out' params
|
||||
|
||||
template <class CharT> class basic_nsLiteralString;
|
||||
// ...because we sometimes use them as in params to force the conversion of |CharT*|s
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//
|
||||
// nsAReadable[C]String
|
||||
//
|
||||
|
||||
template <class CharT>
|
||||
class basic_nsAReadableString
|
||||
/*
|
||||
|
@ -86,18 +77,14 @@ class basic_nsAReadableString
|
|||
{
|
||||
protected:
|
||||
|
||||
|
||||
struct ConstFragment
|
||||
{
|
||||
const CharT* mStart;
|
||||
const CharT* mEnd;
|
||||
const CharT* mStart;
|
||||
const CharT* mEnd;
|
||||
PRUint32 mFragmentIdentifier;
|
||||
|
||||
const basic_nsAReadableString<CharT>* mOwningString;
|
||||
PRUint32 mFragmentIdentifier;
|
||||
|
||||
explicit
|
||||
ConstFragment( const basic_nsAReadableString<CharT>* aOwner = 0 )
|
||||
: mStart(0), mEnd(0), mOwningString(aOwner), mFragmentIdentifier(0)
|
||||
ConstFragment()
|
||||
: mStart(0), mEnd(0), mFragmentIdentifier(0)
|
||||
{
|
||||
// nothing else to do here
|
||||
}
|
||||
|
@ -106,23 +93,32 @@ class basic_nsAReadableString
|
|||
public:
|
||||
enum FragmentRequest { kPrevFragment, kFirstFragment, kLastFragment, kNextFragment, kFragmentAt };
|
||||
|
||||
// Damn! Had to make |GetFragment| public because the compilers suck. Should be protected.
|
||||
virtual const CharT* GetFragment( ConstFragment&, FragmentRequest, PRUint32 = 0 ) const = 0;
|
||||
// Damn! Had to make |GetConstFragment| public because the compilers suck. Should be protected.
|
||||
virtual const CharT* GetConstFragment( ConstFragment&, FragmentRequest, PRUint32 = 0 ) const = 0;
|
||||
|
||||
friend class ConstIterator;
|
||||
class ConstIterator
|
||||
: public std::bidirectional_iterator_tag
|
||||
{
|
||||
public:
|
||||
typedef ptrdiff_t difference_type;
|
||||
typedef CharT value_type;
|
||||
typedef const CharT* pointer;
|
||||
typedef const CharT& reference;
|
||||
typedef bidirectional_iterator_tag iterator_category;
|
||||
|
||||
private:
|
||||
friend class basic_nsAReadableString<CharT>;
|
||||
|
||||
ConstFragment mFragment;
|
||||
const CharT* mPosition;
|
||||
const basic_nsAReadableString<CharT>* mOwningString;
|
||||
|
||||
void
|
||||
normalize_forward()
|
||||
{
|
||||
if ( mPosition == mFragment.mEnd )
|
||||
if ( mFragment.mOwningString->GetFragment(mFragment, kNextFragment) )
|
||||
if ( mOwningString->GetConstFragment(mFragment, kNextFragment) )
|
||||
mPosition = mFragment.mStart;
|
||||
}
|
||||
|
||||
|
@ -130,12 +126,16 @@ class basic_nsAReadableString
|
|||
normalize_backward()
|
||||
{
|
||||
if ( mPosition == mFragment.mStart )
|
||||
if ( mFragment.mOwningString->GetFragment(mFragment, kPrevFragment) )
|
||||
if ( mOwningString->GetConstFragment(mFragment, kPrevFragment) )
|
||||
mPosition = mFragment.mEnd;
|
||||
}
|
||||
|
||||
ConstIterator( const ConstFragment& aFragment, const CharT* aStartingPosition )
|
||||
: mFragment(aFragment), mPosition(aStartingPosition)
|
||||
ConstIterator( const ConstFragment& aFragment,
|
||||
const CharT* aStartingPosition,
|
||||
const basic_nsAReadableString<CharT>& aOwningString )
|
||||
: mFragment(aFragment),
|
||||
mPosition(aStartingPosition),
|
||||
mOwningString(&aOwningString)
|
||||
{
|
||||
// nothing else to do here
|
||||
}
|
||||
|
@ -207,29 +207,40 @@ class basic_nsAReadableString
|
|||
ConstIterator
|
||||
Begin( PRUint32 aOffset = 0 ) const
|
||||
{
|
||||
ConstFragment fragment(this);
|
||||
const CharT* startPos = GetFragment(fragment, kFragmentAt, aOffset);
|
||||
return ConstIterator(fragment, startPos);
|
||||
ConstFragment fragment;
|
||||
const CharT* startPos = GetConstFragment(fragment, kFragmentAt, aOffset);
|
||||
return ConstIterator(fragment, startPos, *this);
|
||||
}
|
||||
|
||||
ConstIterator
|
||||
End( PRUint32 aOffset = 0 ) const
|
||||
{
|
||||
ConstFragment fragment(this);
|
||||
const CharT* startPos = GetFragment(fragment, kFragmentAt, max(0U, Length()-aOffset));
|
||||
return ConstIterator(fragment, startPos);
|
||||
ConstFragment fragment;
|
||||
const CharT* startPos = GetConstFragment(fragment, kFragmentAt, max(0U, Length()-aOffset));
|
||||
return ConstIterator(fragment, startPos, *this);
|
||||
}
|
||||
|
||||
public:
|
||||
virtual ~basic_nsAReadableString<CharT>() { }
|
||||
// ...yes, I expect to be sub-classed.
|
||||
|
||||
virtual PRUint32 Length() const = 0;
|
||||
PRBool IsEmpty() const { return Length()==0; }
|
||||
|
||||
// PRBool IsOrdered() const;
|
||||
PRBool
|
||||
IsEmpty() const
|
||||
{
|
||||
return Length() == 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
RickG says the following three routines, |IsUnicode()|, |GetBuffer()|, and |GetUnicode()|
|
||||
shouldn't be implemented because they're wrong access. I agree. Callers who really need
|
||||
this access should use the iterators instead. We'll use these to ease the transition to
|
||||
|nsAReadable...|, and then remove them as soon as possible.
|
||||
*/
|
||||
|
||||
PRBool IsUnicode() const { return PR_FALSE; }
|
||||
// ...but note specialization for |PRUnichar|, below
|
||||
|
||||
|
@ -237,31 +248,19 @@ class basic_nsAReadableString
|
|||
const PRUnichar* GetUnicode() const { return 0; }
|
||||
// ...but note specializations for |char| and |PRUnichar|, below
|
||||
|
||||
// CharT operator[]( PRUint32 ) const;
|
||||
// CharT CharAt( PRUint32 ) const;
|
||||
// CharT First() const;
|
||||
// CharT Last() const;
|
||||
|
||||
// void ToLowerCase( basic_nsAWritableString<CharT>& ) const;
|
||||
// void ToUpperCase( basic_nsAWritableString<CharT>& ) const;
|
||||
|
||||
// PRUint32 CountChar( char_type ) const;
|
||||
CharT CharAt( PRUint32 ) const;
|
||||
CharT operator[]( PRUint32 ) const;
|
||||
CharT First() const;
|
||||
CharT Last() const;
|
||||
|
||||
// nsString* ToNewString() const; NO! The right way to say this is
|
||||
// new nsString( fromAReadableString )
|
||||
|
||||
// char* ToNewCString() const;
|
||||
// char* ToNewUTF8String() const;
|
||||
// PRUnichar* ToNewUnicode() const;
|
||||
// char* ToCString( char*, PRUint32, PRUint32 ) const;
|
||||
// double ToFLoat( PRInt32* aErrorCode ) const;
|
||||
// long ToInteger( PRInt32* aErrorCode, PRUint32 aRadix );
|
||||
PRUint32 CountChar( CharT ) const;
|
||||
|
||||
PRUint32 Left( basic_nsAWritableString<CharT>&, PRUint32 ) const;
|
||||
PRUint32 Mid( basic_nsAWritableString<CharT>&, PRUint32, PRUint32 ) const;
|
||||
PRUint32 Right( basic_nsAWritableString<CharT>&, PRUint32 ) const;
|
||||
|
||||
// PRUint32 BinarySearch( CharT ) const;
|
||||
// Find( ... ) const;
|
||||
// FindChar( ... ) const;
|
||||
// FindCharInSet( ... ) const;
|
||||
|
@ -270,24 +269,66 @@ class basic_nsAReadableString
|
|||
// RFindCharInSet( ... ) const;
|
||||
|
||||
int Compare( const basic_nsAReadableString<CharT>& rhs ) const;
|
||||
// int Compare( const CharT*, const CharT* ) const;
|
||||
int Compare( const basic_nsLiteralString<CharT>& rhs ) const;
|
||||
|
||||
// Equals
|
||||
|
||||
// |Equals()| is a synonym for |Compare()|
|
||||
|
||||
PRBool
|
||||
Equals( const basic_nsAReadableString<CharT>& rhs ) const
|
||||
{
|
||||
return Compare(rhs) == 0;
|
||||
}
|
||||
|
||||
PRBool
|
||||
Equals( const basic_nsLiteralString<CharT>& rhs ) const
|
||||
{
|
||||
return Compare(rhs) == 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Shouldn't be implemented because they're i18n sensitive.
|
||||
Let's leave them in |nsString| for now.
|
||||
*/
|
||||
|
||||
// ToLowerCase
|
||||
// ToUpperCase
|
||||
// EqualsIgnoreCase
|
||||
|
||||
// IsASCII
|
||||
// IsSpace
|
||||
// IsAlpha
|
||||
// IsDigit
|
||||
// ToFloat
|
||||
// ToInteger
|
||||
|
||||
// char* ToNewCString() const;
|
||||
// char* ToNewUTF8String() const;
|
||||
// PRUnichar* ToNewUnicode() const;
|
||||
// char* ToCString( char*, PRUint32, PRUint32 ) const;
|
||||
|
||||
|
||||
/*
|
||||
Normally you wouldn't declare these as members...
|
||||
|
||||
...explanation to come...
|
||||
Shouldn't be implemented because it's wrong duplication.
|
||||
Let's leave it in |nsString| for now.
|
||||
*/
|
||||
|
||||
// nsString* ToNewString() const;
|
||||
// NO! The right way to say this is |new nsString( fromAReadableString )|
|
||||
|
||||
|
||||
/*
|
||||
Shouldn't be implemented because they're not generally applicable.
|
||||
Let's leave them in |nsString| for now.
|
||||
*/
|
||||
|
||||
// IsOrdered
|
||||
// BinarySearch
|
||||
|
||||
|
||||
|
||||
// Comparison operators are all synonyms for |Compare()|
|
||||
|
||||
PRBool operator!=( const basic_nsAReadableString<CharT>& rhs ) const { return Compare(rhs)!=0; }
|
||||
PRBool operator< ( const basic_nsAReadableString<CharT>& rhs ) const { return Compare(rhs)< 0; }
|
||||
PRBool operator<=( const basic_nsAReadableString<CharT>& rhs ) const { return Compare(rhs)<=0; }
|
||||
|
@ -296,6 +337,28 @@ class basic_nsAReadableString
|
|||
PRBool operator> ( const basic_nsAReadableString<CharT>& rhs ) const { return Compare(rhs)> 0; }
|
||||
};
|
||||
|
||||
#define NS_DEF_1_STRING_COMPARISON_OPERATOR(comp, T1, T2) \
|
||||
template <class CharT> \
|
||||
inline \
|
||||
PRBool \
|
||||
operator comp( T1 lhs, T2 rhs ) \
|
||||
{ \
|
||||
return PRBool(Compare(lhs, rhs) comp 0); \
|
||||
}
|
||||
|
||||
#define NS_DEF_STRING_COMPARISON_OPERATORS(T1, T2) \
|
||||
NS_DEF_1_STRING_COMPARISON_OPERATOR(!=, T1, T2) \
|
||||
NS_DEF_1_STRING_COMPARISON_OPERATOR(< , T1, T2) \
|
||||
NS_DEF_1_STRING_COMPARISON_OPERATOR(<=, T1, T2) \
|
||||
NS_DEF_1_STRING_COMPARISON_OPERATOR(==, T1, T2) \
|
||||
NS_DEF_1_STRING_COMPARISON_OPERATOR(>=, T1, T2) \
|
||||
NS_DEF_1_STRING_COMPARISON_OPERATOR(> , T1, T2)
|
||||
|
||||
#define NS_DEF_STRING_COMPARISONS(T) \
|
||||
NS_DEF_STRING_COMPARISON_OPERATORS(const T&, const CharT*) \
|
||||
NS_DEF_STRING_COMPARISON_OPERATORS(const CharT*, const T&)
|
||||
|
||||
|
||||
NS_DEF_STRING_COMPARISONS(basic_nsAReadableString<CharT>)
|
||||
|
||||
|
||||
|
@ -308,17 +371,6 @@ basic_nsAReadableString<PRUnichar>::IsUnicode() const
|
|||
return PR_TRUE;
|
||||
}
|
||||
|
||||
NS_SPECIALIZE_TEMPLATE
|
||||
inline
|
||||
const PRUnichar*
|
||||
basic_nsAReadableString<PRUnichar>::GetUnicode() const
|
||||
// DEPRECATED: use the iterators instead
|
||||
{
|
||||
ConstFragment fragment;
|
||||
GetFragment(fragment, kFirstFragment);
|
||||
return fragment.mStart;
|
||||
}
|
||||
|
||||
NS_SPECIALIZE_TEMPLATE
|
||||
inline
|
||||
const char*
|
||||
|
@ -326,21 +378,163 @@ basic_nsAReadableString<char>::GetBuffer() const
|
|||
// DEPRECATED: use the iterators instead
|
||||
{
|
||||
ConstFragment fragment;
|
||||
GetFragment(fragment, kFirstFragment);
|
||||
GetConstFragment(fragment, kFirstFragment);
|
||||
return fragment.mStart;
|
||||
}
|
||||
|
||||
NS_SPECIALIZE_TEMPLATE
|
||||
inline
|
||||
const PRUnichar*
|
||||
basic_nsAReadableString<PRUnichar>::GetUnicode() const
|
||||
// DEPRECATED: use the iterators instead
|
||||
{
|
||||
ConstFragment fragment;
|
||||
GetConstFragment(fragment, kFirstFragment);
|
||||
return fragment.mStart;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
Note: the following four functions, |CharAt|, |operator[]|, |First|, and |Last|, are implemented
|
||||
in the simplest reasonable scheme; by calling |GetConstFragment| and resolving the pointer it
|
||||
returns. The alternative is to force at least one of these methods to be |virtual|. The ideal
|
||||
candidate for that change would be |CharAt|.
|
||||
|
||||
This is something to measure in the context of how string classes are actually used. In practice,
|
||||
do people extract a character at a time in performance critical places? If so, can they use
|
||||
iterators instead? If they must extract single characters, _and_ they can't use iterators, _and_
|
||||
it happens enough to notice, then we'll take the hit and make |CharAt| virtual.
|
||||
*/
|
||||
|
||||
template <class CharT>
|
||||
inline
|
||||
CharT
|
||||
basic_nsAReadableString<CharT>::CharAt( PRUint32 aIndex ) const
|
||||
{
|
||||
// ??? Is |CharAt()| supposed to be the 'safe' version?
|
||||
ConstFragment fragment;
|
||||
return *GetConstFragment(fragment, kFragmentAt, aIndex);
|
||||
}
|
||||
|
||||
template <class CharT>
|
||||
inline
|
||||
CharT
|
||||
basic_nsAReadableString<CharT>::operator[]( PRUint32 aIndex ) const
|
||||
{
|
||||
return CharAt(aIndex);
|
||||
}
|
||||
|
||||
template <class CharT>
|
||||
inline
|
||||
CharT
|
||||
basic_nsAReadableString<CharT>::First() const
|
||||
{
|
||||
return CharAt(0);
|
||||
}
|
||||
|
||||
template <class CharT>
|
||||
inline
|
||||
CharT
|
||||
basic_nsAReadableString<CharT>::Last() const
|
||||
{
|
||||
return CharAt(Length()-1);
|
||||
}
|
||||
|
||||
template <class CharT>
|
||||
PRUint32
|
||||
basic_nsAReadableString<CharT>::CountChar( CharT c ) const
|
||||
{
|
||||
return count(Begin(), End(), c);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Note: |Left()|, |Mid()|, and |Right()| could be modified to notice when they degenerate into copying the
|
||||
entire string, and call |Assign()| instead. This would be a win when the underlying implementation of
|
||||
both strings could do buffer sharing. This is _definitely_ something that should be measured before
|
||||
being implemented.
|
||||
*/
|
||||
|
||||
template <class CharT>
|
||||
PRUint32
|
||||
basic_nsAReadableString<CharT>::Left( basic_nsAWritableString<CharT>& aResult, PRUint32 aLengthToCopy ) const
|
||||
{
|
||||
aResult = Substring(*this, 0, aLengthToCopy);
|
||||
return aResult.Length();
|
||||
}
|
||||
|
||||
template <class CharT>
|
||||
PRUint32
|
||||
basic_nsAReadableString<CharT>::Mid( basic_nsAWritableString<CharT>& aResult, PRUint32 aStartPos, PRUint32 aLengthToCopy ) const
|
||||
{
|
||||
aResult = Substring(*this, aStartPos, aLengthToCopy);
|
||||
return aResult.Length();
|
||||
}
|
||||
|
||||
template <class CharT>
|
||||
PRUint32
|
||||
basic_nsAReadableString<CharT>::Right( basic_nsAWritableString<CharT>& aResult, PRUint32 aLengthToCopy ) const
|
||||
{
|
||||
PRUint32 myLength = Length();
|
||||
aLengthToCopy = min(myLength, aLengthToCopy);
|
||||
aResult = Substring(*this, myLength-aLengthToCopy, aLengthToCopy);
|
||||
return aResult.Length();
|
||||
}
|
||||
|
||||
|
||||
|
||||
template <class CharT>
|
||||
inline
|
||||
int
|
||||
basic_nsAReadableString<CharT>::Compare( const basic_nsAReadableString<CharT>& rhs ) const
|
||||
{
|
||||
return ::Compare(*this, rhs);
|
||||
}
|
||||
|
||||
template <class CharT>
|
||||
inline
|
||||
int
|
||||
basic_nsAReadableString<CharT>::Compare( const basic_nsLiteralString<CharT>& rhs ) const
|
||||
{
|
||||
return ::Compare(*this, rhs);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//
|
||||
// nsLiteral[C]String
|
||||
//
|
||||
|
||||
template <class CharT>
|
||||
class basic_nsLiteralString
|
||||
: public basic_nsAReadableString<CharT>
|
||||
/*
|
||||
...this class wraps a constant literal string and lets it act like an |nsAReadable...|.
|
||||
|
||||
Use it like this:
|
||||
|
||||
SomeFunctionTakingACString( nsLiteralCString("Hello, World!") );
|
||||
|
||||
With some tweaking, I think I can make this work as well...
|
||||
|
||||
SomeStringFunc( nsLiteralString( L"Hello, World!" ) );
|
||||
|
||||
This class just holds a pointer. If you don't supply the length, it must calculate it.
|
||||
No copying or allocations are performed.
|
||||
|
||||
|const basic_nsLiteralString<CharT>&| appears frequently in interfaces because it
|
||||
allows the automatic conversion of a |CharT*|.
|
||||
*/
|
||||
{
|
||||
typedef typename basic_nsAReadableString<CharT>::FragmentRequest FragmentRequest;
|
||||
typedef typename basic_nsAWritableString<CharT>::ConstFragment ConstFragment;
|
||||
|
||||
protected:
|
||||
virtual const CharT* GetFragment( ConstFragment&, FragmentRequest, PRUint32 ) const;
|
||||
virtual const CharT* GetConstFragment( ConstFragment&, FragmentRequest, PRUint32 ) const;
|
||||
|
||||
public:
|
||||
|
||||
|
@ -368,37 +562,89 @@ class basic_nsLiteralString
|
|||
|
||||
NS_DEF_STRING_COMPARISONS(basic_nsLiteralString<CharT>)
|
||||
|
||||
template <class CharT>
|
||||
const CharT*
|
||||
basic_nsLiteralString<CharT>::GetConstFragment( ConstFragment& aFragment, FragmentRequest aRequest, PRUint32 aOffset ) const
|
||||
{
|
||||
switch ( aRequest )
|
||||
{
|
||||
case kFirstFragment:
|
||||
case kLastFragment:
|
||||
case kFragmentAt:
|
||||
aFragment.mStart = mStart;
|
||||
aFragment.mEnd = mEnd;
|
||||
return mStart + aOffset;
|
||||
|
||||
case kPrevFragment:
|
||||
case kNextFragment:
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
template <class CharT>
|
||||
PRUint32
|
||||
basic_nsLiteralString<CharT>::Length() const
|
||||
{
|
||||
return PRUint32(mEnd - mStart);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//
|
||||
// nsPromiseConcatenation
|
||||
//
|
||||
|
||||
template <class CharT>
|
||||
class nsPromiseConcatenation
|
||||
: public basic_nsAReadableString<CharT>
|
||||
/*
|
||||
...not unlike RickG's original |nsSubsumeString| in _intent_.
|
||||
NOT FOR USE BY HUMANS
|
||||
|
||||
Instances of this class only exist as anonymous temporary results from |operator+()|.
|
||||
This is the machinery that makes string concatenation efficient. No allocations or
|
||||
character copies are required unless and until a final assignment is made. It works
|
||||
its magic by overriding and forwarding calls to |GetConstFragment()|.
|
||||
|
||||
Note: |nsPromiseConcatenation| imposes some limits on string concatenation with |operator+()|.
|
||||
- no more than 33 strings, e.g., |s1 + s2 + s3 + ... s32 + s33|
|
||||
- left to right evaluation is required ... do not use parentheses to override this
|
||||
|
||||
In practice, neither of these is onerous. Parentheses do not change the semantics of the
|
||||
concatenation, only the order in which the result is assembled ... so there's no reason
|
||||
for a user to need to control it. Too many strings summed together can easily be worked
|
||||
around with an intermediate assignment. I wouldn't have the parentheses limitation if I
|
||||
assigned the identifier mask starting at the top, the first time anybody called
|
||||
|GetConstFragment()|.
|
||||
*/
|
||||
{
|
||||
typedef typename basic_nsAReadableString<CharT>::FragmentRequest FragmentRequest;
|
||||
typedef typename basic_nsAWritableString<CharT>::ConstFragment ConstFragment;
|
||||
|
||||
protected:
|
||||
virtual const CharT* GetFragment( ConstFragment&, FragmentRequest, PRUint32 ) const;
|
||||
virtual const CharT* GetConstFragment( ConstFragment&, FragmentRequest, PRUint32 ) const;
|
||||
|
||||
static const int kLeftString = 0;
|
||||
static const int kRightString = 1;
|
||||
|
||||
int
|
||||
current_string( const ConstFragment& aFragment ) const
|
||||
GetCurrentStringFromFragment( const ConstFragment& aFragment ) const
|
||||
{
|
||||
return (aFragment.mFragmentIdentifier & mFragmentIdentifierMask) ? kRightString : kLeftString;
|
||||
}
|
||||
|
||||
int
|
||||
use_left_string( ConstFragment& aFragment ) const
|
||||
SetLeftStringInFragment( ConstFragment& aFragment ) const
|
||||
{
|
||||
aFragment.mFragmentIdentifier &= ~mFragmentIdentifierMask;
|
||||
return kLeftString;
|
||||
}
|
||||
|
||||
int
|
||||
use_right_string( ConstFragment& aFragment ) const
|
||||
SetRightStringInFragment( ConstFragment& aFragment ) const
|
||||
{
|
||||
aFragment.mFragmentIdentifier |= mFragmentIdentifierMask;
|
||||
return kRightString;
|
||||
|
@ -437,35 +683,37 @@ nsPromiseConcatenation<CharT>::Length() const
|
|||
|
||||
template <class CharT>
|
||||
const CharT*
|
||||
nsPromiseConcatenation<CharT>::GetFragment( ConstFragment& aFragment, FragmentRequest aRequest, PRUint32 aPosition ) const
|
||||
nsPromiseConcatenation<CharT>::GetConstFragment( ConstFragment& aFragment, FragmentRequest aRequest, PRUint32 aPosition ) const
|
||||
{
|
||||
const int kLeftString = 0;
|
||||
const int kRightString = 1;
|
||||
|
||||
int whichString;
|
||||
|
||||
// based on the request, pick which string we will forward the |GetConstFragment()| call into
|
||||
|
||||
switch ( aRequest )
|
||||
{
|
||||
case kPrevFragment:
|
||||
case kNextFragment:
|
||||
whichString = current_string(aFragment);
|
||||
whichString = GetCurrentStringFromFragment(aFragment);
|
||||
break;
|
||||
|
||||
case kFirstFragment:
|
||||
whichString = use_left_string(aFragment);
|
||||
whichString = SetLeftStringInFragment(aFragment);
|
||||
break;
|
||||
|
||||
case kLastFragment:
|
||||
whichString = use_right_string(aFragment);
|
||||
whichString = SetRightStringInFragment(aFragment);
|
||||
break;
|
||||
|
||||
case kFragmentAt:
|
||||
PRUint32 leftLength = mStrings[kLeftString]->Length();
|
||||
if ( aPosition < leftLength )
|
||||
whichString = use_left_string(aFragment);
|
||||
whichString = SetLeftStringInFragment(aFragment);
|
||||
else
|
||||
{
|
||||
whichString = use_right_string(aFragment);
|
||||
whichString = SetRightStringInFragment(aFragment);
|
||||
aPosition -= leftLength;
|
||||
}
|
||||
break;
|
||||
|
@ -477,7 +725,7 @@ nsPromiseConcatenation<CharT>::GetFragment( ConstFragment& aFragment, FragmentRe
|
|||
do
|
||||
{
|
||||
done = true;
|
||||
result = mStrings[whichString]->GetFragment(aFragment, aRequest, aPosition);
|
||||
result = mStrings[whichString]->GetConstFragment(aFragment, aRequest, aPosition);
|
||||
|
||||
if ( !result )
|
||||
{
|
||||
|
@ -485,12 +733,12 @@ nsPromiseConcatenation<CharT>::GetFragment( ConstFragment& aFragment, FragmentRe
|
|||
if ( aRequest == kNextFragment && whichString == kLeftString )
|
||||
{
|
||||
aRequest = kFirstFragment;
|
||||
whichString = use_right_string(aFragment);
|
||||
whichString = SetRightStringInFragment(aFragment);
|
||||
}
|
||||
else if ( aRequest == kPrevFragment && whichString == kRightString )
|
||||
{
|
||||
aRequest = kLastFragment;
|
||||
whichString = use_left_string(aFragment);
|
||||
whichString = SetLeftStringInFragment(aFragment);
|
||||
}
|
||||
else
|
||||
done = true;
|
||||
|
@ -508,15 +756,31 @@ nsPromiseConcatenation<CharT>::operator+( const basic_nsAReadableString<CharT>&
|
|||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//
|
||||
// nsPromiseSubstring
|
||||
//
|
||||
|
||||
template <class CharT>
|
||||
class nsPromiseSubstring
|
||||
: public basic_nsAReadableString<CharT>
|
||||
/*
|
||||
NOT FOR USE BY HUMANS (mostly)
|
||||
|
||||
...not unlike |nsPromiseConcatenation|. Instances of this class exist only as anonymous
|
||||
temporary results from |Substring()|. Like |nsPromiseConcatenation|, this class only
|
||||
holds a pointer, no string data of its own. It does its magic by overriding and forwarding
|
||||
calls to |GetConstFragment()|.
|
||||
*/
|
||||
{
|
||||
typedef typename basic_nsAReadableString<CharT>::FragmentRequest FragmentRequest;
|
||||
typedef typename basic_nsAWritableString<CharT>::ConstFragment ConstFragment;
|
||||
|
||||
protected:
|
||||
virtual const CharT* GetFragment( ConstFragment&, FragmentRequest, PRUint32 ) const;
|
||||
virtual const CharT* GetConstFragment( ConstFragment&, FragmentRequest, PRUint32 ) const;
|
||||
|
||||
public:
|
||||
nsPromiseSubstring( const basic_nsAReadableString<CharT>& aString, PRUint32 aStartPos, PRUint32 aLength )
|
||||
|
@ -546,8 +810,11 @@ nsPromiseSubstring<CharT>::Length() const
|
|||
|
||||
template <class CharT>
|
||||
const CharT*
|
||||
nsPromiseSubstring<CharT>::GetFragment( ConstFragment& aFragment, FragmentRequest aRequest, PRUint32 aPosition ) const
|
||||
nsPromiseSubstring<CharT>::GetConstFragment( ConstFragment& aFragment, FragmentRequest aRequest, PRUint32 aPosition ) const
|
||||
{
|
||||
// Offset any request for a specific position (First, Last, At) by our
|
||||
// substrings startpos within the owning string
|
||||
|
||||
if ( aRequest == kFirstFragment )
|
||||
{
|
||||
aPosition = mStartPos;
|
||||
|
@ -555,15 +822,24 @@ nsPromiseSubstring<CharT>::GetFragment( ConstFragment& aFragment, FragmentReques
|
|||
}
|
||||
else if ( aRequest == kLastFragment )
|
||||
{
|
||||
aPosition = mLength + mStartPos;
|
||||
aPosition = mStartPos + mLength;
|
||||
aRequest = kFragmentAt;
|
||||
}
|
||||
else if ( aRequest == kFragmentAt )
|
||||
aPosition += mStartPos;
|
||||
|
||||
return mString.GetFragment(aFragment, aRequest, aPosition);
|
||||
return mString.GetConstFragment(aFragment, aRequest, aPosition);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//
|
||||
// Global functions
|
||||
//
|
||||
|
||||
template <class CharT>
|
||||
nsPromiseSubstring<CharT>
|
||||
Substring( const basic_nsAReadableString<CharT>& aString, PRUint32 aStartPos, PRUint32 aSubstringLength )
|
||||
|
@ -572,61 +848,6 @@ Substring( const basic_nsAReadableString<CharT>& aString, PRUint32 aStartPos, PR
|
|||
}
|
||||
|
||||
|
||||
template <class CharT>
|
||||
const CharT*
|
||||
basic_nsLiteralString<CharT>::GetFragment( ConstFragment& aFragment, FragmentRequest aRequest, PRUint32 aOffset ) const
|
||||
{
|
||||
switch ( aRequest )
|
||||
{
|
||||
case kFirstFragment:
|
||||
case kLastFragment:
|
||||
case kFragmentAt:
|
||||
aFragment.mStart = mStart;
|
||||
aFragment.mEnd = mEnd;
|
||||
return mStart + aOffset;
|
||||
|
||||
case kPrevFragment:
|
||||
case kNextFragment:
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
template <class CharT>
|
||||
PRUint32
|
||||
basic_nsLiteralString<CharT>::Length() const
|
||||
{
|
||||
return PRUint32(mEnd - mStart);
|
||||
}
|
||||
|
||||
|
||||
|
||||
template <class CharT>
|
||||
PRUint32
|
||||
basic_nsAReadableString<CharT>::Left( basic_nsAWritableString<CharT>& aResult, PRUint32 aLengthToCopy ) const
|
||||
{
|
||||
aResult = Substring(*this, 0, aLengthToCopy);
|
||||
return aResult.Length();
|
||||
}
|
||||
|
||||
template <class CharT>
|
||||
PRUint32
|
||||
basic_nsAReadableString<CharT>::Mid( basic_nsAWritableString<CharT>& aResult, PRUint32 aStartPos, PRUint32 aLengthToCopy ) const
|
||||
{
|
||||
aResult = Substring(*this, aStartPos, aLengthToCopy);
|
||||
return aResult.Length();
|
||||
}
|
||||
|
||||
template <class CharT>
|
||||
PRUint32
|
||||
basic_nsAReadableString<CharT>::Right( basic_nsAWritableString<CharT>& aResult, PRUint32 aLengthToCopy ) const
|
||||
{
|
||||
PRUint32 myLength = Length();
|
||||
aLengthToCopy = min(myLength, aLengthToCopy);
|
||||
aResult = Substring(*this, myLength-aLengthToCopy, aLengthToCopy);
|
||||
return aResult.Length();
|
||||
}
|
||||
|
||||
template <class CharT>
|
||||
int
|
||||
Compare( const basic_nsAReadableString<CharT>& lhs, const basic_nsAReadableString<CharT>& rhs )
|
||||
|
@ -634,17 +855,11 @@ Compare( const basic_nsAReadableString<CharT>& lhs, const basic_nsAReadableStrin
|
|||
/*
|
||||
If this turns out to be too slow (after measurement), there are two important modifications
|
||||
1) chunky iterators
|
||||
2) use char_traits<T>::compare
|
||||
2) and then possibly use |char_traits<T>::compare|
|
||||
*/
|
||||
|
||||
PRUint32 lLength = lhs.Length();
|
||||
PRUint32 rLength = rhs.Length();
|
||||
int result = 0;
|
||||
if ( lLength < rLength )
|
||||
result = -1;
|
||||
else if ( lLength > rLength )
|
||||
result = 1;
|
||||
|
||||
PRUint32 lengthToCompare = min(lLength, rLength);
|
||||
|
||||
typedef typename basic_nsAReadableString<CharT>::ConstIterator ConstIterator;
|
||||
|
@ -663,10 +878,16 @@ Compare( const basic_nsAReadableString<CharT>& lhs, const basic_nsAReadableStrin
|
|||
++rPos;
|
||||
}
|
||||
|
||||
return result;
|
||||
if ( lLength < rLength )
|
||||
return -1;
|
||||
else if ( rLength < lLength )
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <class CharT>
|
||||
inline
|
||||
int
|
||||
Compare( const basic_nsAReadableString<CharT>& lhs, const CharT* rhs )
|
||||
{
|
||||
|
@ -674,20 +895,13 @@ Compare( const basic_nsAReadableString<CharT>& lhs, const CharT* rhs )
|
|||
}
|
||||
|
||||
template <class CharT>
|
||||
inline
|
||||
int
|
||||
Compare( const CharT* lhs, const basic_nsAReadableString<CharT>& rhs )
|
||||
{
|
||||
return Compare(basic_nsLiteralString<CharT>(lhs), rhs);
|
||||
}
|
||||
|
||||
template <class CharT>
|
||||
inline
|
||||
int
|
||||
basic_nsAReadableString<CharT>::Compare( const basic_nsAReadableString<CharT>& rhs ) const
|
||||
{
|
||||
return ::Compare(*this, rhs);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
|
|
|
@ -51,38 +51,43 @@ class basic_nsAWritableString
|
|||
|
||||
struct Fragment
|
||||
{
|
||||
CharT* mStart;
|
||||
CharT* mEnd;
|
||||
CharT* mStart;
|
||||
CharT* mEnd;
|
||||
PRUint32 mFragmentIdentifier;
|
||||
|
||||
basic_nsAWritableString<CharT>* mOwningString;
|
||||
PRUint32 mFragmentIdentifier;
|
||||
|
||||
explicit
|
||||
Fragment( basic_nsAWritableString<CharT>* aOwner = 0 )
|
||||
: mStart(0), mEnd(0), mOwningString(aOwner), mFragmentIdentifier(0)
|
||||
Fragment()
|
||||
: mStart(0), mEnd(0), mFragmentIdentifier(0)
|
||||
{
|
||||
// nothing else to do here
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
using basic_nsAReadableString<CharT>::GetFragment;
|
||||
virtual CharT* GetFragment( Fragment&, FragmentRequest, PRUint32 = 0 ) = 0;
|
||||
|
||||
friend class Iterator;
|
||||
class Iterator
|
||||
: public std::bidirectional_iterator_tag
|
||||
{
|
||||
public:
|
||||
typedef ptrdiff_t difference_type;
|
||||
typedef CharT value_type;
|
||||
typedef const CharT* pointer;
|
||||
typedef const CharT& reference;
|
||||
typedef bidirectional_iterator_tag iterator_category;
|
||||
|
||||
private:
|
||||
friend class basic_nsAWritableString<CharT>;
|
||||
|
||||
Fragment mFragment;
|
||||
CharT* mPosition;
|
||||
basic_nsAWritableString<CharT>* mOwningString;
|
||||
|
||||
void
|
||||
normalize_forward()
|
||||
{
|
||||
if ( mPosition == mFragment.mEnd )
|
||||
if ( mFragment.mOwningString->GetFragment(mFragment, kNextFragment) )
|
||||
if ( mOwningString->GetFragment(mFragment, kNextFragment) )
|
||||
mPosition = mFragment.mStart;
|
||||
}
|
||||
|
||||
|
@ -90,12 +95,16 @@ class basic_nsAWritableString
|
|||
normalize_backward()
|
||||
{
|
||||
if ( mPosition == mFragment.mStart )
|
||||
if ( mFragment.mOwningString->GetFragment(mFragment, kPrevFragment) )
|
||||
if ( mOwningString->GetFragment(mFragment, kPrevFragment) )
|
||||
mPosition = mFragment.mEnd;
|
||||
}
|
||||
|
||||
Iterator( Fragment& aFragment, CharT* aStartingPosition )
|
||||
: mFragment(aFragment), mPosition(aStartingPosition)
|
||||
Iterator( Fragment& aFragment,
|
||||
CharT* aStartingPosition,
|
||||
basic_nsAWritableString<CharT>& aOwningString )
|
||||
: mFragment(aFragment),
|
||||
mPosition(aStartingPosition),
|
||||
mOwningString(&aOwningString)
|
||||
{
|
||||
// nothing else to do here
|
||||
}
|
||||
|
@ -146,40 +155,55 @@ class basic_nsAWritableString
|
|||
}
|
||||
|
||||
PRBool
|
||||
operator==( const ConstIterator& rhs )
|
||||
operator==( const Iterator& rhs )
|
||||
{
|
||||
return mPosition == rhs.mPosition;
|
||||
}
|
||||
|
||||
PRBool
|
||||
operator!=( const ConstIterator& rhs )
|
||||
operator!=( const Iterator& rhs )
|
||||
{
|
||||
return mPosition != rhs.mPosition;
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
#ifdef HAVE_CPP_USING
|
||||
using basic_nsAReadableString<CharT>::Begin;
|
||||
using basic_nsAReadableString<CharT>::End;
|
||||
#else
|
||||
basic_nsAReadableString<CharT>::ConstIterator
|
||||
Begin( PRUint32 aOffset = 0 ) const
|
||||
{
|
||||
return basic_nsAReadableString<CharT>::Begin(aOffset);
|
||||
}
|
||||
|
||||
basic_nsAReadableString<CharT>::ConstIterator
|
||||
End( PRUint32 aOffset = 0 ) const
|
||||
{
|
||||
return basic_nsAReadableString<CharT>::End(aOffset);
|
||||
}
|
||||
#endif
|
||||
|
||||
Iterator
|
||||
Begin( PRUint32 aOffset = 0 )
|
||||
{
|
||||
Fragment fragment(this);
|
||||
Fragment fragment;
|
||||
CharT* startPos = GetFragment(fragment, kFragmentAt, aOffset);
|
||||
return Iterator(fragment, startPos);
|
||||
return Iterator(fragment, startPos, *this);
|
||||
}
|
||||
|
||||
using basic_nsAReadableString<CharT>::End;
|
||||
|
||||
Iterator
|
||||
End( PRUint32 aOffset = 0 )
|
||||
{
|
||||
Fragment fragment(this);
|
||||
Fragment fragment;
|
||||
CharT* startPos = GetFragment(fragment, kFragmentAt, max(0U, Length()-aOffset));
|
||||
return Iterator(fragment, startPos);
|
||||
return Iterator(fragment, startPos, *this);
|
||||
}
|
||||
|
||||
// virtual void Splice( ... );
|
||||
virtual void Splice();
|
||||
|
||||
virtual void SetCapacity( PRUint32 ) = 0;
|
||||
virtual void SetLength( PRUint32 ) = 0;
|
||||
|
@ -195,8 +219,8 @@ class basic_nsAWritableString
|
|||
|
||||
// virtual PRBool SetCharAt( char_type, index_type ) = 0;
|
||||
|
||||
void ToLowerCase();
|
||||
void ToUpperCase();
|
||||
// void ToLowerCase();
|
||||
// void ToUpperCase();
|
||||
|
||||
// void StripChars( const CharT* aSet );
|
||||
// void StripChar( ... );
|
||||
|
@ -246,9 +270,16 @@ class basic_nsAWritableString
|
|||
|
||||
NS_DEF_STRING_COMPARISONS(basic_nsAWritableString<CharT>)
|
||||
|
||||
template <class CharT>
|
||||
void
|
||||
basic_nsAWritableString<CharT>::Splice()
|
||||
{
|
||||
}
|
||||
|
||||
template <class CharT>
|
||||
void
|
||||
basic_nsAWritableString<CharT>::Assign( const basic_nsAReadableString<CharT>& rhs )
|
||||
// Default implementation. Derived classes may be able to do something smarter...
|
||||
{
|
||||
SetLength(rhs.Length());
|
||||
std::copy(rhs.Begin(), rhs.End(), Begin());
|
||||
|
|
Загрузка…
Ссылка в новой задаче