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 "mozilla/Attributes.h" michael@0: michael@0: #include "nsArrayEnumerator.h" michael@0: michael@0: #include "nsIArray.h" michael@0: #include "nsISimpleEnumerator.h" michael@0: michael@0: #include "nsCOMArray.h" michael@0: #include "nsCOMPtr.h" michael@0: michael@0: class nsSimpleArrayEnumerator MOZ_FINAL : public nsISimpleEnumerator michael@0: { michael@0: public: michael@0: // nsISupports interface michael@0: NS_DECL_ISUPPORTS michael@0: michael@0: // nsISimpleEnumerator interface michael@0: NS_DECL_NSISIMPLEENUMERATOR michael@0: michael@0: // nsSimpleArrayEnumerator methods michael@0: nsSimpleArrayEnumerator(nsIArray* aValueArray) : michael@0: mValueArray(aValueArray), mIndex(0) { michael@0: } michael@0: michael@0: private: michael@0: ~nsSimpleArrayEnumerator() {} michael@0: michael@0: protected: michael@0: nsCOMPtr mValueArray; michael@0: uint32_t mIndex; michael@0: }; michael@0: michael@0: NS_IMPL_ISUPPORTS(nsSimpleArrayEnumerator, nsISimpleEnumerator) michael@0: michael@0: NS_IMETHODIMP michael@0: nsSimpleArrayEnumerator::HasMoreElements(bool* aResult) michael@0: { michael@0: NS_PRECONDITION(aResult != 0, "null ptr"); michael@0: if (! aResult) michael@0: return NS_ERROR_NULL_POINTER; michael@0: michael@0: if (!mValueArray) { michael@0: *aResult = false; michael@0: return NS_OK; michael@0: } michael@0: michael@0: uint32_t cnt; michael@0: nsresult rv = mValueArray->GetLength(&cnt); michael@0: if (NS_FAILED(rv)) return rv; michael@0: *aResult = (mIndex < cnt); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsSimpleArrayEnumerator::GetNext(nsISupports** aResult) michael@0: { michael@0: NS_PRECONDITION(aResult != 0, "null ptr"); michael@0: if (! aResult) michael@0: return NS_ERROR_NULL_POINTER; michael@0: michael@0: if (!mValueArray) { michael@0: *aResult = nullptr; michael@0: return NS_OK; michael@0: } michael@0: michael@0: uint32_t cnt; michael@0: nsresult rv = mValueArray->GetLength(&cnt); michael@0: if (NS_FAILED(rv)) return rv; michael@0: if (mIndex >= cnt) michael@0: return NS_ERROR_UNEXPECTED; michael@0: michael@0: return mValueArray->QueryElementAt(mIndex++, NS_GET_IID(nsISupports), (void**)aResult); michael@0: } michael@0: michael@0: nsresult michael@0: NS_NewArrayEnumerator(nsISimpleEnumerator* *result, michael@0: nsIArray* array) michael@0: { michael@0: nsSimpleArrayEnumerator* enumer = new nsSimpleArrayEnumerator(array); michael@0: if (enumer == nullptr) michael@0: return NS_ERROR_OUT_OF_MEMORY; michael@0: michael@0: NS_ADDREF(*result = enumer); michael@0: return NS_OK; michael@0: } michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: michael@0: // enumerator implementation for nsCOMArray michael@0: // creates a snapshot of the array in question michael@0: // you MUST use NS_NewArrayEnumerator to create this, so that michael@0: // allocation is done correctly michael@0: class nsCOMArrayEnumerator MOZ_FINAL : public nsISimpleEnumerator michael@0: { michael@0: public: michael@0: // nsISupports interface michael@0: NS_DECL_ISUPPORTS michael@0: michael@0: // nsISimpleEnumerator interface michael@0: NS_DECL_NSISIMPLEENUMERATOR michael@0: michael@0: // nsSimpleArrayEnumerator methods michael@0: nsCOMArrayEnumerator() : mIndex(0) { michael@0: } michael@0: michael@0: // specialized operator to make sure we make room for mValues michael@0: void* operator new (size_t size, const nsCOMArray_base& aArray) CPP_THROW_NEW; michael@0: void operator delete(void* ptr) { michael@0: ::operator delete(ptr); michael@0: } michael@0: michael@0: private: michael@0: ~nsCOMArrayEnumerator(void); michael@0: michael@0: protected: michael@0: uint32_t mIndex; // current position michael@0: uint32_t mArraySize; // size of the array michael@0: michael@0: // this is actually bigger michael@0: nsISupports* mValueArray[1]; michael@0: }; michael@0: michael@0: NS_IMPL_ISUPPORTS(nsCOMArrayEnumerator, nsISimpleEnumerator) michael@0: michael@0: nsCOMArrayEnumerator::~nsCOMArrayEnumerator() michael@0: { michael@0: // only release the entries that we haven't visited yet michael@0: for (; mIndex < mArraySize; ++mIndex) { michael@0: NS_IF_RELEASE(mValueArray[mIndex]); michael@0: } michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsCOMArrayEnumerator::HasMoreElements(bool* aResult) michael@0: { michael@0: NS_PRECONDITION(aResult != 0, "null ptr"); michael@0: if (! aResult) michael@0: return NS_ERROR_NULL_POINTER; michael@0: michael@0: *aResult = (mIndex < mArraySize); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsCOMArrayEnumerator::GetNext(nsISupports** aResult) michael@0: { michael@0: NS_PRECONDITION(aResult != 0, "null ptr"); michael@0: if (! aResult) michael@0: return NS_ERROR_NULL_POINTER; michael@0: michael@0: if (mIndex >= mArraySize) michael@0: return NS_ERROR_UNEXPECTED; michael@0: michael@0: // pass the ownership of the reference to the caller. Since michael@0: // we AddRef'ed during creation of |this|, there is no need michael@0: // to AddRef here michael@0: *aResult = mValueArray[mIndex++]; michael@0: michael@0: // this really isn't necessary. just pretend this happens, since michael@0: // we'll never visit this value again! michael@0: // mValueArray[(mIndex-1)] = nullptr; michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: void* michael@0: nsCOMArrayEnumerator::operator new (size_t size, const nsCOMArray_base& aArray) michael@0: CPP_THROW_NEW michael@0: { michael@0: // create enough space such that mValueArray points to a large michael@0: // enough value. Note that the initial value of size gives us michael@0: // space for mValueArray[0], so we must subtract michael@0: size += (aArray.Count() - 1) * sizeof(aArray[0]); michael@0: michael@0: // do the actual allocation michael@0: nsCOMArrayEnumerator * result = michael@0: static_cast(::operator new(size)); michael@0: michael@0: // now need to copy over the values, and addref each one michael@0: // now this might seem like a lot of work, but we're actually just michael@0: // doing all our AddRef's ahead of time since GetNext() doesn't michael@0: // need to AddRef() on the way out michael@0: uint32_t i; michael@0: uint32_t max = result->mArraySize = aArray.Count(); michael@0: for (i = 0; imValueArray[i] = aArray[i]; michael@0: NS_IF_ADDREF(result->mValueArray[i]); michael@0: } michael@0: michael@0: return result; michael@0: } michael@0: michael@0: nsresult michael@0: NS_NewArrayEnumerator(nsISimpleEnumerator* *aResult, michael@0: const nsCOMArray_base& aArray) michael@0: { michael@0: nsCOMArrayEnumerator *enumerator = new (aArray) nsCOMArrayEnumerator(); michael@0: if (!enumerator) return NS_ERROR_OUT_OF_MEMORY; michael@0: michael@0: NS_ADDREF(*aResult = enumerator); michael@0: return NS_OK; michael@0: }