Mozilla/mozilla/string/src/nsAString.cpp
jaggernaut%netscape.com bc3d20cba4 Bug 114288: Add nsStringComparator parameter to nsAString::Equals to mirror Compare and provide a way to do CaseInsensitive Equals. r=dbaron, sr=jst
git-svn-id: svn://10.0.0.236/trunk@110154 18797224-902f-48f8-a5cc-f745e15eee43
2001-12-10 10:10:44 +00:00

1052 lines
29 KiB
C++

/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/*
* The contents of this file are subject to the Mozilla Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is Mozilla.
*
* The Initial Developer of the Original Code is Netscape
* Communications. Portions created by Netscape Communications are
* Copyright (C) 2001 by Netscape Communications. All
* Rights Reserved.
*
* Contributor(s):
* Scott Collins <scc@mozilla.org> (original author)
*/
#include "nsAString.h"
#include "nsDependentSubstring.h"
#include "nsDependentString.h"
#include "nsCRT.h"
int
nsDefaultStringComparator::operator()( const char_type* lhs, const char_type* rhs, PRUint32 aLength ) const
{
return nsCharTraits<char_type>::compare(lhs, rhs, aLength);
}
int
nsDefaultStringComparator::operator()( char_type lhs, char_type rhs) const
{
return lhs - rhs;
}
NS_COM
int
Compare( const nsAString& lhs, const nsAString& rhs, const nsStringComparator& aComparator )
{
typedef nsAString::size_type size_type;
if ( &lhs == &rhs )
return 0;
size_type lLength = lhs.Length();
size_type rLength = rhs.Length();
size_type lengthToCompare = NS_MIN(lLength, rLength);
nsAString::const_iterator leftIter, rightIter;
lhs.BeginReading(leftIter);
rhs.BeginReading(rightIter);
for (;;)
{
size_type lengthAvailable = size_type( NS_MIN(leftIter.size_forward(), rightIter.size_forward()) );
if ( lengthAvailable > lengthToCompare )
lengthAvailable = lengthToCompare;
{
int result;
// Note: |result| should be declared in this |if| expression, but some compilers don't like that
if ( (result = aComparator(leftIter.get(), rightIter.get(), lengthAvailable)) != 0 )
return result;
}
if ( !(lengthToCompare -= lengthAvailable) )
break;
leftIter.advance( PRInt32(lengthAvailable) );
rightIter.advance( PRInt32(lengthAvailable) );
}
if ( lLength < rLength )
return -1;
else if ( rLength < lLength )
return 1;
else
return 0;
}
const nsAString::shared_buffer_handle_type*
nsAString::GetSharedBufferHandle() const
{
return 0;
}
const nsAString::buffer_handle_type*
nsAString::GetFlatBufferHandle() const
{
return GetSharedBufferHandle();
}
const nsAString::buffer_handle_type*
nsAString::GetBufferHandle() const
{
return GetSharedBufferHandle();
}
PRUint32
nsAString::GetImplementationFlags() const
{
PRUint32 flags = 0;
const shared_buffer_handle_type* handle = GetSharedBufferHandle();
if ( handle )
flags = handle->GetImplementationFlags();
return flags;
}
PRBool
nsAString::IsVoid() const
{
return PR_FALSE;
}
void
nsAString::SetIsVoid( PRBool )
{
// |SetIsVoid| is ignored by default
}
PRBool
nsAString::Equals( const char_type* rhs, const nsStringComparator& aComparator ) const
{
return Equals(nsDependentString(rhs), aComparator);
}
nsAString::char_type
nsAString::First() const
{
NS_ASSERTION(Length()>0, "|First()| on an empty string");
const_iterator iter;
return *BeginReading(iter);
}
nsAString::char_type
nsAString::Last() const
{
NS_ASSERTION(Length()>0, "|Last()| on an empty string");
const_iterator iter;
if ( !IsEmpty() )
{
EndReading(iter);
iter.advance(-1);
}
return *iter; // Note: this has undefined results if |IsEmpty()|
}
nsAString::size_type
nsAString::CountChar( char_type c ) const
{
/*
re-write this to use a counting sink
*/
size_type result = 0;
size_type lengthToExamine = Length();
const_iterator iter;
for ( BeginReading(iter); ; )
{
PRInt32 lengthToExamineInThisFragment = iter.size_forward();
const char_type* fromBegin = iter.get();
result += size_type(NS_COUNT(fromBegin, fromBegin+lengthToExamineInThisFragment, c));
if ( !(lengthToExamine -= lengthToExamineInThisFragment) )
return result;
iter.advance(lengthToExamineInThisFragment);
}
// never reached; quiets warnings
return 0;
}
nsAString::size_type
nsAString::Mid( self_type& aResult, index_type aStartPos, size_type aLengthToCopy ) const
{
// 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();
}
nsAString::size_type
nsAString::Right( self_type& aResult, size_type aLengthToCopy ) const
{
size_type myLength = Length();
aLengthToCopy = NS_MIN(myLength, aLengthToCopy);
return Mid(aResult, myLength-aLengthToCopy, aLengthToCopy);
}
PRInt32
nsAString::FindChar( char_type aChar, PRUint32 aOffset ) const
{
const_iterator iter, done_searching;
BeginReading(iter).advance( PRInt32(aOffset) );
EndReading(done_searching);
size_type lengthSearched = 0;
while ( iter != done_searching )
{
PRInt32 fragmentLength = iter.size_forward();
const char_type* charFoundAt = nsCharTraits<char_type>::find(iter.get(), fragmentLength, aChar);
if ( charFoundAt )
return lengthSearched + (charFoundAt-iter.get()) + aOffset;
lengthSearched += fragmentLength;
iter.advance(fragmentLength);
}
return -1;
}
//
// |Assign()|
//
void
nsAString::AssignFromReadable( const self_type& rhs )
{
if ( this != &rhs )
do_AssignFromReadable(rhs);
// else, self-assign is a no-op
}
void
nsAString::AssignFromPromise( const self_type& 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.
*/
{
if ( !aReadable.IsDependentOn(*this) )
do_AssignFromReadable(aReadable);
else
{
size_type length = aReadable.Length();
char_type* buffer = new char_type[length];
if ( buffer )
{
// Note: not exception safe. We need something to manage temporary buffers like this
const_iterator fromBegin, fromEnd;
char_type* toBegin = buffer;
copy_string(aReadable.BeginReading(fromBegin), aReadable.EndReading(fromEnd), toBegin);
do_AssignFromElementPtrLength(buffer, length);
delete buffer;
}
// else assert?
}
}
void
nsAString::do_AssignFromReadable( const self_type& aReadable )
{
SetLength(0);
if ( !aReadable.IsEmpty() )
{
SetLength(aReadable.Length());
// first setting the length to |0| avoids copying characters only to be overwritten later
// in the case where the implementation decides to re-allocate
const_iterator fromBegin, fromEnd;
iterator toBegin;
copy_string(aReadable.BeginReading(fromBegin), aReadable.EndReading(fromEnd), BeginWriting(toBegin));
}
}
void
nsAString::do_AssignFromElementPtr( const char_type* aPtr )
{
do_AssignFromReadable(nsDependentString(aPtr));
}
void
nsAString::do_AssignFromElementPtrLength( const char_type* aPtr, size_type aLength )
{
do_AssignFromReadable(Substring(aPtr, aPtr+aLength));
}
void
nsAString::do_AssignFromElement( char_type aChar )
{
do_AssignFromReadable(Substring(&aChar, &aChar+1));
}
//
// |Append()|
//
void
nsAString::AppendFromReadable( const self_type& aReadable )
{
if ( this != &aReadable )
do_AppendFromReadable(aReadable);
else
AppendFromPromise(aReadable);
}
void
nsAString::AppendFromPromise( const self_type& aReadable )
{
if ( !aReadable.IsDependentOn(*this) )
do_AppendFromReadable(aReadable);
else
{
size_type length = aReadable.Length();
char_type* buffer = new char_type[length];
if ( buffer )
{
const_iterator fromBegin, fromEnd;
char_type* toBegin = buffer;
copy_string(aReadable.BeginReading(fromBegin), aReadable.EndReading(fromEnd), toBegin);
do_AppendFromElementPtrLength(buffer, length);
delete buffer;
}
// else assert?
}
}
void
nsAString::do_AppendFromReadable( const self_type& aReadable )
{
size_type oldLength = this->Length();
SetLength(oldLength + aReadable.Length());
const_iterator fromBegin, fromEnd;
iterator toBegin;
copy_string(aReadable.BeginReading(fromBegin), aReadable.EndReading(fromEnd), BeginWriting(toBegin).advance( PRInt32(oldLength) ) );
}
void
nsAString::do_AppendFromElementPtr( const char_type* aPtr )
{
do_AppendFromReadable(nsDependentString(aPtr));
}
void
nsAString::do_AppendFromElementPtrLength( const char_type* aPtr, size_type aLength )
{
do_AppendFromReadable(Substring(aPtr, aPtr+aLength));
}
void
nsAString::do_AppendFromElement( char_type aChar )
{
do_AppendFromReadable(Substring(&aChar, &aChar + 1));
}
//
// |Insert()|
//
void
nsAString::InsertFromReadable( const self_type& aReadable, index_type atPosition )
{
if ( this != &aReadable )
do_InsertFromReadable(aReadable, atPosition);
else
InsertFromPromise(aReadable, atPosition);
}
void
nsAString::InsertFromPromise( const self_type& aReadable, index_type atPosition )
{
if ( !aReadable.IsDependentOn(*this) )
do_InsertFromReadable(aReadable, atPosition);
else
{
size_type length = aReadable.Length();
char_type* buffer = new char_type[length];
if ( buffer )
{
const_iterator fromBegin, fromEnd;
char_type* toBegin = buffer;
copy_string(aReadable.BeginReading(fromBegin), aReadable.EndReading(fromEnd), toBegin);
do_InsertFromElementPtrLength(buffer, atPosition, length);
delete buffer;
}
// else assert
}
}
void
nsAString::do_InsertFromReadable( const self_type& aReadable, index_type atPosition )
{
size_type oldLength = this->Length();
SetLength(oldLength + aReadable.Length());
const_iterator fromBegin, fromEnd;
iterator toBegin;
if ( atPosition < oldLength )
copy_string_backward(this->BeginReading(fromBegin).advance(PRInt32(atPosition)), this->BeginReading(fromEnd).advance(PRInt32(oldLength)), EndWriting(toBegin));
else
atPosition = oldLength;
copy_string(aReadable.BeginReading(fromBegin), aReadable.EndReading(fromEnd), BeginWriting(toBegin).advance(PRInt32(atPosition)));
}
void
nsAString::do_InsertFromElementPtr( const char_type* aPtr, index_type atPosition )
{
do_InsertFromReadable(nsDependentString(aPtr), atPosition);
}
void
nsAString::do_InsertFromElementPtrLength( const char_type* aPtr, index_type atPosition, size_type aLength )
{
do_InsertFromReadable(Substring(aPtr, aPtr+aLength), atPosition);
}
void
nsAString::do_InsertFromElement( char_type aChar, index_type atPosition )
{
do_InsertFromReadable(Substring(&aChar, &aChar+1), atPosition);
}
//
// |Cut()|
//
void
nsAString::Cut( index_type cutStart, size_type cutLength )
{
size_type myLength = this->Length();
cutLength = NS_MIN(cutLength, myLength-cutStart);
index_type cutEnd = cutStart + cutLength;
const_iterator fromBegin, fromEnd;
iterator toBegin;
if ( cutEnd < myLength )
copy_string(this->BeginReading(fromBegin).advance(PRInt32(cutEnd)), this->EndReading(fromEnd), BeginWriting(toBegin).advance(PRInt32(cutStart)));
SetLength(myLength-cutLength);
}
//
// |Replace()|
//
void
nsAString::ReplaceFromReadable( index_type cutStart, size_type cutLength, const self_type& aReplacement )
{
if ( this != &aReplacement )
do_ReplaceFromReadable(cutStart, cutLength, aReplacement);
else
ReplaceFromPromise(cutStart, cutLength, aReplacement);
}
void
nsAString::ReplaceFromPromise( index_type cutStart, size_type cutLength, const self_type& aReadable )
{
if ( !aReadable.IsDependentOn(*this) )
do_ReplaceFromReadable(cutStart, cutLength, aReadable);
else
{
size_type length = aReadable.Length();
char_type* buffer = new char_type[length];
if ( buffer )
{
const_iterator fromBegin, fromEnd;
char_type* toBegin = buffer;
copy_string(aReadable.BeginReading(fromBegin), aReadable.EndReading(fromEnd), toBegin);
do_ReplaceFromReadable(cutStart, cutLength, nsDependentString(buffer, length));
delete buffer;
}
// else assert?
}
}
void
nsAString::do_ReplaceFromReadable( index_type cutStart, size_type cutLength, const self_type& aReplacement )
{
size_type oldLength = this->Length();
cutStart = NS_MIN(cutStart, oldLength);
cutLength = NS_MIN(cutLength, oldLength-cutStart);
index_type cutEnd = cutStart + cutLength;
size_type replacementLength = aReplacement.Length();
index_type replacementEnd = cutStart + replacementLength;
size_type newLength = oldLength - cutLength + replacementLength;
const_iterator fromBegin, fromEnd;
iterator toBegin;
if ( cutLength > replacementLength )
copy_string(this->BeginReading(fromBegin).advance(PRInt32(cutEnd)), this->EndReading(fromEnd), BeginWriting(toBegin).advance(PRInt32(replacementEnd)));
SetLength(newLength);
if ( cutLength < replacementLength )
copy_string_backward(this->BeginReading(fromBegin).advance(PRInt32(cutEnd)), this->BeginReading(fromEnd).advance(PRInt32(oldLength)), EndWriting(toBegin));
copy_string(aReplacement.BeginReading(fromBegin), aReplacement.EndReading(fromEnd), BeginWriting(toBegin).advance(PRInt32(cutStart)));
}
int
nsDefaultCStringComparator::operator()( const char_type* lhs, const char_type* rhs, PRUint32 aLength ) const
{
return nsCharTraits<char_type>::compare(lhs, rhs, aLength);
}
PRBool
nsDefaultCStringComparator::operator()( char_type lhs, char_type rhs ) const
{
return lhs - rhs;
}
int
nsCaseInsensitiveCStringComparator::operator()( const char_type* lhs, const char_type* rhs, PRUint32 aLength ) const
{
return nsCRT::strncasecmp(lhs, rhs, aLength);
}
PRBool
nsCaseInsensitiveCStringComparator::operator()( char lhs, char rhs ) const
{
if (lhs == rhs) return 0;
lhs = nsCRT::ToLower(lhs);
rhs = nsCRT::ToLower(rhs);
return lhs - rhs;
}
NS_COM
int
Compare( const nsACString& lhs, const nsACString& rhs, const nsCStringComparator& aComparator )
{
typedef nsACString::size_type size_type;
if ( &lhs == &rhs )
return 0;
size_type lLength = lhs.Length();
size_type rLength = rhs.Length();
size_type lengthToCompare = NS_MIN(lLength, rLength);
nsACString::const_iterator leftIter, rightIter;
lhs.BeginReading(leftIter);
rhs.BeginReading(rightIter);
for (;;)
{
size_type lengthAvailable = size_type( NS_MIN(leftIter.size_forward(), rightIter.size_forward()) );
if ( lengthAvailable > lengthToCompare )
lengthAvailable = lengthToCompare;
{
int result;
// Note: |result| should be declared in this |if| expression, but some compilers don't like that
if ( (result = aComparator(leftIter.get(), rightIter.get(), lengthAvailable)) != 0 )
return result;
}
if ( !(lengthToCompare -= lengthAvailable) )
break;
leftIter.advance( PRInt32(lengthAvailable) );
rightIter.advance( PRInt32(lengthAvailable) );
}
if ( lLength < rLength )
return -1;
else if ( rLength < lLength )
return 1;
else
return 0;
}
const nsACString::shared_buffer_handle_type*
nsACString::GetSharedBufferHandle() const
{
return 0;
}
const nsACString::buffer_handle_type*
nsACString::GetFlatBufferHandle() const
{
return GetSharedBufferHandle();
}
const nsACString::buffer_handle_type*
nsACString::GetBufferHandle() const
{
return GetSharedBufferHandle();
}
PRUint32
nsACString::GetImplementationFlags() const
{
PRUint32 flags = 0;
const shared_buffer_handle_type* handle = GetSharedBufferHandle();
if ( handle )
flags = handle->GetImplementationFlags();
return flags;
}
PRBool
nsACString::IsVoid() const
{
return PR_FALSE;
}
void
nsACString::SetIsVoid( PRBool )
{
// |SetIsVoid| is ignored by default
}
PRBool
nsACString::Equals( const char_type* rhs, const nsCStringComparator& aComparator ) const
{
return Equals(nsDependentCString(rhs), aComparator);
}
nsACString::char_type
nsACString::First() const
{
NS_ASSERTION(Length()>0, "|First()| on an empty string");
const_iterator iter;
return *BeginReading(iter);
}
nsACString::char_type
nsACString::Last() const
{
NS_ASSERTION(Length()>0, "|Last()| on an empty string");
const_iterator iter;
if ( !IsEmpty() )
{
EndReading(iter);
iter.advance(-1);
}
return *iter; // Note: this has undefined results if |IsEmpty()|
}
nsACString::size_type
nsACString::CountChar( char_type c ) const
{
/*
re-write this to use a counting sink
*/
size_type result = 0;
size_type lengthToExamine = Length();
const_iterator iter;
for ( BeginReading(iter); ; )
{
PRInt32 lengthToExamineInThisFragment = iter.size_forward();
const char_type* fromBegin = iter.get();
result += size_type(NS_COUNT(fromBegin, fromBegin+lengthToExamineInThisFragment, c));
if ( !(lengthToExamine -= lengthToExamineInThisFragment) )
return result;
iter.advance(lengthToExamineInThisFragment);
}
// never reached; quiets warnings
return 0;
}
nsACString::size_type
nsACString::Mid( self_type& aResult, index_type aStartPos, size_type aLengthToCopy ) const
{
// 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();
}
nsACString::size_type
nsACString::Right( self_type& aResult, size_type aLengthToCopy ) const
{
size_type myLength = Length();
aLengthToCopy = NS_MIN(myLength, aLengthToCopy);
return Mid(aResult, myLength-aLengthToCopy, aLengthToCopy);
}
PRInt32
nsACString::FindChar( char_type aChar, PRUint32 aOffset ) const
{
const_iterator iter, done_searching;
BeginReading(iter).advance( PRInt32(aOffset) );
EndReading(done_searching);
size_type lengthSearched = 0;
while ( iter != done_searching )
{
PRInt32 fragmentLength = iter.size_forward();
const char_type* charFoundAt = nsCharTraits<char_type>::find(iter.get(), fragmentLength, aChar);
if ( charFoundAt )
return lengthSearched + (charFoundAt-iter.get()) + aOffset;
lengthSearched += fragmentLength;
iter.advance(fragmentLength);
}
return -1;
}
//
// |Assign()|
//
void
nsACString::AssignFromReadable( const self_type& rhs )
{
if ( this != &rhs )
do_AssignFromReadable(rhs);
// else, self-assign is a no-op
}
void
nsACString::AssignFromPromise( const self_type& 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.
*/
{
if ( !aReadable.IsDependentOn(*this) )
do_AssignFromReadable(aReadable);
else
{
size_type length = aReadable.Length();
char_type* buffer = new char_type[length];
if ( buffer )
{
// Note: not exception safe. We need something to manage temporary buffers like this
const_iterator fromBegin, fromEnd;
char_type* toBegin = buffer;
copy_string(aReadable.BeginReading(fromBegin), aReadable.EndReading(fromEnd), toBegin);
do_AssignFromElementPtrLength(buffer, length);
delete buffer;
}
// else assert?
}
}
void
nsACString::do_AssignFromReadable( const self_type& aReadable )
{
SetLength(0);
if ( !aReadable.IsEmpty() )
{
SetLength(aReadable.Length());
// first setting the length to |0| avoids copying characters only to be overwritten later
// in the case where the implementation decides to re-allocate
const_iterator fromBegin, fromEnd;
iterator toBegin;
copy_string(aReadable.BeginReading(fromBegin), aReadable.EndReading(fromEnd), BeginWriting(toBegin));
}
}
void
nsACString::do_AssignFromElementPtr( const char_type* aPtr )
{
do_AssignFromReadable(nsDependentCString(aPtr));
}
void
nsACString::do_AssignFromElementPtrLength( const char_type* aPtr, size_type aLength )
{
do_AssignFromReadable(Substring(aPtr, aPtr+aLength));
}
void
nsACString::do_AssignFromElement( char_type aChar )
{
do_AssignFromReadable(Substring(&aChar, &aChar+1));
}
//
// |Append()|
//
void
nsACString::AppendFromReadable( const self_type& aReadable )
{
if ( this != &aReadable )
do_AppendFromReadable(aReadable);
else
AppendFromPromise(aReadable);
}
void
nsACString::AppendFromPromise( const self_type& aReadable )
{
if ( !aReadable.IsDependentOn(*this) )
do_AppendFromReadable(aReadable);
else
{
size_type length = aReadable.Length();
char_type* buffer = new char_type[length];
if ( buffer )
{
const_iterator fromBegin, fromEnd;
char_type* toBegin = buffer;
copy_string(aReadable.BeginReading(fromBegin), aReadable.EndReading(fromEnd), toBegin);
do_AppendFromElementPtrLength(buffer, length);
delete buffer;
}
// else assert?
}
}
void
nsACString::do_AppendFromReadable( const self_type& aReadable )
{
size_type oldLength = this->Length();
SetLength(oldLength + aReadable.Length());
const_iterator fromBegin, fromEnd;
iterator toBegin;
copy_string(aReadable.BeginReading(fromBegin), aReadable.EndReading(fromEnd), BeginWriting(toBegin).advance( PRInt32(oldLength) ) );
}
void
nsACString::do_AppendFromElementPtr( const char_type* aPtr )
{
do_AppendFromReadable(nsDependentCString(aPtr));
}
void
nsACString::do_AppendFromElementPtrLength( const char_type* aPtr, size_type aLength )
{
do_AppendFromReadable(Substring(aPtr, aPtr+aLength));
}
void
nsACString::do_AppendFromElement( char_type aChar )
{
do_AppendFromReadable(Substring(&aChar, &aChar + 1));
}
//
// |Insert()|
//
void
nsACString::InsertFromReadable( const self_type& aReadable, index_type atPosition )
{
if ( this != &aReadable )
do_InsertFromReadable(aReadable, atPosition);
else
InsertFromPromise(aReadable, atPosition);
}
void
nsACString::InsertFromPromise( const self_type& aReadable, index_type atPosition )
{
if ( !aReadable.IsDependentOn(*this) )
do_InsertFromReadable(aReadable, atPosition);
else
{
size_type length = aReadable.Length();
char_type* buffer = new char_type[length];
if ( buffer )
{
const_iterator fromBegin, fromEnd;
char_type* toBegin = buffer;
copy_string(aReadable.BeginReading(fromBegin), aReadable.EndReading(fromEnd), toBegin);
do_InsertFromElementPtrLength(buffer, atPosition, length);
delete buffer;
}
// else assert
}
}
void
nsACString::do_InsertFromReadable( const self_type& aReadable, index_type atPosition )
{
size_type oldLength = this->Length();
SetLength(oldLength + aReadable.Length());
const_iterator fromBegin, fromEnd;
iterator toBegin;
if ( atPosition < oldLength )
copy_string_backward(this->BeginReading(fromBegin).advance(PRInt32(atPosition)), this->BeginReading(fromEnd).advance(PRInt32(oldLength)), EndWriting(toBegin));
else
atPosition = oldLength;
copy_string(aReadable.BeginReading(fromBegin), aReadable.EndReading(fromEnd), BeginWriting(toBegin).advance(PRInt32(atPosition)));
}
void
nsACString::do_InsertFromElementPtr( const char_type* aPtr, index_type atPosition )
{
do_InsertFromReadable(nsDependentCString(aPtr), atPosition);
}
void
nsACString::do_InsertFromElementPtrLength( const char_type* aPtr, index_type atPosition, size_type aLength )
{
do_InsertFromReadable(Substring(aPtr, aPtr+aLength), atPosition);
}
void
nsACString::do_InsertFromElement( char_type aChar, index_type atPosition )
{
do_InsertFromReadable(Substring(&aChar, &aChar+1), atPosition);
}
//
// |Cut()|
//
void
nsACString::Cut( index_type cutStart, size_type cutLength )
{
size_type myLength = this->Length();
cutLength = NS_MIN(cutLength, myLength-cutStart);
index_type cutEnd = cutStart + cutLength;
const_iterator fromBegin, fromEnd;
iterator toBegin;
if ( cutEnd < myLength )
copy_string(this->BeginReading(fromBegin).advance(PRInt32(cutEnd)), this->EndReading(fromEnd), BeginWriting(toBegin).advance(PRInt32(cutStart)));
SetLength(myLength-cutLength);
}
//
// |Replace()|
//
void
nsACString::ReplaceFromReadable( index_type cutStart, size_type cutLength, const self_type& aReplacement )
{
if ( this != &aReplacement )
do_ReplaceFromReadable(cutStart, cutLength, aReplacement);
else
ReplaceFromPromise(cutStart, cutLength, aReplacement);
}
void
nsACString::ReplaceFromPromise( index_type cutStart, size_type cutLength, const self_type& aReadable )
{
if ( !aReadable.IsDependentOn(*this) )
do_ReplaceFromReadable(cutStart, cutLength, aReadable);
else
{
size_type length = aReadable.Length();
char_type* buffer = new char_type[length];
if ( buffer )
{
const_iterator fromBegin, fromEnd;
char_type* toBegin = buffer;
copy_string(aReadable.BeginReading(fromBegin), aReadable.EndReading(fromEnd), toBegin);
do_ReplaceFromReadable(cutStart, cutLength, nsDependentCString(buffer, length));
delete buffer;
}
// else assert?
}
}
void
nsACString::do_ReplaceFromReadable( index_type cutStart, size_type cutLength, const self_type& aReplacement )
{
size_type oldLength = this->Length();
cutStart = NS_MIN(cutStart, oldLength);
cutLength = NS_MIN(cutLength, oldLength-cutStart);
index_type cutEnd = cutStart + cutLength;
size_type replacementLength = aReplacement.Length();
index_type replacementEnd = cutStart + replacementLength;
size_type newLength = oldLength - cutLength + replacementLength;
const_iterator fromBegin, fromEnd;
iterator toBegin;
if ( cutLength > replacementLength )
copy_string(this->BeginReading(fromBegin).advance(PRInt32(cutEnd)), this->EndReading(fromEnd), BeginWriting(toBegin).advance(PRInt32(replacementEnd)));
SetLength(newLength);
if ( cutLength < replacementLength )
copy_string_backward(this->BeginReading(fromBegin).advance(PRInt32(cutEnd)), this->BeginReading(fromEnd).advance(PRInt32(oldLength)), EndWriting(toBegin));
copy_string(aReplacement.BeginReading(fromBegin), aReplacement.EndReading(fromEnd), BeginWriting(toBegin).advance(PRInt32(cutStart)));
}