Bug 493711 Part 1: switch nsCOMArray from nsVoidArray to nsTArray r=sicking

This commit is contained in:
Neil Rashbrook 2012-12-19 21:33:54 +00:00
parent 28cc722479
commit 9708d4f1a2
2 changed files with 176 additions and 134 deletions

View File

@ -6,23 +6,47 @@
#include "nsCOMArray.h" #include "nsCOMArray.h"
#include "nsCOMPtr.h" #include "nsCOMPtr.h"
static bool ReleaseObjects(void* aElement, void*); // This specialization is private to nsCOMArray.
// It exists solely to automatically zero-out newly created array elements.
template<>
class nsTArrayElementTraits<nsISupports*>
{
typedef nsISupports* E;
public:
// Zero out the value
static inline void Construct(E *e) {
new (static_cast<void *>(e)) E();
}
// Invoke the copy-constructor in place.
template<class A>
static inline void Construct(E *e, const A &arg) {
new (static_cast<void *>(e)) E(arg);
}
// Invoke the destructor in place.
static inline void Destruct(E *e) {
e->~E();
}
};
static void ReleaseObjects(nsTArray<nsISupports*> &aArray);
// implementations of non-trivial methods in nsCOMArray_base // implementations of non-trivial methods in nsCOMArray_base
// copy constructor - we can't just memcpy here, because
// we have to make sure we own our own array buffer, and that each
// object gets another AddRef()
nsCOMArray_base::nsCOMArray_base(const nsCOMArray_base& aOther) nsCOMArray_base::nsCOMArray_base(const nsCOMArray_base& aOther)
{ {
// make sure we do only one allocation // make sure we do only one allocation
mArray.SizeTo(aOther.Count()); mArray.SetCapacity(aOther.Count());
AppendObjects(aOther); AppendObjects(aOther);
} }
nsCOMArray_base::~nsCOMArray_base() nsCOMArray_base::~nsCOMArray_base()
{ {
Clear(); Clear();
}
int32_t
nsCOMArray_base::IndexOf(nsISupports* aObject) const {
return mArray.IndexOf(aObject);
} }
int32_t int32_t
@ -30,12 +54,11 @@ nsCOMArray_base::IndexOfObject(nsISupports* aObject) const {
nsCOMPtr<nsISupports> supports = do_QueryInterface(aObject); nsCOMPtr<nsISupports> supports = do_QueryInterface(aObject);
NS_ENSURE_TRUE(supports, -1); NS_ENSURE_TRUE(supports, -1);
int32_t i, count; uint32_t i, count;
int32_t retval = -1; int32_t retval = -1;
count = mArray.Count(); count = mArray.Length();
for (i = 0; i < count; ++i) { for (i = 0; i < count; ++i) {
nsCOMPtr<nsISupports> arrayItem = nsCOMPtr<nsISupports> arrayItem = do_QueryInterface(mArray[i]);
do_QueryInterface(reinterpret_cast<nsISupports*>(mArray.ElementAt(i)));
if (arrayItem == supports) { if (arrayItem == supports) {
retval = i; retval = i;
break; break;
@ -44,41 +67,80 @@ nsCOMArray_base::IndexOfObject(nsISupports* aObject) const {
return retval; return retval;
} }
bool
nsCOMArray_base::EnumerateForwards(nsBaseArrayEnumFunc aFunc, void* aData) const
{
for (uint32_t index = 0; index < mArray.Length(); index++)
if (!(*aFunc)(mArray[index], aData))
return false;
return true;
}
bool
nsCOMArray_base::EnumerateBackwards(nsBaseArrayEnumFunc aFunc, void* aData) const
{
for (uint32_t index = mArray.Length(); index--; )
if (!(*aFunc)(mArray[index], aData))
return false;
return true;
}
int
nsCOMArray_base::nsCOMArrayComparator(const void* aElement1, const void* aElement2, void* aData)
{
nsCOMArrayComparatorContext* ctx = static_cast<nsCOMArrayComparatorContext*>(aData);
return (*ctx->mComparatorFunc)(*static_cast<nsISupports* const*>(aElement1),
*static_cast<nsISupports* const*>(aElement2),
ctx->mData);
}
void nsCOMArray_base::Sort(nsBaseArrayComparatorFunc aFunc, void* aData)
{
if (mArray.Length() > 1) {
nsCOMArrayComparatorContext ctx = {aFunc, aData};
NS_QuickSort(mArray.Elements(), mArray.Length(), sizeof(nsISupports*),
nsCOMArrayComparator, &ctx);
}
}
bool bool
nsCOMArray_base::InsertObjectAt(nsISupports* aObject, int32_t aIndex) { nsCOMArray_base::InsertObjectAt(nsISupports* aObject, int32_t aIndex) {
bool result = mArray.InsertElementAt(aObject, aIndex); if ((uint32_t)aIndex > mArray.Length())
if (result) return false;
NS_IF_ADDREF(aObject);
return result; if (!mArray.InsertElementAt(aIndex, aObject))
return false;
NS_IF_ADDREF(aObject);
return true;
} }
bool bool
nsCOMArray_base::InsertObjectsAt(const nsCOMArray_base& aObjects, int32_t aIndex) { nsCOMArray_base::InsertObjectsAt(const nsCOMArray_base& aObjects, int32_t aIndex) {
bool result = mArray.InsertElementsAt(aObjects.mArray, aIndex); if ((uint32_t)aIndex > mArray.Length())
if (result) { return false;
// need to addref all these
int32_t count = aObjects.Count(); if (!mArray.InsertElementsAt(aIndex, aObjects.mArray))
for (int32_t i = 0; i < count; ++i) { return false;
NS_IF_ADDREF(aObjects.ObjectAt(i));
} // need to addref all these
} int32_t count = aObjects.Count();
return result; for (int32_t i = 0; i < count; ++i)
NS_IF_ADDREF(aObjects.ObjectAt(i));
return true;
} }
bool bool
nsCOMArray_base::ReplaceObjectAt(nsISupports* aObject, int32_t aIndex) nsCOMArray_base::ReplaceObjectAt(nsISupports* aObject, int32_t aIndex)
{ {
// its ok if oldObject is null here bool result = mArray.EnsureLengthAtLeast(aIndex + 1);
nsISupports *oldObject =
reinterpret_cast<nsISupports*>(mArray.SafeElementAt(aIndex));
bool result = mArray.ReplaceElementAt(aObject, aIndex);
// ReplaceElementAt could fail, such as if the array grows
// so only release the existing object if the replacement succeeded
if (result) { if (result) {
nsISupports *oldObject = mArray[aIndex];
// Make sure to addref first, in case aObject == oldObject // Make sure to addref first, in case aObject == oldObject
NS_IF_ADDREF(aObject); NS_IF_ADDREF(mArray[aIndex] = aObject);
NS_IF_RELEASE(oldObject); NS_IF_RELEASE(oldObject);
} }
return result; return result;
@ -96,12 +158,12 @@ nsCOMArray_base::RemoveObject(nsISupports *aObject)
bool bool
nsCOMArray_base::RemoveObjectAt(int32_t aIndex) nsCOMArray_base::RemoveObjectAt(int32_t aIndex)
{ {
if (uint32_t(aIndex) < uint32_t(Count())) { if (uint32_t(aIndex) < mArray.Length()) {
nsISupports* element = ObjectAt(aIndex); nsISupports* element = mArray[aIndex];
bool result = mArray.RemoveElementAt(aIndex); mArray.RemoveElementAt(aIndex);
NS_IF_RELEASE(element); NS_IF_RELEASE(element);
return result; return true;
} }
return false; return false;
@ -110,38 +172,31 @@ nsCOMArray_base::RemoveObjectAt(int32_t aIndex)
bool bool
nsCOMArray_base::RemoveObjectsAt(int32_t aIndex, int32_t aCount) nsCOMArray_base::RemoveObjectsAt(int32_t aIndex, int32_t aCount)
{ {
if (uint32_t(aIndex) + uint32_t(aCount) <= uint32_t(Count())) { if (uint32_t(aIndex) + uint32_t(aCount) <= mArray.Length()) {
nsVoidArray elementsToDestroy(aCount); nsTArray<nsISupports*> elementsToDestroy(aCount);
for (int32_t i = 0; i < aCount; ++i) { elementsToDestroy.AppendElements(mArray.Elements() + aIndex, aCount);
elementsToDestroy.InsertElementAt(mArray.FastElementAt(aIndex + i), i); mArray.RemoveElementsAt(aIndex, aCount);
} ReleaseObjects(elementsToDestroy);
bool result = mArray.RemoveElementsAt(aIndex, aCount); return true;
for (int32_t i = 0; i < aCount; ++i) {
nsISupports* element = static_cast<nsISupports*> (elementsToDestroy.FastElementAt(i));
NS_IF_RELEASE(element);
}
return result;
} }
return false; return false;
} }
// useful for destructors // useful for destructors
bool void
ReleaseObjects(void* aElement, void*) ReleaseObjects(nsTArray<nsISupports*> &aArray)
{ {
nsISupports* element = static_cast<nsISupports*>(aElement); for (uint32_t i = 0; i < aArray.Length(); i++)
NS_IF_RELEASE(element); NS_IF_RELEASE(aArray[i]);
return true;
} }
void void
nsCOMArray_base::Clear() nsCOMArray_base::Clear()
{ {
nsAutoVoidArray objects; nsTArray<nsISupports*> objects;
objects = mArray; objects.SwapElements(mArray);
mArray.Clear(); ReleaseObjects(objects);
objects.EnumerateForwards(ReleaseObjects, nullptr);
} }
bool bool
@ -149,18 +204,24 @@ nsCOMArray_base::SetCount(int32_t aNewCount)
{ {
NS_ASSERTION(aNewCount >= 0,"SetCount(negative index)"); NS_ASSERTION(aNewCount >= 0,"SetCount(negative index)");
if (aNewCount < 0) if (aNewCount < 0)
return false; return false;
int32_t count = Count(), i; int32_t count = mArray.Length();
nsAutoVoidArray objects; if (count > aNewCount)
if (count > aNewCount) { RemoveObjectsAt(aNewCount, mArray.Length() - aNewCount);
objects.SetCount(count - aNewCount); return mArray.SetLength(aNewCount);
for (i = aNewCount; i < count; ++i) {
objects.ReplaceElementAt(ObjectAt(i), i - aNewCount);
}
}
bool result = mArray.SetCount(aNewCount);
objects.EnumerateForwards(ReleaseObjects, nullptr);
return result;
} }
size_t
nsCOMArray_base::SizeOfExcludingThis(
nsBaseArraySizeOfElementIncludingThisFunc aSizeOfElementIncludingThis,
nsMallocSizeOfFun aMallocSizeOf, void* aData) const
{
size_t n = mArray.SizeOfExcludingThis(aMallocSizeOf);
if (aSizeOfElementIncludingThis)
for (uint32_t index = 0; index < mArray.Length(); index++)
n += aSizeOfElementIncludingThis(mArray[index], aMallocSizeOf, aData);
return n;
}

View File

@ -10,6 +10,7 @@
#include "nsCycleCollectionNoteChild.h" #include "nsCycleCollectionNoteChild.h"
#include "nsVoidArray.h" #include "nsVoidArray.h"
#include "nsTArray.h"
#include "nsISupports.h" #include "nsISupports.h"
// See below for the definition of nsCOMArray<T> // See below for the definition of nsCOMArray<T>
@ -25,28 +26,28 @@ protected:
nsCOMArray_base(const nsCOMArray_base& other); nsCOMArray_base(const nsCOMArray_base& other);
~nsCOMArray_base(); ~nsCOMArray_base();
int32_t IndexOf(nsISupports* aObject) const { int32_t IndexOf(nsISupports* aObject) const;
return mArray.IndexOf(aObject);
}
int32_t IndexOfObject(nsISupports* aObject) const; int32_t IndexOfObject(nsISupports* aObject) const;
bool EnumerateForwards(nsVoidArrayEnumFunc aFunc, void* aData) { typedef bool (* nsBaseArrayEnumFunc)
return mArray.EnumerateForwards(aFunc, aData); (void* aElement, void *aData);
}
bool EnumerateBackwards(nsVoidArrayEnumFunc aFunc, void* aData) { // enumerate through the array with a callback.
return mArray.EnumerateBackwards(aFunc, aData); bool EnumerateForwards(nsBaseArrayEnumFunc aFunc, void* aData) const;
}
void Sort(nsVoidArrayComparatorFunc aFunc, void* aData) { bool EnumerateBackwards(nsBaseArrayEnumFunc aFunc, void* aData) const;
mArray.Sort(aFunc, aData);
} typedef int (* nsBaseArrayComparatorFunc)
(nsISupports* aElement1, nsISupports* aElement2, void* aData);
// any method which is not a direct forward to mArray should
// avoid inline bodies, so that the compiler doesn't inline them struct nsCOMArrayComparatorContext {
// all over the place nsBaseArrayComparatorFunc mComparatorFunc;
void Clear(); void* mData;
};
static int nsCOMArrayComparator(const void* aElement1, const void* aElement2, void* aData);
void Sort(nsBaseArrayComparatorFunc aFunc, void* aData);
bool InsertObjectAt(nsISupports* aObject, int32_t aIndex); bool InsertObjectAt(nsISupports* aObject, int32_t aIndex);
bool InsertObjectsAt(const nsCOMArray_base& aObjects, int32_t aIndex); bool InsertObjectsAt(const nsCOMArray_base& aObjects, int32_t aIndex);
bool ReplaceObjectAt(nsISupports* aObject, int32_t aIndex); bool ReplaceObjectAt(nsISupports* aObject, int32_t aIndex);
@ -57,58 +58,63 @@ protected:
return InsertObjectsAt(aObjects, Count()); return InsertObjectsAt(aObjects, Count());
} }
bool RemoveObject(nsISupports *aObject); bool RemoveObject(nsISupports *aObject);
bool RemoveObjectAt(int32_t aIndex);
bool RemoveObjectsAt(int32_t aIndex, int32_t aCount);
public: public:
// override nsVoidArray stuff so that they can be accessed by // elements in the array (including null elements!)
// consumers of nsCOMArray
int32_t Count() const { int32_t Count() const {
return mArray.Count(); return mArray.Length();
} }
// If the array grows, the newly created entries will all be null; // If the array grows, the newly created entries will all be null;
// if the array shrinks, the excess entries will all be released. // if the array shrinks, the excess entries will all be released.
bool SetCount(int32_t aNewCount); bool SetCount(int32_t aNewCount);
// remove all elements in the array, and call NS_RELEASE on each one
void Clear();
nsISupports* ObjectAt(int32_t aIndex) const { nsISupports* ObjectAt(int32_t aIndex) const {
return static_cast<nsISupports*>(mArray.FastElementAt(aIndex)); return mArray[aIndex];
} }
nsISupports* SafeObjectAt(int32_t aIndex) const { nsISupports* SafeObjectAt(int32_t aIndex) const {
return static_cast<nsISupports*>(mArray.SafeElementAt(aIndex)); return mArray.SafeElementAt(aIndex, nullptr);
} }
nsISupports* operator[](int32_t aIndex) const { nsISupports* operator[](int32_t aIndex) const {
return ObjectAt(aIndex); return ObjectAt(aIndex);
} }
// remove an element at a specific position, shrinking the array
// as necessary
bool RemoveObjectAt(int32_t aIndex);
// remove a range of elements at a specific position, shrinking the array
// as necessary
bool RemoveObjectsAt(int32_t aIndex, int32_t aCount);
// Ensures there is enough space to store a total of aCapacity objects. // Ensures there is enough space to store a total of aCapacity objects.
// This method never deletes any objects. // This method never deletes any objects.
bool SetCapacity(uint32_t aCapacity) { bool SetCapacity(uint32_t aCapacity) {
return aCapacity > 0 ? mArray.SizeTo(static_cast<int32_t>(aCapacity)) return mArray.SetCapacity(aCapacity);
: true;
} }
typedef size_t (* nsBaseArraySizeOfElementIncludingThisFunc)
(nsISupports* aElement, nsMallocSizeOfFun aMallocSizeOf, void *aData);
// Measures the size of the array's element storage, and if // Measures the size of the array's element storage, and if
// |aSizeOfElement| is non-NULL, measures the size of things pointed to by // |aSizeOfElement| is non-NULL, measures the size of things pointed to by
// elements. // elements.
size_t SizeOfExcludingThis( size_t SizeOfExcludingThis(
nsVoidArraySizeOfElementIncludingThisFunc aSizeOfElementIncludingThis, nsBaseArraySizeOfElementIncludingThisFunc aSizeOfElementIncludingThis,
nsMallocSizeOfFun aMallocSizeOf, void* aData = NULL) const { nsMallocSizeOfFun aMallocSizeOf, void* aData = NULL) const;
return mArray.SizeOfExcludingThis(aSizeOfElementIncludingThis,
aMallocSizeOf, aData);
}
private: private:
// the actual storage // the actual storage
nsVoidArray mArray; nsTArray<nsISupports*> mArray;
// don't implement these, defaults will muck with refcounts! // don't implement these, defaults will muck with refcounts!
nsCOMArray_base& operator=(const nsCOMArray_base& other) MOZ_DELETE; nsCOMArray_base& operator=(const nsCOMArray_base& other) MOZ_DELETE;
// needs to call Clear() which is protected
friend void ImplCycleCollectionUnlink(nsCOMArray_base& aField);
}; };
inline void inline void
@ -211,19 +217,6 @@ class nsCOMArray : public nsCOMArray_base
return nsCOMArray_base::ReplaceObjectAt(static_cast<nsISupports*>(aObject), aIndex); return nsCOMArray_base::ReplaceObjectAt(static_cast<nsISupports*>(aObject), aIndex);
} }
// override nsVoidArray stuff so that they can be accessed by
// other methods
// elements in the array (including null elements!)
int32_t Count() const {
return nsCOMArray_base::Count();
}
// remove all elements in the array, and call NS_RELEASE on each one
void Clear() {
nsCOMArray_base::Clear();
}
// Enumerator callback function. Return false to stop // Enumerator callback function. Return false to stop
// Here's a more readable form: // Here's a more readable form:
// bool enumerate(T* aElement, void* aData) // bool enumerate(T* aElement, void* aData)
@ -232,12 +225,12 @@ class nsCOMArray : public nsCOMArray_base
// enumerate through the array with a callback. // enumerate through the array with a callback.
bool EnumerateForwards(nsCOMArrayEnumFunc aFunc, void* aData) { bool EnumerateForwards(nsCOMArrayEnumFunc aFunc, void* aData) {
return nsCOMArray_base::EnumerateForwards(nsVoidArrayEnumFunc(aFunc), return nsCOMArray_base::EnumerateForwards(nsBaseArrayEnumFunc(aFunc),
aData); aData);
} }
bool EnumerateBackwards(nsCOMArrayEnumFunc aFunc, void* aData) { bool EnumerateBackwards(nsCOMArrayEnumFunc aFunc, void* aData) {
return nsCOMArray_base::EnumerateBackwards(nsVoidArrayEnumFunc(aFunc), return nsCOMArray_base::EnumerateBackwards(nsBaseArrayEnumFunc(aFunc),
aData); aData);
} }
@ -245,7 +238,7 @@ class nsCOMArray : public nsCOMArray_base
(T* aElement1, T* aElement2, void* aData); (T* aElement1, T* aElement2, void* aData);
void Sort(nsCOMArrayComparatorFunc aFunc, void* aData) { void Sort(nsCOMArrayComparatorFunc aFunc, void* aData) {
nsCOMArray_base::Sort(nsVoidArrayComparatorFunc(aFunc), aData); nsCOMArray_base::Sort(nsBaseArrayComparatorFunc(aFunc), aData);
} }
// append an object, growing the array as necessary // append an object, growing the array as necessary
@ -265,18 +258,6 @@ class nsCOMArray : public nsCOMArray_base
return nsCOMArray_base::RemoveObject(static_cast<nsISupports*>(aObject)); return nsCOMArray_base::RemoveObject(static_cast<nsISupports*>(aObject));
} }
// remove an element at a specific position, shrinking the array
// as necessary
bool RemoveObjectAt(int32_t aIndex) {
return nsCOMArray_base::RemoveObjectAt(aIndex);
}
// remove a range of elements at a specific position, shrinking the array
// as necessary
bool RemoveObjectsAt(int32_t aIndex, int32_t aCount) {
return nsCOMArray_base::RemoveObjectsAt(aIndex, aCount);
}
// Each element in an nsCOMArray<T> is actually a T*, so this function is // Each element in an nsCOMArray<T> is actually a T*, so this function is
// "IncludingThis" rather than "ExcludingThis" because it needs to measure // "IncludingThis" rather than "ExcludingThis" because it needs to measure
// the memory taken by the T itself as well as anything it points to. // the memory taken by the T itself as well as anything it points to.
@ -287,7 +268,7 @@ class nsCOMArray : public nsCOMArray_base
nsCOMArraySizeOfElementIncludingThisFunc aSizeOfElementIncludingThis, nsCOMArraySizeOfElementIncludingThisFunc aSizeOfElementIncludingThis,
nsMallocSizeOfFun aMallocSizeOf, void *aData = NULL) const { nsMallocSizeOfFun aMallocSizeOf, void *aData = NULL) const {
return nsCOMArray_base::SizeOfExcludingThis( return nsCOMArray_base::SizeOfExcludingThis(
nsVoidArraySizeOfElementIncludingThisFunc(aSizeOfElementIncludingThis), nsBaseArraySizeOfElementIncludingThisFunc(aSizeOfElementIncludingThis),
aMallocSizeOf, aData); aMallocSizeOf, aData);
} }