Bug 1880216 - Migrate Fenix docs into Sphinx. r=owlish,geckoview-reviewers,android...
[gecko.git] / xpcom / ds / nsArrayEnumerator.cpp
blobec475f9e5b8a7e616da0be669b0ef9bc73d9999d
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "mozilla/Attributes.h"
9 #include "nsArrayEnumerator.h"
11 #include "nsIArray.h"
12 #include "nsSimpleEnumerator.h"
14 #include "nsCOMArray.h"
15 #include "nsCOMPtr.h"
16 #include "mozilla/OperatorNewExtensions.h"
17 #include "mozilla/RefPtr.h"
19 class nsSimpleArrayEnumerator final : public nsSimpleEnumerator {
20 public:
21 // nsISimpleEnumerator interface
22 NS_DECL_NSISIMPLEENUMERATOR
24 // nsSimpleArrayEnumerator methods
25 explicit nsSimpleArrayEnumerator(nsIArray* aValueArray, const nsID& aEntryIID)
26 : mValueArray(aValueArray), mEntryIID(aEntryIID), mIndex(0) {}
28 const nsID& DefaultInterface() override { return mEntryIID; }
30 private:
31 ~nsSimpleArrayEnumerator() override = default;
33 protected:
34 nsCOMPtr<nsIArray> mValueArray;
35 const nsID mEntryIID;
36 uint32_t mIndex;
39 NS_IMETHODIMP
40 nsSimpleArrayEnumerator::HasMoreElements(bool* aResult) {
41 MOZ_ASSERT(aResult != 0, "null ptr");
42 if (!aResult) {
43 return NS_ERROR_NULL_POINTER;
46 if (!mValueArray) {
47 *aResult = false;
48 return NS_OK;
51 uint32_t cnt;
52 nsresult rv = mValueArray->GetLength(&cnt);
53 if (NS_FAILED(rv)) {
54 return rv;
56 *aResult = (mIndex < cnt);
57 return NS_OK;
60 NS_IMETHODIMP
61 nsSimpleArrayEnumerator::GetNext(nsISupports** aResult) {
62 MOZ_ASSERT(aResult != 0, "null ptr");
63 if (!aResult) {
64 return NS_ERROR_NULL_POINTER;
67 if (!mValueArray) {
68 *aResult = nullptr;
69 return NS_OK;
72 uint32_t cnt;
73 nsresult rv = mValueArray->GetLength(&cnt);
74 if (NS_FAILED(rv)) {
75 return rv;
77 if (mIndex >= cnt) {
78 return NS_ERROR_UNEXPECTED;
81 return mValueArray->QueryElementAt(mIndex++, NS_GET_IID(nsISupports),
82 (void**)aResult);
85 nsresult NS_NewArrayEnumerator(nsISimpleEnumerator** aResult, nsIArray* aArray,
86 const nsID& aEntryIID) {
87 RefPtr<nsSimpleArrayEnumerator> enumer =
88 new nsSimpleArrayEnumerator(aArray, aEntryIID);
89 enumer.forget(aResult);
90 return NS_OK;
93 ////////////////////////////////////////////////////////////////////////////////
95 // enumerator implementation for nsCOMArray
96 // creates a snapshot of the array in question
97 // you MUST use NS_NewArrayEnumerator to create this, so that
98 // allocation is done correctly
99 class nsCOMArrayEnumerator final : public nsSimpleEnumerator {
100 public:
101 // nsISimpleEnumerator interface
102 NS_DECL_NSISIMPLEENUMERATOR
104 // Use this instead of `new`.
105 static nsCOMArrayEnumerator* Allocate(const nsCOMArray_base& aArray,
106 const nsID& aEntryIID);
108 // specialized operator to make sure we make room for mValues
109 void operator delete(void* aPtr) { free(aPtr); }
111 const nsID& DefaultInterface() override { return mEntryIID; }
113 private:
114 // nsSimpleArrayEnumerator methods
115 explicit nsCOMArrayEnumerator(const nsID& aEntryIID)
116 : mIndex(0), mArraySize(0), mEntryIID(aEntryIID) {
117 mValueArray[0] = nullptr;
120 ~nsCOMArrayEnumerator(void) override;
122 protected:
123 uint32_t mIndex; // current position
124 uint32_t mArraySize; // size of the array
126 const nsID& mEntryIID;
128 // this is actually bigger
129 nsISupports* mValueArray[1];
132 nsCOMArrayEnumerator::~nsCOMArrayEnumerator() {
133 // only release the entries that we haven't visited yet
134 for (; mIndex < mArraySize; ++mIndex) {
135 NS_IF_RELEASE(mValueArray[mIndex]);
139 NS_IMETHODIMP
140 nsCOMArrayEnumerator::HasMoreElements(bool* aResult) {
141 MOZ_ASSERT(aResult != 0, "null ptr");
142 if (!aResult) {
143 return NS_ERROR_NULL_POINTER;
146 *aResult = (mIndex < mArraySize);
147 return NS_OK;
150 NS_IMETHODIMP
151 nsCOMArrayEnumerator::GetNext(nsISupports** aResult) {
152 MOZ_ASSERT(aResult != 0, "null ptr");
153 if (!aResult) {
154 return NS_ERROR_NULL_POINTER;
157 if (mIndex >= mArraySize) {
158 return NS_ERROR_UNEXPECTED;
161 // pass the ownership of the reference to the caller. Since
162 // we AddRef'ed during creation of |this|, there is no need
163 // to AddRef here
164 *aResult = mValueArray[mIndex++];
166 // this really isn't necessary. just pretend this happens, since
167 // we'll never visit this value again!
168 // mValueArray[(mIndex-1)] = nullptr;
170 return NS_OK;
173 nsCOMArrayEnumerator* nsCOMArrayEnumerator::Allocate(
174 const nsCOMArray_base& aArray, const nsID& aEntryIID) {
175 // create enough space such that mValueArray points to a large
176 // enough value. Note that the initial value of aSize gives us
177 // space for mValueArray[0], so we must subtract
178 size_t size = sizeof(nsCOMArrayEnumerator);
179 uint32_t count;
180 if (aArray.Count() > 0) {
181 count = static_cast<uint32_t>(aArray.Count());
182 size += (count - 1) * sizeof(aArray[0]);
183 } else {
184 count = 0;
187 // Allocate a buffer large enough to contain our object and its array.
188 void* mem = moz_xmalloc(size);
189 auto result =
190 new (mozilla::KnownNotNull, mem) nsCOMArrayEnumerator(aEntryIID);
192 result->mArraySize = count;
194 // now need to copy over the values, and addref each one
195 // now this might seem like a lot of work, but we're actually just
196 // doing all our AddRef's ahead of time since GetNext() doesn't
197 // need to AddRef() on the way out
198 for (uint32_t i = 0; i < count; ++i) {
199 result->mValueArray[i] = aArray[i];
200 NS_IF_ADDREF(result->mValueArray[i]);
203 return result;
206 nsresult NS_NewArrayEnumerator(nsISimpleEnumerator** aResult,
207 const nsCOMArray_base& aArray,
208 const nsID& aEntryIID) {
209 RefPtr<nsCOMArrayEnumerator> enumerator =
210 nsCOMArrayEnumerator::Allocate(aArray, aEntryIID);
211 enumerator.forget(aResult);
212 return NS_OK;