getting ready to turn this stuff on, changes related to that: empty strings specified with null pointer, a couple of other fixes.

git-svn-id: svn://10.0.0.236/trunk@69573 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
scc%netscape.com 2000-05-13 20:17:35 +00:00
parent 7cda96dd36
commit 729eef98f9
9 changed files with 366 additions and 135 deletions

View File

@ -263,6 +263,24 @@ class basic_nsAReadableString
PRUint32 CountChar( CharT ) const;
/*
|Left|, |Mid|, and |Right| are annoying signatures that seem better almost
any _other_ way than they are now. Consider these alternatives
aWritable = aReadable.Left(17); // ...a member function that returns a |Substring|
aWritable = Left(aReadable, 17); // ...a global function that returns a |Substring|
Left(aReadable, 17, aWritable); // ...a global function that does the assignment
as opposed to the current signature
aReadable.Left(aWritable, 17); // ...a member function that does the assignment
or maybe just stamping them out in favor of |Substring|, they are just duplicate functionality
aWritable = Substring(aReadable, 0, 17);
*/
PRUint32 Left( basic_nsAWritableString<CharT>&, PRUint32 ) const;
PRUint32 Mid( basic_nsAWritableString<CharT>&, PRUint32, PRUint32 ) const;
PRUint32 Right( basic_nsAWritableString<CharT>&, PRUint32 ) const;
@ -337,6 +355,7 @@ class basic_nsAReadableString
virtual const void* Implementation() const;
virtual const CharT* GetReadableFragment( nsReadableFragment<CharT>&, nsFragmentRequest, PRUint32 = 0 ) const = 0;
virtual PRBool Promises( const basic_nsAReadableString<CharT>& aString ) const { return &aString == this; }
// virtual PRBool PromisesExactly( const basic_nsAReadableString<CharT>& aString ) const { return false; }
private:
// NOT TO BE IMPLEMENTED
@ -531,27 +550,24 @@ basic_nsAReadableString<CharT>::CountChar( CharT c ) const
}
/*
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
basic_nsAReadableString<CharT>::Mid( basic_nsAWritableString<CharT>& aResult, PRUint32 aStartPos, PRUint32 aLengthToCopy ) const
{
aResult = Substring(*this, 0, aLengthToCopy);
// If we're just assigning our entire self, give |aResult| the opportunity to share
if ( aStartPos == 0 && aLengthToCopy >= Length() )
aResult = *this;
else
aResult = Substring(*this, aStartPos, aLengthToCopy);
return aResult.Length();
}
template <class CharT>
PRUint32
basic_nsAReadableString<CharT>::Mid( basic_nsAWritableString<CharT>& aResult, PRUint32 aStartPos, PRUint32 aLengthToCopy ) const
basic_nsAReadableString<CharT>::Left( basic_nsAWritableString<CharT>& aResult, PRUint32 aLengthToCopy ) const
{
aResult = Substring(*this, aStartPos, aLengthToCopy);
return aResult.Length();
return Mid(aResult, 0, aLengthToCopy);
}
template <class CharT>
@ -560,8 +576,7 @@ basic_nsAReadableString<CharT>::Right( basic_nsAWritableString<CharT>& aResult,
{
PRUint32 myLength = Length();
aLengthToCopy = NS_MIN(myLength, aLengthToCopy);
aResult = Substring(*this, myLength-aLengthToCopy, aLengthToCopy);
return aResult.Length();
return Mid(aResult, myLength-aLengthToCopy, aLengthToCopy);
}
@ -612,7 +627,7 @@ class basic_nsLiteralString
// Note: _not_ explicit
basic_nsLiteralString( const CharT* aLiteral )
: mStart(aLiteral),
mEnd(mStart + nsCharTraits<CharT>::length(mStart))
mEnd(mStart ? (mStart + nsCharTraits<CharT>::length(mStart)) : mStart)
{
// nothing else to do here
}
@ -624,7 +639,10 @@ class basic_nsLiteralString
// This is an annoying hack. Callers should be fixed to use the other
// constructor if they don't really know the length.
if ( aLength == PRUint32(-1) )
mEnd = mStart + nsCharTraits<CharT>::length(mStart);
{
NS_WARNING("Tell scc: Caller constructing a string doesn't know the real length. Please use the other constructor.");
mEnd = mStart + nsCharTraits<CharT>::length(mStart);
}
}
virtual PRUint32 Length() const;
@ -818,6 +836,7 @@ class nsPromiseConcatenation
virtual PRUint32 Length() const;
virtual PRBool Promises( const basic_nsAReadableString<CharT>& ) const;
// virtual PRBool PromisesExactly( const basic_nsAReadableString<CharT>& ) const;
nsPromiseConcatenation<CharT> operator+( const basic_nsAReadableString<CharT>& rhs ) const;
@ -847,6 +866,15 @@ nsPromiseConcatenation<CharT>::Promises( const basic_nsAReadableString<CharT>& a
return mStrings[0]->Promises(aString) || mStrings[1]->Promises(aString);
}
#if 0
PRBool
nsPromiseConcatenation<CharT>::PromisesExactly( const basic_nsAReadableString<CharT>& aString ) const
{
// Not really like this, test for the empty string, etc
return mStrings[0] == &aString && !mStrings[1] || !mStrings[0] && mStrings[1] == &aString;
}
#endif
template <class CharT>
const CharT*
nsPromiseConcatenation<CharT>::GetReadableFragment( nsReadableFragment<CharT>& aFragment, nsFragmentRequest aRequest, PRUint32 aPosition ) const
@ -992,7 +1020,7 @@ nsPromiseSubstring<CharT>::GetReadableFragment( nsReadableFragment<CharT>& aFrag
const CharT* position_ptr = mString.GetReadableFragment(aFragment, aRequest, aPosition);
// if there's more physical data in the returned fragment than I logically have left
// if there's more physical data in the returned fragment than I logically have left...
size_t logical_size_forward = mLength - aPosition;
if ( aFragment.mEnd - position_ptr > logical_size_forward )
aFragment.mEnd = position_ptr + logical_size_forward;
@ -1027,7 +1055,7 @@ copy_string( InputIterator first, InputIterator last, OutputIterator result )
while ( first != last )
{
PRInt32 count_copied = PRInt32(sink_traits::write(result, source_traits::read(first), source_traits::readable_size(first, last)));
PRInt32 count_copied = PRInt32(sink_traits::write(result, source_traits::read(first), source_traits::readable_distance(first, last)));
NS_ASSERTION(count_copied > 0, "|copy_string| will never terminate");
first += count_copied;
}
@ -1060,11 +1088,6 @@ template <class CharT>
nsPromiseSubstring<CharT>
Substring( const basic_nsAReadableString<CharT>& aString, PRUint32 aStartPos, PRUint32 aSubstringLength )
{
#if 0
// signatures don't work, but consider this twist to help in assignments
if ( aSubstringLength == aString.Length() && aStartPos == 0 )
return aString;
#endif
return nsPromiseSubstring<CharT>(aString, aStartPos, aSubstringLength);
}
@ -1145,6 +1168,11 @@ Compare( const CharT* lhs, const basic_nsAReadableString<CharT>& rhs )
to implement the virtual functions of readables.
*/
/*
I probably need to add |operator+()| for appropriate |CharT| and |CharT*| comparisons, since
automatic conversion to a literal string will not happen.
*/
template <class CharT>
inline
nsPromiseConcatenation<CharT>

