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