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/. */
6
7 #include "mozilla/Attributes.h"
8
9 #include "nsArrayEnumerator.h"
10
11 #include "nsIArray.h"
12 #include "nsISimpleEnumerator.h"
13
14 #include "nsCOMArray.h"
15 #include "nsCOMPtr.h"
16 #include "mozilla/RefPtr.h"
17
18 class nsSimpleArrayEnumerator final : public nsISimpleEnumerator
19 {
20 public:
21 // nsISupports interface
22 NS_DECL_ISUPPORTS
23
24 // nsISimpleEnumerator interface
25 NS_DECL_NSISIMPLEENUMERATOR
26
27 // nsSimpleArrayEnumerator methods
nsSimpleArrayEnumerator(nsIArray * aValueArray)28 explicit nsSimpleArrayEnumerator(nsIArray* aValueArray)
29 : mValueArray(aValueArray)
30 , mIndex(0)
31 {
32 }
33
34 private:
~nsSimpleArrayEnumerator()35 ~nsSimpleArrayEnumerator() {}
36
37 protected:
38 nsCOMPtr<nsIArray> mValueArray;
39 uint32_t mIndex;
40 };
41
NS_IMPL_ISUPPORTS(nsSimpleArrayEnumerator,nsISimpleEnumerator)42 NS_IMPL_ISUPPORTS(nsSimpleArrayEnumerator, nsISimpleEnumerator)
43
44 NS_IMETHODIMP
45 nsSimpleArrayEnumerator::HasMoreElements(bool* aResult)
46 {
47 NS_PRECONDITION(aResult != 0, "null ptr");
48 if (!aResult) {
49 return NS_ERROR_NULL_POINTER;
50 }
51
52 if (!mValueArray) {
53 *aResult = false;
54 return NS_OK;
55 }
56
57 uint32_t cnt;
58 nsresult rv = mValueArray->GetLength(&cnt);
59 if (NS_FAILED(rv)) {
60 return rv;
61 }
62 *aResult = (mIndex < cnt);
63 return NS_OK;
64 }
65
66 NS_IMETHODIMP
GetNext(nsISupports ** aResult)67 nsSimpleArrayEnumerator::GetNext(nsISupports** aResult)
68 {
69 NS_PRECONDITION(aResult != 0, "null ptr");
70 if (!aResult) {
71 return NS_ERROR_NULL_POINTER;
72 }
73
74 if (!mValueArray) {
75 *aResult = nullptr;
76 return NS_OK;
77 }
78
79 uint32_t cnt;
80 nsresult rv = mValueArray->GetLength(&cnt);
81 if (NS_FAILED(rv)) {
82 return rv;
83 }
84 if (mIndex >= cnt) {
85 return NS_ERROR_UNEXPECTED;
86 }
87
88 return mValueArray->QueryElementAt(mIndex++, NS_GET_IID(nsISupports),
89 (void**)aResult);
90 }
91
92 nsresult
NS_NewArrayEnumerator(nsISimpleEnumerator ** aResult,nsIArray * aArray)93 NS_NewArrayEnumerator(nsISimpleEnumerator** aResult, nsIArray* aArray)
94 {
95 RefPtr<nsSimpleArrayEnumerator> enumer = new nsSimpleArrayEnumerator(aArray);
96 enumer.forget(aResult);
97 return NS_OK;
98 }
99
100 ////////////////////////////////////////////////////////////////////////////////
101
102 // enumerator implementation for nsCOMArray
103 // creates a snapshot of the array in question
104 // you MUST use NS_NewArrayEnumerator to create this, so that
105 // allocation is done correctly
106 class nsCOMArrayEnumerator final : public nsISimpleEnumerator
107 {
108 public:
109 // nsISupports interface
110 NS_DECL_ISUPPORTS
111
112 // nsISimpleEnumerator interface
113 NS_DECL_NSISIMPLEENUMERATOR
114
115 // nsSimpleArrayEnumerator methods
nsCOMArrayEnumerator()116 nsCOMArrayEnumerator() : mIndex(0) {}
117
118 // specialized operator to make sure we make room for mValues
119 void* operator new(size_t aSize, const nsCOMArray_base& aArray) CPP_THROW_NEW;
operator delete(void * aPtr)120 void operator delete(void* aPtr) { ::operator delete(aPtr); }
121
122 private:
123 ~nsCOMArrayEnumerator(void);
124
125 protected:
126 uint32_t mIndex; // current position
127 uint32_t mArraySize; // size of the array
128
129 // this is actually bigger
130 nsISupports* mValueArray[1];
131 };
132
NS_IMPL_ISUPPORTS(nsCOMArrayEnumerator,nsISimpleEnumerator)133 NS_IMPL_ISUPPORTS(nsCOMArrayEnumerator, nsISimpleEnumerator)
134
135 nsCOMArrayEnumerator::~nsCOMArrayEnumerator()
136 {
137 // only release the entries that we haven't visited yet
138 for (; mIndex < mArraySize; ++mIndex) {
139 NS_IF_RELEASE(mValueArray[mIndex]);
140 }
141 }
142
143 NS_IMETHODIMP
HasMoreElements(bool * aResult)144 nsCOMArrayEnumerator::HasMoreElements(bool* aResult)
145 {
146 NS_PRECONDITION(aResult != 0, "null ptr");
147 if (!aResult) {
148 return NS_ERROR_NULL_POINTER;
149 }
150
151 *aResult = (mIndex < mArraySize);
152 return NS_OK;
153 }
154
155 NS_IMETHODIMP
GetNext(nsISupports ** aResult)156 nsCOMArrayEnumerator::GetNext(nsISupports** aResult)
157 {
158 NS_PRECONDITION(aResult != 0, "null ptr");
159 if (!aResult) {
160 return NS_ERROR_NULL_POINTER;
161 }
162
163 if (mIndex >= mArraySize) {
164 return NS_ERROR_UNEXPECTED;
165 }
166
167 // pass the ownership of the reference to the caller. Since
168 // we AddRef'ed during creation of |this|, there is no need
169 // to AddRef here
170 *aResult = mValueArray[mIndex++];
171
172 // this really isn't necessary. just pretend this happens, since
173 // we'll never visit this value again!
174 // mValueArray[(mIndex-1)] = nullptr;
175
176 return NS_OK;
177 }
178
179 void*
operator new(size_t aSize,const nsCOMArray_base & aArray)180 nsCOMArrayEnumerator::operator new(size_t aSize,
181 const nsCOMArray_base& aArray) CPP_THROW_NEW
182 {
183 // create enough space such that mValueArray points to a large
184 // enough value. Note that the initial value of aSize gives us
185 // space for mValueArray[0], so we must subtract
186 aSize += (aArray.Count() - 1) * sizeof(aArray[0]);
187
188 // do the actual allocation
189 nsCOMArrayEnumerator* result =
190 static_cast<nsCOMArrayEnumerator*>(::operator new(aSize));
191
192 // now need to copy over the values, and addref each one
193 // now this might seem like a lot of work, but we're actually just
194 // doing all our AddRef's ahead of time since GetNext() doesn't
195 // need to AddRef() on the way out
196 uint32_t i;
197 uint32_t max = result->mArraySize = aArray.Count();
198 for (i = 0; i < max; ++i) {
199 result->mValueArray[i] = aArray[i];
200 NS_IF_ADDREF(result->mValueArray[i]);
201 }
202
203 return result;
204 }
205
206 nsresult
NS_NewArrayEnumerator(nsISimpleEnumerator ** aResult,const nsCOMArray_base & aArray)207 NS_NewArrayEnumerator(nsISimpleEnumerator** aResult,
208 const nsCOMArray_base& aArray)
209 {
210 RefPtr<nsCOMArrayEnumerator> enumerator = new (aArray) nsCOMArrayEnumerator();
211 enumerator.forget(aResult);
212 return NS_OK;
213 }
214