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: #include "nsCOMArray.h" michael@0: michael@0: #include "mozilla/MemoryReporting.h" michael@0: michael@0: #include "nsCOMPtr.h" michael@0: michael@0: // This specialization is private to nsCOMArray. michael@0: // It exists solely to automatically zero-out newly created array elements. michael@0: template<> michael@0: class nsTArrayElementTraits michael@0: { michael@0: typedef nsISupports* E; michael@0: public: michael@0: // Zero out the value michael@0: static inline void Construct(E *e) { michael@0: new (static_cast(e)) E(); michael@0: } michael@0: // Invoke the copy-constructor in place. michael@0: template michael@0: static inline void Construct(E *e, const A &arg) { michael@0: new (static_cast(e)) E(arg); michael@0: } michael@0: // Invoke the destructor in place. michael@0: static inline void Destruct(E *e) { michael@0: e->~E(); michael@0: } michael@0: }; michael@0: michael@0: static void ReleaseObjects(nsTArray &aArray); michael@0: michael@0: // implementations of non-trivial methods in nsCOMArray_base michael@0: michael@0: nsCOMArray_base::nsCOMArray_base(const nsCOMArray_base& aOther) michael@0: { michael@0: // make sure we do only one allocation michael@0: mArray.SetCapacity(aOther.Count()); michael@0: AppendObjects(aOther); michael@0: } michael@0: michael@0: nsCOMArray_base::~nsCOMArray_base() michael@0: { michael@0: Clear(); michael@0: } michael@0: michael@0: int32_t michael@0: nsCOMArray_base::IndexOf(nsISupports* aObject, uint32_t aStartIndex) const michael@0: { michael@0: return mArray.IndexOf(aObject, aStartIndex); michael@0: } michael@0: michael@0: int32_t michael@0: nsCOMArray_base::IndexOfObject(nsISupports* aObject) const michael@0: { michael@0: nsCOMPtr supports = do_QueryInterface(aObject); michael@0: if (NS_WARN_IF(!supports)) michael@0: return -1; michael@0: michael@0: uint32_t i, count; michael@0: int32_t retval = -1; michael@0: count = mArray.Length(); michael@0: for (i = 0; i < count; ++i) { michael@0: nsCOMPtr arrayItem = do_QueryInterface(mArray[i]); michael@0: if (arrayItem == supports) { michael@0: retval = i; michael@0: break; michael@0: } michael@0: } michael@0: return retval; michael@0: } michael@0: michael@0: bool michael@0: nsCOMArray_base::EnumerateForwards(nsBaseArrayEnumFunc aFunc, void* aData) const michael@0: { michael@0: for (uint32_t index = 0; index < mArray.Length(); index++) michael@0: if (!(*aFunc)(mArray[index], aData)) michael@0: return false; michael@0: michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: nsCOMArray_base::EnumerateBackwards(nsBaseArrayEnumFunc aFunc, void* aData) const michael@0: { michael@0: for (uint32_t index = mArray.Length(); index--; ) michael@0: if (!(*aFunc)(mArray[index], aData)) michael@0: return false; michael@0: michael@0: return true; michael@0: } michael@0: michael@0: int michael@0: nsCOMArray_base::nsCOMArrayComparator(const void* aElement1, const void* aElement2, void* aData) michael@0: { michael@0: nsCOMArrayComparatorContext* ctx = static_cast(aData); michael@0: return (*ctx->mComparatorFunc)(*static_cast(aElement1), michael@0: *static_cast(aElement2), michael@0: ctx->mData); michael@0: } michael@0: michael@0: void michael@0: nsCOMArray_base::Sort(nsBaseArrayComparatorFunc aFunc, void* aData) michael@0: { michael@0: if (mArray.Length() > 1) { michael@0: nsCOMArrayComparatorContext ctx = {aFunc, aData}; michael@0: NS_QuickSort(mArray.Elements(), mArray.Length(), sizeof(nsISupports*), michael@0: nsCOMArrayComparator, &ctx); michael@0: } michael@0: } michael@0: michael@0: bool michael@0: nsCOMArray_base::InsertObjectAt(nsISupports* aObject, int32_t aIndex) michael@0: { michael@0: if ((uint32_t)aIndex > mArray.Length()) michael@0: return false; michael@0: michael@0: if (!mArray.InsertElementAt(aIndex, aObject)) michael@0: return false; michael@0: michael@0: NS_IF_ADDREF(aObject); michael@0: return true; michael@0: } michael@0: michael@0: void michael@0: nsCOMArray_base::InsertElementAt(uint32_t aIndex, nsISupports* aElement) michael@0: { michael@0: mArray.InsertElementAt(aIndex, aElement); michael@0: NS_IF_ADDREF(aElement); michael@0: } michael@0: michael@0: bool michael@0: nsCOMArray_base::InsertObjectsAt(const nsCOMArray_base& aObjects, int32_t aIndex) michael@0: { michael@0: if ((uint32_t)aIndex > mArray.Length()) michael@0: return false; michael@0: michael@0: if (!mArray.InsertElementsAt(aIndex, aObjects.mArray)) michael@0: return false; michael@0: michael@0: // need to addref all these michael@0: uint32_t count = aObjects.Length(); michael@0: for (uint32_t i = 0; i < count; ++i) michael@0: NS_IF_ADDREF(aObjects[i]); michael@0: michael@0: return true; michael@0: } michael@0: michael@0: void michael@0: nsCOMArray_base::InsertElementsAt(uint32_t aIndex, const nsCOMArray_base& aElements) michael@0: { michael@0: mArray.InsertElementsAt(aIndex, aElements.mArray); michael@0: michael@0: // need to addref all these michael@0: uint32_t count = aElements.Length(); michael@0: for (uint32_t i = 0; i < count; ++i) michael@0: NS_IF_ADDREF(aElements[i]); michael@0: } michael@0: michael@0: void michael@0: nsCOMArray_base::InsertElementsAt(uint32_t aIndex, nsISupports* const* aElements, uint32_t aCount) michael@0: { michael@0: mArray.InsertElementsAt(aIndex, aElements, aCount); michael@0: michael@0: // need to addref all these michael@0: for (uint32_t i = 0; i < aCount; ++i) michael@0: NS_IF_ADDREF(aElements[i]); michael@0: } michael@0: michael@0: bool michael@0: nsCOMArray_base::ReplaceObjectAt(nsISupports* aObject, int32_t aIndex) michael@0: { michael@0: mArray.EnsureLengthAtLeast(aIndex + 1); michael@0: nsISupports *oldObject = mArray[aIndex]; michael@0: // Make sure to addref first, in case aObject == oldObject michael@0: NS_IF_ADDREF(mArray[aIndex] = aObject); michael@0: NS_IF_RELEASE(oldObject); michael@0: // XXX make this return void michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: nsCOMArray_base::RemoveObject(nsISupports *aObject) michael@0: { michael@0: bool result = mArray.RemoveElement(aObject); michael@0: if (result) michael@0: NS_IF_RELEASE(aObject); michael@0: return result; michael@0: } michael@0: michael@0: bool michael@0: nsCOMArray_base::RemoveObjectAt(int32_t aIndex) michael@0: { michael@0: if (uint32_t(aIndex) < mArray.Length()) { michael@0: nsISupports* element = mArray[aIndex]; michael@0: michael@0: mArray.RemoveElementAt(aIndex); michael@0: NS_IF_RELEASE(element); michael@0: return true; michael@0: } michael@0: michael@0: return false; michael@0: } michael@0: michael@0: void michael@0: nsCOMArray_base::RemoveElementAt(uint32_t aIndex) michael@0: { michael@0: nsISupports* element = mArray[aIndex]; michael@0: mArray.RemoveElementAt(aIndex); michael@0: NS_IF_RELEASE(element); michael@0: } michael@0: michael@0: bool michael@0: nsCOMArray_base::RemoveObjectsAt(int32_t aIndex, int32_t aCount) michael@0: { michael@0: if (uint32_t(aIndex) + uint32_t(aCount) <= mArray.Length()) { michael@0: nsTArray elementsToDestroy(aCount); michael@0: elementsToDestroy.AppendElements(mArray.Elements() + aIndex, aCount); michael@0: mArray.RemoveElementsAt(aIndex, aCount); michael@0: ReleaseObjects(elementsToDestroy); michael@0: return true; michael@0: } michael@0: michael@0: return false; michael@0: } michael@0: michael@0: void michael@0: nsCOMArray_base::RemoveElementsAt(uint32_t aIndex, uint32_t aCount) michael@0: { michael@0: nsTArray elementsToDestroy(aCount); michael@0: elementsToDestroy.AppendElements(mArray.Elements() + aIndex, aCount); michael@0: mArray.RemoveElementsAt(aIndex, aCount); michael@0: ReleaseObjects(elementsToDestroy); michael@0: } michael@0: michael@0: // useful for destructors michael@0: void michael@0: ReleaseObjects(nsTArray &aArray) michael@0: { michael@0: for (uint32_t i = 0; i < aArray.Length(); i++) michael@0: NS_IF_RELEASE(aArray[i]); michael@0: } michael@0: michael@0: void michael@0: nsCOMArray_base::Clear() michael@0: { michael@0: nsTArray objects; michael@0: objects.SwapElements(mArray); michael@0: ReleaseObjects(objects); michael@0: } michael@0: michael@0: bool michael@0: nsCOMArray_base::SetCount(int32_t aNewCount) michael@0: { michael@0: NS_ASSERTION(aNewCount >= 0,"SetCount(negative index)"); michael@0: if (aNewCount < 0) michael@0: return false; michael@0: michael@0: int32_t count = mArray.Length(); michael@0: if (count > aNewCount) michael@0: RemoveObjectsAt(aNewCount, mArray.Length() - aNewCount); michael@0: mArray.SetLength(aNewCount); michael@0: return true; michael@0: } michael@0: michael@0: size_t michael@0: nsCOMArray_base::SizeOfExcludingThis( michael@0: nsBaseArraySizeOfElementIncludingThisFunc aSizeOfElementIncludingThis, michael@0: mozilla::MallocSizeOf aMallocSizeOf, void* aData) const michael@0: { michael@0: size_t n = mArray.SizeOfExcludingThis(aMallocSizeOf); michael@0: michael@0: if (aSizeOfElementIncludingThis) michael@0: for (uint32_t index = 0; index < mArray.Length(); index++) michael@0: n += aSizeOfElementIncludingThis(mArray[index], aMallocSizeOf, aData); michael@0: michael@0: return n; michael@0: } michael@0: michael@0: michael@0: void michael@0: nsCOMArray_base::Adopt(nsISupports** aElements, uint32_t aSize) michael@0: { michael@0: Clear(); michael@0: mArray.AppendElements(aElements, aSize); michael@0: michael@0: // Free the allocated array as well. michael@0: NS_Free(aElements); michael@0: } michael@0: michael@0: uint32_t michael@0: nsCOMArray_base::Forget(nsISupports*** elements) michael@0: { michael@0: uint32_t length = Length(); michael@0: size_t array_size = sizeof(nsISupports*) * length; michael@0: nsISupports** array = static_cast(NS_Alloc(array_size)); michael@0: memmove(array, Elements(), array_size); michael@0: *elements = array; michael@0: // Don't Release the contained pointers; the caller of the method will michael@0: // do this eventually. michael@0: mArray.Clear(); michael@0: michael@0: return length; michael@0: }