fixed bug found by DavidBienvenu -- I owe him a beer

This commit is contained in:
rickg%netscape.com 1999-04-05 21:28:55 +00:00
Родитель ba8a7d30b8
Коммит 640480851f
8 изменённых файлов: 832 добавлений и 544 удалений

Просмотреть файл

@ -31,9 +31,101 @@
#include "nsStr.h"
#include "bufferRoutines.h"
#include "stdio.h" //only used for printf
#include "nsDeque.h"
#include "nsCRT.h"
static const char* kFoolMsg = "Error: Some fool overwrote the shared buffer.";
//----------------------------------------------------------------------------------------
// The following is a memory agent who knows how to recycled (pool) freed memory...
//----------------------------------------------------------------------------------------
/**************************************************************
Define the char* (pooled) deallocator class...
**************************************************************/
class nsBufferDeallocator: public nsDequeFunctor{
public:
virtual void* operator()(void* anObject) {
char* aCString= (char*)anObject;
delete [] aCString;
return 0;
}
};
/**
*
* @update gess10/30/98
* @param
* @return
*/
class nsPoolingMemoryAgent : public nsMemoryAgent{
public:
nsPoolingMemoryAgent() {
memset(mPools,0,sizeof(mPools));
}
~nsPoolingMemoryAgent() {
nsBufferDeallocator theDeallocator;
int i=0;
for(i=0;i<10;i++){
if(mPools[i]){
mPools[i]->ForEach(theDeallocator); //now delete the buffers
}
delete mPools[i];
mPools[i]=0;
}
}
virtual PRBool Alloc(nsStr& aDest,PRInt32 aCount) {
//we're given the acount value in charunits; we have to scale up by the charsize.
int theShift=4;
PRInt32 theNewCapacity=eDefaultSize;
while(theNewCapacity<aCount){
theNewCapacity<<=1;
theShift++;
}
aDest.mCapacity=theNewCapacity++;
theShift=(theShift<<aDest.mMultibyte)-4;
if((theShift<12) && (mPools[theShift])){
aDest.mStr=(char*)mPools[theShift]->Pop();
}
if(!aDest.mStr) {
//we're given the acount value in charunits; we have to scale up by the charsize.
size_t theSize=(theNewCapacity<<aDest.mMultibyte);
aDest.mStr=new char[theSize];
}
aDest.mOwnsBuffer=1;
return PR_TRUE;
}
virtual PRBool Free(nsStr& aDest){
if(aDest.mStr){
if(aDest.mOwnsBuffer){
int theShift=1;
unsigned int theValue=1;
while((theValue<<=1)<aDest.mCapacity){
theShift++;
}
theShift-=4;
if(theShift<12){
if(!mPools[theShift]){
mPools[theShift]=new nsDeque(0);
}
mPools[theShift]->Push(aDest.mStr);
}
else delete [] aDest.mStr; //it's too big. Just delete it.
}
aDest.mStr=0;
aDest.mOwnsBuffer=0;
return PR_TRUE;
}
return PR_FALSE;
}
nsDeque* mPools[16];
};
//----------------------------------------------------------------------------------------
@ -80,14 +172,25 @@ void nsStr::Initialize(nsStr& aDest,eCharSize aCharSize) {
* @param
* @return
*/
nsIMemoryAgent* GetDefaultAgent(void){
static nsIMemoryAgent* gDefaultAgent=0;
if(!gDefaultAgent)
gDefaultAgent=new nsMemoryAgent();
NS_ASSERTION(gDefaultAgent,"You MUST always have an allocator!");
void nsStr::Initialize(nsStr& aDest,char* aCString,PRUint32 aCapacity,PRUint32 aLength,eCharSize aCharSize,PRBool aOwnsBuffer){
aDest.mStr=(aCString) ? aCString : GetSharedEmptyBuffer();
aDest.mLength=aLength;
aDest.mCapacity=aCapacity;
aDest.mMultibyte=aCharSize;
aDest.mOwnsBuffer=aOwnsBuffer;
aDest.mUnused=0;
}
return gDefaultAgent;
/**
*
* @update gess10/30/98
* @param
* @return
*/
nsIMemoryAgent* GetDefaultAgent(void){
// static nsPoolingMemoryAgent gDefaultAgent;
static nsMemoryAgent gDefaultAgent;
return (nsIMemoryAgent*)&gDefaultAgent;
}
/**
@ -110,20 +213,6 @@ void nsStr::Destroy(nsStr& aDest,nsIMemoryAgent* anAgent) {
}
}
/**
*
* @update gess11/12/98
* @param
* @return
*/
PRUnichar nsStr::GetCharAt(const nsStr& aDest,PRUint32 anIndex) {
PRUnichar result=0;
if((anIndex>=0) && (anIndex<aDest.mLength)) {
result=(eTwoByte==aDest.mMultibyte) ? aDest.mUStr[anIndex] : aDest.mStr[anIndex];
}//if
return result;
}
/**
* This method gets called when the internal buffer needs
@ -155,8 +244,8 @@ void nsStr::GrowCapacity(nsStr& aDest,PRUint32 aNewLength,nsIMemoryAgent* anAgen
nsIMemoryAgent* theAgent=(anAgent) ? anAgent : GetDefaultAgent();
EnsureCapacity(theTempStr,aNewLength,theAgent);
if(0<aDest.mLength) {
Append(theTempStr,aDest,0,aDest.mLength,anAgent);
if(aDest.mLength) {
Append(theTempStr,aDest,0,aDest.mLength,theAgent);
}
theAgent->Free(aDest);
aDest.mStr = theTempStr.mStr;
@ -188,8 +277,7 @@ void nsStr::Assign(nsStr& aDest,const nsStr& aSource,PRUint32 anOffset,PRInt32 a
* @aCount is the number of bytes to be copied
*/
void nsStr::Append(nsStr& aDest,const nsStr& aSource,PRUint32 anOffset,PRInt32 aCount,nsIMemoryAgent* anAgent){
if(anOffset<aSource.mLength-1){
if(anOffset<aSource.mLength) {
PRUint32 theRealLen=(aCount<0) ? aSource.mLength : MinInt(aCount,aSource.mLength);
PRUint32 theLength=(anOffset+theRealLen<aSource.mLength) ? theRealLen : (aSource.mLength-anOffset);
if(0<theLength){
@ -221,30 +309,31 @@ void nsStr::Insert( nsStr& aDest,PRUint32 aDestOffset,const nsStr& aSource,PRUin
// 1. You're inserting chars into an empty string (assign)
// 2. You're inserting onto the end of a string (append)
// 3. You're inserting onto the 1..n-1 pos of a string (the hard case).
if((0<aSource.mLength) && (aDestOffset<aDest.mLength-1)){
if(0<aSource.mLength){
ToRange(aDestOffset,0,aDest.mLength);
if(aDest.mLength){
if(aDestOffset<aDest.mLength){
if(aSrcOffset<aSource.mLength-1) {
PRInt32 theRealLen=(aCount<0) ? aSource.mLength : MinInt(aCount,aSource.mLength);
PRInt32 theLength=(aSrcOffset+theRealLen<aSource.mLength) ? theRealLen : (aSource.mLength-aSrcOffset);
if(aSrcOffset<aSource.mLength) {
//here's the only new case we have to handle.
//chars are really being inserted into our buffer...
GrowCapacity(aDest,aDest.mLength+theLength,anAgent);
ToRange(aSrcOffset,0,aSource.mLength-1);
PRInt32 theRealLen=(aCount<0) ? aSource.mLength : MinInt(aCount,aSource.mLength);
PRInt32 theLength=(aSrcOffset+theRealLen<aSource.mLength) ? theRealLen : (aSource.mLength-aSrcOffset);
//shift the chars right by theDelta...
(*gShiftChars[aDest.mMultibyte][PR_TRUE])(aDest.mStr,aDest.mLength,aDestOffset,theLength);
if(aSrcOffset<aSource.mLength) {
//here's the only new case we have to handle.
//chars are really being inserted into our buffer...
GrowCapacity(aDest,aDest.mLength+theLength,anAgent);
//shift the chars right by theDelta...
(*gShiftChars[aDest.mMultibyte][PR_TRUE])(aDest.mStr,aDest.mLength,aDestOffset,theLength);
//now insert new chars, starting at offset
(*gCopyChars[aSource.mMultibyte][aDest.mMultibyte])(aDest.mStr,aDestOffset,aSource.mStr,aSrcOffset,theLength);
//now insert new chars, starting at offset
(*gCopyChars[aSource.mMultibyte][aDest.mMultibyte])(aDest.mStr,aDestOffset,aSource.mStr,aSrcOffset,theLength);
//finally, make sure to update the string length...
aDest.mLength+=theLength;
//finally, make sure to update the string length...
aDest.mLength+=theLength;
}//if
//else nothing to do!
}
}//if
//else nothing to do!
}
else Append(aDest,aSource,0,aCount,anAgent);
}
@ -260,22 +349,21 @@ void nsStr::Insert( nsStr& aDest,PRUint32 aDestOffset,const nsStr& aSource,PRUin
* @param aDestOffset is where in aDest deletion is to occur
* @param aCount is the number of chars to be deleted in aDest
*/
void nsStr::Delete(nsStr& aDest,PRUint32 aDestOffset,PRInt32 aCount,nsIMemoryAgent* anAgent){
if(0<aCount){
if(aDestOffset<aDest.mLength){
void nsStr::Delete(nsStr& aDest,PRUint32 aDestOffset,PRUint32 aCount,nsIMemoryAgent* anAgent){
PRInt32 theDelta=aDest.mLength-aDestOffset;
PRInt32 theLength=(theDelta<aCount) ? theDelta : aCount;
if(aDestOffset<aDest.mLength){
if(aDestOffset+theLength<aDest.mLength) {
PRUint32 theDelta=aDest.mLength-aDestOffset;
PRUint32 theLength=(theDelta<aCount) ? theDelta : aCount;
//if you're here, it means we're cutting chars out of the middle of the string...
//so shift the chars left by theLength...
(*gShiftChars[aDest.mMultibyte][PR_FALSE])(aDest.mStr,aDest.mLength,aDestOffset,theLength);
aDest.mLength-=theLength;
}
else Truncate(aDest,aDestOffset,anAgent);
}//if
if(aDestOffset+theLength<aDest.mLength) {
//if you're here, it means we're cutting chars out of the middle of the string...
//so shift the chars left by theLength...
(*gShiftChars[aDest.mMultibyte][PR_FALSE])(aDest.mStr,aDest.mLength,aDestOffset,theLength);
aDest.mLength-=theLength;
}
else Truncate(aDest,aDestOffset,anAgent);
}//if
}
@ -343,28 +431,28 @@ void nsStr::CompressSet(nsStr& aDest,const char* aSet,PRUint32 aChar,PRBool aEli
**************************************************************/
PRInt32 nsStr::FindSubstr(const nsStr& aDest,const nsStr& aTarget, PRBool /*aIgnoreCase*/,PRUint32 anOffset) {
PRInt32 nsStr::FindSubstr(const nsStr& aDest,const nsStr& aTarget, PRBool aIgnoreCase,PRUint32 anOffset) {
PRInt32 index=anOffset-1;
PRInt32 theMax=aDest.mLength-aTarget.mLength;
if((aDest.mLength>0) && (aTarget.mLength>0)){
PRInt32 theNewStartPos=-1;
PRUnichar theFirstTargetChar=nsStr::GetCharAt(aTarget,0);
PRUnichar theLastTargetChar=nsStr::GetCharAt(aTarget,aTarget.mLength-1);
PRUnichar theFirstTargetChar=GetCharAt(aTarget,0);
PRUnichar theLastTargetChar=GetCharAt(aTarget,aTarget.mLength-1);
PRInt32 theTargetMax=aTarget.mLength;
while(++index<=theMax) {
PRInt32 theSubIndex=-1;
PRBool matches=PR_TRUE;
while((++theSubIndex<theTargetMax) && (matches)){
PRUnichar theChar=nsStr::GetCharAt(aDest,index+theSubIndex);
PRUnichar theChar=GetCharAt(aDest,index+theSubIndex);
if(theSubIndex>0) {
if(theFirstTargetChar==theChar){
PRUnichar theDestJumpChar=nsStr::GetCharAt(aDest,index+theTargetMax);
PRUnichar theDestJumpChar=GetCharAt(aDest,index+theTargetMax);
if(theDestJumpChar==theLastTargetChar) {
theNewStartPos=index; //this lets us jump ahead during our search where possible.
}//if
}//if
}//if
PRUnichar theTargetChar=nsStr::GetCharAt(aTarget,theSubIndex);
PRUnichar theTargetChar=GetCharAt(aTarget,theSubIndex);
matches=PRBool(theChar==theTargetChar);
}
if(matches)
@ -384,8 +472,8 @@ PRInt32 nsStr::FindSubstr(const nsStr& aDest,const nsStr& aTarget, PRBool /*aIgn
* @param
* @return
*/
PRInt32 nsStr::FindChar(const nsStr& aDest, PRUnichar aChar, PRBool aIgnoreCase,PRUint32 anOffset) {
PRInt32 result=gFindChars[aDest.mMultibyte](aDest.mStr,aDest.mLength,anOffset,aChar,aIgnoreCase);
PRInt32 nsStr::FindChar(const nsStr& aDest,const PRUnichar aChar, PRBool aIgnoreCase,PRUint32 anOffset) {
PRInt32 result=gFindChars[aDest.mMultibyte](aDest.mStr,aDest.mLength,0,aChar,aIgnoreCase);
return result;
}
@ -415,12 +503,12 @@ PRInt32 nsStr::FindCharInSet(const nsStr& aDest,const nsStr& aSet,PRBool aIgnore
**************************************************************/
PRInt32 nsStr::RFindSubstr(const nsStr& aDest,const nsStr& aTarget, PRBool /*aIgnoreCase*/,PRUint32 anOffset) {
PRInt32 nsStr::RFindSubstr(const nsStr& aDest,const nsStr& aTarget, PRBool aIgnoreCase,PRUint32 anOffset) {
PRInt32 index=(anOffset ? anOffset : aDest.mLength-aTarget.mLength+1);
if((aDest.mLength>0) && (aTarget.mLength>0)){
PRInt32 theNewStartPos=-1;
PRUnichar theFirstTargetChar=nsStr::GetCharAt(aTarget,0);
PRUnichar theLastTargetChar=nsStr::GetCharAt(aTarget,aTarget.mLength-1);
PRUnichar theFirstTargetChar=GetCharAt(aTarget,0);
PRUnichar theLastTargetChar=GetCharAt(aTarget,aTarget.mLength-1);
PRInt32 theTargetMax=aTarget.mLength;
while(index--) {
@ -429,16 +517,16 @@ PRInt32 nsStr::RFindSubstr(const nsStr& aDest,const nsStr& aTarget, PRBool /*aIg
if(anOffset+aTarget.mLength<=aDest.mLength) {
while((++theSubIndex<theTargetMax) && (matches)){
PRUnichar theChar=nsStr::GetCharAt(aDest,index+theSubIndex);
PRUnichar theChar=GetCharAt(aDest,index+theSubIndex);
if(theSubIndex>0) {
if(theFirstTargetChar==theChar){
PRUnichar theDestJumpChar=nsStr::GetCharAt(aDest,index+theTargetMax);
PRUnichar theDestJumpChar=GetCharAt(aDest,index+theTargetMax);
if(theDestJumpChar==theLastTargetChar) {
theNewStartPos=index; //this lets us jump ahead during our search where possible.
}//if
}//if
}//if
PRUnichar theTargetChar=nsStr::GetCharAt(aTarget,theSubIndex);
PRUnichar theTargetChar=GetCharAt(aTarget,theSubIndex);
matches=PRBool(theChar==theTargetChar);
} //while
} //if
@ -459,8 +547,8 @@ PRInt32 nsStr::RFindSubstr(const nsStr& aDest,const nsStr& aTarget, PRBool /*aIg
* @param
* @return
*/
PRInt32 nsStr::RFindChar(const nsStr& aDest,PRUnichar aChar, PRBool aIgnoreCase,PRUint32 anOffset) {
PRInt32 result=gRFindChars[aDest.mMultibyte](aDest.mStr,aDest.mLength,anOffset,aChar,aIgnoreCase);
PRInt32 nsStr::RFindChar(const nsStr& aDest,const PRUnichar aChar, PRBool aIgnoreCase,PRUint32 anOffset) {
PRInt32 result=gRFindChars[aDest.mMultibyte](aDest.mStr,aDest.mLength,0,aChar,aIgnoreCase);
return result;
}
@ -472,11 +560,11 @@ PRInt32 nsStr::RFindChar(const nsStr& aDest,PRUnichar aChar, PRBool aIgnoreCase,
* @return
*/
PRInt32 nsStr::RFindCharInSet(const nsStr& aDest,const nsStr& aSet,PRBool aIgnoreCase,PRUint32 anOffset) {
PRInt32 offset=aDest.mLength-anOffset;
PRUint32 offset=aDest.mLength-anOffset;
PRInt32 thePos;
while(--offset>=0) {
PRUnichar theChar=GetCharAt(aDest,PRUint32(offset));
PRUnichar theChar=GetCharAt(aDest,offset);
thePos=gRFindChars[aSet.mMultibyte](aSet.mStr,aSet.mLength,0,theChar,aIgnoreCase);
if(kNotFound!=thePos)
return offset;
@ -491,7 +579,7 @@ PRInt32 nsStr::RFindCharInSet(const nsStr& aDest,const nsStr& aSet,PRBool aIgnor
* @param
* @return aDest<aSource=-1;aDest==aSource==0;aDest>aSource=1
*/
PRInt32 nsStr::Compare(const nsStr& aDest,const nsStr& aSource,PRInt32 /*aCount*/,PRBool aIgnoreCase) {
PRInt32 nsStr::Compare(const nsStr& aDest,const nsStr& aSource,PRInt32 aCount,PRBool aIgnoreCase) {
int minlen=(aSource.mLength<aDest.mLength) ? aSource.mLength : aDest.mLength;
if(0==minlen) {

Просмотреть файл

@ -27,8 +27,6 @@
We chose the option B for performance reasons.
2 Our internal buffer always holds capacity+1 bytes.
3. Note that our internal format for this class makes our memory
layout compatible with BStrings.
The nsStr struct is a simple structure (no methods) that contains
the necessary info to be described as a string. This simple struct
@ -44,8 +42,7 @@
#ifndef _nsStr
#define _nsStr
#include "prtypes.h"
#include "nscore.h"
#include "nsCore.h"
//----------------------------------------------------------------------------------------
@ -53,34 +50,6 @@ enum eCharSize {eOneByte=0,eTwoByte=1};
#define kDefaultCharSize eTwoByte
union UStrPtr {
char* mCharBuf;
PRUnichar* mUnicharBuf;
};
/**************************************************************************
Here comes the nsBufDescriptor class which describes buffer properties.
**************************************************************************/
struct nsBufDescriptor {
nsBufDescriptor(char* aBuffer,PRUint32 aBufferSize,eCharSize aCharSize,PRBool aOwnsBuffer) {
mStr=aBuffer;
mMultibyte=aCharSize;
mCapacity=(aBufferSize>>mMultibyte)-1;
mOwnsBuffer=aOwnsBuffer;
}
PRUint32 mCapacity;
PRBool mOwnsBuffer;
eCharSize mMultibyte;
// UStrPtr mStr;
union {
char* mStr;
PRUnichar* mUStr;
};
};
class nsIMemoryAgent;
//----------------------------------------------------------------------------------------
@ -97,6 +66,15 @@ struct nsStr {
*/
static void Initialize(nsStr& aDest,eCharSize aCharSize);
/**
* This method initializes an nsStr for use
*
* @update gess 01/04/99
* @param aString is the nsStr to be initialized
* @param aCharSize tells us the requested char size (1 or 2 bytes)
*/
static void Initialize(nsStr& aDest,char* aCString,PRUint32 aCapacity,PRUint32 aLength,eCharSize aCharSize,PRBool aOwnsBuffer);
/**
* This method destroys the given nsStr, and *MAY*
* deallocate it's memory depending on the setting
@ -166,7 +144,7 @@ struct nsStr {
* @param aCount tells us the (max) # of chars to delete
* @param anAgent is the allocator to be used for alloc/free operations
*/
static void Delete(nsStr& aDest,PRUint32 aDestOffset,PRInt32 aCount,nsIMemoryAgent* anAgent=0);
static void Delete(nsStr& aDest,PRUint32 aDestOffset,PRUint32 aCount,nsIMemoryAgent* anAgent=0);
/**
* This method is used to truncate the given string.
@ -254,21 +232,20 @@ struct nsStr {
static PRInt32 RFindChar(const nsStr& aDest,PRUnichar aChar, PRBool aIgnoreCase,PRUint32 anOffset);
static PRInt32 RFindCharInSet(const nsStr& aDest,const nsStr& aSet,PRBool aIgnoreCase,PRUint32 anOffset);
/**
* This method is used to access a given char in the given string
*
* @update gess 01/04/99
* @param aDest is the nsStr to be appended to
* @param anIndex tells us where in dest to get the char from
* @return the given char, or 0 if anIndex is out of range
*/
static PRUnichar GetCharAt(const nsStr& aDest,PRUint32 anIndex);
PRUint32 mLength : 30;
eCharSize mMultibyte : 2;
#ifdef NS_DEBUG
PRUint32 mLength;
eCharSize mMultibyte;
PRUint32 mCapacity;
PRUint32 mOwnsBuffer;
PRUint32 mUnused;
#else
PRUint32 mLength: 30;
eCharSize mMultibyte: 2;
PRUint32 mCapacity: 30;
PRUint32 mOwnsBuffer: 1;
PRUint32 mUnused: 1;
PRUint32 mOwnsBuffer: 1;
PRUint32 mUnused: 1;
#endif
union {
char* mStr;
PRUnichar* mUStr;
@ -307,6 +284,21 @@ inline void AddNullTerminator(nsStr& aDest) {
else aDest.mStr[aDest.mLength]=0;
}
/**
* This method is used to access a given char in the given string
*
* @update gess 01/04/99
* @param aDest is the nsStr to be appended to
* @param anIndex tells us where in dest to get the char from
* @return the given char, or 0 if anIndex is out of range
*/
inline PRUnichar GetCharAt(const nsStr& aDest,PRUint32 anIndex){
if(anIndex<aDest.mLength) {
return (eTwoByte==aDest.mMultibyte) ? aDest.mUStr[anIndex] : aDest.mStr[anIndex];
}//if
return 0;
}
//----------------------------------------------------------------------------------------
class nsIMemoryAgent {
@ -317,25 +309,18 @@ public:
};
class nsMemoryAgent : public nsIMemoryAgent {
enum eDelta{eGrowthDelta=8};
protected:
enum eDelta{eDefaultSize=16};
public:
virtual PRBool Alloc(nsStr& aDest,PRInt32 aCount) {
//we're given the acount value in charunits; we have to scale up by the charsize.
PRInt32 theNewCapacity;
if (aDest.mCapacity > 64) {
// When the string starts getting large, double the capacity as we grow.
theNewCapacity = aDest.mCapacity * 2;
if (theNewCapacity < aCount) {
theNewCapacity = aDest.mCapacity + aCount;
}
} else {
// When the string is small, keep it's capacity a multiple of kGrowthDelta
PRInt32 unitDelta=(aCount/eGrowthDelta)+1;
theNewCapacity=unitDelta*eGrowthDelta;
//we're given the acount value in charunits; now scale up to next multiple.
PRInt32 theNewCapacity=eDefaultSize;
while(theNewCapacity<aCount){
theNewCapacity<<=1;
}
aDest.mCapacity=theNewCapacity++;
size_t theSize=(theNewCapacity<<aDest.mMultibyte);
aDest.mStr=new char[theSize];
@ -362,6 +347,5 @@ public:
};
#endif

Просмотреть файл

@ -31,9 +31,101 @@
#include "nsStr.h"
#include "bufferRoutines.h"
#include "stdio.h" //only used for printf
#include "nsDeque.h"
#include "nsCRT.h"
static const char* kFoolMsg = "Error: Some fool overwrote the shared buffer.";
//----------------------------------------------------------------------------------------
// The following is a memory agent who knows how to recycled (pool) freed memory...
//----------------------------------------------------------------------------------------
/**************************************************************
Define the char* (pooled) deallocator class...
**************************************************************/
class nsBufferDeallocator: public nsDequeFunctor{
public:
virtual void* operator()(void* anObject) {
char* aCString= (char*)anObject;
delete [] aCString;
return 0;
}
};
/**
*
* @update gess10/30/98
* @param
* @return
*/
class nsPoolingMemoryAgent : public nsMemoryAgent{
public:
nsPoolingMemoryAgent() {
memset(mPools,0,sizeof(mPools));
}
~nsPoolingMemoryAgent() {
nsBufferDeallocator theDeallocator;
int i=0;
for(i=0;i<10;i++){
if(mPools[i]){
mPools[i]->ForEach(theDeallocator); //now delete the buffers
}
delete mPools[i];
mPools[i]=0;
}
}
virtual PRBool Alloc(nsStr& aDest,PRInt32 aCount) {
//we're given the acount value in charunits; we have to scale up by the charsize.
int theShift=4;
PRInt32 theNewCapacity=eDefaultSize;
while(theNewCapacity<aCount){
theNewCapacity<<=1;
theShift++;
}
aDest.mCapacity=theNewCapacity++;
theShift=(theShift<<aDest.mMultibyte)-4;
if((theShift<12) && (mPools[theShift])){
aDest.mStr=(char*)mPools[theShift]->Pop();
}
if(!aDest.mStr) {
//we're given the acount value in charunits; we have to scale up by the charsize.
size_t theSize=(theNewCapacity<<aDest.mMultibyte);
aDest.mStr=new char[theSize];
}
aDest.mOwnsBuffer=1;
return PR_TRUE;
}
virtual PRBool Free(nsStr& aDest){
if(aDest.mStr){
if(aDest.mOwnsBuffer){
int theShift=1;
unsigned int theValue=1;
while((theValue<<=1)<aDest.mCapacity){
theShift++;
}
theShift-=4;
if(theShift<12){
if(!mPools[theShift]){
mPools[theShift]=new nsDeque(0);
}
mPools[theShift]->Push(aDest.mStr);
}
else delete [] aDest.mStr; //it's too big. Just delete it.
}
aDest.mStr=0;
aDest.mOwnsBuffer=0;
return PR_TRUE;
}
return PR_FALSE;
}
nsDeque* mPools[16];
};
//----------------------------------------------------------------------------------------
@ -80,14 +172,25 @@ void nsStr::Initialize(nsStr& aDest,eCharSize aCharSize) {
* @param
* @return
*/
nsIMemoryAgent* GetDefaultAgent(void){
static nsIMemoryAgent* gDefaultAgent=0;
if(!gDefaultAgent)
gDefaultAgent=new nsMemoryAgent();
NS_ASSERTION(gDefaultAgent,"You MUST always have an allocator!");
void nsStr::Initialize(nsStr& aDest,char* aCString,PRUint32 aCapacity,PRUint32 aLength,eCharSize aCharSize,PRBool aOwnsBuffer){
aDest.mStr=(aCString) ? aCString : GetSharedEmptyBuffer();
aDest.mLength=aLength;
aDest.mCapacity=aCapacity;
aDest.mMultibyte=aCharSize;
aDest.mOwnsBuffer=aOwnsBuffer;
aDest.mUnused=0;
}
return gDefaultAgent;
/**
*
* @update gess10/30/98
* @param
* @return
*/
nsIMemoryAgent* GetDefaultAgent(void){
// static nsPoolingMemoryAgent gDefaultAgent;
static nsMemoryAgent gDefaultAgent;
return (nsIMemoryAgent*)&gDefaultAgent;
}
/**
@ -110,20 +213,6 @@ void nsStr::Destroy(nsStr& aDest,nsIMemoryAgent* anAgent) {
}
}
/**
*
* @update gess11/12/98
* @param
* @return
*/
PRUnichar nsStr::GetCharAt(const nsStr& aDest,PRUint32 anIndex) {
PRUnichar result=0;
if((anIndex>=0) && (anIndex<aDest.mLength)) {
result=(eTwoByte==aDest.mMultibyte) ? aDest.mUStr[anIndex] : aDest.mStr[anIndex];
}//if
return result;
}
/**
* This method gets called when the internal buffer needs
@ -155,8 +244,8 @@ void nsStr::GrowCapacity(nsStr& aDest,PRUint32 aNewLength,nsIMemoryAgent* anAgen
nsIMemoryAgent* theAgent=(anAgent) ? anAgent : GetDefaultAgent();
EnsureCapacity(theTempStr,aNewLength,theAgent);
if(0<aDest.mLength) {
Append(theTempStr,aDest,0,aDest.mLength,anAgent);
if(aDest.mLength) {
Append(theTempStr,aDest,0,aDest.mLength,theAgent);
}
theAgent->Free(aDest);
aDest.mStr = theTempStr.mStr;
@ -188,8 +277,7 @@ void nsStr::Assign(nsStr& aDest,const nsStr& aSource,PRUint32 anOffset,PRInt32 a
* @aCount is the number of bytes to be copied
*/
void nsStr::Append(nsStr& aDest,const nsStr& aSource,PRUint32 anOffset,PRInt32 aCount,nsIMemoryAgent* anAgent){
if(anOffset<aSource.mLength-1){
if(anOffset<aSource.mLength) {
PRUint32 theRealLen=(aCount<0) ? aSource.mLength : MinInt(aCount,aSource.mLength);
PRUint32 theLength=(anOffset+theRealLen<aSource.mLength) ? theRealLen : (aSource.mLength-anOffset);
if(0<theLength){
@ -221,30 +309,31 @@ void nsStr::Insert( nsStr& aDest,PRUint32 aDestOffset,const nsStr& aSource,PRUin
// 1. You're inserting chars into an empty string (assign)
// 2. You're inserting onto the end of a string (append)
// 3. You're inserting onto the 1..n-1 pos of a string (the hard case).
if((0<aSource.mLength) && (aDestOffset<aDest.mLength-1)){
if(0<aSource.mLength){
ToRange(aDestOffset,0,aDest.mLength);
if(aDest.mLength){
if(aDestOffset<aDest.mLength){
if(aSrcOffset<aSource.mLength-1) {
PRInt32 theRealLen=(aCount<0) ? aSource.mLength : MinInt(aCount,aSource.mLength);
PRInt32 theLength=(aSrcOffset+theRealLen<aSource.mLength) ? theRealLen : (aSource.mLength-aSrcOffset);
if(aSrcOffset<aSource.mLength) {
//here's the only new case we have to handle.
//chars are really being inserted into our buffer...
GrowCapacity(aDest,aDest.mLength+theLength,anAgent);
ToRange(aSrcOffset,0,aSource.mLength-1);
PRInt32 theRealLen=(aCount<0) ? aSource.mLength : MinInt(aCount,aSource.mLength);
PRInt32 theLength=(aSrcOffset+theRealLen<aSource.mLength) ? theRealLen : (aSource.mLength-aSrcOffset);
//shift the chars right by theDelta...
(*gShiftChars[aDest.mMultibyte][PR_TRUE])(aDest.mStr,aDest.mLength,aDestOffset,theLength);
if(aSrcOffset<aSource.mLength) {
//here's the only new case we have to handle.
//chars are really being inserted into our buffer...
GrowCapacity(aDest,aDest.mLength+theLength,anAgent);
//shift the chars right by theDelta...
(*gShiftChars[aDest.mMultibyte][PR_TRUE])(aDest.mStr,aDest.mLength,aDestOffset,theLength);
//now insert new chars, starting at offset
(*gCopyChars[aSource.mMultibyte][aDest.mMultibyte])(aDest.mStr,aDestOffset,aSource.mStr,aSrcOffset,theLength);
//now insert new chars, starting at offset
(*gCopyChars[aSource.mMultibyte][aDest.mMultibyte])(aDest.mStr,aDestOffset,aSource.mStr,aSrcOffset,theLength);
//finally, make sure to update the string length...
aDest.mLength+=theLength;
//finally, make sure to update the string length...
aDest.mLength+=theLength;
}//if
//else nothing to do!
}
}//if
//else nothing to do!
}
else Append(aDest,aSource,0,aCount,anAgent);
}
@ -260,22 +349,21 @@ void nsStr::Insert( nsStr& aDest,PRUint32 aDestOffset,const nsStr& aSource,PRUin
* @param aDestOffset is where in aDest deletion is to occur
* @param aCount is the number of chars to be deleted in aDest
*/
void nsStr::Delete(nsStr& aDest,PRUint32 aDestOffset,PRInt32 aCount,nsIMemoryAgent* anAgent){
if(0<aCount){
if(aDestOffset<aDest.mLength){
void nsStr::Delete(nsStr& aDest,PRUint32 aDestOffset,PRUint32 aCount,nsIMemoryAgent* anAgent){
PRInt32 theDelta=aDest.mLength-aDestOffset;
PRInt32 theLength=(theDelta<aCount) ? theDelta : aCount;
if(aDestOffset<aDest.mLength){
if(aDestOffset+theLength<aDest.mLength) {
PRUint32 theDelta=aDest.mLength-aDestOffset;
PRUint32 theLength=(theDelta<aCount) ? theDelta : aCount;
//if you're here, it means we're cutting chars out of the middle of the string...
//so shift the chars left by theLength...
(*gShiftChars[aDest.mMultibyte][PR_FALSE])(aDest.mStr,aDest.mLength,aDestOffset,theLength);
aDest.mLength-=theLength;
}
else Truncate(aDest,aDestOffset,anAgent);
}//if
if(aDestOffset+theLength<aDest.mLength) {
//if you're here, it means we're cutting chars out of the middle of the string...
//so shift the chars left by theLength...
(*gShiftChars[aDest.mMultibyte][PR_FALSE])(aDest.mStr,aDest.mLength,aDestOffset,theLength);
aDest.mLength-=theLength;
}
else Truncate(aDest,aDestOffset,anAgent);
}//if
}
@ -343,28 +431,28 @@ void nsStr::CompressSet(nsStr& aDest,const char* aSet,PRUint32 aChar,PRBool aEli
**************************************************************/
PRInt32 nsStr::FindSubstr(const nsStr& aDest,const nsStr& aTarget, PRBool /*aIgnoreCase*/,PRUint32 anOffset) {
PRInt32 nsStr::FindSubstr(const nsStr& aDest,const nsStr& aTarget, PRBool aIgnoreCase,PRUint32 anOffset) {
PRInt32 index=anOffset-1;
PRInt32 theMax=aDest.mLength-aTarget.mLength;
if((aDest.mLength>0) && (aTarget.mLength>0)){
PRInt32 theNewStartPos=-1;
PRUnichar theFirstTargetChar=nsStr::GetCharAt(aTarget,0);
PRUnichar theLastTargetChar=nsStr::GetCharAt(aTarget,aTarget.mLength-1);
PRUnichar theFirstTargetChar=GetCharAt(aTarget,0);
PRUnichar theLastTargetChar=GetCharAt(aTarget,aTarget.mLength-1);
PRInt32 theTargetMax=aTarget.mLength;
while(++index<=theMax) {
PRInt32 theSubIndex=-1;
PRBool matches=PR_TRUE;
while((++theSubIndex<theTargetMax) && (matches)){
PRUnichar theChar=nsStr::GetCharAt(aDest,index+theSubIndex);
PRUnichar theChar=GetCharAt(aDest,index+theSubIndex);
if(theSubIndex>0) {
if(theFirstTargetChar==theChar){
PRUnichar theDestJumpChar=nsStr::GetCharAt(aDest,index+theTargetMax);
PRUnichar theDestJumpChar=GetCharAt(aDest,index+theTargetMax);
if(theDestJumpChar==theLastTargetChar) {
theNewStartPos=index; //this lets us jump ahead during our search where possible.
}//if
}//if
}//if
PRUnichar theTargetChar=nsStr::GetCharAt(aTarget,theSubIndex);
PRUnichar theTargetChar=GetCharAt(aTarget,theSubIndex);
matches=PRBool(theChar==theTargetChar);
}
if(matches)
@ -384,8 +472,8 @@ PRInt32 nsStr::FindSubstr(const nsStr& aDest,const nsStr& aTarget, PRBool /*aIgn
* @param
* @return
*/
PRInt32 nsStr::FindChar(const nsStr& aDest, PRUnichar aChar, PRBool aIgnoreCase,PRUint32 anOffset) {
PRInt32 result=gFindChars[aDest.mMultibyte](aDest.mStr,aDest.mLength,anOffset,aChar,aIgnoreCase);
PRInt32 nsStr::FindChar(const nsStr& aDest,const PRUnichar aChar, PRBool aIgnoreCase,PRUint32 anOffset) {
PRInt32 result=gFindChars[aDest.mMultibyte](aDest.mStr,aDest.mLength,0,aChar,aIgnoreCase);
return result;
}
@ -415,12 +503,12 @@ PRInt32 nsStr::FindCharInSet(const nsStr& aDest,const nsStr& aSet,PRBool aIgnore
**************************************************************/
PRInt32 nsStr::RFindSubstr(const nsStr& aDest,const nsStr& aTarget, PRBool /*aIgnoreCase*/,PRUint32 anOffset) {
PRInt32 nsStr::RFindSubstr(const nsStr& aDest,const nsStr& aTarget, PRBool aIgnoreCase,PRUint32 anOffset) {
PRInt32 index=(anOffset ? anOffset : aDest.mLength-aTarget.mLength+1);
if((aDest.mLength>0) && (aTarget.mLength>0)){
PRInt32 theNewStartPos=-1;
PRUnichar theFirstTargetChar=nsStr::GetCharAt(aTarget,0);
PRUnichar theLastTargetChar=nsStr::GetCharAt(aTarget,aTarget.mLength-1);
PRUnichar theFirstTargetChar=GetCharAt(aTarget,0);
PRUnichar theLastTargetChar=GetCharAt(aTarget,aTarget.mLength-1);
PRInt32 theTargetMax=aTarget.mLength;
while(index--) {
@ -429,16 +517,16 @@ PRInt32 nsStr::RFindSubstr(const nsStr& aDest,const nsStr& aTarget, PRBool /*aIg
if(anOffset+aTarget.mLength<=aDest.mLength) {
while((++theSubIndex<theTargetMax) && (matches)){
PRUnichar theChar=nsStr::GetCharAt(aDest,index+theSubIndex);
PRUnichar theChar=GetCharAt(aDest,index+theSubIndex);
if(theSubIndex>0) {
if(theFirstTargetChar==theChar){
PRUnichar theDestJumpChar=nsStr::GetCharAt(aDest,index+theTargetMax);
PRUnichar theDestJumpChar=GetCharAt(aDest,index+theTargetMax);
if(theDestJumpChar==theLastTargetChar) {
theNewStartPos=index; //this lets us jump ahead during our search where possible.
}//if
}//if
}//if
PRUnichar theTargetChar=nsStr::GetCharAt(aTarget,theSubIndex);
PRUnichar theTargetChar=GetCharAt(aTarget,theSubIndex);
matches=PRBool(theChar==theTargetChar);
} //while
} //if
@ -459,8 +547,8 @@ PRInt32 nsStr::RFindSubstr(const nsStr& aDest,const nsStr& aTarget, PRBool /*aIg
* @param
* @return
*/
PRInt32 nsStr::RFindChar(const nsStr& aDest,PRUnichar aChar, PRBool aIgnoreCase,PRUint32 anOffset) {
PRInt32 result=gRFindChars[aDest.mMultibyte](aDest.mStr,aDest.mLength,anOffset,aChar,aIgnoreCase);
PRInt32 nsStr::RFindChar(const nsStr& aDest,const PRUnichar aChar, PRBool aIgnoreCase,PRUint32 anOffset) {
PRInt32 result=gRFindChars[aDest.mMultibyte](aDest.mStr,aDest.mLength,0,aChar,aIgnoreCase);
return result;
}
@ -472,11 +560,11 @@ PRInt32 nsStr::RFindChar(const nsStr& aDest,PRUnichar aChar, PRBool aIgnoreCase,
* @return
*/
PRInt32 nsStr::RFindCharInSet(const nsStr& aDest,const nsStr& aSet,PRBool aIgnoreCase,PRUint32 anOffset) {
PRInt32 offset=aDest.mLength-anOffset;
PRUint32 offset=aDest.mLength-anOffset;
PRInt32 thePos;
while(--offset>=0) {
PRUnichar theChar=GetCharAt(aDest,PRUint32(offset));
PRUnichar theChar=GetCharAt(aDest,offset);
thePos=gRFindChars[aSet.mMultibyte](aSet.mStr,aSet.mLength,0,theChar,aIgnoreCase);
if(kNotFound!=thePos)
return offset;
@ -491,7 +579,7 @@ PRInt32 nsStr::RFindCharInSet(const nsStr& aDest,const nsStr& aSet,PRBool aIgnor
* @param
* @return aDest<aSource=-1;aDest==aSource==0;aDest>aSource=1
*/
PRInt32 nsStr::Compare(const nsStr& aDest,const nsStr& aSource,PRInt32 /*aCount*/,PRBool aIgnoreCase) {
PRInt32 nsStr::Compare(const nsStr& aDest,const nsStr& aSource,PRInt32 aCount,PRBool aIgnoreCase) {
int minlen=(aSource.mLength<aDest.mLength) ? aSource.mLength : aDest.mLength;
if(0==minlen) {

Просмотреть файл

@ -27,8 +27,6 @@
We chose the option B for performance reasons.
2 Our internal buffer always holds capacity+1 bytes.
3. Note that our internal format for this class makes our memory
layout compatible with BStrings.
The nsStr struct is a simple structure (no methods) that contains
the necessary info to be described as a string. This simple struct
@ -44,8 +42,7 @@
#ifndef _nsStr
#define _nsStr
#include "prtypes.h"
#include "nscore.h"
#include "nsCore.h"
//----------------------------------------------------------------------------------------
@ -53,34 +50,6 @@ enum eCharSize {eOneByte=0,eTwoByte=1};
#define kDefaultCharSize eTwoByte
union UStrPtr {
char* mCharBuf;
PRUnichar* mUnicharBuf;
};
/**************************************************************************
Here comes the nsBufDescriptor class which describes buffer properties.
**************************************************************************/
struct nsBufDescriptor {
nsBufDescriptor(char* aBuffer,PRUint32 aBufferSize,eCharSize aCharSize,PRBool aOwnsBuffer) {
mStr=aBuffer;
mMultibyte=aCharSize;
mCapacity=(aBufferSize>>mMultibyte)-1;
mOwnsBuffer=aOwnsBuffer;
}
PRUint32 mCapacity;
PRBool mOwnsBuffer;
eCharSize mMultibyte;
// UStrPtr mStr;
union {
char* mStr;
PRUnichar* mUStr;
};
};
class nsIMemoryAgent;
//----------------------------------------------------------------------------------------
@ -97,6 +66,15 @@ struct nsStr {
*/
static void Initialize(nsStr& aDest,eCharSize aCharSize);
/**
* This method initializes an nsStr for use
*
* @update gess 01/04/99
* @param aString is the nsStr to be initialized
* @param aCharSize tells us the requested char size (1 or 2 bytes)
*/
static void Initialize(nsStr& aDest,char* aCString,PRUint32 aCapacity,PRUint32 aLength,eCharSize aCharSize,PRBool aOwnsBuffer);
/**
* This method destroys the given nsStr, and *MAY*
* deallocate it's memory depending on the setting
@ -166,7 +144,7 @@ struct nsStr {
* @param aCount tells us the (max) # of chars to delete
* @param anAgent is the allocator to be used for alloc/free operations
*/
static void Delete(nsStr& aDest,PRUint32 aDestOffset,PRInt32 aCount,nsIMemoryAgent* anAgent=0);
static void Delete(nsStr& aDest,PRUint32 aDestOffset,PRUint32 aCount,nsIMemoryAgent* anAgent=0);
/**
* This method is used to truncate the given string.
@ -254,21 +232,20 @@ struct nsStr {
static PRInt32 RFindChar(const nsStr& aDest,PRUnichar aChar, PRBool aIgnoreCase,PRUint32 anOffset);
static PRInt32 RFindCharInSet(const nsStr& aDest,const nsStr& aSet,PRBool aIgnoreCase,PRUint32 anOffset);
/**
* This method is used to access a given char in the given string
*
* @update gess 01/04/99
* @param aDest is the nsStr to be appended to
* @param anIndex tells us where in dest to get the char from
* @return the given char, or 0 if anIndex is out of range
*/
static PRUnichar GetCharAt(const nsStr& aDest,PRUint32 anIndex);
PRUint32 mLength : 30;
eCharSize mMultibyte : 2;
#ifdef NS_DEBUG
PRUint32 mLength;
eCharSize mMultibyte;
PRUint32 mCapacity;
PRUint32 mOwnsBuffer;
PRUint32 mUnused;
#else
PRUint32 mLength: 30;
eCharSize mMultibyte: 2;
PRUint32 mCapacity: 30;
PRUint32 mOwnsBuffer: 1;
PRUint32 mUnused: 1;
PRUint32 mOwnsBuffer: 1;
PRUint32 mUnused: 1;
#endif
union {
char* mStr;
PRUnichar* mUStr;
@ -307,6 +284,21 @@ inline void AddNullTerminator(nsStr& aDest) {
else aDest.mStr[aDest.mLength]=0;
}
/**
* This method is used to access a given char in the given string
*
* @update gess 01/04/99
* @param aDest is the nsStr to be appended to
* @param anIndex tells us where in dest to get the char from
* @return the given char, or 0 if anIndex is out of range
*/
inline PRUnichar GetCharAt(const nsStr& aDest,PRUint32 anIndex){
if(anIndex<aDest.mLength) {
return (eTwoByte==aDest.mMultibyte) ? aDest.mUStr[anIndex] : aDest.mStr[anIndex];
}//if
return 0;
}
//----------------------------------------------------------------------------------------
class nsIMemoryAgent {
@ -317,25 +309,18 @@ public:
};
class nsMemoryAgent : public nsIMemoryAgent {
enum eDelta{eGrowthDelta=8};
protected:
enum eDelta{eDefaultSize=16};
public:
virtual PRBool Alloc(nsStr& aDest,PRInt32 aCount) {
//we're given the acount value in charunits; we have to scale up by the charsize.
PRInt32 theNewCapacity;
if (aDest.mCapacity > 64) {
// When the string starts getting large, double the capacity as we grow.
theNewCapacity = aDest.mCapacity * 2;
if (theNewCapacity < aCount) {
theNewCapacity = aDest.mCapacity + aCount;
}
} else {
// When the string is small, keep it's capacity a multiple of kGrowthDelta
PRInt32 unitDelta=(aCount/eGrowthDelta)+1;
theNewCapacity=unitDelta*eGrowthDelta;
//we're given the acount value in charunits; now scale up to next multiple.
PRInt32 theNewCapacity=eDefaultSize;
while(theNewCapacity<aCount){
theNewCapacity<<=1;
}
aDest.mCapacity=theNewCapacity++;
size_t theSize=(theNewCapacity<<aDest.mMultibyte);
aDest.mStr=new char[theSize];
@ -362,6 +347,5 @@ public:
};
#endif

Просмотреть файл

@ -31,9 +31,101 @@
#include "nsStr.h"
#include "bufferRoutines.h"
#include "stdio.h" //only used for printf
#include "nsDeque.h"
#include "nsCRT.h"
static const char* kFoolMsg = "Error: Some fool overwrote the shared buffer.";
//----------------------------------------------------------------------------------------
// The following is a memory agent who knows how to recycled (pool) freed memory...
//----------------------------------------------------------------------------------------
/**************************************************************
Define the char* (pooled) deallocator class...
**************************************************************/
class nsBufferDeallocator: public nsDequeFunctor{
public:
virtual void* operator()(void* anObject) {
char* aCString= (char*)anObject;
delete [] aCString;
return 0;
}
};
/**
*
* @update gess10/30/98
* @param
* @return
*/
class nsPoolingMemoryAgent : public nsMemoryAgent{
public:
nsPoolingMemoryAgent() {
memset(mPools,0,sizeof(mPools));
}
~nsPoolingMemoryAgent() {
nsBufferDeallocator theDeallocator;
int i=0;
for(i=0;i<10;i++){
if(mPools[i]){
mPools[i]->ForEach(theDeallocator); //now delete the buffers
}
delete mPools[i];
mPools[i]=0;
}
}
virtual PRBool Alloc(nsStr& aDest,PRInt32 aCount) {
//we're given the acount value in charunits; we have to scale up by the charsize.
int theShift=4;
PRInt32 theNewCapacity=eDefaultSize;
while(theNewCapacity<aCount){
theNewCapacity<<=1;
theShift++;
}
aDest.mCapacity=theNewCapacity++;
theShift=(theShift<<aDest.mMultibyte)-4;
if((theShift<12) && (mPools[theShift])){
aDest.mStr=(char*)mPools[theShift]->Pop();
}
if(!aDest.mStr) {
//we're given the acount value in charunits; we have to scale up by the charsize.
size_t theSize=(theNewCapacity<<aDest.mMultibyte);
aDest.mStr=new char[theSize];
}
aDest.mOwnsBuffer=1;
return PR_TRUE;
}
virtual PRBool Free(nsStr& aDest){
if(aDest.mStr){
if(aDest.mOwnsBuffer){
int theShift=1;
unsigned int theValue=1;
while((theValue<<=1)<aDest.mCapacity){
theShift++;
}
theShift-=4;
if(theShift<12){
if(!mPools[theShift]){
mPools[theShift]=new nsDeque(0);
}
mPools[theShift]->Push(aDest.mStr);
}
else delete [] aDest.mStr; //it's too big. Just delete it.
}
aDest.mStr=0;
aDest.mOwnsBuffer=0;
return PR_TRUE;
}
return PR_FALSE;
}
nsDeque* mPools[16];
};
//----------------------------------------------------------------------------------------
@ -80,14 +172,25 @@ void nsStr::Initialize(nsStr& aDest,eCharSize aCharSize) {
* @param
* @return
*/
nsIMemoryAgent* GetDefaultAgent(void){
static nsIMemoryAgent* gDefaultAgent=0;
if(!gDefaultAgent)
gDefaultAgent=new nsMemoryAgent();
NS_ASSERTION(gDefaultAgent,"You MUST always have an allocator!");
void nsStr::Initialize(nsStr& aDest,char* aCString,PRUint32 aCapacity,PRUint32 aLength,eCharSize aCharSize,PRBool aOwnsBuffer){
aDest.mStr=(aCString) ? aCString : GetSharedEmptyBuffer();
aDest.mLength=aLength;
aDest.mCapacity=aCapacity;
aDest.mMultibyte=aCharSize;
aDest.mOwnsBuffer=aOwnsBuffer;
aDest.mUnused=0;
}
return gDefaultAgent;
/**
*
* @update gess10/30/98
* @param
* @return
*/
nsIMemoryAgent* GetDefaultAgent(void){
// static nsPoolingMemoryAgent gDefaultAgent;
static nsMemoryAgent gDefaultAgent;
return (nsIMemoryAgent*)&gDefaultAgent;
}
/**
@ -110,20 +213,6 @@ void nsStr::Destroy(nsStr& aDest,nsIMemoryAgent* anAgent) {
}
}
/**
*
* @update gess11/12/98
* @param
* @return
*/
PRUnichar nsStr::GetCharAt(const nsStr& aDest,PRUint32 anIndex) {
PRUnichar result=0;
if((anIndex>=0) && (anIndex<aDest.mLength)) {
result=(eTwoByte==aDest.mMultibyte) ? aDest.mUStr[anIndex] : aDest.mStr[anIndex];
}//if
return result;
}
/**
* This method gets called when the internal buffer needs
@ -155,8 +244,8 @@ void nsStr::GrowCapacity(nsStr& aDest,PRUint32 aNewLength,nsIMemoryAgent* anAgen
nsIMemoryAgent* theAgent=(anAgent) ? anAgent : GetDefaultAgent();
EnsureCapacity(theTempStr,aNewLength,theAgent);
if(0<aDest.mLength) {
Append(theTempStr,aDest,0,aDest.mLength,anAgent);
if(aDest.mLength) {
Append(theTempStr,aDest,0,aDest.mLength,theAgent);
}
theAgent->Free(aDest);
aDest.mStr = theTempStr.mStr;
@ -188,8 +277,7 @@ void nsStr::Assign(nsStr& aDest,const nsStr& aSource,PRUint32 anOffset,PRInt32 a
* @aCount is the number of bytes to be copied
*/
void nsStr::Append(nsStr& aDest,const nsStr& aSource,PRUint32 anOffset,PRInt32 aCount,nsIMemoryAgent* anAgent){
if(anOffset<aSource.mLength-1){
if(anOffset<aSource.mLength) {
PRUint32 theRealLen=(aCount<0) ? aSource.mLength : MinInt(aCount,aSource.mLength);
PRUint32 theLength=(anOffset+theRealLen<aSource.mLength) ? theRealLen : (aSource.mLength-anOffset);
if(0<theLength){
@ -221,30 +309,31 @@ void nsStr::Insert( nsStr& aDest,PRUint32 aDestOffset,const nsStr& aSource,PRUin
// 1. You're inserting chars into an empty string (assign)
// 2. You're inserting onto the end of a string (append)
// 3. You're inserting onto the 1..n-1 pos of a string (the hard case).
if((0<aSource.mLength) && (aDestOffset<aDest.mLength-1)){
if(0<aSource.mLength){
ToRange(aDestOffset,0,aDest.mLength);
if(aDest.mLength){
if(aDestOffset<aDest.mLength){
if(aSrcOffset<aSource.mLength-1) {
PRInt32 theRealLen=(aCount<0) ? aSource.mLength : MinInt(aCount,aSource.mLength);
PRInt32 theLength=(aSrcOffset+theRealLen<aSource.mLength) ? theRealLen : (aSource.mLength-aSrcOffset);
if(aSrcOffset<aSource.mLength) {
//here's the only new case we have to handle.
//chars are really being inserted into our buffer...
GrowCapacity(aDest,aDest.mLength+theLength,anAgent);
ToRange(aSrcOffset,0,aSource.mLength-1);
PRInt32 theRealLen=(aCount<0) ? aSource.mLength : MinInt(aCount,aSource.mLength);
PRInt32 theLength=(aSrcOffset+theRealLen<aSource.mLength) ? theRealLen : (aSource.mLength-aSrcOffset);
//shift the chars right by theDelta...
(*gShiftChars[aDest.mMultibyte][PR_TRUE])(aDest.mStr,aDest.mLength,aDestOffset,theLength);
if(aSrcOffset<aSource.mLength) {
//here's the only new case we have to handle.
//chars are really being inserted into our buffer...
GrowCapacity(aDest,aDest.mLength+theLength,anAgent);
//shift the chars right by theDelta...
(*gShiftChars[aDest.mMultibyte][PR_TRUE])(aDest.mStr,aDest.mLength,aDestOffset,theLength);
//now insert new chars, starting at offset
(*gCopyChars[aSource.mMultibyte][aDest.mMultibyte])(aDest.mStr,aDestOffset,aSource.mStr,aSrcOffset,theLength);
//now insert new chars, starting at offset
(*gCopyChars[aSource.mMultibyte][aDest.mMultibyte])(aDest.mStr,aDestOffset,aSource.mStr,aSrcOffset,theLength);
//finally, make sure to update the string length...
aDest.mLength+=theLength;
//finally, make sure to update the string length...
aDest.mLength+=theLength;
}//if
//else nothing to do!
}
}//if
//else nothing to do!
}
else Append(aDest,aSource,0,aCount,anAgent);
}
@ -260,22 +349,21 @@ void nsStr::Insert( nsStr& aDest,PRUint32 aDestOffset,const nsStr& aSource,PRUin
* @param aDestOffset is where in aDest deletion is to occur
* @param aCount is the number of chars to be deleted in aDest
*/
void nsStr::Delete(nsStr& aDest,PRUint32 aDestOffset,PRInt32 aCount,nsIMemoryAgent* anAgent){
if(0<aCount){
if(aDestOffset<aDest.mLength){
void nsStr::Delete(nsStr& aDest,PRUint32 aDestOffset,PRUint32 aCount,nsIMemoryAgent* anAgent){
PRInt32 theDelta=aDest.mLength-aDestOffset;
PRInt32 theLength=(theDelta<aCount) ? theDelta : aCount;
if(aDestOffset<aDest.mLength){
if(aDestOffset+theLength<aDest.mLength) {
PRUint32 theDelta=aDest.mLength-aDestOffset;
PRUint32 theLength=(theDelta<aCount) ? theDelta : aCount;
//if you're here, it means we're cutting chars out of the middle of the string...
//so shift the chars left by theLength...
(*gShiftChars[aDest.mMultibyte][PR_FALSE])(aDest.mStr,aDest.mLength,aDestOffset,theLength);
aDest.mLength-=theLength;
}
else Truncate(aDest,aDestOffset,anAgent);
}//if
if(aDestOffset+theLength<aDest.mLength) {
//if you're here, it means we're cutting chars out of the middle of the string...
//so shift the chars left by theLength...
(*gShiftChars[aDest.mMultibyte][PR_FALSE])(aDest.mStr,aDest.mLength,aDestOffset,theLength);
aDest.mLength-=theLength;
}
else Truncate(aDest,aDestOffset,anAgent);
}//if
}
@ -343,28 +431,28 @@ void nsStr::CompressSet(nsStr& aDest,const char* aSet,PRUint32 aChar,PRBool aEli
**************************************************************/
PRInt32 nsStr::FindSubstr(const nsStr& aDest,const nsStr& aTarget, PRBool /*aIgnoreCase*/,PRUint32 anOffset) {
PRInt32 nsStr::FindSubstr(const nsStr& aDest,const nsStr& aTarget, PRBool aIgnoreCase,PRUint32 anOffset) {
PRInt32 index=anOffset-1;
PRInt32 theMax=aDest.mLength-aTarget.mLength;
if((aDest.mLength>0) && (aTarget.mLength>0)){
PRInt32 theNewStartPos=-1;
PRUnichar theFirstTargetChar=nsStr::GetCharAt(aTarget,0);
PRUnichar theLastTargetChar=nsStr::GetCharAt(aTarget,aTarget.mLength-1);
PRUnichar theFirstTargetChar=GetCharAt(aTarget,0);
PRUnichar theLastTargetChar=GetCharAt(aTarget,aTarget.mLength-1);
PRInt32 theTargetMax=aTarget.mLength;
while(++index<=theMax) {
PRInt32 theSubIndex=-1;
PRBool matches=PR_TRUE;
while((++theSubIndex<theTargetMax) && (matches)){
PRUnichar theChar=nsStr::GetCharAt(aDest,index+theSubIndex);
PRUnichar theChar=GetCharAt(aDest,index+theSubIndex);
if(theSubIndex>0) {
if(theFirstTargetChar==theChar){
PRUnichar theDestJumpChar=nsStr::GetCharAt(aDest,index+theTargetMax);
PRUnichar theDestJumpChar=GetCharAt(aDest,index+theTargetMax);
if(theDestJumpChar==theLastTargetChar) {
theNewStartPos=index; //this lets us jump ahead during our search where possible.
}//if
}//if
}//if
PRUnichar theTargetChar=nsStr::GetCharAt(aTarget,theSubIndex);
PRUnichar theTargetChar=GetCharAt(aTarget,theSubIndex);
matches=PRBool(theChar==theTargetChar);
}
if(matches)
@ -384,8 +472,8 @@ PRInt32 nsStr::FindSubstr(const nsStr& aDest,const nsStr& aTarget, PRBool /*aIgn
* @param
* @return
*/
PRInt32 nsStr::FindChar(const nsStr& aDest, PRUnichar aChar, PRBool aIgnoreCase,PRUint32 anOffset) {
PRInt32 result=gFindChars[aDest.mMultibyte](aDest.mStr,aDest.mLength,anOffset,aChar,aIgnoreCase);
PRInt32 nsStr::FindChar(const nsStr& aDest,const PRUnichar aChar, PRBool aIgnoreCase,PRUint32 anOffset) {
PRInt32 result=gFindChars[aDest.mMultibyte](aDest.mStr,aDest.mLength,0,aChar,aIgnoreCase);
return result;
}
@ -415,12 +503,12 @@ PRInt32 nsStr::FindCharInSet(const nsStr& aDest,const nsStr& aSet,PRBool aIgnore
**************************************************************/
PRInt32 nsStr::RFindSubstr(const nsStr& aDest,const nsStr& aTarget, PRBool /*aIgnoreCase*/,PRUint32 anOffset) {
PRInt32 nsStr::RFindSubstr(const nsStr& aDest,const nsStr& aTarget, PRBool aIgnoreCase,PRUint32 anOffset) {
PRInt32 index=(anOffset ? anOffset : aDest.mLength-aTarget.mLength+1);
if((aDest.mLength>0) && (aTarget.mLength>0)){
PRInt32 theNewStartPos=-1;
PRUnichar theFirstTargetChar=nsStr::GetCharAt(aTarget,0);
PRUnichar theLastTargetChar=nsStr::GetCharAt(aTarget,aTarget.mLength-1);
PRUnichar theFirstTargetChar=GetCharAt(aTarget,0);
PRUnichar theLastTargetChar=GetCharAt(aTarget,aTarget.mLength-1);
PRInt32 theTargetMax=aTarget.mLength;
while(index--) {
@ -429,16 +517,16 @@ PRInt32 nsStr::RFindSubstr(const nsStr& aDest,const nsStr& aTarget, PRBool /*aIg
if(anOffset+aTarget.mLength<=aDest.mLength) {
while((++theSubIndex<theTargetMax) && (matches)){
PRUnichar theChar=nsStr::GetCharAt(aDest,index+theSubIndex);
PRUnichar theChar=GetCharAt(aDest,index+theSubIndex);
if(theSubIndex>0) {
if(theFirstTargetChar==theChar){
PRUnichar theDestJumpChar=nsStr::GetCharAt(aDest,index+theTargetMax);
PRUnichar theDestJumpChar=GetCharAt(aDest,index+theTargetMax);
if(theDestJumpChar==theLastTargetChar) {
theNewStartPos=index; //this lets us jump ahead during our search where possible.
}//if
}//if
}//if
PRUnichar theTargetChar=nsStr::GetCharAt(aTarget,theSubIndex);
PRUnichar theTargetChar=GetCharAt(aTarget,theSubIndex);
matches=PRBool(theChar==theTargetChar);
} //while
} //if
@ -459,8 +547,8 @@ PRInt32 nsStr::RFindSubstr(const nsStr& aDest,const nsStr& aTarget, PRBool /*aIg
* @param
* @return
*/
PRInt32 nsStr::RFindChar(const nsStr& aDest,PRUnichar aChar, PRBool aIgnoreCase,PRUint32 anOffset) {
PRInt32 result=gRFindChars[aDest.mMultibyte](aDest.mStr,aDest.mLength,anOffset,aChar,aIgnoreCase);
PRInt32 nsStr::RFindChar(const nsStr& aDest,const PRUnichar aChar, PRBool aIgnoreCase,PRUint32 anOffset) {
PRInt32 result=gRFindChars[aDest.mMultibyte](aDest.mStr,aDest.mLength,0,aChar,aIgnoreCase);
return result;
}
@ -472,11 +560,11 @@ PRInt32 nsStr::RFindChar(const nsStr& aDest,PRUnichar aChar, PRBool aIgnoreCase,
* @return
*/
PRInt32 nsStr::RFindCharInSet(const nsStr& aDest,const nsStr& aSet,PRBool aIgnoreCase,PRUint32 anOffset) {
PRInt32 offset=aDest.mLength-anOffset;
PRUint32 offset=aDest.mLength-anOffset;
PRInt32 thePos;
while(--offset>=0) {
PRUnichar theChar=GetCharAt(aDest,PRUint32(offset));
PRUnichar theChar=GetCharAt(aDest,offset);
thePos=gRFindChars[aSet.mMultibyte](aSet.mStr,aSet.mLength,0,theChar,aIgnoreCase);
if(kNotFound!=thePos)
return offset;
@ -491,7 +579,7 @@ PRInt32 nsStr::RFindCharInSet(const nsStr& aDest,const nsStr& aSet,PRBool aIgnor
* @param
* @return aDest<aSource=-1;aDest==aSource==0;aDest>aSource=1
*/
PRInt32 nsStr::Compare(const nsStr& aDest,const nsStr& aSource,PRInt32 /*aCount*/,PRBool aIgnoreCase) {
PRInt32 nsStr::Compare(const nsStr& aDest,const nsStr& aSource,PRInt32 aCount,PRBool aIgnoreCase) {
int minlen=(aSource.mLength<aDest.mLength) ? aSource.mLength : aDest.mLength;
if(0==minlen) {

Просмотреть файл

@ -27,8 +27,6 @@
We chose the option B for performance reasons.
2 Our internal buffer always holds capacity+1 bytes.
3. Note that our internal format for this class makes our memory
layout compatible with BStrings.
The nsStr struct is a simple structure (no methods) that contains
the necessary info to be described as a string. This simple struct
@ -44,8 +42,7 @@
#ifndef _nsStr
#define _nsStr
#include "prtypes.h"
#include "nscore.h"
#include "nsCore.h"
//----------------------------------------------------------------------------------------
@ -53,34 +50,6 @@ enum eCharSize {eOneByte=0,eTwoByte=1};
#define kDefaultCharSize eTwoByte
union UStrPtr {
char* mCharBuf;
PRUnichar* mUnicharBuf;
};
/**************************************************************************
Here comes the nsBufDescriptor class which describes buffer properties.
**************************************************************************/
struct nsBufDescriptor {
nsBufDescriptor(char* aBuffer,PRUint32 aBufferSize,eCharSize aCharSize,PRBool aOwnsBuffer) {
mStr=aBuffer;
mMultibyte=aCharSize;
mCapacity=(aBufferSize>>mMultibyte)-1;
mOwnsBuffer=aOwnsBuffer;
}
PRUint32 mCapacity;
PRBool mOwnsBuffer;
eCharSize mMultibyte;
// UStrPtr mStr;
union {
char* mStr;
PRUnichar* mUStr;
};
};
class nsIMemoryAgent;
//----------------------------------------------------------------------------------------
@ -97,6 +66,15 @@ struct nsStr {
*/
static void Initialize(nsStr& aDest,eCharSize aCharSize);
/**
* This method initializes an nsStr for use
*
* @update gess 01/04/99
* @param aString is the nsStr to be initialized
* @param aCharSize tells us the requested char size (1 or 2 bytes)
*/
static void Initialize(nsStr& aDest,char* aCString,PRUint32 aCapacity,PRUint32 aLength,eCharSize aCharSize,PRBool aOwnsBuffer);
/**
* This method destroys the given nsStr, and *MAY*
* deallocate it's memory depending on the setting
@ -166,7 +144,7 @@ struct nsStr {
* @param aCount tells us the (max) # of chars to delete
* @param anAgent is the allocator to be used for alloc/free operations
*/
static void Delete(nsStr& aDest,PRUint32 aDestOffset,PRInt32 aCount,nsIMemoryAgent* anAgent=0);
static void Delete(nsStr& aDest,PRUint32 aDestOffset,PRUint32 aCount,nsIMemoryAgent* anAgent=0);
/**
* This method is used to truncate the given string.
@ -254,21 +232,20 @@ struct nsStr {
static PRInt32 RFindChar(const nsStr& aDest,PRUnichar aChar, PRBool aIgnoreCase,PRUint32 anOffset);
static PRInt32 RFindCharInSet(const nsStr& aDest,const nsStr& aSet,PRBool aIgnoreCase,PRUint32 anOffset);
/**
* This method is used to access a given char in the given string
*
* @update gess 01/04/99
* @param aDest is the nsStr to be appended to
* @param anIndex tells us where in dest to get the char from
* @return the given char, or 0 if anIndex is out of range
*/
static PRUnichar GetCharAt(const nsStr& aDest,PRUint32 anIndex);
PRUint32 mLength : 30;
eCharSize mMultibyte : 2;
#ifdef NS_DEBUG
PRUint32 mLength;
eCharSize mMultibyte;
PRUint32 mCapacity;
PRUint32 mOwnsBuffer;
PRUint32 mUnused;
#else
PRUint32 mLength: 30;
eCharSize mMultibyte: 2;
PRUint32 mCapacity: 30;
PRUint32 mOwnsBuffer: 1;
PRUint32 mUnused: 1;
PRUint32 mOwnsBuffer: 1;
PRUint32 mUnused: 1;
#endif
union {
char* mStr;
PRUnichar* mUStr;
@ -307,6 +284,21 @@ inline void AddNullTerminator(nsStr& aDest) {
else aDest.mStr[aDest.mLength]=0;
}
/**
* This method is used to access a given char in the given string
*
* @update gess 01/04/99
* @param aDest is the nsStr to be appended to
* @param anIndex tells us where in dest to get the char from
* @return the given char, or 0 if anIndex is out of range
*/
inline PRUnichar GetCharAt(const nsStr& aDest,PRUint32 anIndex){
if(anIndex<aDest.mLength) {
return (eTwoByte==aDest.mMultibyte) ? aDest.mUStr[anIndex] : aDest.mStr[anIndex];
}//if
return 0;
}
//----------------------------------------------------------------------------------------
class nsIMemoryAgent {
@ -317,25 +309,18 @@ public:
};
class nsMemoryAgent : public nsIMemoryAgent {
enum eDelta{eGrowthDelta=8};
protected:
enum eDelta{eDefaultSize=16};
public:
virtual PRBool Alloc(nsStr& aDest,PRInt32 aCount) {
//we're given the acount value in charunits; we have to scale up by the charsize.
PRInt32 theNewCapacity;
if (aDest.mCapacity > 64) {
// When the string starts getting large, double the capacity as we grow.
theNewCapacity = aDest.mCapacity * 2;
if (theNewCapacity < aCount) {
theNewCapacity = aDest.mCapacity + aCount;
}
} else {
// When the string is small, keep it's capacity a multiple of kGrowthDelta
PRInt32 unitDelta=(aCount/eGrowthDelta)+1;
theNewCapacity=unitDelta*eGrowthDelta;
//we're given the acount value in charunits; now scale up to next multiple.
PRInt32 theNewCapacity=eDefaultSize;
while(theNewCapacity<aCount){
theNewCapacity<<=1;
}
aDest.mCapacity=theNewCapacity++;
size_t theSize=(theNewCapacity<<aDest.mMultibyte);
aDest.mStr=new char[theSize];
@ -362,6 +347,5 @@ public:
};
#endif

Просмотреть файл

@ -31,9 +31,101 @@
#include "nsStr.h"
#include "bufferRoutines.h"
#include "stdio.h" //only used for printf
#include "nsDeque.h"
#include "nsCRT.h"
static const char* kFoolMsg = "Error: Some fool overwrote the shared buffer.";
//----------------------------------------------------------------------------------------
// The following is a memory agent who knows how to recycled (pool) freed memory...
//----------------------------------------------------------------------------------------
/**************************************************************
Define the char* (pooled) deallocator class...
**************************************************************/
class nsBufferDeallocator: public nsDequeFunctor{
public:
virtual void* operator()(void* anObject) {
char* aCString= (char*)anObject;
delete [] aCString;
return 0;
}
};
/**
*
* @update gess10/30/98
* @param
* @return
*/
class nsPoolingMemoryAgent : public nsMemoryAgent{
public:
nsPoolingMemoryAgent() {
memset(mPools,0,sizeof(mPools));
}
~nsPoolingMemoryAgent() {
nsBufferDeallocator theDeallocator;
int i=0;
for(i=0;i<10;i++){
if(mPools[i]){
mPools[i]->ForEach(theDeallocator); //now delete the buffers
}
delete mPools[i];
mPools[i]=0;
}
}
virtual PRBool Alloc(nsStr& aDest,PRInt32 aCount) {
//we're given the acount value in charunits; we have to scale up by the charsize.
int theShift=4;
PRInt32 theNewCapacity=eDefaultSize;
while(theNewCapacity<aCount){
theNewCapacity<<=1;
theShift++;
}
aDest.mCapacity=theNewCapacity++;
theShift=(theShift<<aDest.mMultibyte)-4;
if((theShift<12) && (mPools[theShift])){
aDest.mStr=(char*)mPools[theShift]->Pop();
}
if(!aDest.mStr) {
//we're given the acount value in charunits; we have to scale up by the charsize.
size_t theSize=(theNewCapacity<<aDest.mMultibyte);
aDest.mStr=new char[theSize];
}
aDest.mOwnsBuffer=1;
return PR_TRUE;
}
virtual PRBool Free(nsStr& aDest){
if(aDest.mStr){
if(aDest.mOwnsBuffer){
int theShift=1;
unsigned int theValue=1;
while((theValue<<=1)<aDest.mCapacity){
theShift++;
}
theShift-=4;
if(theShift<12){
if(!mPools[theShift]){
mPools[theShift]=new nsDeque(0);
}
mPools[theShift]->Push(aDest.mStr);
}
else delete [] aDest.mStr; //it's too big. Just delete it.
}
aDest.mStr=0;
aDest.mOwnsBuffer=0;
return PR_TRUE;
}
return PR_FALSE;
}
nsDeque* mPools[16];
};
//----------------------------------------------------------------------------------------
@ -80,14 +172,25 @@ void nsStr::Initialize(nsStr& aDest,eCharSize aCharSize) {
* @param
* @return
*/
nsIMemoryAgent* GetDefaultAgent(void){
static nsIMemoryAgent* gDefaultAgent=0;
if(!gDefaultAgent)
gDefaultAgent=new nsMemoryAgent();
NS_ASSERTION(gDefaultAgent,"You MUST always have an allocator!");
void nsStr::Initialize(nsStr& aDest,char* aCString,PRUint32 aCapacity,PRUint32 aLength,eCharSize aCharSize,PRBool aOwnsBuffer){
aDest.mStr=(aCString) ? aCString : GetSharedEmptyBuffer();
aDest.mLength=aLength;
aDest.mCapacity=aCapacity;
aDest.mMultibyte=aCharSize;
aDest.mOwnsBuffer=aOwnsBuffer;
aDest.mUnused=0;
}
return gDefaultAgent;
/**
*
* @update gess10/30/98
* @param
* @return
*/
nsIMemoryAgent* GetDefaultAgent(void){
// static nsPoolingMemoryAgent gDefaultAgent;
static nsMemoryAgent gDefaultAgent;
return (nsIMemoryAgent*)&gDefaultAgent;
}
/**
@ -110,20 +213,6 @@ void nsStr::Destroy(nsStr& aDest,nsIMemoryAgent* anAgent) {
}
}
/**
*
* @update gess11/12/98
* @param
* @return
*/
PRUnichar nsStr::GetCharAt(const nsStr& aDest,PRUint32 anIndex) {
PRUnichar result=0;
if((anIndex>=0) && (anIndex<aDest.mLength)) {
result=(eTwoByte==aDest.mMultibyte) ? aDest.mUStr[anIndex] : aDest.mStr[anIndex];
}//if
return result;
}
/**
* This method gets called when the internal buffer needs
@ -155,8 +244,8 @@ void nsStr::GrowCapacity(nsStr& aDest,PRUint32 aNewLength,nsIMemoryAgent* anAgen
nsIMemoryAgent* theAgent=(anAgent) ? anAgent : GetDefaultAgent();
EnsureCapacity(theTempStr,aNewLength,theAgent);
if(0<aDest.mLength) {
Append(theTempStr,aDest,0,aDest.mLength,anAgent);
if(aDest.mLength) {
Append(theTempStr,aDest,0,aDest.mLength,theAgent);
}
theAgent->Free(aDest);
aDest.mStr = theTempStr.mStr;
@ -188,8 +277,7 @@ void nsStr::Assign(nsStr& aDest,const nsStr& aSource,PRUint32 anOffset,PRInt32 a
* @aCount is the number of bytes to be copied
*/
void nsStr::Append(nsStr& aDest,const nsStr& aSource,PRUint32 anOffset,PRInt32 aCount,nsIMemoryAgent* anAgent){
if(anOffset<aSource.mLength-1){
if(anOffset<aSource.mLength) {
PRUint32 theRealLen=(aCount<0) ? aSource.mLength : MinInt(aCount,aSource.mLength);
PRUint32 theLength=(anOffset+theRealLen<aSource.mLength) ? theRealLen : (aSource.mLength-anOffset);
if(0<theLength){
@ -221,30 +309,31 @@ void nsStr::Insert( nsStr& aDest,PRUint32 aDestOffset,const nsStr& aSource,PRUin
// 1. You're inserting chars into an empty string (assign)
// 2. You're inserting onto the end of a string (append)
// 3. You're inserting onto the 1..n-1 pos of a string (the hard case).
if((0<aSource.mLength) && (aDestOffset<aDest.mLength-1)){
if(0<aSource.mLength){
ToRange(aDestOffset,0,aDest.mLength);
if(aDest.mLength){
if(aDestOffset<aDest.mLength){
if(aSrcOffset<aSource.mLength-1) {
PRInt32 theRealLen=(aCount<0) ? aSource.mLength : MinInt(aCount,aSource.mLength);
PRInt32 theLength=(aSrcOffset+theRealLen<aSource.mLength) ? theRealLen : (aSource.mLength-aSrcOffset);
if(aSrcOffset<aSource.mLength) {
//here's the only new case we have to handle.
//chars are really being inserted into our buffer...
GrowCapacity(aDest,aDest.mLength+theLength,anAgent);
ToRange(aSrcOffset,0,aSource.mLength-1);
PRInt32 theRealLen=(aCount<0) ? aSource.mLength : MinInt(aCount,aSource.mLength);
PRInt32 theLength=(aSrcOffset+theRealLen<aSource.mLength) ? theRealLen : (aSource.mLength-aSrcOffset);
//shift the chars right by theDelta...
(*gShiftChars[aDest.mMultibyte][PR_TRUE])(aDest.mStr,aDest.mLength,aDestOffset,theLength);
if(aSrcOffset<aSource.mLength) {
//here's the only new case we have to handle.
//chars are really being inserted into our buffer...
GrowCapacity(aDest,aDest.mLength+theLength,anAgent);
//shift the chars right by theDelta...
(*gShiftChars[aDest.mMultibyte][PR_TRUE])(aDest.mStr,aDest.mLength,aDestOffset,theLength);
//now insert new chars, starting at offset
(*gCopyChars[aSource.mMultibyte][aDest.mMultibyte])(aDest.mStr,aDestOffset,aSource.mStr,aSrcOffset,theLength);
//now insert new chars, starting at offset
(*gCopyChars[aSource.mMultibyte][aDest.mMultibyte])(aDest.mStr,aDestOffset,aSource.mStr,aSrcOffset,theLength);
//finally, make sure to update the string length...
aDest.mLength+=theLength;
//finally, make sure to update the string length...
aDest.mLength+=theLength;
}//if
//else nothing to do!
}
}//if
//else nothing to do!
}
else Append(aDest,aSource,0,aCount,anAgent);
}
@ -260,22 +349,21 @@ void nsStr::Insert( nsStr& aDest,PRUint32 aDestOffset,const nsStr& aSource,PRUin
* @param aDestOffset is where in aDest deletion is to occur
* @param aCount is the number of chars to be deleted in aDest
*/
void nsStr::Delete(nsStr& aDest,PRUint32 aDestOffset,PRInt32 aCount,nsIMemoryAgent* anAgent){
if(0<aCount){
if(aDestOffset<aDest.mLength){
void nsStr::Delete(nsStr& aDest,PRUint32 aDestOffset,PRUint32 aCount,nsIMemoryAgent* anAgent){
PRInt32 theDelta=aDest.mLength-aDestOffset;
PRInt32 theLength=(theDelta<aCount) ? theDelta : aCount;
if(aDestOffset<aDest.mLength){
if(aDestOffset+theLength<aDest.mLength) {
PRUint32 theDelta=aDest.mLength-aDestOffset;
PRUint32 theLength=(theDelta<aCount) ? theDelta : aCount;
//if you're here, it means we're cutting chars out of the middle of the string...
//so shift the chars left by theLength...
(*gShiftChars[aDest.mMultibyte][PR_FALSE])(aDest.mStr,aDest.mLength,aDestOffset,theLength);
aDest.mLength-=theLength;
}
else Truncate(aDest,aDestOffset,anAgent);
}//if
if(aDestOffset+theLength<aDest.mLength) {
//if you're here, it means we're cutting chars out of the middle of the string...
//so shift the chars left by theLength...
(*gShiftChars[aDest.mMultibyte][PR_FALSE])(aDest.mStr,aDest.mLength,aDestOffset,theLength);
aDest.mLength-=theLength;
}
else Truncate(aDest,aDestOffset,anAgent);
}//if
}
@ -343,28 +431,28 @@ void nsStr::CompressSet(nsStr& aDest,const char* aSet,PRUint32 aChar,PRBool aEli
**************************************************************/
PRInt32 nsStr::FindSubstr(const nsStr& aDest,const nsStr& aTarget, PRBool /*aIgnoreCase*/,PRUint32 anOffset) {
PRInt32 nsStr::FindSubstr(const nsStr& aDest,const nsStr& aTarget, PRBool aIgnoreCase,PRUint32 anOffset) {
PRInt32 index=anOffset-1;
PRInt32 theMax=aDest.mLength-aTarget.mLength;
if((aDest.mLength>0) && (aTarget.mLength>0)){
PRInt32 theNewStartPos=-1;
PRUnichar theFirstTargetChar=nsStr::GetCharAt(aTarget,0);
PRUnichar theLastTargetChar=nsStr::GetCharAt(aTarget,aTarget.mLength-1);
PRUnichar theFirstTargetChar=GetCharAt(aTarget,0);
PRUnichar theLastTargetChar=GetCharAt(aTarget,aTarget.mLength-1);
PRInt32 theTargetMax=aTarget.mLength;
while(++index<=theMax) {
PRInt32 theSubIndex=-1;
PRBool matches=PR_TRUE;
while((++theSubIndex<theTargetMax) && (matches)){
PRUnichar theChar=nsStr::GetCharAt(aDest,index+theSubIndex);
PRUnichar theChar=GetCharAt(aDest,index+theSubIndex);
if(theSubIndex>0) {
if(theFirstTargetChar==theChar){
PRUnichar theDestJumpChar=nsStr::GetCharAt(aDest,index+theTargetMax);
PRUnichar theDestJumpChar=GetCharAt(aDest,index+theTargetMax);
if(theDestJumpChar==theLastTargetChar) {
theNewStartPos=index; //this lets us jump ahead during our search where possible.
}//if
}//if
}//if
PRUnichar theTargetChar=nsStr::GetCharAt(aTarget,theSubIndex);
PRUnichar theTargetChar=GetCharAt(aTarget,theSubIndex);
matches=PRBool(theChar==theTargetChar);
}
if(matches)
@ -384,8 +472,8 @@ PRInt32 nsStr::FindSubstr(const nsStr& aDest,const nsStr& aTarget, PRBool /*aIgn
* @param
* @return
*/
PRInt32 nsStr::FindChar(const nsStr& aDest, PRUnichar aChar, PRBool aIgnoreCase,PRUint32 anOffset) {
PRInt32 result=gFindChars[aDest.mMultibyte](aDest.mStr,aDest.mLength,anOffset,aChar,aIgnoreCase);
PRInt32 nsStr::FindChar(const nsStr& aDest,const PRUnichar aChar, PRBool aIgnoreCase,PRUint32 anOffset) {
PRInt32 result=gFindChars[aDest.mMultibyte](aDest.mStr,aDest.mLength,0,aChar,aIgnoreCase);
return result;
}
@ -415,12 +503,12 @@ PRInt32 nsStr::FindCharInSet(const nsStr& aDest,const nsStr& aSet,PRBool aIgnore
**************************************************************/
PRInt32 nsStr::RFindSubstr(const nsStr& aDest,const nsStr& aTarget, PRBool /*aIgnoreCase*/,PRUint32 anOffset) {
PRInt32 nsStr::RFindSubstr(const nsStr& aDest,const nsStr& aTarget, PRBool aIgnoreCase,PRUint32 anOffset) {
PRInt32 index=(anOffset ? anOffset : aDest.mLength-aTarget.mLength+1);
if((aDest.mLength>0) && (aTarget.mLength>0)){
PRInt32 theNewStartPos=-1;
PRUnichar theFirstTargetChar=nsStr::GetCharAt(aTarget,0);
PRUnichar theLastTargetChar=nsStr::GetCharAt(aTarget,aTarget.mLength-1);
PRUnichar theFirstTargetChar=GetCharAt(aTarget,0);
PRUnichar theLastTargetChar=GetCharAt(aTarget,aTarget.mLength-1);
PRInt32 theTargetMax=aTarget.mLength;
while(index--) {
@ -429,16 +517,16 @@ PRInt32 nsStr::RFindSubstr(const nsStr& aDest,const nsStr& aTarget, PRBool /*aIg
if(anOffset+aTarget.mLength<=aDest.mLength) {
while((++theSubIndex<theTargetMax) && (matches)){
PRUnichar theChar=nsStr::GetCharAt(aDest,index+theSubIndex);
PRUnichar theChar=GetCharAt(aDest,index+theSubIndex);
if(theSubIndex>0) {
if(theFirstTargetChar==theChar){
PRUnichar theDestJumpChar=nsStr::GetCharAt(aDest,index+theTargetMax);
PRUnichar theDestJumpChar=GetCharAt(aDest,index+theTargetMax);
if(theDestJumpChar==theLastTargetChar) {
theNewStartPos=index; //this lets us jump ahead during our search where possible.
}//if
}//if
}//if
PRUnichar theTargetChar=nsStr::GetCharAt(aTarget,theSubIndex);
PRUnichar theTargetChar=GetCharAt(aTarget,theSubIndex);
matches=PRBool(theChar==theTargetChar);
} //while
} //if
@ -459,8 +547,8 @@ PRInt32 nsStr::RFindSubstr(const nsStr& aDest,const nsStr& aTarget, PRBool /*aIg
* @param
* @return
*/
PRInt32 nsStr::RFindChar(const nsStr& aDest,PRUnichar aChar, PRBool aIgnoreCase,PRUint32 anOffset) {
PRInt32 result=gRFindChars[aDest.mMultibyte](aDest.mStr,aDest.mLength,anOffset,aChar,aIgnoreCase);
PRInt32 nsStr::RFindChar(const nsStr& aDest,const PRUnichar aChar, PRBool aIgnoreCase,PRUint32 anOffset) {
PRInt32 result=gRFindChars[aDest.mMultibyte](aDest.mStr,aDest.mLength,0,aChar,aIgnoreCase);
return result;
}
@ -472,11 +560,11 @@ PRInt32 nsStr::RFindChar(const nsStr& aDest,PRUnichar aChar, PRBool aIgnoreCase,
* @return
*/
PRInt32 nsStr::RFindCharInSet(const nsStr& aDest,const nsStr& aSet,PRBool aIgnoreCase,PRUint32 anOffset) {
PRInt32 offset=aDest.mLength-anOffset;
PRUint32 offset=aDest.mLength-anOffset;
PRInt32 thePos;
while(--offset>=0) {
PRUnichar theChar=GetCharAt(aDest,PRUint32(offset));
PRUnichar theChar=GetCharAt(aDest,offset);
thePos=gRFindChars[aSet.mMultibyte](aSet.mStr,aSet.mLength,0,theChar,aIgnoreCase);
if(kNotFound!=thePos)
return offset;
@ -491,7 +579,7 @@ PRInt32 nsStr::RFindCharInSet(const nsStr& aDest,const nsStr& aSet,PRBool aIgnor
* @param
* @return aDest<aSource=-1;aDest==aSource==0;aDest>aSource=1
*/
PRInt32 nsStr::Compare(const nsStr& aDest,const nsStr& aSource,PRInt32 /*aCount*/,PRBool aIgnoreCase) {
PRInt32 nsStr::Compare(const nsStr& aDest,const nsStr& aSource,PRInt32 aCount,PRBool aIgnoreCase) {
int minlen=(aSource.mLength<aDest.mLength) ? aSource.mLength : aDest.mLength;
if(0==minlen) {

Просмотреть файл

@ -27,8 +27,6 @@
We chose the option B for performance reasons.
2 Our internal buffer always holds capacity+1 bytes.
3. Note that our internal format for this class makes our memory
layout compatible with BStrings.
The nsStr struct is a simple structure (no methods) that contains
the necessary info to be described as a string. This simple struct
@ -44,8 +42,7 @@
#ifndef _nsStr
#define _nsStr
#include "prtypes.h"
#include "nscore.h"
#include "nsCore.h"
//----------------------------------------------------------------------------------------
@ -53,34 +50,6 @@ enum eCharSize {eOneByte=0,eTwoByte=1};
#define kDefaultCharSize eTwoByte
union UStrPtr {
char* mCharBuf;
PRUnichar* mUnicharBuf;
};
/**************************************************************************
Here comes the nsBufDescriptor class which describes buffer properties.
**************************************************************************/
struct nsBufDescriptor {
nsBufDescriptor(char* aBuffer,PRUint32 aBufferSize,eCharSize aCharSize,PRBool aOwnsBuffer) {
mStr=aBuffer;
mMultibyte=aCharSize;
mCapacity=(aBufferSize>>mMultibyte)-1;
mOwnsBuffer=aOwnsBuffer;
}
PRUint32 mCapacity;
PRBool mOwnsBuffer;
eCharSize mMultibyte;
// UStrPtr mStr;
union {
char* mStr;
PRUnichar* mUStr;
};
};
class nsIMemoryAgent;
//----------------------------------------------------------------------------------------
@ -97,6 +66,15 @@ struct nsStr {
*/
static void Initialize(nsStr& aDest,eCharSize aCharSize);
/**
* This method initializes an nsStr for use
*
* @update gess 01/04/99
* @param aString is the nsStr to be initialized
* @param aCharSize tells us the requested char size (1 or 2 bytes)
*/
static void Initialize(nsStr& aDest,char* aCString,PRUint32 aCapacity,PRUint32 aLength,eCharSize aCharSize,PRBool aOwnsBuffer);
/**
* This method destroys the given nsStr, and *MAY*
* deallocate it's memory depending on the setting
@ -166,7 +144,7 @@ struct nsStr {
* @param aCount tells us the (max) # of chars to delete
* @param anAgent is the allocator to be used for alloc/free operations
*/
static void Delete(nsStr& aDest,PRUint32 aDestOffset,PRInt32 aCount,nsIMemoryAgent* anAgent=0);
static void Delete(nsStr& aDest,PRUint32 aDestOffset,PRUint32 aCount,nsIMemoryAgent* anAgent=0);
/**
* This method is used to truncate the given string.
@ -254,21 +232,20 @@ struct nsStr {
static PRInt32 RFindChar(const nsStr& aDest,PRUnichar aChar, PRBool aIgnoreCase,PRUint32 anOffset);
static PRInt32 RFindCharInSet(const nsStr& aDest,const nsStr& aSet,PRBool aIgnoreCase,PRUint32 anOffset);
/**
* This method is used to access a given char in the given string
*
* @update gess 01/04/99
* @param aDest is the nsStr to be appended to
* @param anIndex tells us where in dest to get the char from
* @return the given char, or 0 if anIndex is out of range
*/
static PRUnichar GetCharAt(const nsStr& aDest,PRUint32 anIndex);
PRUint32 mLength : 30;
eCharSize mMultibyte : 2;
#ifdef NS_DEBUG
PRUint32 mLength;
eCharSize mMultibyte;
PRUint32 mCapacity;
PRUint32 mOwnsBuffer;
PRUint32 mUnused;
#else
PRUint32 mLength: 30;
eCharSize mMultibyte: 2;
PRUint32 mCapacity: 30;
PRUint32 mOwnsBuffer: 1;
PRUint32 mUnused: 1;
PRUint32 mOwnsBuffer: 1;
PRUint32 mUnused: 1;
#endif
union {
char* mStr;
PRUnichar* mUStr;
@ -307,6 +284,21 @@ inline void AddNullTerminator(nsStr& aDest) {
else aDest.mStr[aDest.mLength]=0;
}
/**
* This method is used to access a given char in the given string
*
* @update gess 01/04/99
* @param aDest is the nsStr to be appended to
* @param anIndex tells us where in dest to get the char from
* @return the given char, or 0 if anIndex is out of range
*/
inline PRUnichar GetCharAt(const nsStr& aDest,PRUint32 anIndex){
if(anIndex<aDest.mLength) {
return (eTwoByte==aDest.mMultibyte) ? aDest.mUStr[anIndex] : aDest.mStr[anIndex];
}//if
return 0;
}
//----------------------------------------------------------------------------------------
class nsIMemoryAgent {
@ -317,25 +309,18 @@ public:
};
class nsMemoryAgent : public nsIMemoryAgent {
enum eDelta{eGrowthDelta=8};
protected:
enum eDelta{eDefaultSize=16};
public:
virtual PRBool Alloc(nsStr& aDest,PRInt32 aCount) {
//we're given the acount value in charunits; we have to scale up by the charsize.
PRInt32 theNewCapacity;
if (aDest.mCapacity > 64) {
// When the string starts getting large, double the capacity as we grow.
theNewCapacity = aDest.mCapacity * 2;
if (theNewCapacity < aCount) {
theNewCapacity = aDest.mCapacity + aCount;
}
} else {
// When the string is small, keep it's capacity a multiple of kGrowthDelta
PRInt32 unitDelta=(aCount/eGrowthDelta)+1;
theNewCapacity=unitDelta*eGrowthDelta;
//we're given the acount value in charunits; now scale up to next multiple.
PRInt32 theNewCapacity=eDefaultSize;
while(theNewCapacity<aCount){
theNewCapacity<<=1;
}
aDest.mCapacity=theNewCapacity++;
size_t theSize=(theNewCapacity<<aDest.mMultibyte);
aDest.mStr=new char[theSize];
@ -362,6 +347,5 @@ public:
};
#endif