michael@0: /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #ifndef nsCOMArray_h__ michael@0: #define nsCOMArray_h__ michael@0: michael@0: #include "mozilla/Attributes.h" michael@0: #include "mozilla/MemoryReporting.h" michael@0: michael@0: #include "nsCycleCollectionNoteChild.h" michael@0: #include "nsTArray.h" michael@0: #include "nsISupports.h" michael@0: michael@0: // See below for the definition of nsCOMArray michael@0: michael@0: // a class that's nsISupports-specific, so that we can contain the michael@0: // work of this class in the XPCOM dll michael@0: class NS_COM_GLUE nsCOMArray_base michael@0: { michael@0: friend class nsArray; michael@0: protected: michael@0: nsCOMArray_base() {} michael@0: nsCOMArray_base(int32_t aCount) : mArray(aCount) {} michael@0: nsCOMArray_base(const nsCOMArray_base& other); michael@0: ~nsCOMArray_base(); michael@0: michael@0: int32_t IndexOf(nsISupports* aObject, uint32_t aStartIndex = 0) const; michael@0: bool Contains(nsISupports* aObject) const { michael@0: return IndexOf(aObject) != -1; michael@0: } michael@0: michael@0: int32_t IndexOfObject(nsISupports* aObject) const; michael@0: bool ContainsObject(nsISupports* aObject) const { michael@0: return IndexOfObject(aObject) != -1; michael@0: } michael@0: michael@0: typedef bool (* nsBaseArrayEnumFunc) michael@0: (void* aElement, void *aData); michael@0: michael@0: // enumerate through the array with a callback. michael@0: bool EnumerateForwards(nsBaseArrayEnumFunc aFunc, void* aData) const; michael@0: michael@0: bool EnumerateBackwards(nsBaseArrayEnumFunc aFunc, void* aData) const; michael@0: michael@0: typedef int (* nsBaseArrayComparatorFunc) michael@0: (nsISupports* aElement1, nsISupports* aElement2, void* aData); michael@0: michael@0: struct nsCOMArrayComparatorContext { michael@0: nsBaseArrayComparatorFunc mComparatorFunc; michael@0: void* mData; michael@0: }; michael@0: michael@0: static int nsCOMArrayComparator(const void* aElement1, const void* aElement2, void* aData); michael@0: void Sort(nsBaseArrayComparatorFunc aFunc, void* aData); michael@0: michael@0: bool InsertObjectAt(nsISupports* aObject, int32_t aIndex); michael@0: void InsertElementAt(uint32_t aIndex, nsISupports* aElement); michael@0: bool InsertObjectsAt(const nsCOMArray_base& aObjects, int32_t aIndex); michael@0: void InsertElementsAt(uint32_t aIndex, const nsCOMArray_base& aElements); michael@0: void InsertElementsAt(uint32_t aIndex, nsISupports* const* aElements, uint32_t aCount); michael@0: bool ReplaceObjectAt(nsISupports* aObject, int32_t aIndex); michael@0: void ReplaceElementAt(uint32_t aIndex, nsISupports* aElement) { michael@0: nsISupports* oldElement = mArray[aIndex]; michael@0: NS_IF_ADDREF(mArray[aIndex] = aElement); michael@0: NS_IF_RELEASE(oldElement); michael@0: } michael@0: bool AppendObject(nsISupports *aObject) { michael@0: return InsertObjectAt(aObject, Count()); michael@0: } michael@0: void AppendElement(nsISupports* aElement) { michael@0: InsertElementAt(Length(), aElement); michael@0: } michael@0: bool AppendObjects(const nsCOMArray_base& aObjects) { michael@0: return InsertObjectsAt(aObjects, Count()); michael@0: } michael@0: void AppendElements(const nsCOMArray_base& aElements) { michael@0: return InsertElementsAt(Length(), aElements); michael@0: } michael@0: void AppendElements(nsISupports* const* aElements, uint32_t aCount) { michael@0: return InsertElementsAt(Length(), aElements, aCount); michael@0: } michael@0: bool RemoveObject(nsISupports *aObject); michael@0: nsISupports** Elements() { michael@0: return mArray.Elements(); michael@0: } michael@0: void SwapElements(nsCOMArray_base& aOther) { michael@0: mArray.SwapElements(aOther.mArray); michael@0: } michael@0: michael@0: void Adopt(nsISupports** aElements, uint32_t aCount); michael@0: uint32_t Forget(nsISupports*** aElements); michael@0: public: michael@0: // elements in the array (including null elements!) michael@0: int32_t Count() const { michael@0: return mArray.Length(); michael@0: } michael@0: // nsTArray-compatible version michael@0: uint32_t Length() const { michael@0: return mArray.Length(); michael@0: } michael@0: bool IsEmpty() const { michael@0: return mArray.IsEmpty(); michael@0: } michael@0: michael@0: // If the array grows, the newly created entries will all be null; michael@0: // if the array shrinks, the excess entries will all be released. michael@0: bool SetCount(int32_t aNewCount); michael@0: // nsTArray-compatible version michael@0: void TruncateLength(uint32_t aNewLength) { michael@0: if (mArray.Length() > aNewLength) michael@0: RemoveElementsAt(aNewLength, mArray.Length() - aNewLength); michael@0: } michael@0: michael@0: // remove all elements in the array, and call NS_RELEASE on each one michael@0: void Clear(); michael@0: michael@0: nsISupports* ObjectAt(int32_t aIndex) const { michael@0: return mArray[aIndex]; michael@0: } michael@0: // nsTArray-compatible version michael@0: nsISupports* ElementAt(uint32_t aIndex) const { michael@0: return mArray[aIndex]; michael@0: } michael@0: michael@0: nsISupports* SafeObjectAt(int32_t aIndex) const { michael@0: return mArray.SafeElementAt(aIndex, nullptr); michael@0: } michael@0: // nsTArray-compatible version michael@0: nsISupports* SafeElementAt(uint32_t aIndex) const { michael@0: return mArray.SafeElementAt(aIndex, nullptr); michael@0: } michael@0: michael@0: nsISupports* operator[](int32_t aIndex) const { michael@0: return mArray[aIndex]; michael@0: } michael@0: michael@0: // remove an element at a specific position, shrinking the array michael@0: // as necessary michael@0: bool RemoveObjectAt(int32_t aIndex); michael@0: // nsTArray-compatible version michael@0: void RemoveElementAt(uint32_t aIndex); michael@0: michael@0: // remove a range of elements at a specific position, shrinking the array michael@0: // as necessary michael@0: bool RemoveObjectsAt(int32_t aIndex, int32_t aCount); michael@0: // nsTArray-compatible version michael@0: void RemoveElementsAt(uint32_t aIndex, uint32_t aCount); michael@0: michael@0: void SwapElementsAt(uint32_t aIndex1, uint32_t aIndex2) { michael@0: nsISupports *tmp = mArray[aIndex1]; michael@0: mArray[aIndex1] = mArray[aIndex2]; michael@0: mArray[aIndex2] = tmp; michael@0: } michael@0: michael@0: // Ensures there is enough space to store a total of aCapacity objects. michael@0: // This method never deletes any objects. michael@0: void SetCapacity(uint32_t aCapacity) { michael@0: mArray.SetCapacity(aCapacity); michael@0: } michael@0: uint32_t Capacity() { michael@0: return mArray.Capacity(); michael@0: } michael@0: michael@0: typedef size_t (* nsBaseArraySizeOfElementIncludingThisFunc) michael@0: (nsISupports* aElement, mozilla::MallocSizeOf aMallocSizeOf, void *aData); michael@0: michael@0: // Measures the size of the array's element storage, and if michael@0: // |aSizeOfElement| is non-nullptr, measures the size of things pointed to michael@0: // by elements. michael@0: size_t SizeOfExcludingThis( michael@0: nsBaseArraySizeOfElementIncludingThisFunc aSizeOfElementIncludingThis, michael@0: mozilla::MallocSizeOf aMallocSizeOf, void* aData = nullptr) const; michael@0: michael@0: private: michael@0: michael@0: // the actual storage michael@0: nsTArray mArray; michael@0: michael@0: // don't implement these, defaults will muck with refcounts! michael@0: nsCOMArray_base& operator=(const nsCOMArray_base& other) MOZ_DELETE; michael@0: }; michael@0: michael@0: inline void michael@0: ImplCycleCollectionUnlink(nsCOMArray_base& aField) michael@0: { michael@0: aField.Clear(); michael@0: } michael@0: michael@0: inline void michael@0: ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& aCallback, michael@0: nsCOMArray_base& aField, michael@0: const char* aName, michael@0: uint32_t aFlags = 0) michael@0: { michael@0: aFlags |= CycleCollectionEdgeNameArrayFlag; michael@0: int32_t length = aField.Count(); michael@0: for (int32_t i = 0; i < length; ++i) { michael@0: CycleCollectionNoteChild(aCallback, aField[i], aName, aFlags); michael@0: } michael@0: } michael@0: michael@0: michael@0: // a non-XPCOM, refcounting array of XPCOM objects michael@0: // used as a member variable or stack variable - this object is NOT michael@0: // refcounted, but the objects that it holds are michael@0: // michael@0: // most of the read-only accessors like ObjectAt()/etc do NOT refcount michael@0: // on the way out. This means that you can do one of two things: michael@0: // michael@0: // * does an addref, but holds onto a reference michael@0: // nsCOMPtr foo = array[i]; michael@0: // michael@0: // * avoids the refcount, but foo might go stale if array[i] is ever michael@0: // * modified/removed. Be careful not to NS_RELEASE(foo)! michael@0: // T* foo = array[i]; michael@0: // michael@0: // This array will accept null as an argument for any object, and will michael@0: // store null in the array, just like nsVoidArray. But that also means michael@0: // that methods like ObjectAt() may return null when referring to an michael@0: // existing, but null entry in the array. michael@0: template michael@0: class nsCOMArray : public nsCOMArray_base michael@0: { michael@0: public: michael@0: nsCOMArray() {} michael@0: michael@0: explicit michael@0: nsCOMArray(int32_t aCount) : nsCOMArray_base(aCount) {} michael@0: michael@0: explicit michael@0: nsCOMArray(const nsCOMArray& aOther) : nsCOMArray_base(aOther) { } michael@0: michael@0: nsCOMArray(nsCOMArray&& aOther) { SwapElements(aOther); } michael@0: michael@0: ~nsCOMArray() {} michael@0: michael@0: // We have a move assignment operator, but no copy assignment operator. michael@0: nsCOMArray& operator=(nsCOMArray&& aOther) { michael@0: SwapElements(aOther); michael@0: return *this; michael@0: } michael@0: michael@0: // these do NOT refcount on the way out, for speed michael@0: T* ObjectAt(int32_t aIndex) const { michael@0: return static_cast(nsCOMArray_base::ObjectAt(aIndex)); michael@0: } michael@0: // nsTArray-compatible version michael@0: T* ElementAt(uint32_t aIndex) const { michael@0: return static_cast(nsCOMArray_base::ElementAt(aIndex)); michael@0: } michael@0: michael@0: // these do NOT refcount on the way out, for speed michael@0: T* SafeObjectAt(int32_t aIndex) const { michael@0: return static_cast(nsCOMArray_base::SafeObjectAt(aIndex)); michael@0: } michael@0: // nsTArray-compatible version michael@0: T* SafeElementAt(uint32_t aIndex) const { michael@0: return static_cast(nsCOMArray_base::SafeElementAt(aIndex)); michael@0: } michael@0: michael@0: // indexing operator for syntactic sugar michael@0: T* operator[](int32_t aIndex) const { michael@0: return ObjectAt(aIndex); michael@0: } michael@0: michael@0: // index of the element in question.. does NOT refcount michael@0: // note: this does not check COM object identity. Use michael@0: // IndexOfObject() for that purpose michael@0: int32_t IndexOf(T* aObject, uint32_t aStartIndex = 0) const { michael@0: return nsCOMArray_base::IndexOf(aObject, aStartIndex); michael@0: } michael@0: bool Contains(nsISupports* aObject) const { michael@0: return nsCOMArray_base::Contains(aObject); michael@0: } michael@0: michael@0: // index of the element in question.. be careful! michael@0: // this is much slower than IndexOf() because it uses michael@0: // QueryInterface to determine actual COM identity of the object michael@0: // if you need to do this frequently then consider enforcing michael@0: // COM object identity before adding/comparing elements michael@0: int32_t IndexOfObject(T* aObject) const { michael@0: return nsCOMArray_base::IndexOfObject(aObject); michael@0: } michael@0: bool ContainsObject(nsISupports* aObject) const { michael@0: return nsCOMArray_base::ContainsObject(aObject); michael@0: } michael@0: michael@0: // inserts aObject at aIndex, shifting the objects at aIndex and michael@0: // later to make space michael@0: bool InsertObjectAt(T* aObject, int32_t aIndex) { michael@0: return nsCOMArray_base::InsertObjectAt(aObject, aIndex); michael@0: } michael@0: // nsTArray-compatible version michael@0: void InsertElementAt(uint32_t aIndex, T* aElement) { michael@0: nsCOMArray_base::InsertElementAt(aIndex, aElement); michael@0: } michael@0: michael@0: // inserts the objects from aObject at aIndex, shifting the michael@0: // objects at aIndex and later to make space michael@0: bool InsertObjectsAt(const nsCOMArray& aObjects, int32_t aIndex) { michael@0: return nsCOMArray_base::InsertObjectsAt(aObjects, aIndex); michael@0: } michael@0: // nsTArray-compatible version michael@0: void InsertElementsAt(uint32_t aIndex, const nsCOMArray& aElements) { michael@0: nsCOMArray_base::InsertElementsAt(aIndex, aElements); michael@0: } michael@0: void InsertElementsAt(uint32_t aIndex, T* const* aElements, uint32_t aCount) { michael@0: nsCOMArray_base::InsertElementsAt(aIndex, reinterpret_cast(aElements), aCount); michael@0: } michael@0: michael@0: // replaces an existing element. Warning: if the array grows, michael@0: // the newly created entries will all be null michael@0: bool ReplaceObjectAt(T* aObject, int32_t aIndex) { michael@0: return nsCOMArray_base::ReplaceObjectAt(aObject, aIndex); michael@0: } michael@0: // nsTArray-compatible version michael@0: void ReplaceElementAt(uint32_t aIndex, T* aElement) { michael@0: nsCOMArray_base::ReplaceElementAt(aIndex, aElement); michael@0: } michael@0: michael@0: // Enumerator callback function. Return false to stop michael@0: // Here's a more readable form: michael@0: // bool enumerate(T* aElement, void* aData) michael@0: typedef bool (* nsCOMArrayEnumFunc) michael@0: (T* aElement, void *aData); michael@0: michael@0: // enumerate through the array with a callback. michael@0: bool EnumerateForwards(nsCOMArrayEnumFunc aFunc, void* aData) { michael@0: return nsCOMArray_base::EnumerateForwards(nsBaseArrayEnumFunc(aFunc), michael@0: aData); michael@0: } michael@0: michael@0: bool EnumerateBackwards(nsCOMArrayEnumFunc aFunc, void* aData) { michael@0: return nsCOMArray_base::EnumerateBackwards(nsBaseArrayEnumFunc(aFunc), michael@0: aData); michael@0: } michael@0: michael@0: typedef int (* nsCOMArrayComparatorFunc) michael@0: (T* aElement1, T* aElement2, void* aData); michael@0: michael@0: void Sort(nsCOMArrayComparatorFunc aFunc, void* aData) { michael@0: nsCOMArray_base::Sort(nsBaseArrayComparatorFunc(aFunc), aData); michael@0: } michael@0: michael@0: // append an object, growing the array as necessary michael@0: bool AppendObject(T *aObject) { michael@0: return nsCOMArray_base::AppendObject(aObject); michael@0: } michael@0: // nsTArray-compatible version michael@0: void AppendElement(T* aElement) { michael@0: nsCOMArray_base::AppendElement(aElement); michael@0: } michael@0: michael@0: // append objects, growing the array as necessary michael@0: bool AppendObjects(const nsCOMArray& aObjects) { michael@0: return nsCOMArray_base::AppendObjects(aObjects); michael@0: } michael@0: // nsTArray-compatible version michael@0: void AppendElements(const nsCOMArray& aElements) { michael@0: return nsCOMArray_base::AppendElements(aElements); michael@0: } michael@0: void AppendElements(T* const* aElements, uint32_t aCount) { michael@0: InsertElementsAt(Length(), aElements, aCount); michael@0: } michael@0: michael@0: // remove the first instance of the given object and shrink the michael@0: // array as necessary michael@0: // Warning: if you pass null here, it will remove the first null element michael@0: bool RemoveObject(T *aObject) { michael@0: return nsCOMArray_base::RemoveObject(aObject); michael@0: } michael@0: // nsTArray-compatible version michael@0: bool RemoveElement(T* aElement) { michael@0: return nsCOMArray_base::RemoveObject(aElement); michael@0: } michael@0: michael@0: T** Elements() { michael@0: return reinterpret_cast(nsCOMArray_base::Elements()); michael@0: } michael@0: void SwapElements(nsCOMArray& aOther) { michael@0: nsCOMArray_base::SwapElements(aOther); michael@0: } michael@0: michael@0: // Each element in an nsCOMArray is actually a T*, so this function is michael@0: // "IncludingThis" rather than "ExcludingThis" because it needs to measure michael@0: // the memory taken by the T itself as well as anything it points to. michael@0: typedef size_t (* nsCOMArraySizeOfElementIncludingThisFunc) michael@0: (T* aElement, mozilla::MallocSizeOf aMallocSizeOf, void *aData); michael@0: michael@0: size_t SizeOfExcludingThis( michael@0: nsCOMArraySizeOfElementIncludingThisFunc aSizeOfElementIncludingThis, michael@0: mozilla::MallocSizeOf aMallocSizeOf, void *aData = nullptr) const { michael@0: return nsCOMArray_base::SizeOfExcludingThis( michael@0: nsBaseArraySizeOfElementIncludingThisFunc(aSizeOfElementIncludingThis), michael@0: aMallocSizeOf, aData); michael@0: } michael@0: michael@0: /** michael@0: * Adopt parameters that resulted from an XPIDL outparam. The aElements michael@0: * parameter will be freed as a result of the call. michael@0: * michael@0: * Example usage: michael@0: * nsCOMArray array; michael@0: * nsISomeInterface** elements; michael@0: * uint32_t length; michael@0: * ptr->GetSomeArray(&elements, &length); michael@0: * array.Adopt(elements, length); michael@0: */ michael@0: void Adopt(T** aElements, uint32_t aSize) { michael@0: nsCOMArray_base::Adopt(reinterpret_cast(aElements), michael@0: aSize); michael@0: } michael@0: michael@0: /** michael@0: * Export the contents of this array to an XPIDL outparam. The array will be michael@0: * Clear()'d after this operation. michael@0: * michael@0: * Example usage: michael@0: * nsCOMArray array; michael@0: * *length = array.Forget(retval); michael@0: */ michael@0: uint32_t Forget(T*** elements) { michael@0: return nsCOMArray_base::Forget( michael@0: reinterpret_cast(elements)); michael@0: } michael@0: michael@0: private: michael@0: michael@0: // don't implement these! michael@0: nsCOMArray& operator=(const nsCOMArray& other) MOZ_DELETE; michael@0: }; michael@0: michael@0: template michael@0: inline void michael@0: ImplCycleCollectionUnlink(nsCOMArray& aField) michael@0: { michael@0: aField.Clear(); michael@0: } michael@0: michael@0: template michael@0: inline void michael@0: ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& aCallback, michael@0: nsCOMArray& aField, michael@0: const char* aName, michael@0: uint32_t aFlags = 0) michael@0: { michael@0: aFlags |= CycleCollectionEdgeNameArrayFlag; michael@0: int32_t length = aField.Count(); michael@0: for (int32_t i = 0; i < length; ++i) { michael@0: CycleCollectionNoteChild(aCallback, aField[i], aName, aFlags); michael@0: } michael@0: } michael@0: michael@0: #endif