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