mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-10 03:45:46 +00:00
Bug 90545. nsVoidArray and nsSupportsArray cleanup. Patch submitted by rjesup@wgate.com, r=jst, sr=waterson.
This commit is contained in:
parent
a26a6ba8d2
commit
ec45d8212e
@ -87,6 +87,18 @@ interface nsISupportsArray : nsICollection {
|
||||
in voidPtr aData);
|
||||
|
||||
nsISupportsArray clone();
|
||||
|
||||
[notxpcom] boolean MoveElement(in long aFrom,
|
||||
in long aTo);
|
||||
|
||||
[notxpcom] boolean InsertElementsAt(in nsISupportsArray aOther,
|
||||
in unsigned long aIndex);
|
||||
|
||||
[notxpcom] boolean RemoveElementsAt(in unsigned long aIndex,
|
||||
in unsigned long aCount);
|
||||
|
||||
[notxpcom] boolean SizeTo(in long aSize);
|
||||
|
||||
%{C++
|
||||
private:
|
||||
// NS_IMETHOD_(nsISupportsArray&) operator=(const nsISupportsArray& other) = 0;
|
||||
|
@ -27,6 +27,74 @@
|
||||
#include "nsSupportsArrayEnumerator.h"
|
||||
#include "nsIObjectInputStream.h"
|
||||
#include "nsIObjectOutputStream.h"
|
||||
#include <string.h>
|
||||
|
||||
#if DEBUG_SUPPORTSARRAY
|
||||
#define MAXSUPPORTS 20
|
||||
|
||||
class SupportsStats {
|
||||
public:
|
||||
SupportsStats();
|
||||
~SupportsStats();
|
||||
|
||||
};
|
||||
|
||||
static int sizesUsed; // number of the elements of the arrays used
|
||||
static int sizesAlloced[MAXSUPPORTS]; // sizes of the allocations. sorted
|
||||
static int NumberOfSize[MAXSUPPORTS]; // number of this allocation size (1 per array)
|
||||
static int AllocedOfSize[MAXSUPPORTS]; // number of this allocation size (each size for array used)
|
||||
static int GrowInPlace[MAXSUPPORTS];
|
||||
|
||||
// these are per-allocation
|
||||
static int MaxElements[3000];
|
||||
|
||||
// very evil
|
||||
#define ADD_TO_STATS(x,size) do {int i; for (i = 0; i < sizesUsed; i++) \
|
||||
{ \
|
||||
if (sizesAlloced[i] == (int)(size)) \
|
||||
{ ((x)[i])++; break; } \
|
||||
} \
|
||||
if (i >= sizesUsed && sizesUsed < MAXSUPPORTS) \
|
||||
{ sizesAlloced[sizesUsed] = (size); \
|
||||
((x)[sizesUsed++])++; break; \
|
||||
} \
|
||||
} while (0);
|
||||
|
||||
#define SUB_FROM_STATS(x,size) do {int i; for (i = 0; i < sizesUsed; i++) \
|
||||
{ \
|
||||
if (sizesAlloced[i] == (int)(size)) \
|
||||
{ ((x)[i])--; break; } \
|
||||
} \
|
||||
} while (0);
|
||||
|
||||
|
||||
SupportsStats::SupportsStats()
|
||||
{
|
||||
sizesUsed = 1;
|
||||
sizesAlloced[0] = 0;
|
||||
}
|
||||
|
||||
SupportsStats::~SupportsStats()
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < sizesUsed; i++)
|
||||
{
|
||||
printf("Size %d:\n",sizesAlloced[i]);
|
||||
printf("\tNumber of SupportsArrays this size (max): %d\n",NumberOfSize[i]);
|
||||
printf("\tNumber of allocations this size (total): %d\n",AllocedOfSize[i]);
|
||||
printf("\tNumber of GrowsInPlace this size (total): %d\n",GrowInPlace[i]);
|
||||
}
|
||||
printf("Max Size of SupportsArray:\n");
|
||||
for (i = 0; i < (int)(sizeof(MaxElements)/sizeof(MaxElements[0])); i++)
|
||||
{
|
||||
if (MaxElements[i])
|
||||
printf("\t%d: %d\n",i,MaxElements[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// Just so constructor/destructor get called
|
||||
SupportsStats gSupportsStats;
|
||||
#endif
|
||||
|
||||
nsresult
|
||||
nsQueryElementAt::operator()( const nsIID& aIID, void** aResult ) const
|
||||
@ -41,7 +109,8 @@ nsQueryElementAt::operator()( const nsIID& aIID, void** aResult ) const
|
||||
return status;
|
||||
}
|
||||
|
||||
static const PRUint32 kGrowArrayBy = 8;
|
||||
static const PRInt32 kGrowArrayBy = 8;
|
||||
static const PRInt32 kLinearThreshold = 16 * sizeof(nsISupports *);
|
||||
|
||||
nsSupportsArray::nsSupportsArray()
|
||||
{
|
||||
@ -49,6 +118,12 @@ nsSupportsArray::nsSupportsArray()
|
||||
mArray = mAutoArray;
|
||||
mArraySize = kAutoArraySize;
|
||||
mCount = 0;
|
||||
#if DEBUG_SUPPORTSARRAY
|
||||
mMaxCount = 0;
|
||||
mMaxSize = 0;
|
||||
ADD_TO_STATS(NumberOfSize,kAutoArraySize*sizeof(mArray[0]));
|
||||
MaxElements[0]++;
|
||||
#endif
|
||||
}
|
||||
|
||||
nsSupportsArray::~nsSupportsArray()
|
||||
@ -56,6 +131,82 @@ nsSupportsArray::~nsSupportsArray()
|
||||
DeleteArray();
|
||||
}
|
||||
|
||||
PRBool nsSupportsArray::GrowArrayBy(PRInt32 aGrowBy)
|
||||
{
|
||||
// We have to grow the array. Grow by kGrowArrayBy slots if we're smaller
|
||||
// than kLinearThreshold bytes, or a power of two if we're larger.
|
||||
// This is much more efficient with most memory allocators, especially
|
||||
// if it's very large, or of the allocator is binned.
|
||||
if (aGrowBy < kGrowArrayBy)
|
||||
aGrowBy = kGrowArrayBy;
|
||||
|
||||
PRUint32 newCount = mArraySize + aGrowBy; // Minimum increase
|
||||
PRUint32 newSize = sizeof(mArray[0]) * newCount;
|
||||
|
||||
if (newSize >= (PRUint32) kLinearThreshold)
|
||||
{
|
||||
// newCount includes enough space for at least kGrowArrayBy new slots.
|
||||
// Select the next power-of-two size in bytes above that.
|
||||
// It's painful to find the biggest 1 bit. We check for a
|
||||
// power-of-two here, and then double if it is one.
|
||||
PRUint32 oldSize = sizeof(mArray[0]) * mArraySize;
|
||||
|
||||
if ((oldSize & (oldSize-1)) == 0) // oldSize = 2^n for some n
|
||||
{
|
||||
newSize = oldSize << 1; // easy 2^(n+1)
|
||||
}
|
||||
else // count bits and stuff.
|
||||
{
|
||||
PRUint32 bits = 0;
|
||||
while (newSize >>= 1)
|
||||
{
|
||||
bits++;
|
||||
}
|
||||
bits++; // bump to the next power of two;
|
||||
newSize = 1 << bits;
|
||||
}
|
||||
// Make sure we have enough space -- the array can grow by a lot
|
||||
while (newSize/sizeof(mArray[0]) < newCount)
|
||||
newSize <<= 1;
|
||||
|
||||
// inverse of equation above.
|
||||
newCount = newSize/sizeof(mArray[0]);
|
||||
}
|
||||
// XXX This would be far more efficient in many allocators if we used
|
||||
// XXX PR_Realloc(), etc
|
||||
nsISupports** oldArray = mArray;
|
||||
|
||||
mArray = new nsISupports*[newCount];
|
||||
if (!mArray) { // ran out of memory
|
||||
mArray = oldArray;
|
||||
return PR_FALSE;
|
||||
}
|
||||
mArraySize = newCount;
|
||||
|
||||
#if DEBUG_SUPPORTSARRAY
|
||||
if (oldArray == mArray) // can't happen without use of realloc
|
||||
ADD_TO_STATS(GrowInPlace,mCount);
|
||||
ADD_TO_STATS(AllocedOfSize,mArraySize*sizeof(mArray[0]));
|
||||
if (mArraySize > mMaxSize)
|
||||
{
|
||||
ADD_TO_STATS(NumberOfSize,mArraySize*sizeof(mArray[0]));
|
||||
if (oldArray != &(mAutoArray[0]))
|
||||
SUB_FROM_STATS(NumberOfSize,mCount*sizeof(mArray[0]));
|
||||
mMaxSize = mArraySize;
|
||||
}
|
||||
#endif
|
||||
if (oldArray) { // need to move old data
|
||||
if (0 < mCount) {
|
||||
::memcpy(mArray, oldArray, mCount * sizeof(nsISupports*));
|
||||
}
|
||||
if (oldArray != &(mAutoArray[0])) {
|
||||
delete[] oldArray;
|
||||
}
|
||||
}
|
||||
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
NS_METHOD
|
||||
nsSupportsArray::Create(nsISupports *aOuter, REFNSIID aIID, void **aResult)
|
||||
{
|
||||
@ -84,7 +235,7 @@ nsSupportsArray::Read(nsIObjectInputStream *aStream)
|
||||
|
||||
if (newArraySize <= kAutoArraySize) {
|
||||
if (mArray != mAutoArray) {
|
||||
delete mArray;
|
||||
delete[] mArray;
|
||||
mArray = mAutoArray;
|
||||
newArraySize = kAutoArraySize;
|
||||
}
|
||||
@ -99,7 +250,7 @@ nsSupportsArray::Read(nsIObjectInputStream *aStream)
|
||||
if (!array)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
if (mArray != mAutoArray)
|
||||
delete mArray;
|
||||
delete[] mArray;
|
||||
mArray = array;
|
||||
}
|
||||
}
|
||||
@ -164,15 +315,9 @@ nsSupportsArray::operator=(nsISupportsArray const& aOther)
|
||||
|
||||
if (otherCount > mArraySize) {
|
||||
DeleteArray();
|
||||
nsISupports** array = new nsISupports*[otherCount];
|
||||
if (!array) {
|
||||
// Can't grow mArray, can't return an error -- copy mCount elements.
|
||||
otherCount = mCount;
|
||||
}
|
||||
else {
|
||||
mArraySize = otherCount;
|
||||
mArray = array;
|
||||
}
|
||||
if (!GrowArrayBy(otherCount - mArraySize))
|
||||
// Can't grow mArray, can't return an error -- copy mArraySize elements.
|
||||
otherCount = mArraySize;
|
||||
}
|
||||
else {
|
||||
Clear();
|
||||
@ -181,6 +326,15 @@ nsSupportsArray::operator=(nsISupportsArray const& aOther)
|
||||
while (0 < otherCount--) {
|
||||
mArray[otherCount] = ((nsISupportsArray&)aOther).ElementAt(otherCount);
|
||||
}
|
||||
#if DEBUG_SUPPORTSARRAY
|
||||
if (mCount > mMaxCount &&
|
||||
mCount < (PRInt32)(sizeof(MaxElements)/sizeof(MaxElements[0])))
|
||||
{
|
||||
MaxElements[mCount]++;
|
||||
MaxElements[mMaxCount]--;
|
||||
mMaxCount = mCount;
|
||||
}
|
||||
#endif
|
||||
return *this;
|
||||
}
|
||||
|
||||
@ -267,38 +421,77 @@ nsSupportsArray::InsertElementAt(nsISupports* aElement, PRUint32 aIndex)
|
||||
return PR_FALSE;
|
||||
}
|
||||
if (aIndex <= mCount) {
|
||||
if (mArraySize < (mCount + 1)) { // need to grow the array
|
||||
mArraySize += kGrowArrayBy;
|
||||
nsISupports** oldArray = mArray;
|
||||
mArray = new nsISupports*[mArraySize];
|
||||
if (!mArray) { // ran out of memory
|
||||
mArray = oldArray;
|
||||
mArraySize -= kGrowArrayBy;
|
||||
if (mArraySize < (mCount + 1)) {
|
||||
// need to grow the array
|
||||
if (!GrowArrayBy(1))
|
||||
return PR_FALSE;
|
||||
}
|
||||
if (oldArray) { // need to move old data
|
||||
if (0 < aIndex) {
|
||||
::memcpy(mArray, oldArray, aIndex * sizeof(nsISupports*));
|
||||
}
|
||||
PRUint32 slide = (mCount - aIndex);
|
||||
if (0 < slide) {
|
||||
::memcpy(mArray + aIndex + 1, oldArray + aIndex, slide * sizeof(nsISupports*));
|
||||
}
|
||||
if (oldArray != &(mAutoArray[0])) {
|
||||
delete[] oldArray;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
PRUint32 slide = (mCount - aIndex);
|
||||
if (0 < slide) {
|
||||
::memmove(mArray + aIndex + 1, mArray + aIndex, slide * sizeof(nsISupports*));
|
||||
}
|
||||
|
||||
// Could be slightly more efficient if GrowArrayBy knew about the
|
||||
// split, but the difference is trivial.
|
||||
PRUint32 slide = (mCount - aIndex);
|
||||
if (0 < slide) {
|
||||
::memmove(mArray + aIndex + 1, mArray + aIndex, slide * sizeof(nsISupports*));
|
||||
}
|
||||
|
||||
mArray[aIndex] = aElement;
|
||||
NS_ADDREF(aElement);
|
||||
mCount++;
|
||||
|
||||
#if DEBUG_SUPPORTSARRAY
|
||||
if (mCount > mMaxCount &&
|
||||
mCount < (PRInt32)(sizeof(MaxElements)/sizeof(MaxElements[0])))
|
||||
{
|
||||
MaxElements[mCount]++;
|
||||
MaxElements[mMaxCount]--;
|
||||
mMaxCount = mCount;
|
||||
}
|
||||
#endif
|
||||
return PR_TRUE;
|
||||
}
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP_(PRBool)
|
||||
nsSupportsArray::InsertElementsAt(nsISupportsArray* aElements, PRUint32 aIndex)
|
||||
{
|
||||
if (!aElements) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
PRUint32 countElements;
|
||||
if (NS_FAILED( aElements->Count( &countElements ) ))
|
||||
return PR_FALSE;
|
||||
|
||||
if (aIndex <= mCount) {
|
||||
if (mArraySize < (mCount + countElements)) {
|
||||
// need to grow the array
|
||||
if (!GrowArrayBy(countElements))
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
// Could be slightly more efficient if GrowArrayBy knew about the
|
||||
// split, but the difference is trivial.
|
||||
PRUint32 slide = (mCount - aIndex);
|
||||
if (0 < slide) {
|
||||
::memmove(mArray + aIndex + countElements, mArray + aIndex,
|
||||
slide * sizeof(nsISupports*));
|
||||
}
|
||||
|
||||
for (PRUint32 i = 0; i < countElements; ++i, ++mCount) {
|
||||
// use GetElementAt to copy and do AddRef for us
|
||||
if (NS_FAILED( aElements->GetElementAt( i, mArray + aIndex + i) ))
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
#if DEBUG_SUPPORTSARRAY
|
||||
if (mCount > mMaxCount &&
|
||||
mCount < (PRInt32)(sizeof(MaxElements)/sizeof(MaxElements[0])))
|
||||
{
|
||||
MaxElements[mCount]++;
|
||||
MaxElements[mMaxCount]--;
|
||||
mMaxCount = mCount;
|
||||
}
|
||||
#endif
|
||||
return PR_TRUE;
|
||||
}
|
||||
return PR_FALSE;
|
||||
@ -317,14 +510,17 @@ nsSupportsArray::ReplaceElementAt(nsISupports* aElement, PRUint32 aIndex)
|
||||
}
|
||||
|
||||
NS_IMETHODIMP_(PRBool)
|
||||
nsSupportsArray::RemoveElementAt(PRUint32 aIndex)
|
||||
nsSupportsArray::RemoveElementsAt(PRUint32 aIndex, PRUint32 aCount)
|
||||
{
|
||||
if (aIndex < mCount) {
|
||||
NS_RELEASE(mArray[aIndex]);
|
||||
mCount--;
|
||||
for (PRUint32 i = 0; i < aCount; i++)
|
||||
{
|
||||
NS_RELEASE(mArray[aIndex+i]);
|
||||
}
|
||||
mCount -= aCount;
|
||||
PRInt32 slide = (mCount - aIndex);
|
||||
if (0 < slide) {
|
||||
::memmove(mArray + aIndex, mArray + aIndex + 1,
|
||||
::memmove(mArray + aIndex, mArray + aIndex + aCount,
|
||||
slide * sizeof(nsISupports*));
|
||||
}
|
||||
return PR_TRUE;
|
||||
@ -335,76 +531,55 @@ nsSupportsArray::RemoveElementAt(PRUint32 aIndex)
|
||||
NS_IMETHODIMP_(PRBool)
|
||||
nsSupportsArray::RemoveElement(const nsISupports* aElement, PRUint32 aStartIndex)
|
||||
{
|
||||
if (aStartIndex < mCount) {
|
||||
nsISupports** ep = mArray;
|
||||
nsISupports** end = ep + mCount;
|
||||
while (ep < end) {
|
||||
if (*ep == aElement) {
|
||||
return RemoveElementAt(PRUint32(ep - mArray));
|
||||
}
|
||||
ep++;
|
||||
}
|
||||
}
|
||||
PRInt32 theIndex = IndexOfStartingAt(aElement,aStartIndex);
|
||||
if (theIndex >= 0)
|
||||
return RemoveElementAt(theIndex);
|
||||
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP_(PRBool)
|
||||
nsSupportsArray::RemoveLastElement(const nsISupports* aElement)
|
||||
{
|
||||
if (0 < mCount) {
|
||||
nsISupports** ep = (mArray + mCount);
|
||||
while (mArray <= --ep) {
|
||||
if (*ep == aElement) {
|
||||
return RemoveElementAt(PRUint32(ep - mArray));
|
||||
}
|
||||
}
|
||||
}
|
||||
PRInt32 theIndex = LastIndexOf(aElement);
|
||||
if (theIndex >= 0)
|
||||
return RemoveElementAt(theIndex);
|
||||
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP_(PRBool)
|
||||
nsSupportsArray::AppendElements(nsISupportsArray* aElements)
|
||||
nsSupportsArray::MoveElement(PRInt32 aFrom, PRInt32 aTo)
|
||||
{
|
||||
if (!aElements)
|
||||
return PR_FALSE;
|
||||
nsISupports *tempElement;
|
||||
|
||||
PRUint32 countElements;
|
||||
if (NS_FAILED( aElements->Count( &countElements ) ))
|
||||
return PR_FALSE;
|
||||
|
||||
if (0 < countElements) {
|
||||
if (mArraySize < (mCount + countElements)) { // need to grow the array
|
||||
PRUint32 count = mCount + countElements;
|
||||
PRUint32 oldSize = mArraySize;
|
||||
// growth is linear; consider geometric (e.g., doubling) to avoid the n^2
|
||||
// (amortized) cost we are paying to copy elements now
|
||||
mArraySize += ((count - mArraySize + kGrowArrayBy - 1) / kGrowArrayBy) * kGrowArrayBy;
|
||||
nsISupports** oldArray = mArray;
|
||||
mArray = new nsISupports*[mArraySize];
|
||||
if (!mArray) { // ran out of memory
|
||||
mArray = oldArray;
|
||||
mArraySize = oldSize;
|
||||
return PR_FALSE;
|
||||
}
|
||||
if (oldArray) { // need to move old data
|
||||
if (0 < mCount) {
|
||||
::memcpy(mArray, oldArray, mCount * sizeof(nsISupports*));
|
||||
}
|
||||
if (oldArray != &(mAutoArray[0])) {
|
||||
delete[] oldArray;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PRUint32 i = 0;
|
||||
for (i = 0; i < countElements; ++i, ++mCount) {
|
||||
// use GetElementAt to copy and do AddRef for us
|
||||
if (NS_FAILED( aElements->GetElementAt( i, mArray + mCount) ))
|
||||
return PR_FALSE;
|
||||
}
|
||||
if (aTo == aFrom)
|
||||
return PR_TRUE;
|
||||
|
||||
if (aTo < 0 || aFrom < 0 ||
|
||||
(PRUint32) aTo >= mCount || (PRUint32) aFrom >= mCount)
|
||||
{
|
||||
// can't extend the array when moving an element. Also catches mImpl = null
|
||||
return PR_FALSE;
|
||||
}
|
||||
return PR_FALSE;
|
||||
tempElement = mArray[aFrom];
|
||||
|
||||
if (aTo < aFrom)
|
||||
{
|
||||
// Moving one element closer to the head; the elements inbetween move down
|
||||
::memmove(mArray + aTo + 1, mArray + aTo,
|
||||
(aFrom-aTo) * sizeof(mArray[0]));
|
||||
mArray[aTo] = tempElement;
|
||||
}
|
||||
else // already handled aFrom == aTo
|
||||
{
|
||||
// Moving one element closer to the tail; the elements inbetween move up
|
||||
::memmove(mArray + aFrom, mArray + aFrom + 1,
|
||||
(aTo-aFrom) * sizeof(mArray[0]));
|
||||
mArray[aTo] = tempElement;
|
||||
}
|
||||
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
@ -422,6 +597,9 @@ nsSupportsArray::Clear(void)
|
||||
NS_IMETHODIMP
|
||||
nsSupportsArray::Compact(void)
|
||||
{
|
||||
#if DEBUG_SUPPORTSARRAY
|
||||
PRUint32 oldArraySize = mArraySize;
|
||||
#endif
|
||||
if ((mArraySize != mCount) && (kAutoArraySize < mArraySize)) {
|
||||
nsISupports** oldArray = mArray;
|
||||
if (mCount <= kAutoArraySize) {
|
||||
@ -436,12 +614,57 @@ nsSupportsArray::Compact(void)
|
||||
}
|
||||
mArraySize = mCount;
|
||||
}
|
||||
#if DEBUG_SUPPORTSARRAY
|
||||
if (oldArray == mArray &&
|
||||
oldArray != &(mAutoArray[0])) // can't happen without use of realloc
|
||||
ADD_TO_STATS(GrowInPlace,oldArraySize);
|
||||
if (oldArray != &(mAutoArray[0]))
|
||||
ADD_TO_STATS(AllocedOfSize,mArraySize*sizeof(mArray[0]));
|
||||
#endif
|
||||
::memcpy(mArray, oldArray, mCount * sizeof(nsISupports*));
|
||||
delete[] oldArray;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP_(PRBool)
|
||||
nsSupportsArray::SizeTo(PRInt32 aSize)
|
||||
{
|
||||
#if DEBUG_SUPPORTSARRAY
|
||||
PRUint32 oldArraySize = mArraySize;
|
||||
#endif
|
||||
// XXX for aSize < mCount we could resize to mCount
|
||||
if (mArraySize == aSize || aSize < mCount) // nothing to do
|
||||
return PR_TRUE;
|
||||
|
||||
// switch back to autoarray if possible
|
||||
nsISupports** oldArray = mArray;
|
||||
if (kAutoArraySize <= aSize) {
|
||||
mArray = mAutoArray;
|
||||
mArraySize = kAutoArraySize;
|
||||
}
|
||||
else {
|
||||
mArray = new nsISupports*[aSize];
|
||||
if (!mArray) {
|
||||
mArray = oldArray;
|
||||
return PR_FALSE;
|
||||
}
|
||||
mArraySize = aSize;
|
||||
}
|
||||
#if DEBUG_SUPPORTSARRAY
|
||||
if (oldArray == mArray &&
|
||||
oldArray != &(mAutoArray[0])) // can't happen without use of realloc
|
||||
ADD_TO_STATS(GrowInPlace,oldArraySize);
|
||||
if (oldArray != &(mAutoArray[0]))
|
||||
ADD_TO_STATS(AllocedOfSize,mArraySize*sizeof(mArray[0]));
|
||||
#endif
|
||||
::memcpy(mArray, oldArray, mCount * sizeof(nsISupports*));
|
||||
if (oldArray != mAutoArray)
|
||||
delete[] oldArray;
|
||||
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP_(PRBool)
|
||||
nsSupportsArray::EnumerateForwards(nsISupportsArrayEnumFunc aFunc, void* aData)
|
||||
{
|
||||
|
@ -23,9 +23,11 @@
|
||||
#ifndef nsSupportsArray_h__
|
||||
#define nsSupportsArray_h__
|
||||
|
||||
//#define DEBUG_SUPPORTSARRAY 1
|
||||
|
||||
#include "nsISupportsArray.h"
|
||||
|
||||
static const PRUint32 kAutoArraySize = 4;
|
||||
static const PRUint32 kAutoArraySize = 8;
|
||||
|
||||
class NS_COM nsSupportsArray : public nsISupportsArray {
|
||||
public:
|
||||
@ -65,6 +67,7 @@ public:
|
||||
// XXX This incorrectly returns a PRBool instead of an nsresult.
|
||||
return RemoveElement(aElement, 0);
|
||||
}
|
||||
NS_IMETHOD_(PRBool) MoveElement(PRInt32 aFrom, PRInt32 aTo);
|
||||
NS_IMETHOD Enumerate(nsIEnumerator* *result);
|
||||
NS_IMETHOD Clear(void);
|
||||
|
||||
@ -98,7 +101,9 @@ public:
|
||||
|
||||
NS_IMETHOD_(PRBool) ReplaceElementAt(nsISupports* aElement, PRUint32 aIndex);
|
||||
|
||||
NS_IMETHOD_(PRBool) RemoveElementAt(PRUint32 aIndex);
|
||||
NS_IMETHOD_(PRBool) RemoveElementAt(PRUint32 aIndex) {
|
||||
return RemoveElementsAt(aIndex,1);
|
||||
}
|
||||
NS_IMETHOD_(PRBool) RemoveElement(const nsISupports* aElement, PRUint32 aStartIndex = 0);
|
||||
NS_IMETHOD_(PRBool) RemoveLastElement(const nsISupports* aElement);
|
||||
|
||||
@ -110,7 +115,9 @@ public:
|
||||
return (RemoveElementAt(aIndex) ? NS_OK : NS_ERROR_FAILURE);
|
||||
}
|
||||
|
||||
NS_IMETHOD_(PRBool) AppendElements(nsISupportsArray* aElements);
|
||||
NS_IMETHOD_(PRBool) AppendElements(nsISupportsArray* aElements) {
|
||||
return InsertElementsAt(aElements,mCount);
|
||||
}
|
||||
|
||||
NS_IMETHOD Compact(void);
|
||||
|
||||
@ -119,6 +126,11 @@ public:
|
||||
|
||||
NS_IMETHOD Clone(nsISupportsArray **_retval);
|
||||
|
||||
NS_IMETHOD_(PRBool) InsertElementsAt(nsISupportsArray *aOther, PRUint32 aIndex);
|
||||
|
||||
NS_IMETHOD_(PRBool) RemoveElementsAt(PRUint32 aIndex, PRUint32 aCount);
|
||||
|
||||
NS_IMETHOD_(PRBool) SizeTo(PRInt32 aSize);
|
||||
protected:
|
||||
NS_IMETHOD_(nsISupportsArray&) operator=(const nsISupportsArray& aOther);
|
||||
NS_IMETHOD_(PRBool) operator==(const nsISupportsArray& aOther) { return Equals(&aOther); }
|
||||
@ -126,10 +138,16 @@ protected:
|
||||
|
||||
void DeleteArray(void);
|
||||
|
||||
NS_IMETHOD_(PRBool) GrowArrayBy(PRInt32 aGrowBy);
|
||||
|
||||
nsISupports** mArray;
|
||||
PRUint32 mArraySize;
|
||||
PRUint32 mCount;
|
||||
nsISupports* mAutoArray[kAutoArraySize];
|
||||
#if DEBUG_SUPPORTSARRAY
|
||||
PRUint32 mMaxCount;
|
||||
PRUint32 mMaxSize;
|
||||
#endif
|
||||
|
||||
private:
|
||||
// Copy constructors are not allowed
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -23,6 +23,8 @@
|
||||
#ifndef nsVoidArray_h___
|
||||
#define nsVoidArray_h___
|
||||
|
||||
//#define DEBUG_VOIDARRAY 1
|
||||
|
||||
#include "nscore.h"
|
||||
#include "nsAWritableString.h"
|
||||
#include "nsQuickSort.h"
|
||||
@ -45,11 +47,15 @@ public:
|
||||
|
||||
nsVoidArray& operator=(const nsVoidArray& other);
|
||||
|
||||
void SizeOf(nsISizeOfHandler* aHandler, PRUint32* aResult) const;
|
||||
virtual void SizeOf(nsISizeOfHandler* aHandler, PRUint32* aResult) const;
|
||||
|
||||
PRInt32 Count() const {
|
||||
inline PRInt32 Count() const {
|
||||
return mImpl ? mImpl->mCount : 0;
|
||||
}
|
||||
// returns the max number that can be held without allocating
|
||||
inline PRInt32 GetArraySize() const {
|
||||
return mImpl ? PRInt32(mImpl->mBits & kArraySizeMask) : 0;
|
||||
}
|
||||
|
||||
void* ElementAt(PRInt32 aIndex) const;
|
||||
void* operator[](PRInt32 aIndex) const { return ElementAt(aIndex); }
|
||||
@ -57,18 +63,27 @@ public:
|
||||
PRInt32 IndexOf(void* aPossibleElement) const;
|
||||
|
||||
PRBool InsertElementAt(void* aElement, PRInt32 aIndex);
|
||||
PRBool InsertElementsAt(const nsVoidArray &other, PRInt32 aIndex);
|
||||
|
||||
PRBool ReplaceElementAt(void* aElement, PRInt32 aIndex);
|
||||
|
||||
// useful for doing LRU arrays, sorting, etc
|
||||
PRBool MoveElement(PRInt32 aFrom, PRInt32 aTo);
|
||||
|
||||
PRBool AppendElement(void* aElement) {
|
||||
return InsertElementAt(aElement, Count());
|
||||
}
|
||||
|
||||
PRBool RemoveElement(void* aElement);
|
||||
PRBool RemoveElementAt(PRInt32 aIndex);
|
||||
void Clear();
|
||||
PRBool RemoveElementsAt(PRInt32 aIndex, PRInt32 aCount);
|
||||
PRBool RemoveElementAt(PRInt32 aIndex) { return RemoveElementsAt(aIndex,1); }
|
||||
|
||||
void Compact();
|
||||
virtual void Clear();
|
||||
|
||||
virtual PRBool SizeTo(PRInt32 aMin);
|
||||
// Subtly different - Compact() tries to be smart about whether we
|
||||
// should reallocate the array; SizeTo() just does it.
|
||||
virtual void Compact();
|
||||
|
||||
void Sort(nsVoidArrayComparatorFunc aFunc, void* aData);
|
||||
|
||||
@ -76,10 +91,12 @@ public:
|
||||
PRBool EnumerateBackwards(nsVoidArrayEnumFunc aFunc, void* aData);
|
||||
|
||||
protected:
|
||||
virtual PRBool GrowArrayBy(PRInt32 aGrowBy);
|
||||
|
||||
struct Impl {
|
||||
/**
|
||||
* Packed bits. The highest 31 bits are the array's size, which must
|
||||
* always be 0 mod 2. The lowest bit is a flag that indicates
|
||||
* Packed bits. The low 31 bits are the array's size.
|
||||
* The highest bit is a flag that indicates
|
||||
* whether or not we "own" mArray, and must free() it when
|
||||
* destroyed.
|
||||
*/
|
||||
@ -97,6 +114,11 @@ protected:
|
||||
};
|
||||
|
||||
Impl* mImpl;
|
||||
#if DEBUG_VOIDARRAY
|
||||
PRInt32 mMaxCount;
|
||||
PRInt32 mMaxSize;
|
||||
PRBool mIsAuto;
|
||||
#endif
|
||||
|
||||
enum {
|
||||
kArrayOwnerMask = 1 << 31,
|
||||
@ -105,10 +127,10 @@ protected:
|
||||
|
||||
|
||||
// bit twiddlers
|
||||
PRInt32 GetArraySize() const;
|
||||
void SetArraySize(PRInt32 aSize);
|
||||
PRBool IsArrayOwner() const;
|
||||
void SetArrayOwner(PRBool aOwner);
|
||||
void SetArray(Impl *newImpl, PRInt32 aSize, PRInt32 aCount, PRBool owner);
|
||||
inline PRBool IsArrayOwner() const {
|
||||
return mImpl ? PRBool(mImpl->mBits & kArrayOwnerMask) : PR_FALSE;
|
||||
}
|
||||
|
||||
private:
|
||||
/// Copy constructors are not allowed
|
||||
@ -120,10 +142,13 @@ private:
|
||||
class NS_COM nsAutoVoidArray : public nsVoidArray {
|
||||
public:
|
||||
nsAutoVoidArray();
|
||||
void Clear();
|
||||
|
||||
virtual PRBool SizeTo(PRInt32 aMin);
|
||||
virtual void Compact();
|
||||
|
||||
protected:
|
||||
// The internal storage. Note that this value must be divisible by
|
||||
// two because we use the LSB of mInfo to indicate array ownership.
|
||||
// The internal storage
|
||||
enum { kAutoBufSize = 8 };
|
||||
char mAutoBuf[sizeof(Impl) + (kAutoBufSize - 1) * sizeof(void*)];
|
||||
};
|
||||
@ -140,6 +165,7 @@ class NS_COM nsStringArray: protected nsVoidArray
|
||||
{
|
||||
public:
|
||||
nsStringArray(void);
|
||||
nsStringArray(PRInt32 aCount); // Storage for aCount elements will be pre-allocated
|
||||
virtual ~nsStringArray(void);
|
||||
|
||||
nsStringArray& operator=(const nsStringArray& other);
|
||||
@ -198,6 +224,7 @@ class NS_COM nsCStringArray: protected nsVoidArray
|
||||
{
|
||||
public:
|
||||
nsCStringArray(void);
|
||||
nsCStringArray(PRInt32 aCount); // Storage for aCount elements will be pre-allocated
|
||||
virtual ~nsCStringArray(void);
|
||||
|
||||
nsCStringArray& operator=(const nsCStringArray& other);
|
||||
|
Loading…
Reference in New Issue
Block a user