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