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