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 "nsIStringEnumerator.h"
12 #include "nsSimpleEnumerator.h"
13
14 #include "nsCOMPtr.h"
15 #include "mozilla/RefPtr.h"
16
17 class EmptyEnumeratorImpl : public nsSimpleEnumerator,
18 public nsIUTF8StringEnumerator,
19 public nsIStringEnumerator {
20 public:
21 EmptyEnumeratorImpl() = default;
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 NS_DECL_NSISTRINGENUMERATORBASE
30 // can't use NS_DECL_NSISTRINGENUMERATOR because they share the
31 // HasMore() signature
32
33 NS_IMETHOD GetNext(nsAString& aResult) override;
34
GetInstance()35 static EmptyEnumeratorImpl* GetInstance() {
36 static const EmptyEnumeratorImpl kInstance;
37 return const_cast<EmptyEnumeratorImpl*>(&kInstance);
38 }
39 };
40
41 // nsISupports interface
NS_IMETHODIMP_(MozExternalRefCountType)42 NS_IMETHODIMP_(MozExternalRefCountType)
43 EmptyEnumeratorImpl::AddRef(void) { return 2; }
44
NS_IMETHODIMP_(MozExternalRefCountType)45 NS_IMETHODIMP_(MozExternalRefCountType)
46 EmptyEnumeratorImpl::Release(void) { return 1; }
47
NS_IMPL_QUERY_INTERFACE_INHERITED(EmptyEnumeratorImpl,nsSimpleEnumerator,nsIUTF8StringEnumerator,nsIStringEnumerator)48 NS_IMPL_QUERY_INTERFACE_INHERITED(EmptyEnumeratorImpl, nsSimpleEnumerator,
49 nsIUTF8StringEnumerator, nsIStringEnumerator)
50
51 // nsISimpleEnumerator interface
52 NS_IMETHODIMP
53 EmptyEnumeratorImpl::HasMoreElements(bool* aResult) {
54 *aResult = false;
55 return NS_OK;
56 }
57
58 NS_IMETHODIMP
HasMore(bool * aResult)59 EmptyEnumeratorImpl::HasMore(bool* aResult) {
60 *aResult = false;
61 return NS_OK;
62 }
63
64 NS_IMETHODIMP
GetNext(nsISupports ** aResult)65 EmptyEnumeratorImpl::GetNext(nsISupports** aResult) { return NS_ERROR_FAILURE; }
66
67 NS_IMETHODIMP
GetNext(nsACString & aResult)68 EmptyEnumeratorImpl::GetNext(nsACString& aResult) {
69 return NS_ERROR_UNEXPECTED;
70 }
71
72 NS_IMETHODIMP
GetNext(nsAString & aResult)73 EmptyEnumeratorImpl::GetNext(nsAString& aResult) { return NS_ERROR_UNEXPECTED; }
74
75 NS_IMETHODIMP
StringIterator(nsIJSEnumerator ** aRetVal)76 EmptyEnumeratorImpl::StringIterator(nsIJSEnumerator** aRetVal) {
77 return NS_ERROR_NOT_IMPLEMENTED;
78 }
79
NS_NewEmptyEnumerator(nsISimpleEnumerator ** aResult)80 nsresult NS_NewEmptyEnumerator(nsISimpleEnumerator** aResult) {
81 *aResult = EmptyEnumeratorImpl::GetInstance();
82 return NS_OK;
83 }
84
85 ////////////////////////////////////////////////////////////////////////////////
86
87 class nsSingletonEnumerator final : public nsSimpleEnumerator {
88 public:
89 // nsISimpleEnumerator methods
90 NS_IMETHOD HasMoreElements(bool* aResult) override;
91 NS_IMETHOD GetNext(nsISupports** aResult) override;
92
93 explicit nsSingletonEnumerator(nsISupports* aValue);
94
95 private:
96 ~nsSingletonEnumerator() override;
97
98 protected:
99 nsCOMPtr<nsISupports> mValue;
100 bool mConsumed;
101 };
102
nsSingletonEnumerator(nsISupports * aValue)103 nsSingletonEnumerator::nsSingletonEnumerator(nsISupports* aValue)
104 : mValue(aValue) {
105 mConsumed = (mValue ? false : true);
106 }
107
108 nsSingletonEnumerator::~nsSingletonEnumerator() = default;
109
110 NS_IMETHODIMP
HasMoreElements(bool * aResult)111 nsSingletonEnumerator::HasMoreElements(bool* aResult) {
112 MOZ_ASSERT(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 MOZ_ASSERT(aResult != 0, "null ptr");
124 if (!aResult) {
125 return NS_ERROR_NULL_POINTER;
126 }
127
128 if (mConsumed) {
129 return NS_ERROR_FAILURE;
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 nsSimpleEnumerator {
149 public:
150 // nsISimpleEnumerator methods
151 NS_IMETHOD HasMoreElements(bool* aResult) override;
152 NS_IMETHOD GetNext(nsISupports** aResult) override;
153
154 nsUnionEnumerator(nsISimpleEnumerator* aFirstEnumerator,
155 nsISimpleEnumerator* aSecondEnumerator);
156
157 private:
158 ~nsUnionEnumerator() override;
159
160 protected:
161 nsCOMPtr<nsISimpleEnumerator> mFirstEnumerator, mSecondEnumerator;
162 bool mConsumed;
163 bool mAtSecond;
164 };
165
nsUnionEnumerator(nsISimpleEnumerator * aFirstEnumerator,nsISimpleEnumerator * aSecondEnumerator)166 nsUnionEnumerator::nsUnionEnumerator(nsISimpleEnumerator* aFirstEnumerator,
167 nsISimpleEnumerator* aSecondEnumerator)
168 : mFirstEnumerator(aFirstEnumerator),
169 mSecondEnumerator(aSecondEnumerator),
170 mConsumed(false),
171 mAtSecond(false) {}
172
173 nsUnionEnumerator::~nsUnionEnumerator() = default;
174
175 NS_IMETHODIMP
HasMoreElements(bool * aResult)176 nsUnionEnumerator::HasMoreElements(bool* aResult) {
177 MOZ_ASSERT(aResult != 0, "null ptr");
178 if (!aResult) {
179 return NS_ERROR_NULL_POINTER;
180 }
181
182 nsresult rv;
183
184 if (mConsumed) {
185 *aResult = false;
186 return NS_OK;
187 }
188
189 if (!mAtSecond) {
190 rv = mFirstEnumerator->HasMoreElements(aResult);
191 if (NS_FAILED(rv)) {
192 return rv;
193 }
194
195 if (*aResult) {
196 return NS_OK;
197 }
198
199 mAtSecond = true;
200 }
201
202 rv = mSecondEnumerator->HasMoreElements(aResult);
203 if (NS_FAILED(rv)) {
204 return rv;
205 }
206
207 if (*aResult) {
208 return NS_OK;
209 }
210
211 *aResult = false;
212 mConsumed = true;
213 return NS_OK;
214 }
215
216 NS_IMETHODIMP
GetNext(nsISupports ** aResult)217 nsUnionEnumerator::GetNext(nsISupports** aResult) {
218 MOZ_ASSERT(aResult != 0, "null ptr");
219 if (!aResult) {
220 return NS_ERROR_NULL_POINTER;
221 }
222
223 if (mConsumed) {
224 return NS_ERROR_FAILURE;
225 }
226
227 if (!mAtSecond) {
228 return mFirstEnumerator->GetNext(aResult);
229 }
230
231 return mSecondEnumerator->GetNext(aResult);
232 }
233
NS_NewUnionEnumerator(nsISimpleEnumerator ** aResult,nsISimpleEnumerator * aFirstEnumerator,nsISimpleEnumerator * aSecondEnumerator)234 nsresult NS_NewUnionEnumerator(nsISimpleEnumerator** aResult,
235 nsISimpleEnumerator* aFirstEnumerator,
236 nsISimpleEnumerator* aSecondEnumerator) {
237 *aResult = nullptr;
238 if (!aFirstEnumerator) {
239 *aResult = aSecondEnumerator;
240 } else if (!aSecondEnumerator) {
241 *aResult = aFirstEnumerator;
242 } else {
243 auto* enumer = new nsUnionEnumerator(aFirstEnumerator, aSecondEnumerator);
244 *aResult = enumer;
245 }
246 NS_ADDREF(*aResult);
247 return NS_OK;
248 }
249