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 "nsEnumeratorUtils.h"
10
11 #include "nsISimpleEnumerator.h"
12 #include "nsIStringEnumerator.h"
13
14 #include "nsCOMPtr.h"
15 #include "mozilla/RefPtr.h"
16
17 class EmptyEnumeratorImpl
18 : public nsISimpleEnumerator
19 , public nsIUTF8StringEnumerator
20 , public nsIStringEnumerator
21 {
22 public:
EmptyEnumeratorImpl()23 EmptyEnumeratorImpl() {}
24
25 // nsISupports interface
26 NS_DECL_ISUPPORTS_INHERITED // not really inherited, but no mRefCnt
27
28 // nsISimpleEnumerator
29 NS_DECL_NSISIMPLEENUMERATOR
30 NS_DECL_NSIUTF8STRINGENUMERATOR
31 // can't use NS_DECL_NSISTRINGENUMERATOR because they share the
32 // HasMore() signature
33 NS_IMETHOD GetNext(nsAString& aResult) override;
34
GetInstance()35 static EmptyEnumeratorImpl* GetInstance()
36 {
37 static const EmptyEnumeratorImpl kInstance;
38 return const_cast<EmptyEnumeratorImpl*>(&kInstance);
39 }
40 };
41
42 // nsISupports interface
NS_IMETHODIMP_(MozExternalRefCountType)43 NS_IMETHODIMP_(MozExternalRefCountType)
44 EmptyEnumeratorImpl::AddRef(void)
45 {
46 return 2;
47 }
48
NS_IMETHODIMP_(MozExternalRefCountType)49 NS_IMETHODIMP_(MozExternalRefCountType)
50 EmptyEnumeratorImpl::Release(void)
51 {
52 return 1;
53 }
54
NS_IMPL_QUERY_INTERFACE(EmptyEnumeratorImpl,nsISimpleEnumerator,nsIUTF8StringEnumerator,nsIStringEnumerator)55 NS_IMPL_QUERY_INTERFACE(EmptyEnumeratorImpl, nsISimpleEnumerator,
56 nsIUTF8StringEnumerator, nsIStringEnumerator)
57
58 // nsISimpleEnumerator interface
59 NS_IMETHODIMP
60 EmptyEnumeratorImpl::HasMoreElements(bool* aResult)
61 {
62 *aResult = false;
63 return NS_OK;
64 }
65
66 NS_IMETHODIMP
HasMore(bool * aResult)67 EmptyEnumeratorImpl::HasMore(bool* aResult)
68 {
69 *aResult = false;
70 return NS_OK;
71 }
72
73 NS_IMETHODIMP
GetNext(nsISupports ** aResult)74 EmptyEnumeratorImpl::GetNext(nsISupports** aResult)
75 {
76 return NS_ERROR_UNEXPECTED;
77 }
78
79 NS_IMETHODIMP
GetNext(nsACString & aResult)80 EmptyEnumeratorImpl::GetNext(nsACString& aResult)
81 {
82 return NS_ERROR_UNEXPECTED;
83 }
84
85 NS_IMETHODIMP
GetNext(nsAString & aResult)86 EmptyEnumeratorImpl::GetNext(nsAString& aResult)
87 {
88 return NS_ERROR_UNEXPECTED;
89 }
90
91 nsresult
NS_NewEmptyEnumerator(nsISimpleEnumerator ** aResult)92 NS_NewEmptyEnumerator(nsISimpleEnumerator** aResult)
93 {
94 *aResult = EmptyEnumeratorImpl::GetInstance();
95 return NS_OK;
96 }
97
98 ////////////////////////////////////////////////////////////////////////////////
99
100 class nsSingletonEnumerator final : public nsISimpleEnumerator
101 {
102 public:
103 NS_DECL_ISUPPORTS
104
105 // nsISimpleEnumerator methods
106 NS_IMETHOD HasMoreElements(bool* aResult) override;
107 NS_IMETHOD GetNext(nsISupports** aResult) override;
108
109 explicit nsSingletonEnumerator(nsISupports* aValue);
110
111 private:
112 ~nsSingletonEnumerator();
113
114 protected:
115 nsCOMPtr<nsISupports> mValue;
116 bool mConsumed;
117 };
118
nsSingletonEnumerator(nsISupports * aValue)119 nsSingletonEnumerator::nsSingletonEnumerator(nsISupports* aValue)
120 : mValue(aValue)
121 {
122 mConsumed = (mValue ? false : true);
123 }
124
~nsSingletonEnumerator()125 nsSingletonEnumerator::~nsSingletonEnumerator()
126 {
127 }
128
NS_IMPL_ISUPPORTS(nsSingletonEnumerator,nsISimpleEnumerator)129 NS_IMPL_ISUPPORTS(nsSingletonEnumerator, nsISimpleEnumerator)
130
131 NS_IMETHODIMP
132 nsSingletonEnumerator::HasMoreElements(bool* aResult)
133 {
134 NS_PRECONDITION(aResult != 0, "null ptr");
135 if (!aResult) {
136 return NS_ERROR_NULL_POINTER;
137 }
138
139 *aResult = !mConsumed;
140 return NS_OK;
141 }
142
143
144 NS_IMETHODIMP
GetNext(nsISupports ** aResult)145 nsSingletonEnumerator::GetNext(nsISupports** aResult)
146 {
147 NS_PRECONDITION(aResult != 0, "null ptr");
148 if (!aResult) {
149 return NS_ERROR_NULL_POINTER;
150 }
151
152 if (mConsumed) {
153 return NS_ERROR_UNEXPECTED;
154 }
155
156 mConsumed = true;
157
158 *aResult = mValue;
159 NS_ADDREF(*aResult);
160 return NS_OK;
161 }
162
163 nsresult
NS_NewSingletonEnumerator(nsISimpleEnumerator ** aResult,nsISupports * aSingleton)164 NS_NewSingletonEnumerator(nsISimpleEnumerator** aResult,
165 nsISupports* aSingleton)
166 {
167 RefPtr<nsSingletonEnumerator> enumer = new nsSingletonEnumerator(aSingleton);
168 enumer.forget(aResult);
169 return NS_OK;
170 }
171
172 ////////////////////////////////////////////////////////////////////////////////
173
174 class nsUnionEnumerator final : public nsISimpleEnumerator
175 {
176 public:
177 NS_DECL_ISUPPORTS
178
179 // nsISimpleEnumerator methods
180 NS_IMETHOD HasMoreElements(bool* aResult) override;
181 NS_IMETHOD GetNext(nsISupports** aResult) override;
182
183 nsUnionEnumerator(nsISimpleEnumerator* aFirstEnumerator,
184 nsISimpleEnumerator* aSecondEnumerator);
185
186 private:
187 ~nsUnionEnumerator();
188
189 protected:
190 nsCOMPtr<nsISimpleEnumerator> mFirstEnumerator, mSecondEnumerator;
191 bool mConsumed;
192 bool mAtSecond;
193 };
194
nsUnionEnumerator(nsISimpleEnumerator * aFirstEnumerator,nsISimpleEnumerator * aSecondEnumerator)195 nsUnionEnumerator::nsUnionEnumerator(nsISimpleEnumerator* aFirstEnumerator,
196 nsISimpleEnumerator* aSecondEnumerator)
197 : mFirstEnumerator(aFirstEnumerator)
198 , mSecondEnumerator(aSecondEnumerator)
199 , mConsumed(false)
200 , mAtSecond(false)
201 {
202 }
203
~nsUnionEnumerator()204 nsUnionEnumerator::~nsUnionEnumerator()
205 {
206 }
207
NS_IMPL_ISUPPORTS(nsUnionEnumerator,nsISimpleEnumerator)208 NS_IMPL_ISUPPORTS(nsUnionEnumerator, nsISimpleEnumerator)
209
210 NS_IMETHODIMP
211 nsUnionEnumerator::HasMoreElements(bool* aResult)
212 {
213 NS_PRECONDITION(aResult != 0, "null ptr");
214 if (!aResult) {
215 return NS_ERROR_NULL_POINTER;
216 }
217
218 nsresult rv;
219
220 if (mConsumed) {
221 *aResult = false;
222 return NS_OK;
223 }
224
225 if (!mAtSecond) {
226 rv = mFirstEnumerator->HasMoreElements(aResult);
227 if (NS_FAILED(rv)) {
228 return rv;
229 }
230
231 if (*aResult) {
232 return NS_OK;
233 }
234
235 mAtSecond = true;
236 }
237
238 rv = mSecondEnumerator->HasMoreElements(aResult);
239 if (NS_FAILED(rv)) {
240 return rv;
241 }
242
243 if (*aResult) {
244 return NS_OK;
245 }
246
247 *aResult = false;
248 mConsumed = true;
249 return NS_OK;
250 }
251
252 NS_IMETHODIMP
GetNext(nsISupports ** aResult)253 nsUnionEnumerator::GetNext(nsISupports** aResult)
254 {
255 NS_PRECONDITION(aResult != 0, "null ptr");
256 if (!aResult) {
257 return NS_ERROR_NULL_POINTER;
258 }
259
260 if (mConsumed) {
261 return NS_ERROR_UNEXPECTED;
262 }
263
264 if (!mAtSecond) {
265 return mFirstEnumerator->GetNext(aResult);
266 }
267
268 return mSecondEnumerator->GetNext(aResult);
269 }
270
271 nsresult
NS_NewUnionEnumerator(nsISimpleEnumerator ** aResult,nsISimpleEnumerator * aFirstEnumerator,nsISimpleEnumerator * aSecondEnumerator)272 NS_NewUnionEnumerator(nsISimpleEnumerator** aResult,
273 nsISimpleEnumerator* aFirstEnumerator,
274 nsISimpleEnumerator* aSecondEnumerator)
275 {
276 *aResult = nullptr;
277 if (!aFirstEnumerator) {
278 *aResult = aSecondEnumerator;
279 } else if (!aSecondEnumerator) {
280 *aResult = aFirstEnumerator;
281 } else {
282 nsUnionEnumerator* enumer = new nsUnionEnumerator(aFirstEnumerator,
283 aSecondEnumerator);
284 if (!enumer) {
285 return NS_ERROR_OUT_OF_MEMORY;
286 }
287 *aResult = enumer;
288 }
289 NS_ADDREF(*aResult);
290 return NS_OK;
291 }
292