View File

@ -270,39 +270,39 @@ class basic_nsAWritableString
//
// |operator=()|, |Assign()|
// |Assign()|, |operator=()|
//
basic_nsAWritableString<CharT>& operator=( const basic_nsAReadableString<CharT>& aReadable ) { do_AssignFromReadable(aReadable); return *this; }
basic_nsAWritableString<CharT>& operator=( const nsPromiseReadable<CharT>& aReadable ) { Assign(aReadable); return *this; }
basic_nsAWritableString<CharT>& operator=( const CharT* aPtr ) { do_AssignFromElementPtr(aPtr); return *this; }
basic_nsAWritableString<CharT>& operator=( CharT aChar ) { do_AssignFromElement(aChar); return *this; }
void Assign( const basic_nsAReadableString<CharT>& aReadable ) { do_AssignFromReadable(aReadable); }
void Assign( const nsPromiseReadable<CharT>& aReadable ) { aReadable.Promises(*this) ? AssignFromPromise(aReadable) : do_AssignFromReadable(aReadable); }
// void Assign( const nsReadingIterator<CharT>& aStart, const nsReadingIterator<CharT>& aEnd ) { do_AssignFromIterators(aStart, aEnd); }
void Assign( const CharT* aPtr ) { do_AssignFromElementPtr(aPtr); }
void Assign( const CharT* aPtr ) { aPtr ? do_AssignFromElementPtr(aPtr) : SetLength(0); }
void Assign( const CharT* aPtr, PRUint32 aLength ) { do_AssignFromElementPtrLength(aPtr, aLength); }
void Assign( CharT aChar ) { do_AssignFromElement(aChar); }
basic_nsAWritableString<CharT>& operator=( const basic_nsAReadableString<CharT>& aReadable ) { Assign(aReadable); return *this; }
basic_nsAWritableString<CharT>& operator=( const nsPromiseReadable<CharT>& aReadable ) { Assign(aReadable); return *this; }
basic_nsAWritableString<CharT>& operator=( const CharT* aPtr ) { Assign(aPtr); return *this; }
basic_nsAWritableString<CharT>& operator=( CharT aChar ) { Assign(aChar); return *this; }
//
// |operator+=()|, |Append()|
// |Append()|, |operator+=()|
//
basic_nsAWritableString<CharT>& operator+=( const basic_nsAReadableString<CharT>& aReadable ) { do_AppendFromReadable(aReadable); return *this; }
basic_nsAWritableString<CharT>& operator+=( const nsPromiseReadable<CharT>& aReadable ) { Append(aReadable); return *this; }
basic_nsAWritableString<CharT>& operator+=( const CharT* aPtr ) { do_AppendFromElementPtr(aPtr); return *this; }
basic_nsAWritableString<CharT>& operator+=( CharT aChar ) { do_AppendFromElement(aChar); return *this; }
void Append( const basic_nsAReadableString<CharT>& aReadable ) { do_AppendFromReadable(aReadable); }
void Append( const nsPromiseReadable<CharT>& aReadable ) { aReadable.Promises(*this) ? AppendFromPromise(aReadable) : do_AppendFromReadable(aReadable); }
// void Append( const nsReadingIterator<CharT>& aStart, const nsReadingIterator<CharT>& aEnd ) { do_AppendFromIterators(aStart, aEnd); }
void Append( const CharT* aPtr ) { do_AppendFromElementPtr(aPtr); }
void Append( const CharT* aPtr ) { if (aPtr) do_AppendFromElementPtr(aPtr); }
void Append( const CharT* aPtr, PRUint32 aLength ) { do_AppendFromElementPtrLength(aPtr, aLength); }
void Append( CharT aChar ) { do_AppendFromElement(aChar); }
basic_nsAWritableString<CharT>& operator+=( const basic_nsAReadableString<CharT>& aReadable ) { Append(aReadable); return *this; }
basic_nsAWritableString<CharT>& operator+=( const nsPromiseReadable<CharT>& aReadable ) { Append(aReadable); return *this; }
basic_nsAWritableString<CharT>& operator+=( const CharT* aPtr ) { Append(aPtr); return *this; }
basic_nsAWritableString<CharT>& operator+=( CharT aChar ) { Append(aChar); return *this; }
//
@ -313,7 +313,7 @@ class basic_nsAWritableString
void Insert( const basic_nsAReadableString<CharT>& aReadable, PRUint32 atPosition ) { do_InsertFromReadable(aReadable, atPosition); }
void Insert( const nsPromiseReadable<CharT>& aReadable, PRUint32 atPosition ) { aReadable.Promises(*this) ? InsertFromPromise(aReadable, atPosition) : do_InsertFromReadable(aReadable, atPosition); }
// void Insert( const nsReadingIterator<CharT>& aStart, const nsReadingIterator<CharT>& aEnd, PRUint32 atPosition ) { do_InsertFromIterators(aStart, aEnd, atPosition); }
void Insert( const CharT* aPtr, PRUint32 atPosition ) { do_InsertFromElementPtr(aPtr, atPosition); }
void Insert( const CharT* aPtr, PRUint32 atPosition ) { if (aPtr) do_InsertFromElementPtr(aPtr, atPosition); }
void Insert( const CharT* aPtr, PRUint32 atPosition, PRUint32 aLength ) { do_InsertFromElementPtrLength(aPtr, atPosition, aLength); }
void Insert( CharT aChar, PRUint32 atPosition ) { do_InsertFromElement(aChar, atPosition); }
@ -433,14 +433,37 @@ basic_nsAWritableString<CharT>::do_AssignFromReadable( const basic_nsAReadableSt
template <class CharT>
void
basic_nsAWritableString<CharT>::AssignFromPromise( const nsPromiseReadable<CharT>& aReadable )
/*
...this function is only called when a promise that somehow references |this| is assigned _into_ |this|.
E.g.,
... writable& w ...
... readable& r ...
w = r + w;
In this example, you can see that unless the characters promised by |w| in |r+w| are resolved before
anything starts getting copied into |w|, there will be trouble. They will be overritten by the contents
of |r| before being retrieved to be appended.
We could have a really tricky solution where we tell the promise to resolve _just_ the data promised
by |this|, but this should be a rare case, since clients with more local knowledge will know that, e.g.,
in the case above, |Insert| could have special behavior with significantly better performance. Since
it's a rare case anyway, we should just do the simplest thing that could possibly work, resolve the
entire promise. If we measure and this turns out to show up on performance radar, we then have the
option to fix either the callers or this mechanism.
*/
{
PRUint32 length = aReadable.Length();
if ( CharT* buffer = new CharT[length] )
{
// Note: not exception safe. We need something to manage temporary buffers like this
copy_string(aReadable.BeginReading(), aReadable.EndReading(), buffer);
do_AssignFromElementPtrLength(buffer, length);
delete buffer;
}
// else assert?
}
#if 0

View File

@ -463,20 +463,28 @@ struct nsCharTraits<wchar_t>
#endif
template <class InputIterator>
struct nsCharSourceTraits
{
#if 0
static
PRUint32
readable_size( const InputIterator& iter )
distance( const InputIterator& first, const InputIterator& last )
{
// ...
}
#endif
static
PRUint32
readable_distance( const InputIterator& iter )
{
return iter.size_forward();
}
static
PRUint32
readable_size( const InputIterator& first, const InputIterator& last )
readable_distance( const InputIterator& first, const InputIterator& last )
{
return PRUint32(SameFragment(first, last) ? last.operator->()-first.operator->() : first.size_forward());
}
@ -494,9 +502,18 @@ struct nsCharSourceTraits
template <class CharT>
struct nsCharSourceTraits<CharT*>
{
#if 0
static
PRUint32
readable_size( CharT* s )
distance( CharT* first, CharT* last )
{
return PRUint32(last-first);
}
#endif
static
PRUint32
readable_distance( CharT* s )
{
return PRUint32(nsCharTraits<CharT>::length(s));
// return numeric_limits<PRUint32>::max();
@ -504,7 +521,7 @@ struct nsCharSourceTraits<CharT*>
static
PRUint32
readable_size( CharT* first, CharT* last )
readable_distance( CharT* first, CharT* last )
{
return PRUint32(last-first);
}
@ -522,9 +539,18 @@ struct nsCharSourceTraits<CharT*>
NS_SPECIALIZE_TEMPLATE
struct nsCharSourceTraits<const char*>
{
#if 0
static
PRUint32
readable_size( const char* s )
distance( const char* first, const char* last )
{
return PRUint32(last-first);
}
#endif
static
PRUint32
readable_distance( const char* s )
{
return PRUint32(nsCharTraits<char>::length(s));
// return numeric_limits<PRUint32>::max();
@ -532,7 +558,7 @@ struct nsCharSourceTraits<const char*>
static
PRUint32
readable_size( const char* first, const char* last )
readable_distance( const char* first, const char* last )
{
return PRUint32(last-first);
}

View File

@ -263,6 +263,24 @@ class basic_nsAReadableString
PRUint32 CountChar( CharT ) const;
/*
|Left|, |Mid|, and |Right| are annoying signatures that seem better almost
any _other_ way than they are now. Consider these alternatives
aWritable = aReadable.Left(17); // ...a member function that returns a |Substring|
aWritable = Left(aReadable, 17); // ...a global function that returns a |Substring|
Left(aReadable, 17, aWritable); // ...a global function that does the assignment
as opposed to the current signature
aReadable.Left(aWritable, 17); // ...a member function that does the assignment
or maybe just stamping them out in favor of |Substring|, they are just duplicate functionality
aWritable = Substring(aReadable, 0, 17);
*/
PRUint32 Left( basic_nsAWritableString<CharT>&, PRUint32 ) const;
PRUint32 Mid( basic_nsAWritableString<CharT>&, PRUint32, PRUint32 ) const;
PRUint32 Right( basic_nsAWritableString<CharT>&, PRUint32 ) const;
@ -337,6 +355,7 @@ class basic_nsAReadableString
virtual const void* Implementation() const;
virtual const CharT* GetReadableFragment( nsReadableFragment<CharT>&, nsFragmentRequest, PRUint32 = 0 ) const = 0;
virtual PRBool Promises( const basic_nsAReadableString<CharT>& aString ) const { return &aString == this; }
// virtual PRBool PromisesExactly( const basic_nsAReadableString<CharT>& aString ) const { return false; }
private:
// NOT TO BE IMPLEMENTED
@ -531,27 +550,24 @@ basic_nsAReadableString<CharT>::CountChar( CharT c ) const
}
/*
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
basic_nsAReadableString<CharT>::Mid( basic_nsAWritableString<CharT>& aResult, PRUint32 aStartPos, PRUint32 aLengthToCopy ) const
{
aResult = Substring(*this, 0, aLengthToCopy);
// If we're just assigning our entire self, give |aResult| the opportunity to share
if ( aStartPos == 0 && aLengthToCopy >= Length() )
aResult = *this;
else
aResult = Substring(*this, aStartPos, aLengthToCopy);
return aResult.Length();
}
template <class CharT>
PRUint32
basic_nsAReadableString<CharT>::Mid( basic_nsAWritableString<CharT>& aResult, PRUint32 aStartPos, PRUint32 aLengthToCopy ) const
basic_nsAReadableString<CharT>::Left( basic_nsAWritableString<CharT>& aResult, PRUint32 aLengthToCopy ) const
{
aResult = Substring(*this, aStartPos, aLengthToCopy);
return aResult.Length();
return Mid(aResult, 0, aLengthToCopy);
}
template <class CharT>
@ -560,8 +576,7 @@ basic_nsAReadableString<CharT>::Right( basic_nsAWritableString<CharT>& aResult,
{
PRUint32 myLength = Length();
aLengthToCopy = NS_MIN(myLength, aLengthToCopy);
aResult = Substring(*this, myLength-aLengthToCopy, aLengthToCopy);
return aResult.Length();
return Mid(aResult, myLength-aLengthToCopy, aLengthToCopy);
}
@ -612,7 +627,7 @@ class basic_nsLiteralString
// Note: _not_ explicit
basic_nsLiteralString( const CharT* aLiteral )
: mStart(aLiteral),
mEnd(mStart + nsCharTraits<CharT>::length(mStart))
mEnd(mStart ? (mStart + nsCharTraits<CharT>::length(mStart)) : mStart)
{
// nothing else to do here
}
@ -624,7 +639,10 @@ class basic_nsLiteralString
// This is an annoying hack. Callers should be fixed to use the other
// constructor if they don't really know the length.
if ( aLength == PRUint32(-1) )
mEnd = mStart + nsCharTraits<CharT>::length(mStart);
{
NS_WARNING("Tell scc: Caller constructing a string doesn't know the real length. Please use the other constructor.");
mEnd = mStart + nsCharTraits<CharT>::length(mStart);
}
}
virtual PRUint32 Length() const;
@ -818,6 +836,7 @@ class nsPromiseConcatenation
virtual PRUint32 Length() const;
virtual PRBool Promises( const basic_nsAReadableString<CharT>& ) const;
// virtual PRBool PromisesExactly( const basic_nsAReadableString<CharT>& ) const;
nsPromiseConcatenation<CharT> operator+( const basic_nsAReadableString<CharT>& rhs ) const;
@ -847,6 +866,15 @@ nsPromiseConcatenation<CharT>::Promises( const basic_nsAReadableString<CharT>& a
return mStrings[0]->Promises(aString) || mStrings[1]->Promises(aString);
}
#if 0
PRBool
nsPromiseConcatenation<CharT>::PromisesExactly( const basic_nsAReadableString<CharT>& aString ) const
{
// Not really like this, test for the empty string, etc
return mStrings[0] == &aString && !mStrings[1] || !mStrings[0] && mStrings[1] == &aString;
}
#endif
template <class CharT>
const CharT*
nsPromiseConcatenation<CharT>::GetReadableFragment( nsReadableFragment<CharT>& aFragment, nsFragmentRequest aRequest, PRUint32 aPosition ) const
@ -992,7 +1020,7 @@ nsPromiseSubstring<CharT>::GetReadableFragment( nsReadableFragment<CharT>& aFrag
const CharT* position_ptr = mString.GetReadableFragment(aFragment, aRequest, aPosition);
// if there's more physical data in the returned fragment than I logically have left
// if there's more physical data in the returned fragment than I logically have left...
size_t logical_size_forward = mLength - aPosition;
if ( aFragment.mEnd - position_ptr > logical_size_forward )
aFragment.mEnd = position_ptr + logical_size_forward;
@ -1027,7 +1055,7 @@ copy_string( InputIterator first, InputIterator last, OutputIterator result )
while ( first != last )
{
PRInt32 count_copied = PRInt32(sink_traits::write(result, source_traits::read(first), source_traits::readable_size(first, last)));
PRInt32 count_copied = PRInt32(sink_traits::write(result, source_traits::read(first), source_traits::readable_distance(first, last)));
NS_ASSERTION(count_copied > 0, "|copy_string| will never terminate");
first += count_copied;
}
@ -1060,11 +1088,6 @@ template <class CharT>
nsPromiseSubstring<CharT>
Substring( const basic_nsAReadableString<CharT>& aString, PRUint32 aStartPos, PRUint32 aSubstringLength )
{
#if 0
// signatures don't work, but consider this twist to help in assignments
if ( aSubstringLength == aString.Length() && aStartPos == 0 )
return aString;
#endif
return nsPromiseSubstring<CharT>(aString, aStartPos, aSubstringLength);
}
@ -1145,6 +1168,11 @@ Compare( const CharT* lhs, const basic_nsAReadableString<CharT>& rhs )
to implement the virtual functions of readables.
*/
/*
I probably need to add |operator+()| for appropriate |CharT| and |CharT*| comparisons, since
automatic conversion to a literal string will not happen.
*/
template <class CharT>
inline
nsPromiseConcatenation<CharT>

View File

@ -270,39 +270,39 @@ class basic_nsAWritableString
//
// |operator=()|, |Assign()|
// |Assign()|, |operator=()|
//
basic_nsAWritableString<CharT>& operator=( const basic_nsAReadableString<CharT>& aReadable ) { do_AssignFromReadable(aReadable); return *this; }
basic_nsAWritableString<CharT>& operator=( const nsPromiseReadable<CharT>& aReadable ) { Assign(aReadable); return *this; }
basic_nsAWritableString<CharT>& operator=( const CharT* aPtr ) { do_AssignFromElementPtr(aPtr); return *this; }
basic_nsAWritableString<CharT>& operator=( CharT aChar ) { do_AssignFromElement(aChar); return *this; }
void Assign( const basic_nsAReadableString<CharT>& aReadable ) { do_AssignFromReadable(aReadable); }
void Assign( const nsPromiseReadable<CharT>& aReadable ) { aReadable.Promises(*this) ? AssignFromPromise(aReadable) : do_AssignFromReadable(aReadable); }
// void Assign( const nsReadingIterator<CharT>& aStart, const nsReadingIterator<CharT>& aEnd ) { do_AssignFromIterators(aStart, aEnd); }
void Assign( const CharT* aPtr ) { do_AssignFromElementPtr(aPtr); }
void Assign( const CharT* aPtr ) { aPtr ? do_AssignFromElementPtr(aPtr) : SetLength(0); }
void Assign( const CharT* aPtr, PRUint32 aLength ) { do_AssignFromElementPtrLength(aPtr, aLength); }
void Assign( CharT aChar ) { do_AssignFromElement(aChar); }
basic_nsAWritableString<CharT>& operator=( const basic_nsAReadableString<CharT>& aReadable ) { Assign(aReadable); return *this; }
basic_nsAWritableString<CharT>& operator=( const nsPromiseReadable<CharT>& aReadable ) { Assign(aReadable); return *this; }
basic_nsAWritableString<CharT>& operator=( const CharT* aPtr ) { Assign(aPtr); return *this; }
basic_nsAWritableString<CharT>& operator=( CharT aChar ) { Assign(aChar); return *this; }
//
// |operator+=()|, |Append()|
// |Append()|, |operator+=()|
//
basic_nsAWritableString<CharT>& operator+=( const basic_nsAReadableString<CharT>& aReadable ) { do_AppendFromReadable(aReadable); return *this; }
basic_nsAWritableString<CharT>& operator+=( const nsPromiseReadable<CharT>& aReadable ) { Append(aReadable); return *this; }
basic_nsAWritableString<CharT>& operator+=( const CharT* aPtr ) { do_AppendFromElementPtr(aPtr); return *this; }
basic_nsAWritableString<CharT>& operator+=( CharT aChar ) { do_AppendFromElement(aChar); return *this; }
void Append( const basic_nsAReadableString<CharT>& aReadable ) { do_AppendFromReadable(aReadable); }
void Append( const nsPromiseReadable<CharT>& aReadable ) { aReadable.Promises(*this) ? AppendFromPromise(aReadable) : do_AppendFromReadable(aReadable); }
// void Append( const nsReadingIterator<CharT>& aStart, const nsReadingIterator<CharT>& aEnd ) { do_AppendFromIterators(aStart, aEnd); }
void Append( const CharT* aPtr ) { do_AppendFromElementPtr(aPtr); }
void Append( const CharT* aPtr ) { if (aPtr) do_AppendFromElementPtr(aPtr); }
void Append( const CharT* aPtr, PRUint32 aLength ) { do_AppendFromElementPtrLength(aPtr, aLength); }
void Append( CharT aChar ) { do_AppendFromElement(aChar); }
basic_nsAWritableString<CharT>& operator+=( const basic_nsAReadableString<CharT>& aReadable ) { Append(aReadable); return *this; }
basic_nsAWritableString<CharT>& operator+=( const nsPromiseReadable<CharT>& aReadable ) { Append(aReadable); return *this; }
basic_nsAWritableString<CharT>& operator+=( const CharT* aPtr ) { Append(aPtr); return *this; }
basic_nsAWritableString<CharT>& operator+=( CharT aChar ) { Append(aChar); return *this; }
//
@ -313,7 +313,7 @@ class basic_nsAWritableString
void Insert( const basic_nsAReadableString<CharT>& aReadable, PRUint32 atPosition ) { do_InsertFromReadable(aReadable, atPosition); }
void Insert( const nsPromiseReadable<CharT>& aReadable, PRUint32 atPosition ) { aReadable.Promises(*this) ? InsertFromPromise(aReadable, atPosition) : do_InsertFromReadable(aReadable, atPosition); }
// void Insert( const nsReadingIterator<CharT>& aStart, const nsReadingIterator<CharT>& aEnd, PRUint32 atPosition ) { do_InsertFromIterators(aStart, aEnd, atPosition); }
void Insert( const CharT* aPtr, PRUint32 atPosition ) { do_InsertFromElementPtr(aPtr, atPosition); }
void Insert( const CharT* aPtr, PRUint32 atPosition ) { if (aPtr) do_InsertFromElementPtr(aPtr, atPosition); }
void Insert( const CharT* aPtr, PRUint32 atPosition, PRUint32 aLength ) { do_InsertFromElementPtrLength(aPtr, atPosition, aLength); }
void Insert( CharT aChar, PRUint32 atPosition ) { do_InsertFromElement(aChar, atPosition); }
@ -433,14 +433,37 @@ basic_nsAWritableString<CharT>::do_AssignFromReadable( const basic_nsAReadableSt
template <class CharT>
void
basic_nsAWritableString<CharT>::AssignFromPromise( const nsPromiseReadable<CharT>& aReadable )
/*
...this function is only called when a promise that somehow references |this| is assigned _into_ |this|.
E.g.,
... writable& w ...
... readable& r ...
w = r + w;
In this example, you can see that unless the characters promised by |w| in |r+w| are resolved before
anything starts getting copied into |w|, there will be trouble. They will be overritten by the contents
of |r| before being retrieved to be appended.
We could have a really tricky solution where we tell the promise to resolve _just_ the data promised
by |this|, but this should be a rare case, since clients with more local knowledge will know that, e.g.,
in the case above, |Insert| could have special behavior with significantly better performance. Since
it's a rare case anyway, we should just do the simplest thing that could possibly work, resolve the
entire promise. If we measure and this turns out to show up on performance radar, we then have the
option to fix either the callers or this mechanism.
*/
{
PRUint32 length = aReadable.Length();
if ( CharT* buffer = new CharT[length] )
{
// Note: not exception safe. We need something to manage temporary buffers like this
copy_string(aReadable.BeginReading(), aReadable.EndReading(), buffer);
do_AssignFromElementPtrLength(buffer, length);
delete buffer;
}
// else assert?
}
#if 0

View File

@ -463,20 +463,28 @@ struct nsCharTraits<wchar_t>
#endif
template <class InputIterator>
struct nsCharSourceTraits
{
#if 0
static
PRUint32
readable_size( const InputIterator& iter )
distance( const InputIterator& first, const InputIterator& last )
{
// ...
}
#endif
static
PRUint32
readable_distance( const InputIterator& iter )
{
return iter.size_forward();
}
static
PRUint32
readable_size( const InputIterator& first, const InputIterator& last )
readable_distance( const InputIterator& first, const InputIterator& last )
{
return PRUint32(SameFragment(first, last) ? last.operator->()-first.operator->() : first.size_forward());
}
@ -494,9 +502,18 @@ struct nsCharSourceTraits
template <class CharT>
struct nsCharSourceTraits<CharT*>
{
#if 0
static
PRUint32
readable_size( CharT* s )
distance( CharT* first, CharT* last )
{
return PRUint32(last-first);
}
#endif
static
PRUint32
readable_distance( CharT* s )
{
return PRUint32(nsCharTraits<CharT>::length(s));
// return numeric_limits<PRUint32>::max();
@ -504,7 +521,7 @@ struct nsCharSourceTraits<CharT*>
static
PRUint32
readable_size( CharT* first, CharT* last )
readable_distance( CharT* first, CharT* last )
{
return PRUint32(last-first);
}
@ -522,9 +539,18 @@ struct nsCharSourceTraits<CharT*>
NS_SPECIALIZE_TEMPLATE
struct nsCharSourceTraits<const char*>
{
#if 0
static
PRUint32
readable_size( const char* s )
distance( const char* first, const char* last )
{
return PRUint32(last-first);
}
#endif
static
PRUint32
readable_distance( const char* s )
{
return PRUint32(nsCharTraits<char>::length(s));
// return numeric_limits<PRUint32>::max();
@ -532,7 +558,7 @@ struct nsCharSourceTraits<const char*>
static
PRUint32
readable_size( const char* first, const char* last )
readable_distance( const char* first, const char* last )
{
return PRUint32(last-first);
}

View File

@ -263,6 +263,24 @@ class basic_nsAReadableString
PRUint32 CountChar( CharT ) const;
/*
|Left|, |Mid|, and |Right| are annoying signatures that seem better almost
any _other_ way than they are now. Consider these alternatives
aWritable = aReadable.Left(17); // ...a member function that returns a |Substring|
aWritable = Left(aReadable, 17); // ...a global function that returns a |Substring|
Left(aReadable, 17, aWritable); // ...a global function that does the assignment
as opposed to the current signature
aReadable.Left(aWritable, 17); // ...a member function that does the assignment
or maybe just stamping them out in favor of |Substring|, they are just duplicate functionality
aWritable = Substring(aReadable, 0, 17);
*/
PRUint32 Left( basic_nsAWritableString<CharT>&, PRUint32 ) const;
PRUint32 Mid( basic_nsAWritableString<CharT>&, PRUint32, PRUint32 ) const;
PRUint32 Right( basic_nsAWritableString<CharT>&, PRUint32 ) const;
@ -337,6 +355,7 @@ class basic_nsAReadableString
virtual const void* Implementation() const;
virtual const CharT* GetReadableFragment( nsReadableFragment<CharT>&, nsFragmentRequest, PRUint32 = 0 ) const = 0;
virtual PRBool Promises( const basic_nsAReadableString<CharT>& aString ) const { return &aString == this; }
// virtual PRBool PromisesExactly( const basic_nsAReadableString<CharT>& aString ) const { return false; }
private:
// NOT TO BE IMPLEMENTED
@ -531,27 +550,24 @@ basic_nsAReadableString<CharT>::CountChar( CharT c ) const
}
/*
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
basic_nsAReadableString<CharT>::Mid( basic_nsAWritableString<CharT>& aResult, PRUint32 aStartPos, PRUint32 aLengthToCopy ) const
{
aResult = Substring(*this, 0, aLengthToCopy);
// If we're just assigning our entire self, give |aResult| the opportunity to share
if ( aStartPos == 0 && aLengthToCopy >= Length() )
aResult = *this;
else
aResult = Substring(*this, aStartPos, aLengthToCopy);
return aResult.Length();
}
template <class CharT>
PRUint32
basic_nsAReadableString<CharT>::Mid( basic_nsAWritableString<CharT>& aResult, PRUint32 aStartPos, PRUint32 aLengthToCopy ) const
basic_nsAReadableString<CharT>::Left( basic_nsAWritableString<CharT>& aResult, PRUint32 aLengthToCopy ) const
{
aResult = Substring(*this, aStartPos, aLengthToCopy);
return aResult.Length();
return Mid(aResult, 0, aLengthToCopy);
}
template <class CharT>
@ -560,8 +576,7 @@ basic_nsAReadableString<CharT>::Right( basic_nsAWritableString<CharT>& aResult,
{
PRUint32 myLength = Length();
aLengthToCopy = NS_MIN(myLength, aLengthToCopy);
aResult = Substring(*this, myLength-aLengthToCopy, aLengthToCopy);
return aResult.Length();
return Mid(aResult, myLength-aLengthToCopy, aLengthToCopy);
}
@ -612,7 +627,7 @@ class basic_nsLiteralString
// Note: _not_ explicit
basic_nsLiteralString( const CharT* aLiteral )
: mStart(aLiteral),
mEnd(mStart + nsCharTraits<CharT>::length(mStart))
mEnd(mStart ? (mStart + nsCharTraits<CharT>::length(mStart)) : mStart)
{
// nothing else to do here
}
@ -624,7 +639,10 @@ class basic_nsLiteralString
// This is an annoying hack. Callers should be fixed to use the other
// constructor if they don't really know the length.
if ( aLength == PRUint32(-1) )
mEnd = mStart + nsCharTraits<CharT>::length(mStart);
{
NS_WARNING("Tell scc: Caller constructing a string doesn't know the real length. Please use the other constructor.");
mEnd = mStart + nsCharTraits<CharT>::length(mStart);
}
}
virtual PRUint32 Length() const;
@ -818,6 +836,7 @@ class nsPromiseConcatenation
virtual PRUint32 Length() const;
virtual PRBool Promises( const basic_nsAReadableString<CharT>& ) const;
// virtual PRBool PromisesExactly( const basic_nsAReadableString<CharT>& ) const;
nsPromiseConcatenation<CharT> operator+( const basic_nsAReadableString<CharT>& rhs ) const;
@ -847,6 +866,15 @@ nsPromiseConcatenation<CharT>::Promises( const basic_nsAReadableString<CharT>& a
return mStrings[0]->Promises(aString) || mStrings[1]->Promises(aString);
}
#if 0
PRBool
nsPromiseConcatenation<CharT>::PromisesExactly( const basic_nsAReadableString<CharT>& aString ) const
{
// Not really like this, test for the empty string, etc
return mStrings[0] == &aString && !mStrings[1] || !mStrings[0] && mStrings[1] == &aString;
}
#endif
template <class CharT>
const CharT*
nsPromiseConcatenation<CharT>::GetReadableFragment( nsReadableFragment<CharT>& aFragment, nsFragmentRequest aRequest, PRUint32 aPosition ) const
@ -992,7 +1020,7 @@ nsPromiseSubstring<CharT>::GetReadableFragment( nsReadableFragment<CharT>& aFrag
const CharT* position_ptr = mString.GetReadableFragment(aFragment, aRequest, aPosition);
// if there's more physical data in the returned fragment than I logically have left
// if there's more physical data in the returned fragment than I logically have left...
size_t logical_size_forward = mLength - aPosition;
if ( aFragment.mEnd - position_ptr > logical_size_forward )
aFragment.mEnd = position_ptr + logical_size_forward;
@ -1027,7 +1055,7 @@ copy_string( InputIterator first, InputIterator last, OutputIterator result )
while ( first != last )
{
PRInt32 count_copied = PRInt32(sink_traits::write(result, source_traits::read(first), source_traits::readable_size(first, last)));
PRInt32 count_copied = PRInt32(sink_traits::write(result, source_traits::read(first), source_traits::readable_distance(first, last)));
NS_ASSERTION(count_copied > 0, "|copy_string| will never terminate");
first += count_copied;
}
@ -1060,11 +1088,6 @@ template <class CharT>
nsPromiseSubstring<CharT>
Substring( const basic_nsAReadableString<CharT>& aString, PRUint32 aStartPos, PRUint32 aSubstringLength )
{
#if 0
// signatures don't work, but consider this twist to help in assignments
if ( aSubstringLength == aString.Length() && aStartPos == 0 )
return aString;
#endif
return nsPromiseSubstring<CharT>(aString, aStartPos, aSubstringLength);
}
@ -1145,6 +1168,11 @@ Compare( const CharT* lhs, const basic_nsAReadableString<CharT>& rhs )
to implement the virtual functions of readables.
*/
/*
I probably need to add |operator+()| for appropriate |CharT| and |CharT*| comparisons, since
automatic conversion to a literal string will not happen.
*/
template <class CharT>
inline
nsPromiseConcatenation<CharT>

View File

@ -270,39 +270,39 @@ class basic_nsAWritableString
//
// |operator=()|, |Assign()|
// |Assign()|, |operator=()|
//
basic_nsAWritableString<CharT>& operator=( const basic_nsAReadableString<CharT>& aReadable ) { do_AssignFromReadable(aReadable); return *this; }
basic_nsAWritableString<CharT>& operator=( const nsPromiseReadable<CharT>& aReadable ) { Assign(aReadable); return *this; }
basic_nsAWritableString<CharT>& operator=( const CharT* aPtr ) { do_AssignFromElementPtr(aPtr); return *this; }
basic_nsAWritableString<CharT>& operator=( CharT aChar ) { do_AssignFromElement(aChar); return *this; }
void Assign( const basic_nsAReadableString<CharT>& aReadable ) { do_AssignFromReadable(aReadable); }
void Assign( const nsPromiseReadable<CharT>& aReadable ) { aReadable.Promises(*this) ? AssignFromPromise(aReadable) : do_AssignFromReadable(aReadable); }
// void Assign( const nsReadingIterator<CharT>& aStart, const nsReadingIterator<CharT>& aEnd ) { do_AssignFromIterators(aStart, aEnd); }
void Assign( const CharT* aPtr ) { do_AssignFromElementPtr(aPtr); }
void Assign( const CharT* aPtr ) { aPtr ? do_AssignFromElementPtr(aPtr) : SetLength(0); }
void Assign( const CharT* aPtr, PRUint32 aLength ) { do_AssignFromElementPtrLength(aPtr, aLength); }
void Assign( CharT aChar ) { do_AssignFromElement(aChar); }
basic_nsAWritableString<CharT>& operator=( const basic_nsAReadableString<CharT>& aReadable ) { Assign(aReadable); return *this; }
basic_nsAWritableString<CharT>& operator=( const nsPromiseReadable<CharT>& aReadable ) { Assign(aReadable); return *this; }
basic_nsAWritableString<CharT>& operator=( const CharT* aPtr ) { Assign(aPtr); return *this; }
basic_nsAWritableString<CharT>& operator=( CharT aChar ) { Assign(aChar); return *this; }
//
// |operator+=()|, |Append()|
// |Append()|, |operator+=()|
//
basic_nsAWritableString<CharT>& operator+=( const basic_nsAReadableString<CharT>& aReadable ) { do_AppendFromReadable(aReadable); return *this; }
basic_nsAWritableString<CharT>& operator+=( const nsPromiseReadable<CharT>& aReadable ) { Append(aReadable); return *this; }
basic_nsAWritableString<CharT>& operator+=( const CharT* aPtr ) { do_AppendFromElementPtr(aPtr); return *this; }
basic_nsAWritableString<CharT>& operator+=( CharT aChar ) { do_AppendFromElement(aChar); return *this; }
void Append( const basic_nsAReadableString<CharT>& aReadable ) { do_AppendFromReadable(aReadable); }
void Append( const nsPromiseReadable<CharT>& aReadable ) { aReadable.Promises(*this) ? AppendFromPromise(aReadable) : do_AppendFromReadable(aReadable); }
// void Append( const nsReadingIterator<CharT>& aStart, const nsReadingIterator<CharT>& aEnd ) { do_AppendFromIterators(aStart, aEnd); }
void Append( const CharT* aPtr ) { do_AppendFromElementPtr(aPtr); }
void Append( const CharT* aPtr ) { if (aPtr) do_AppendFromElementPtr(aPtr); }
void Append( const CharT* aPtr, PRUint32 aLength ) { do_AppendFromElementPtrLength(aPtr, aLength); }
void Append( CharT aChar ) { do_AppendFromElement(aChar); }
basic_nsAWritableString<CharT>& operator+=( const basic_nsAReadableString<CharT>& aReadable ) { Append(aReadable); return *this; }
basic_nsAWritableString<CharT>& operator+=( const nsPromiseReadable<CharT>& aReadable ) { Append(aReadable); return *this; }
basic_nsAWritableString<CharT>& operator+=( const CharT* aPtr ) { Append(aPtr); return *this; }
basic_nsAWritableString<CharT>& operator+=( CharT aChar ) { Append(aChar); return *this; }
//
@ -313,7 +313,7 @@ class basic_nsAWritableString
void Insert( const basic_nsAReadableString<CharT>& aReadable, PRUint32 atPosition ) { do_InsertFromReadable(aReadable, atPosition); }
void Insert( const nsPromiseReadable<CharT>& aReadable, PRUint32 atPosition ) { aReadable.Promises(*this) ? InsertFromPromise(aReadable, atPosition) : do_InsertFromReadable(aReadable, atPosition); }
// void Insert( const nsReadingIterator<CharT>& aStart, const nsReadingIterator<CharT>& aEnd, PRUint32 atPosition ) { do_InsertFromIterators(aStart, aEnd, atPosition); }
void Insert( const CharT* aPtr, PRUint32 atPosition ) { do_InsertFromElementPtr(aPtr, atPosition); }
void Insert( const CharT* aPtr, PRUint32 atPosition ) { if (aPtr) do_InsertFromElementPtr(aPtr, atPosition); }
void Insert( const CharT* aPtr, PRUint32 atPosition, PRUint32 aLength ) { do_InsertFromElementPtrLength(aPtr, atPosition, aLength); }
void Insert( CharT aChar, PRUint32 atPosition ) { do_InsertFromElement(aChar, atPosition); }
@ -433,14 +433,37 @@ basic_nsAWritableString<CharT>::do_AssignFromReadable( const basic_nsAReadableSt
template <class CharT>
void
basic_nsAWritableString<CharT>::AssignFromPromise( const nsPromiseReadable<CharT>& aReadable )
/*
...this function is only called when a promise that somehow references |this| is assigned _into_ |this|.
E.g.,
... writable& w ...
... readable& r ...
w = r + w;
In this example, you can see that unless the characters promised by |w| in |r+w| are resolved before
anything starts getting copied into |w|, there will be trouble. They will be overritten by the contents
of |r| before being retrieved to be appended.
We could have a really tricky solution where we tell the promise to resolve _just_ the data promised
by |this|, but this should be a rare case, since clients with more local knowledge will know that, e.g.,
in the case above, |Insert| could have special behavior with significantly better performance. Since
it's a rare case anyway, we should just do the simplest thing that could possibly work, resolve the
entire promise. If we measure and this turns out to show up on performance radar, we then have the
option to fix either the callers or this mechanism.
*/
{
PRUint32 length = aReadable.Length();
if ( CharT* buffer = new CharT[length] )
{
// Note: not exception safe. We need something to manage temporary buffers like this
copy_string(aReadable.BeginReading(), aReadable.EndReading(), buffer);
do_AssignFromElementPtrLength(buffer, length);
delete buffer;
}
// else assert?
}
#if 0

View File

@ -463,20 +463,28 @@ struct nsCharTraits<wchar_t>
#endif
template <class InputIterator>
struct nsCharSourceTraits
{
#if 0
static
PRUint32
readable_size( const InputIterator& iter )
distance( const InputIterator& first, const InputIterator& last )
{
// ...
}
#endif
static
PRUint32
readable_distance( const InputIterator& iter )
{
return iter.size_forward();
}
static
PRUint32
readable_size( const InputIterator& first, const InputIterator& last )
readable_distance( const InputIterator& first, const InputIterator& last )
{
return PRUint32(SameFragment(first, last) ? last.operator->()-first.operator->() : first.size_forward());
}
@ -494,9 +502,18 @@ struct nsCharSourceTraits
template <class CharT>
struct nsCharSourceTraits<CharT*>
{
#if 0
static
PRUint32
readable_size( CharT* s )
distance( CharT* first, CharT* last )
{
return PRUint32(last-first);
}
#endif
static
PRUint32
readable_distance( CharT* s )
{
return PRUint32(nsCharTraits<CharT>::length(s));
// return numeric_limits<PRUint32>::max();
@ -504,7 +521,7 @@ struct nsCharSourceTraits<CharT*>
static
PRUint32
readable_size( CharT* first, CharT* last )
readable_distance( CharT* first, CharT* last )
{
return PRUint32(last-first);
}
@ -522,9 +539,18 @@ struct nsCharSourceTraits<CharT*>
NS_SPECIALIZE_TEMPLATE
struct nsCharSourceTraits<const char*>
{
#if 0
static
PRUint32
readable_size( const char* s )
distance( const char* first, const char* last )
{
return PRUint32(last-first);
}
#endif
static
PRUint32
readable_distance( const char* s )
{
return PRUint32(nsCharTraits<char>::length(s));
// return numeric_limits<PRUint32>::max();
@ -532,7 +558,7 @@ struct nsCharSourceTraits<const char*>
static
PRUint32
readable_size( const char* first, const char* last )
readable_distance( const char* first, const char* last )
{
return PRUint32(last-first);
}