/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "nsCOMArray.h" #include "mozilla/MemoryReporting.h" #include "nsCOMPtr.h" // This specialization is private to nsCOMArray. // It exists solely to automatically zero-out newly created array elements. template<> class nsTArrayElementTraits { typedef nsISupports* E; public: // Zero out the value static inline void Construct(E *e) { new (static_cast(e)) E(); } // Invoke the copy-constructor in place. template static inline void Construct(E *e, const A &arg) { new (static_cast(e)) E(arg); } // Invoke the destructor in place. static inline void Destruct(E *e) { e->~E(); } }; static void ReleaseObjects(nsTArray &aArray); // implementations of non-trivial methods in nsCOMArray_base nsCOMArray_base::nsCOMArray_base(const nsCOMArray_base& aOther) { // make sure we do only one allocation mArray.SetCapacity(aOther.Count()); AppendObjects(aOther); } nsCOMArray_base::~nsCOMArray_base() { Clear(); } int32_t nsCOMArray_base::IndexOf(nsISupports* aObject, uint32_t aStartIndex) const { return mArray.IndexOf(aObject, aStartIndex); } int32_t nsCOMArray_base::IndexOfObject(nsISupports* aObject) const { nsCOMPtr supports = do_QueryInterface(aObject); if (NS_WARN_IF(!supports)) return -1; uint32_t i, count; int32_t retval = -1; count = mArray.Length(); for (i = 0; i < count; ++i) { nsCOMPtr arrayItem = do_QueryInterface(mArray[i]); if (arrayItem == supports) { retval = i; break; } } 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(aData); return (*ctx->mComparatorFunc)(*static_cast(aElement1), *static_cast(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 nsCOMArray_base::InsertObjectAt(nsISupports* aObject, int32_t aIndex) { if ((uint32_t)aIndex > mArray.Length()) return false; if (!mArray.InsertElementAt(aIndex, aObject)) return false; NS_IF_ADDREF(aObject); return true; } void nsCOMArray_base::InsertElementAt(uint32_t aIndex, nsISupports* aElement) { mArray.InsertElementAt(aIndex, aElement); NS_IF_ADDREF(aElement); } bool nsCOMArray_base::InsertObjectsAt(const nsCOMArray_base& aObjects, int32_t aIndex) { if ((uint32_t)aIndex > mArray.Length()) return false; if (!mArray.InsertElementsAt(aIndex, aObjects.mArray)) return false; // need to addref all these uint32_t count = aObjects.Length(); for (uint32_t i = 0; i < count; ++i) NS_IF_ADDREF(aObjects[i]); return true; } void nsCOMArray_base::InsertElementsAt(uint32_t aIndex, const nsCOMArray_base& aElements) { mArray.InsertElementsAt(aIndex, aElements.mArray); // need to addref all these uint32_t count = aElements.Length(); for (uint32_t i = 0; i < count; ++i) NS_IF_ADDREF(aElements[i]); } void nsCOMArray_base::InsertElementsAt(uint32_t aIndex, nsISupports* const* aElements, uint32_t aCount) { mArray.InsertElementsAt(aIndex, aElements, aCount); // need to addref all these for (uint32_t i = 0; i < aCount; ++i) NS_IF_ADDREF(aElements[i]); } bool nsCOMArray_base::ReplaceObjectAt(nsISupports* aObject, int32_t aIndex) { mArray.EnsureLengthAtLeast(aIndex + 1); nsISupports *oldObject = mArray[aIndex]; // Make sure to addref first, in case aObject == oldObject NS_IF_ADDREF(mArray[aIndex] = aObject); NS_IF_RELEASE(oldObject); // XXX make this return void return true; } bool nsCOMArray_base::RemoveObject(nsISupports *aObject) { bool result = mArray.RemoveElement(aObject); if (result) NS_IF_RELEASE(aObject); return result; } bool nsCOMArray_base::RemoveObjectAt(int32_t aIndex) { if (uint32_t(aIndex) < mArray.Length()) { nsISupports* element = mArray[aIndex]; mArray.RemoveElementAt(aIndex); NS_IF_RELEASE(element); return true; } return false; } void nsCOMArray_base::RemoveElementAt(uint32_t aIndex) { nsISupports* element = mArray[aIndex]; mArray.RemoveElementAt(aIndex); NS_IF_RELEASE(element); } bool nsCOMArray_base::RemoveObjectsAt(int32_t aIndex, int32_t aCount) { if (uint32_t(aIndex) + uint32_t(aCount) <= mArray.Length()) { nsTArray elementsToDestroy(aCount); elementsToDestroy.AppendElements(mArray.Elements() + aIndex, aCount); mArray.RemoveElementsAt(aIndex, aCount); ReleaseObjects(elementsToDestroy); return true; } return false; } void nsCOMArray_base::RemoveElementsAt(uint32_t aIndex, uint32_t aCount) { nsTArray elementsToDestroy(aCount); elementsToDestroy.AppendElements(mArray.Elements() + aIndex, aCount); mArray.RemoveElementsAt(aIndex, aCount); ReleaseObjects(elementsToDestroy); } // useful for destructors void ReleaseObjects(nsTArray &aArray) { for (uint32_t i = 0; i < aArray.Length(); i++) NS_IF_RELEASE(aArray[i]); } void nsCOMArray_base::Clear() { nsTArray objects; objects.SwapElements(mArray); ReleaseObjects(objects); } bool nsCOMArray_base::SetCount(int32_t aNewCount) { NS_ASSERTION(aNewCount >= 0,"SetCount(negative index)"); if (aNewCount < 0) return false; int32_t count = mArray.Length(); if (count > aNewCount) RemoveObjectsAt(aNewCount, mArray.Length() - aNewCount); mArray.SetLength(aNewCount); return true; } size_t nsCOMArray_base::SizeOfExcludingThis( nsBaseArraySizeOfElementIncludingThisFunc aSizeOfElementIncludingThis, mozilla::MallocSizeOf 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; } void nsCOMArray_base::Adopt(nsISupports** aElements, uint32_t aSize) { Clear(); mArray.AppendElements(aElements, aSize); // Free the allocated array as well. NS_Free(aElements); } uint32_t nsCOMArray_base::Forget(nsISupports*** elements) { uint32_t length = Length(); size_t array_size = sizeof(nsISupports*) * length; nsISupports** array = static_cast(NS_Alloc(array_size)); memmove(array, Elements(), array_size); *elements = array; // Don't Release the contained pointers; the caller of the method will // do this eventually. mArray.Clear(); return length; }