diff --git a/xpcom/ds/nsArray.cpp b/xpcom/ds/nsArray.cpp index 8789d237b9c..13075806b3b 100644 --- a/xpcom/ds/nsArray.cpp +++ b/xpcom/ds/nsArray.cpp @@ -46,6 +46,9 @@ struct findIndexOfClosure PRUint32 resultIndex; }; +static PRBool FindElementCallback(nsISupports* aElement, void* aClosure); + + NS_IMPL_ISUPPORTS2(nsArray, nsIArray, nsIMutableArray) nsArray::~nsArray() @@ -80,8 +83,6 @@ nsArray::IndexOf(PRUint32 aStartIndex, nsISupports* aElement, *aResult = mArray.IndexOf(aElement); if (*aResult == -1) return NS_ERROR_FAILURE; - - NS_ADDREF(*aResult); return NS_OK; } @@ -130,7 +131,8 @@ nsArray::Clear() return NS_OK; } -nsArray::FindElementCallback(void *aElement, void* aClosure) +PRBool +FindElementCallback(nsISupports *aElement, void* aClosure) { findIndexOfClosure* closure = NS_STATIC_CAST(findIndexOfClosure*, aClosure); @@ -144,3 +146,27 @@ nsArray::FindElementCallback(void *aElement, void* aClosure) return PR_TRUE; } + +nsresult +NS_NewArray(nsIArray** aResult) +{ + nsArray* arr = new nsArray; + if (!arr) return NS_ERROR_OUT_OF_MEMORY; + + *aResult = NS_STATIC_CAST(nsIArray*,arr); + NS_ADDREF(*aResult); + + return NS_OK; +} + +nsresult +NS_NewArray(const nsCOMArray_base& aBaseArray, nsIArray** aResult) +{ + nsArray* arr = new nsArray(aBaseArray); + if (!arr) return NS_ERROR_OUT_OF_MEMORY; + + *aResult = NS_STATIC_CAST(nsIArray*, arr); + NS_ADDREF(*aResult); + + return NS_OK; +} diff --git a/xpcom/ds/nsArray.h b/xpcom/ds/nsArray.h index c14b9aea2c0..bc4d8134341 100644 --- a/xpcom/ds/nsArray.h +++ b/xpcom/ds/nsArray.h @@ -57,6 +57,9 @@ class nsArray : public nsIMutableArray { public: nsArray() { NS_INIT_ISUPPORTS(); } + nsArray(const nsCOMArray_base& aBaseArray) : mArray(aBaseArray) + { NS_INIT_ISUPPORTS(); } + virtual ~nsArray(); NS_DECL_ISUPPORTS @@ -64,10 +67,17 @@ public: NS_DECL_NSIMUTABLEARRAY private: - static PRBool FindElementCallback(void* aElement, void* aClosure); nsCOMArray mArray; }; +// create a new, empty array +nsresult NS_COM +NS_NewArray(nsIArray** aResult); + +// makes a copy of an nsCOMArray - any further changes to the base +// array will not affect the new array +nsresult NS_COM +NS_NewArray(const nsCOMArray_base& base, nsIArray** aResult); #endif diff --git a/xpcom/ds/nsCOMArray.cpp b/xpcom/ds/nsCOMArray.cpp index e0d9970b75b..6023a58b857 100644 --- a/xpcom/ds/nsCOMArray.cpp +++ b/xpcom/ds/nsCOMArray.cpp @@ -38,8 +38,27 @@ #include "nsCOMArray.h" +static PRBool AddRefObjects(void* aElement, void*); +static PRBool ReleaseObjects(void* aElement, void*); + + // 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) +{ + PRInt32 count = aOther.Count(); + // make sure we do only one allocation + mArray.SizeTo(count); + + PRInt32 i; + for (i=0; i + // a class that's nsISupports-specific, so that we can contain the // work of this class in the XPCOM dll class NS_COM nsCOMArray_base @@ -49,6 +51,7 @@ class NS_COM nsCOMArray_base protected: nsCOMArray_base() {} nsCOMArray_base(PRInt32 aCount) : mArray(aCount) {} + nsCOMArray_base(const nsCOMArray_base& other); nsISupports* ObjectAt(PRInt32 aIndex) const { return NS_STATIC_CAST(nsISupports*, mArray.ElementAt(aIndex)); @@ -88,19 +91,35 @@ protected: nsVoidArray mArray; // don't implement these, defaults will muck with refcounts! - nsCOMArray_base(const nsCOMArray_base& other); nsCOMArray_base& operator=(const nsCOMArray_base& other); }; // a non-XPCOM, refcounting array of XPCOM objects // used as a member variable or stack variable - this object is NOT // refcounted, but the objects that it holds are +// +// most of the read-only accessors like ObjectAt()/etc do NOT refcount +// on the way out. This means that you can do one of two things: +// +// * does an addref, but holds onto a reference +// nsCOMPtr foo = array[i]; +// +// * avoids the refcount, but foo might go stale if array[i] is ever +// * modified/removed. Be careful not to NS_RELEASE(foo)! +// T* foo = array[i]; +// +// This array will accept null as an argument for any object, and will +// store null in the array, just like nsVoidArray. But that also means +// that methods like ObjectAt() may return null when refering to an +// existing, but null entry in the array. template class nsCOMArray : protected nsCOMArray_base { public: nsCOMArray() {} nsCOMArray(PRInt32 aCount) : nsCOMArray_base(aCount) {} + + nsCOMArray(const nsCOMArray_base& aOther) : nsCOMArray_base(aOther) { } ~nsCOMArray() {} @@ -108,50 +127,72 @@ class nsCOMArray : protected nsCOMArray_base T* ObjectAt(PRInt32 aIndex) const { return NS_STATIC_CAST(T*,nsCOMArray_base::ObjectAt(aIndex)); } - + + // indexing operator for syntactic sugar T* operator[](PRInt32 aIndex) const { return ObjectAt(aIndex); } + // index of the element in question.. does NOT refcount PRInt32 IndexOf(T* aObject) { return nsCOMArray_base::IndexOf(aObject); } - + + // inserts the object at aIndex, and move all objects after aIndex + // to the right PRBool InsertObjectAt(T* aObject, PRInt32 aIndex) { return nsCOMArray_base::InsertObjectAt(aObject, aIndex); } - + + // replaces an existing element. Warning: if the array grows, + // the newly created entries will all be null PRBool ReplaceObjectAt(T* aObject, PRInt32 aIndex) { return nsCOMArray_base::ReplaceObjectAt(aObject, aIndex); } // override nsVoidArray stuff so that they can be accessed by // other methods + + // elements in the array (including null elements!) PRInt32 Count() const { return nsCOMArray_base::Count(); } + // remove all elements in the array, and call NS_RELEASE on each one void Clear() { nsCOMArray_base::Clear(); } - PRBool EnumerateForwards(nsVoidArrayEnumFunc aFunc, void* aData) { - return nsCOMArray_base::EnumerateForwards(aFunc, aData); - } + // Enumerator callback function. Return PR_FALSE to stop + // Here's a more readable form: + // PRBool PR_CALLBACK enumerate(T* aElement, void* aData) + typedef PRBool (* PR_CALLBACK nsCOMArrayEnumFunc) + (T* aElement, void *aData); + // enumerate through the array with a callback. + PRBool EnumerateForwards(nsCOMArrayEnumFunc aFunc, void* aData) { + return nsCOMArray_base::EnumerateForwards(nsVoidArrayEnumFunc(aFunc), + aData); + } + + // append an object, growing the array as necessary PRBool AppendObject(T *aObject) { return nsCOMArray_base::AppendObject(aObject); } + // remove the first instance of the given object and shrink the + // array as necessary + // Warning: if you pass null here, it will remove the first null element PRBool RemoveObject(T *aObject) { return nsCOMArray_base::RemoveObject(aObject); } - + + // remove an element at a specific position, shrinking the array + // as necessary PRBool RemoveObjectAt(PRInt32 aIndex) { return nsCOMArray_base::RemoveObjectAt(aIndex); } - private: // don't implement these! diff --git a/xpcom/ds/nsIArray.idl b/xpcom/ds/nsIArray.idl index e9f7f427b7c..a51de44a929 100644 --- a/xpcom/ds/nsIArray.idl +++ b/xpcom/ds/nsIArray.idl @@ -101,7 +101,7 @@ interface nsIArray : nsISupports /** * nsIMutableArray - * A seperate set of methods that will act on the array. Consumers of + * A separate set of methods that will act on the array. Consumers of * nsIArray should not QueryInterface to nsIMutableArray unless they * own the array. *