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