1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /* ***** BEGIN LICENSE BLOCK *****
3 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 : *
5 : * The contents of this file are subject to the Mozilla Public License Version
6 : * 1.1 (the "License"); you may not use this file except in compliance with
7 : * the License. You may obtain a copy of the License at
8 : * http://www.mozilla.org/MPL/
9 : *
10 : * Software distributed under the License is distributed on an "AS IS" basis,
11 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 : * for the specific language governing rights and limitations under the
13 : * License.
14 : *
15 : * The Original Code is XPCOM Array implementation.
16 : *
17 : * The Initial Developer of the Original Code is
18 : * Netscape Communications Corp.
19 : * Portions created by the Initial Developer are Copyright (C) 2002
20 : * the Initial Developer. All Rights Reserved.
21 : *
22 : * Contributor(s):
23 : * Alec Flett <alecf@netscape.com>
24 : *
25 : * Alternatively, the contents of this file may be used under the terms of
26 : * either the GNU General Public License Version 2 or later (the "GPL"), or
27 : * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 : * in which case the provisions of the GPL or the LGPL are applicable instead
29 : * of those above. If you wish to allow use of your version of this file only
30 : * under the terms of either the GPL or the LGPL, and not to allow others to
31 : * use your version of this file under the terms of the MPL, indicate your
32 : * decision by deleting the provisions above and replace them with the notice
33 : * and other provisions required by the GPL or the LGPL. If you do not delete
34 : * the provisions above, a recipient may use your version of this file under
35 : * the terms of any one of the MPL, the GPL or the LGPL.
36 : *
37 : * ***** END LICENSE BLOCK ***** */
38 :
39 : #include "mozilla/Attributes.h"
40 :
41 : #include "nsArrayEnumerator.h"
42 :
43 : #include "nsIArray.h"
44 : #include "nsISimpleEnumerator.h"
45 :
46 : #include "nsCOMArray.h"
47 : #include "nsCOMPtr.h"
48 :
49 : class nsSimpleArrayEnumerator MOZ_FINAL : public nsISimpleEnumerator
50 : {
51 : public:
52 : // nsISupports interface
53 : NS_DECL_ISUPPORTS
54 :
55 : // nsISimpleEnumerator interface
56 : NS_DECL_NSISIMPLEENUMERATOR
57 :
58 : // nsSimpleArrayEnumerator methods
59 0 : nsSimpleArrayEnumerator(nsIArray* aValueArray) :
60 0 : mValueArray(aValueArray), mIndex(0) {
61 0 : }
62 :
63 : private:
64 0 : ~nsSimpleArrayEnumerator() {}
65 :
66 : protected:
67 : nsCOMPtr<nsIArray> mValueArray;
68 : PRUint32 mIndex;
69 : };
70 :
71 0 : NS_IMPL_ISUPPORTS1(nsSimpleArrayEnumerator, nsISimpleEnumerator)
72 :
73 : NS_IMETHODIMP
74 0 : nsSimpleArrayEnumerator::HasMoreElements(bool* aResult)
75 : {
76 0 : NS_PRECONDITION(aResult != 0, "null ptr");
77 0 : if (! aResult)
78 0 : return NS_ERROR_NULL_POINTER;
79 :
80 0 : if (!mValueArray) {
81 0 : *aResult = false;
82 0 : return NS_OK;
83 : }
84 :
85 : PRUint32 cnt;
86 0 : nsresult rv = mValueArray->GetLength(&cnt);
87 0 : if (NS_FAILED(rv)) return rv;
88 0 : *aResult = (mIndex < cnt);
89 0 : return NS_OK;
90 : }
91 :
92 : NS_IMETHODIMP
93 0 : nsSimpleArrayEnumerator::GetNext(nsISupports** aResult)
94 : {
95 0 : NS_PRECONDITION(aResult != 0, "null ptr");
96 0 : if (! aResult)
97 0 : return NS_ERROR_NULL_POINTER;
98 :
99 0 : if (!mValueArray) {
100 0 : *aResult = nsnull;
101 0 : return NS_OK;
102 : }
103 :
104 : PRUint32 cnt;
105 0 : nsresult rv = mValueArray->GetLength(&cnt);
106 0 : if (NS_FAILED(rv)) return rv;
107 0 : if (mIndex >= cnt)
108 0 : return NS_ERROR_UNEXPECTED;
109 :
110 0 : return mValueArray->QueryElementAt(mIndex++, NS_GET_IID(nsISupports), (void**)aResult);
111 : }
112 :
113 : nsresult
114 0 : NS_NewArrayEnumerator(nsISimpleEnumerator* *result,
115 : nsIArray* array)
116 : {
117 0 : nsSimpleArrayEnumerator* enumer = new nsSimpleArrayEnumerator(array);
118 0 : if (enumer == nsnull)
119 0 : return NS_ERROR_OUT_OF_MEMORY;
120 :
121 0 : NS_ADDREF(*result = enumer);
122 0 : return NS_OK;
123 : }
124 :
125 : ////////////////////////////////////////////////////////////////////////////////
126 :
127 : // enumerator implementation for nsCOMArray
128 : // creates a snapshot of the array in question
129 : // you MUST use NS_NewArrayEnumerator to create this, so that
130 : // allocation is done correctly
131 : class nsCOMArrayEnumerator MOZ_FINAL : public nsISimpleEnumerator
132 : {
133 : public:
134 : // nsISupports interface
135 : NS_DECL_ISUPPORTS
136 :
137 : // nsISimpleEnumerator interface
138 : NS_DECL_NSISIMPLEENUMERATOR
139 :
140 : // nsSimpleArrayEnumerator methods
141 1390 : nsCOMArrayEnumerator() : mIndex(0) {
142 1390 : }
143 :
144 : // specialized operator to make sure we make room for mValues
145 : void* operator new (size_t size, const nsCOMArray_base& aArray) CPP_THROW_NEW;
146 1390 : void operator delete(void* ptr) {
147 : ::operator delete(ptr);
148 1390 : }
149 :
150 : private:
151 : ~nsCOMArrayEnumerator(void);
152 :
153 : protected:
154 : PRUint32 mIndex; // current position
155 : PRUint32 mArraySize; // size of the array
156 :
157 : // this is actually bigger
158 : nsISupports* mValueArray[1];
159 : };
160 :
161 18062 : NS_IMPL_ISUPPORTS1(nsCOMArrayEnumerator, nsISimpleEnumerator)
162 :
163 1390 : nsCOMArrayEnumerator::~nsCOMArrayEnumerator()
164 : {
165 : // only release the entries that we haven't visited yet
166 1391 : for (; mIndex < mArraySize; ++mIndex) {
167 1 : NS_IF_RELEASE(mValueArray[mIndex]);
168 : }
169 1390 : }
170 :
171 : NS_IMETHODIMP
172 2778 : nsCOMArrayEnumerator::HasMoreElements(bool* aResult)
173 : {
174 2778 : NS_PRECONDITION(aResult != 0, "null ptr");
175 2778 : if (! aResult)
176 0 : return NS_ERROR_NULL_POINTER;
177 :
178 2778 : *aResult = (mIndex < mArraySize);
179 2778 : return NS_OK;
180 : }
181 :
182 : NS_IMETHODIMP
183 1389 : nsCOMArrayEnumerator::GetNext(nsISupports** aResult)
184 : {
185 1389 : NS_PRECONDITION(aResult != 0, "null ptr");
186 1389 : if (! aResult)
187 0 : return NS_ERROR_NULL_POINTER;
188 :
189 1389 : if (mIndex >= mArraySize)
190 0 : return NS_ERROR_UNEXPECTED;
191 :
192 : // pass the ownership of the reference to the caller. Since
193 : // we AddRef'ed during creation of |this|, there is no need
194 : // to AddRef here
195 1389 : *aResult = mValueArray[mIndex++];
196 :
197 : // this really isn't necessary. just pretend this happens, since
198 : // we'll never visit this value again!
199 : // mValueArray[(mIndex-1)] = nsnull;
200 :
201 1389 : return NS_OK;
202 : }
203 :
204 : void*
205 1390 : nsCOMArrayEnumerator::operator new (size_t size, const nsCOMArray_base& aArray)
206 : CPP_THROW_NEW
207 : {
208 : // create enough space such that mValueArray points to a large
209 : // enough value. Note that the initial value of size gives us
210 : // space for mValueArray[0], so we must subtract
211 1390 : size += (aArray.Count() - 1) * sizeof(aArray[0]);
212 :
213 : // do the actual allocation
214 : nsCOMArrayEnumerator * result =
215 1390 : static_cast<nsCOMArrayEnumerator*>(::operator new(size));
216 1390 : NS_ENSURE_TRUE(result, nsnull);
217 :
218 : // now need to copy over the values, and addref each one
219 : // now this might seem like a lot of work, but we're actually just
220 : // doing all our AddRef's ahead of time since GetNext() doesn't
221 : // need to AddRef() on the way out
222 : PRUint32 i;
223 1390 : PRUint32 max = result->mArraySize = aArray.Count();
224 2780 : for (i = 0; i<max; i++) {
225 1390 : result->mValueArray[i] = aArray[i];
226 1390 : NS_IF_ADDREF(result->mValueArray[i]);
227 : }
228 :
229 1390 : return result;
230 : }
231 :
232 : nsresult
233 1390 : NS_NewArrayEnumerator(nsISimpleEnumerator* *aResult,
234 : const nsCOMArray_base& aArray)
235 : {
236 1390 : nsCOMArrayEnumerator *enumerator = new (aArray) nsCOMArrayEnumerator();
237 1390 : if (!enumerator) return NS_ERROR_OUT_OF_MEMORY;
238 :
239 1390 : NS_ADDREF(*aResult = enumerator);
240 1390 : return NS_OK;
241 : }
|