Reduce string copying and allocation in the parser by only copying the scanner buffer when we need to mutate the string. Allow a nsDependentString / nsDependentSubstring to be created without being bound to anything. Move StripChar() onto nsSubstring from nsString. Bug 269853, r=jst, sr=darin.

git-svn-id: svn://10.0.0.236/trunk@165773 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
bryner%brianryner.com
2004-11-25 07:03:20 +00:00
parent 2e6bee01c4
commit 7a461c49a4
17 changed files with 458 additions and 138 deletions

View File

@@ -244,16 +244,8 @@ nsScannerSubstring::AsString() const
if (mStart.mBuffer == mEnd.mBuffer) {
// We only have a single fragment to deal with, so just return it
// as a substring. We take advantage of the fact that |nsString| and
// |nsDependentSubstring| don't have any members that aren't on
// |nsSubstring|, so that have same same layout. Furthermore,
// we know that the implementation of ~nsString() will not try
// to free the data if the string was constructed as a
// |nsDependentSubstring|.
mFlattenedRep.~nsString(); // in case we have a buffer currently
new (&mutable_this->mFlattenedRep)
nsDependentSubstring(mStart.mPosition, mEnd.mPosition);
// as a substring.
mutable_this->mFlattenedRep.Rebind(mStart.mPosition, mEnd.mPosition);
} else {
// Otherwise, we need to copy the data into a flattened buffer.
nsScannerIterator start, end;
@@ -429,6 +421,64 @@ nsScannerString::ReplaceCharacter(nsScannerIterator& aPosition, PRUnichar aChar)
}
/**
* nsScannerSharedSubstring
*/
void
nsScannerSharedSubstring::Rebind(const nsScannerIterator &aStart,
const nsScannerIterator &aEnd)
{
// If the start and end positions are inside the same buffer, we must
// acquire ownership of the buffer. If not, we can optimize by not holding
// onto it.
Buffer *buffer = NS_CONST_CAST(Buffer*, aStart.buffer());
PRBool sameBuffer = buffer == aEnd.buffer();
nsScannerBufferList *bufferList;
if (sameBuffer) {
bufferList = aStart.mOwner->mBufferList;
bufferList->AddRef();
buffer->IncrementUsageCount();
}
if (mBufferList)
ReleaseBuffer();
if (sameBuffer) {
mBuffer = buffer;
mBufferList = bufferList;
mString.Rebind(aStart.mPosition, aEnd.mPosition);
} else {
mBuffer = nsnull;
mBufferList = nsnull;
CopyUnicodeTo(aStart, aEnd, mString);
}
}
void
nsScannerSharedSubstring::ReleaseBuffer()
{
NS_ASSERTION(mBufferList, "Should only be called with non-null mBufferList");
mBuffer->DecrementUsageCount();
mBufferList->DiscardUnreferencedPrefix(mBuffer);
mBufferList->Release();
}
void
nsScannerSharedSubstring::MakeMutable()
{
nsString temp(mString); // this will force a copy of the data
mString.Assign(temp); // mString will now share the just-allocated buffer
ReleaseBuffer();
mBuffer = nsnull;
mBufferList = nsnull;
}
/**
* utils -- based on code from nsReadableUtils.cpp
*/
@@ -446,6 +496,22 @@ CopyUnicodeTo( const nsScannerIterator& aSrcStart,
copy_string(fromBegin, aSrcEnd, writer);
}
void
AppendUnicodeTo( const nsScannerIterator& aSrcStart,
const nsScannerIterator& aSrcEnd,
nsScannerSharedSubstring& aDest )
{
// Check whether we can just create a dependent string.
if (aDest.str().IsEmpty()) {
// We can just make |aDest| point to the buffer.
// This will take care of copying if the buffer spans fragments.
aDest.Rebind(aSrcStart, aSrcEnd);
} else {
// The dest string is not empty, so it can't be a dependent substring.
AppendUnicodeTo(aSrcStart, aSrcEnd, aDest.writable());
}
}
void
AppendUnicodeTo( const nsScannerIterator& aSrcStart,
const nsScannerIterator& aSrcEnd,