1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
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 mozilla.org code.
16 : *
17 : * The Initial Developer of the Original Code is
18 : * Netscape Communications Corporation.
19 : * Portions created by the Initial Developer are Copyright (C) 1998
20 : * the Initial Developer. All Rights Reserved.
21 : *
22 : * Contributor(s):
23 : * Scott Collins <scc@mozilla.org>: |do_QueryElementAt|
24 : * Pierre Phaneuf <pp@ludusdesign.com>
25 : *
26 : * Alternatively, the contents of this file may be used under the terms of
27 : * either of the GNU General Public License Version 2 or later (the "GPL"),
28 : * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29 : * in which case the provisions of the GPL or the LGPL are applicable instead
30 : * of those above. If you wish to allow use of your version of this file only
31 : * under the terms of either the GPL or the LGPL, and not to allow others to
32 : * use your version of this file under the terms of the MPL, indicate your
33 : * decision by deleting the provisions above and replace them with the notice
34 : * and other provisions required by the GPL or the LGPL. If you do not delete
35 : * the provisions above, a recipient may use your version of this file under
36 : * the terms of any one of the MPL, the GPL or the LGPL.
37 : *
38 : * ***** END LICENSE BLOCK ***** */
39 :
40 : #include <string.h>
41 : #include "prbit.h"
42 : #include "nsSupportsArray.h"
43 : #include "nsSupportsArrayEnumerator.h"
44 : #include "nsAString.h"
45 : #include "nsIObjectInputStream.h"
46 : #include "nsIObjectOutputStream.h"
47 :
48 : #if DEBUG_SUPPORTSARRAY
49 : #define MAXSUPPORTS 20
50 :
51 : class SupportsStats {
52 : public:
53 : SupportsStats();
54 : ~SupportsStats();
55 :
56 : };
57 :
58 : static int sizesUsed; // number of the elements of the arrays used
59 : static int sizesAlloced[MAXSUPPORTS]; // sizes of the allocations. sorted
60 : static int NumberOfSize[MAXSUPPORTS]; // number of this allocation size (1 per array)
61 : static int AllocedOfSize[MAXSUPPORTS]; // number of this allocation size (each size for array used)
62 : static int GrowInPlace[MAXSUPPORTS];
63 :
64 : // these are per-allocation
65 : static int MaxElements[3000];
66 :
67 : // very evil
68 : #define ADD_TO_STATS(x,size) do {int i; for (i = 0; i < sizesUsed; i++) \
69 : { \
70 : if (sizesAlloced[i] == (int)(size)) \
71 : { ((x)[i])++; break; } \
72 : } \
73 : if (i >= sizesUsed && sizesUsed < MAXSUPPORTS) \
74 : { sizesAlloced[sizesUsed] = (size); \
75 : ((x)[sizesUsed++])++; break; \
76 : } \
77 : } while (0);
78 :
79 : #define SUB_FROM_STATS(x,size) do {int i; for (i = 0; i < sizesUsed; i++) \
80 : { \
81 : if (sizesAlloced[i] == (int)(size)) \
82 : { ((x)[i])--; break; } \
83 : } \
84 : } while (0);
85 :
86 :
87 : SupportsStats::SupportsStats()
88 : {
89 : sizesUsed = 1;
90 : sizesAlloced[0] = 0;
91 : }
92 :
93 : SupportsStats::~SupportsStats()
94 : {
95 : int i;
96 : for (i = 0; i < sizesUsed; i++)
97 : {
98 : printf("Size %d:\n",sizesAlloced[i]);
99 : printf("\tNumber of SupportsArrays this size (max): %d\n",NumberOfSize[i]);
100 : printf("\tNumber of allocations this size (total): %d\n",AllocedOfSize[i]);
101 : printf("\tNumber of GrowsInPlace this size (total): %d\n",GrowInPlace[i]);
102 : }
103 : printf("Max Size of SupportsArray:\n");
104 : for (i = 0; i < (int)(sizeof(MaxElements)/sizeof(MaxElements[0])); i++)
105 : {
106 : if (MaxElements[i])
107 : printf("\t%d: %d\n",i,MaxElements[i]);
108 : }
109 : }
110 :
111 : // Just so constructor/destructor get called
112 : SupportsStats gSupportsStats;
113 : #endif
114 :
115 : nsresult
116 0 : nsQueryElementAt::operator()( const nsIID& aIID, void** aResult ) const
117 : {
118 : nsresult status = mCollection
119 0 : ? mCollection->QueryElementAt(mIndex, aIID, aResult)
120 0 : : NS_ERROR_NULL_POINTER;
121 :
122 0 : if ( mErrorPtr )
123 0 : *mErrorPtr = status;
124 :
125 0 : return status;
126 : }
127 :
128 : static const PRInt32 kGrowArrayBy = 8;
129 : static const PRInt32 kLinearThreshold = 16 * sizeof(nsISupports *);
130 :
131 1748 : nsSupportsArray::nsSupportsArray()
132 : {
133 1748 : mArray = mAutoArray;
134 1748 : mArraySize = kAutoArraySize;
135 1748 : mCount = 0;
136 : #if DEBUG_SUPPORTSARRAY
137 : mMaxCount = 0;
138 : mMaxSize = 0;
139 : ADD_TO_STATS(NumberOfSize,kAutoArraySize*sizeof(mArray[0]));
140 : MaxElements[0]++;
141 : #endif
142 1748 : }
143 :
144 1748 : nsSupportsArray::~nsSupportsArray()
145 : {
146 1748 : DeleteArray();
147 1748 : }
148 :
149 1863 : bool nsSupportsArray::GrowArrayBy(PRInt32 aGrowBy)
150 : {
151 : // We have to grow the array. Grow by kGrowArrayBy slots if we're smaller
152 : // than kLinearThreshold bytes, or a power of two if we're larger.
153 : // This is much more efficient with most memory allocators, especially
154 : // if it's very large, or of the allocator is binned.
155 1863 : if (aGrowBy < kGrowArrayBy)
156 1863 : aGrowBy = kGrowArrayBy;
157 :
158 1863 : PRUint32 newCount = mArraySize + aGrowBy; // Minimum increase
159 1863 : PRUint32 newSize = sizeof(mArray[0]) * newCount;
160 :
161 1863 : if (newSize >= (PRUint32) kLinearThreshold)
162 : {
163 : // newCount includes enough space for at least kGrowArrayBy new slots.
164 : // Select the next power-of-two size in bytes above that if newSize is
165 : // not a power of two.
166 1863 : if (newSize & (newSize - 1))
167 1540 : newSize = PR_BIT(PR_CeilingLog2(newSize));
168 :
169 1863 : newCount = newSize / sizeof(mArray[0]);
170 : }
171 : // XXX This would be far more efficient in many allocators if we used
172 : // XXX PR_Realloc(), etc
173 1863 : nsISupports** oldArray = mArray;
174 :
175 3726 : mArray = new nsISupports*[newCount];
176 1863 : if (!mArray) { // ran out of memory
177 0 : mArray = oldArray;
178 0 : return false;
179 : }
180 1863 : mArraySize = newCount;
181 :
182 : #if DEBUG_SUPPORTSARRAY
183 : if (oldArray == mArray) // can't happen without use of realloc
184 : ADD_TO_STATS(GrowInPlace,mCount);
185 : ADD_TO_STATS(AllocedOfSize,mArraySize*sizeof(mArray[0]));
186 : if (mArraySize > mMaxSize)
187 : {
188 : ADD_TO_STATS(NumberOfSize,mArraySize*sizeof(mArray[0]));
189 : if (oldArray != &(mAutoArray[0]))
190 : SUB_FROM_STATS(NumberOfSize,mCount*sizeof(mArray[0]));
191 : mMaxSize = mArraySize;
192 : }
193 : #endif
194 1863 : if (oldArray) { // need to move old data
195 1863 : if (0 < mCount) {
196 1863 : ::memcpy(mArray, oldArray, mCount * sizeof(nsISupports*));
197 : }
198 1863 : if (oldArray != &(mAutoArray[0])) {
199 1540 : delete[] oldArray;
200 : }
201 : }
202 :
203 1863 : return true;
204 : }
205 :
206 : nsresult
207 1748 : nsSupportsArray::Create(nsISupports *aOuter, REFNSIID aIID, void **aResult)
208 : {
209 1748 : if (aOuter)
210 0 : return NS_ERROR_NO_AGGREGATION;
211 :
212 3496 : nsCOMPtr<nsISupportsArray> it = new nsSupportsArray();
213 1748 : if (!it)
214 0 : return NS_ERROR_OUT_OF_MEMORY;
215 :
216 1748 : return it->QueryInterface(aIID, aResult);
217 : }
218 :
219 21674 : NS_IMPL_THREADSAFE_ISUPPORTS3(nsSupportsArray, nsISupportsArray, nsICollection, nsISerializable)
220 :
221 : NS_IMETHODIMP
222 0 : nsSupportsArray::Read(nsIObjectInputStream *aStream)
223 : {
224 : nsresult rv;
225 :
226 : PRUint32 newArraySize;
227 0 : rv = aStream->Read32(&newArraySize);
228 :
229 0 : if (newArraySize <= kAutoArraySize) {
230 0 : if (mArray != mAutoArray) {
231 0 : delete[] mArray;
232 0 : mArray = mAutoArray;
233 : }
234 0 : newArraySize = kAutoArraySize;
235 : }
236 : else {
237 0 : if (newArraySize <= mArraySize) {
238 : // Keep non-default-size mArray, it's more than big enough.
239 0 : newArraySize = mArraySize;
240 : }
241 : else {
242 0 : nsISupports** array = new nsISupports*[newArraySize];
243 0 : if (!array)
244 0 : return NS_ERROR_OUT_OF_MEMORY;
245 0 : if (mArray != mAutoArray)
246 0 : delete[] mArray;
247 0 : mArray = array;
248 : }
249 : }
250 0 : mArraySize = newArraySize;
251 :
252 0 : rv = aStream->Read32(&mCount);
253 0 : if (NS_FAILED(rv)) return rv;
254 :
255 0 : NS_ASSERTION(mCount <= mArraySize, "overlarge mCount!");
256 0 : if (mCount > mArraySize)
257 0 : mCount = mArraySize;
258 :
259 0 : for (PRUint32 i = 0; i < mCount; i++) {
260 0 : rv = aStream->ReadObject(true, &mArray[i]);
261 0 : if (NS_FAILED(rv)) return rv;
262 : }
263 :
264 0 : return NS_OK;
265 : }
266 :
267 : NS_IMETHODIMP
268 0 : nsSupportsArray::Write(nsIObjectOutputStream *aStream)
269 : {
270 : nsresult rv;
271 :
272 0 : rv = aStream->Write32(mArraySize);
273 0 : if (NS_FAILED(rv)) return rv;
274 :
275 0 : rv = aStream->Write32(mCount);
276 0 : if (NS_FAILED(rv)) return rv;
277 :
278 0 : for (PRUint32 i = 0; i < mCount; i++) {
279 0 : rv = aStream->WriteObject(mArray[i], true);
280 0 : if (NS_FAILED(rv)) return rv;
281 : }
282 :
283 0 : return NS_OK;
284 : }
285 :
286 1748 : void nsSupportsArray::DeleteArray(void)
287 : {
288 1748 : Clear();
289 1748 : if (mArray != &(mAutoArray[0])) {
290 323 : delete[] mArray;
291 323 : mArray = mAutoArray;
292 323 : mArraySize = kAutoArraySize;
293 : }
294 1748 : }
295 :
296 :
297 : NS_IMETHODIMP_(bool)
298 0 : nsSupportsArray::Equals(const nsISupportsArray* aOther)
299 : {
300 0 : if (aOther) {
301 : PRUint32 countOther;
302 0 : nsISupportsArray* other = const_cast<nsISupportsArray*>(aOther);
303 0 : nsresult rv = other->Count(&countOther);
304 0 : if (NS_FAILED( rv ))
305 0 : return false;
306 :
307 0 : if (mCount == countOther) {
308 0 : PRUint32 index = mCount;
309 0 : nsCOMPtr<nsISupports> otherElem;
310 0 : while (index--) {
311 0 : if (NS_FAILED(other->GetElementAt(index, getter_AddRefs(otherElem))))
312 0 : return false;
313 0 : if (mArray[index] != otherElem)
314 0 : return false;
315 : }
316 0 : return true;
317 : }
318 : }
319 0 : return false;
320 : }
321 :
322 : NS_IMETHODIMP_(nsISupports*)
323 130399 : nsSupportsArray::ElementAt(PRUint32 aIndex)
324 : {
325 130399 : if (aIndex < mCount) {
326 130399 : nsISupports* element = mArray[aIndex];
327 130399 : NS_IF_ADDREF(element);
328 130399 : return element;
329 : }
330 0 : return 0;
331 : }
332 :
333 : NS_IMETHODIMP_(PRInt32)
334 0 : nsSupportsArray::IndexOf(const nsISupports* aPossibleElement)
335 : {
336 0 : return IndexOfStartingAt(aPossibleElement, 0);
337 : }
338 :
339 : NS_IMETHODIMP_(PRInt32)
340 35 : nsSupportsArray::IndexOfStartingAt(const nsISupports* aPossibleElement,
341 : PRUint32 aStartIndex)
342 : {
343 35 : if (aStartIndex < mCount) {
344 35 : const nsISupports** start = (const nsISupports**)mArray; // work around goofy compiler behavior
345 35 : const nsISupports** ep = (start + aStartIndex);
346 35 : const nsISupports** end = (start + mCount);
347 210 : while (ep < end) {
348 175 : if (aPossibleElement == *ep) {
349 35 : return (ep - start);
350 : }
351 140 : ep++;
352 : }
353 : }
354 0 : return -1;
355 : }
356 :
357 : NS_IMETHODIMP_(PRInt32)
358 0 : nsSupportsArray::LastIndexOf(const nsISupports* aPossibleElement)
359 : {
360 0 : if (0 < mCount) {
361 0 : const nsISupports** start = (const nsISupports**)mArray; // work around goofy compiler behavior
362 0 : const nsISupports** ep = (start + mCount);
363 0 : while (start <= --ep) {
364 0 : if (aPossibleElement == *ep) {
365 0 : return (ep - start);
366 : }
367 : }
368 : }
369 0 : return -1;
370 : }
371 :
372 : NS_IMETHODIMP_(bool)
373 137303 : nsSupportsArray::InsertElementAt(nsISupports* aElement, PRUint32 aIndex)
374 : {
375 137303 : if (aIndex <= mCount) {
376 137303 : if (mArraySize < (mCount + 1)) {
377 : // need to grow the array
378 1863 : if (!GrowArrayBy(1))
379 0 : return false;
380 : }
381 :
382 : // Could be slightly more efficient if GrowArrayBy knew about the
383 : // split, but the difference is trivial.
384 137303 : PRUint32 slide = (mCount - aIndex);
385 137303 : if (0 < slide) {
386 0 : ::memmove(mArray + aIndex + 1, mArray + aIndex, slide * sizeof(nsISupports*));
387 : }
388 :
389 137303 : mArray[aIndex] = aElement;
390 137303 : NS_IF_ADDREF(aElement);
391 137303 : mCount++;
392 :
393 : #if DEBUG_SUPPORTSARRAY
394 : if (mCount > mMaxCount &&
395 : mCount < (PRInt32)(sizeof(MaxElements)/sizeof(MaxElements[0])))
396 : {
397 : MaxElements[mCount]++;
398 : MaxElements[mMaxCount]--;
399 : mMaxCount = mCount;
400 : }
401 : #endif
402 137303 : return true;
403 : }
404 0 : return false;
405 : }
406 :
407 : NS_IMETHODIMP_(bool)
408 0 : nsSupportsArray::InsertElementsAt(nsISupportsArray* aElements, PRUint32 aIndex)
409 : {
410 0 : if (!aElements) {
411 0 : return false;
412 : }
413 : PRUint32 countElements;
414 0 : if (NS_FAILED( aElements->Count( &countElements ) ))
415 0 : return false;
416 :
417 0 : if (aIndex <= mCount) {
418 0 : if (mArraySize < (mCount + countElements)) {
419 : // need to grow the array
420 0 : if (!GrowArrayBy(countElements))
421 0 : return false;
422 : }
423 :
424 : // Could be slightly more efficient if GrowArrayBy knew about the
425 : // split, but the difference is trivial.
426 0 : PRUint32 slide = (mCount - aIndex);
427 0 : if (0 < slide) {
428 0 : ::memmove(mArray + aIndex + countElements, mArray + aIndex,
429 0 : slide * sizeof(nsISupports*));
430 : }
431 :
432 0 : for (PRUint32 i = 0; i < countElements; ++i, ++mCount) {
433 : // use GetElementAt to copy and do AddRef for us
434 0 : if (NS_FAILED( aElements->GetElementAt( i, mArray + aIndex + i) ))
435 0 : return false;
436 : }
437 :
438 : #if DEBUG_SUPPORTSARRAY
439 : if (mCount > mMaxCount &&
440 : mCount < (PRInt32)(sizeof(MaxElements)/sizeof(MaxElements[0])))
441 : {
442 : MaxElements[mCount]++;
443 : MaxElements[mMaxCount]--;
444 : mMaxCount = mCount;
445 : }
446 : #endif
447 0 : return true;
448 : }
449 0 : return false;
450 : }
451 :
452 : NS_IMETHODIMP_(bool)
453 0 : nsSupportsArray::ReplaceElementAt(nsISupports* aElement, PRUint32 aIndex)
454 : {
455 0 : if (aIndex < mCount) {
456 0 : NS_IF_ADDREF(aElement); // addref first in case it's the same object!
457 0 : NS_IF_RELEASE(mArray[aIndex]);
458 0 : mArray[aIndex] = aElement;
459 0 : return true;
460 : }
461 0 : return false;
462 : }
463 :
464 : NS_IMETHODIMP_(bool)
465 35 : nsSupportsArray::RemoveElementsAt(PRUint32 aIndex, PRUint32 aCount)
466 : {
467 35 : if (aIndex + aCount <= mCount) {
468 70 : for (PRUint32 i = 0; i < aCount; i++)
469 35 : NS_IF_RELEASE(mArray[aIndex+i]);
470 35 : mCount -= aCount;
471 35 : PRInt32 slide = (mCount - aIndex);
472 35 : if (0 < slide) {
473 0 : ::memmove(mArray + aIndex, mArray + aIndex + aCount,
474 0 : slide * sizeof(nsISupports*));
475 : }
476 35 : return true;
477 : }
478 0 : return false;
479 : }
480 :
481 : NS_IMETHODIMP_(bool)
482 35 : nsSupportsArray::RemoveElement(const nsISupports* aElement, PRUint32 aStartIndex)
483 : {
484 35 : PRInt32 theIndex = IndexOfStartingAt(aElement,aStartIndex);
485 35 : if (theIndex >= 0)
486 35 : return RemoveElementAt(theIndex);
487 :
488 0 : return false;
489 : }
490 :
491 : NS_IMETHODIMP_(bool)
492 0 : nsSupportsArray::RemoveLastElement(const nsISupports* aElement)
493 : {
494 0 : PRInt32 theIndex = LastIndexOf(aElement);
495 0 : if (theIndex >= 0)
496 0 : return RemoveElementAt(theIndex);
497 :
498 0 : return false;
499 : }
500 :
501 : NS_IMETHODIMP_(bool)
502 0 : nsSupportsArray::MoveElement(PRInt32 aFrom, PRInt32 aTo)
503 : {
504 : nsISupports *tempElement;
505 :
506 0 : if (aTo == aFrom)
507 0 : return true;
508 :
509 0 : if (aTo < 0 || aFrom < 0 ||
510 : (PRUint32) aTo >= mCount || (PRUint32) aFrom >= mCount)
511 : {
512 : // can't extend the array when moving an element. Also catches mImpl = null
513 0 : return false;
514 : }
515 0 : tempElement = mArray[aFrom];
516 :
517 0 : if (aTo < aFrom)
518 : {
519 : // Moving one element closer to the head; the elements inbetween move down
520 0 : ::memmove(mArray + aTo + 1, mArray + aTo,
521 0 : (aFrom-aTo) * sizeof(mArray[0]));
522 0 : mArray[aTo] = tempElement;
523 : }
524 : else // already handled aFrom == aTo
525 : {
526 : // Moving one element closer to the tail; the elements inbetween move up
527 0 : ::memmove(mArray + aFrom, mArray + aFrom + 1,
528 0 : (aTo-aFrom) * sizeof(mArray[0]));
529 0 : mArray[aTo] = tempElement;
530 : }
531 :
532 0 : return true;
533 : }
534 :
535 : NS_IMETHODIMP
536 1748 : nsSupportsArray::Clear(void)
537 : {
538 1748 : if (0 < mCount) {
539 137268 : do {
540 137268 : --mCount;
541 137268 : NS_IF_RELEASE(mArray[mCount]);
542 : } while (0 != mCount);
543 : }
544 1748 : return NS_OK;
545 : }
546 :
547 : NS_IMETHODIMP
548 0 : nsSupportsArray::Compact(void)
549 : {
550 : #if DEBUG_SUPPORTSARRAY
551 : PRUint32 oldArraySize = mArraySize;
552 : #endif
553 0 : if ((mArraySize != mCount) && (kAutoArraySize < mArraySize)) {
554 0 : nsISupports** oldArray = mArray;
555 0 : if (mCount <= kAutoArraySize) {
556 0 : mArray = mAutoArray;
557 0 : mArraySize = kAutoArraySize;
558 : }
559 : else {
560 0 : mArray = new nsISupports*[mCount];
561 0 : if (!mArray) {
562 0 : mArray = oldArray;
563 0 : return NS_OK;
564 : }
565 0 : mArraySize = mCount;
566 : }
567 : #if DEBUG_SUPPORTSARRAY
568 : if (oldArray == mArray &&
569 : oldArray != &(mAutoArray[0])) // can't happen without use of realloc
570 : ADD_TO_STATS(GrowInPlace,oldArraySize);
571 : if (oldArray != &(mAutoArray[0]))
572 : ADD_TO_STATS(AllocedOfSize,mArraySize*sizeof(mArray[0]));
573 : #endif
574 0 : ::memcpy(mArray, oldArray, mCount * sizeof(nsISupports*));
575 0 : delete[] oldArray;
576 : }
577 0 : return NS_OK;
578 : }
579 :
580 : NS_IMETHODIMP_(bool)
581 0 : nsSupportsArray::SizeTo(PRInt32 aSize)
582 : {
583 : #if DEBUG_SUPPORTSARRAY
584 : PRUint32 oldArraySize = mArraySize;
585 : #endif
586 0 : NS_ASSERTION(aSize >= 0, "negative aSize!");
587 :
588 : // XXX for aSize < mCount we could resize to mCount
589 0 : if (mArraySize == (PRUint32) aSize || (PRUint32) aSize < mCount)
590 0 : return true; // nothing to do
591 :
592 : // switch back to autoarray if possible
593 0 : nsISupports** oldArray = mArray;
594 0 : if ((PRUint32) aSize <= kAutoArraySize) {
595 0 : mArray = mAutoArray;
596 0 : mArraySize = kAutoArraySize;
597 : }
598 : else {
599 0 : mArray = new nsISupports*[aSize];
600 0 : if (!mArray) {
601 0 : mArray = oldArray;
602 0 : return false;
603 : }
604 0 : mArraySize = aSize;
605 : }
606 : #if DEBUG_SUPPORTSARRAY
607 : if (oldArray == mArray &&
608 : oldArray != &(mAutoArray[0])) // can't happen without use of realloc
609 : ADD_TO_STATS(GrowInPlace,oldArraySize);
610 : if (oldArray != &(mAutoArray[0]))
611 : ADD_TO_STATS(AllocedOfSize,mArraySize*sizeof(mArray[0]));
612 : #endif
613 0 : ::memcpy(mArray, oldArray, mCount * sizeof(nsISupports*));
614 0 : if (oldArray != mAutoArray)
615 0 : delete[] oldArray;
616 :
617 0 : return true;
618 : }
619 :
620 : NS_IMETHODIMP_(bool)
621 0 : nsSupportsArray::EnumerateForwards(nsISupportsArrayEnumFunc aFunc, void* aData)
622 : {
623 0 : PRInt32 aIndex = -1;
624 0 : bool running = true;
625 :
626 0 : while (running && (++aIndex < (PRInt32)mCount)) {
627 0 : running = (*aFunc)(mArray[aIndex], aData);
628 : }
629 0 : return running;
630 : }
631 :
632 : NS_IMETHODIMP_(bool)
633 20182 : nsSupportsArray::EnumerateBackwards(nsISupportsArrayEnumFunc aFunc, void* aData)
634 : {
635 20182 : PRUint32 aIndex = mCount;
636 20182 : bool running = true;
637 :
638 97813 : while (running && (0 < aIndex--)) {
639 57449 : running = (*aFunc)(mArray[aIndex], aData);
640 : }
641 20182 : return running;
642 : }
643 :
644 : NS_IMETHODIMP
645 306 : nsSupportsArray::Enumerate(nsIEnumerator* *result)
646 : {
647 306 : nsSupportsArrayEnumerator* e = new nsSupportsArrayEnumerator(this);
648 306 : if (!e)
649 0 : return NS_ERROR_OUT_OF_MEMORY;
650 306 : *result = e;
651 306 : NS_ADDREF(e);
652 306 : return NS_OK;
653 : }
654 :
655 : static bool
656 0 : CopyElement(nsISupports* aElement, void *aData)
657 : {
658 : nsresult rv;
659 0 : nsISupportsArray* newArray = (nsISupportsArray*)aData;
660 0 : rv = newArray->AppendElement(aElement);
661 0 : return NS_SUCCEEDED(rv);
662 : }
663 :
664 : NS_IMETHODIMP
665 0 : nsSupportsArray::Clone(nsISupportsArray* *result)
666 : {
667 : nsresult rv;
668 : nsISupportsArray* newArray;
669 0 : rv = NS_NewISupportsArray(&newArray);
670 0 : bool ok = EnumerateForwards(CopyElement, newArray);
671 0 : if (!ok) return NS_ERROR_OUT_OF_MEMORY;
672 0 : *result = newArray;
673 0 : return NS_OK;
674 : }
675 :
676 : nsresult
677 1746 : NS_NewISupportsArray(nsISupportsArray** aInstancePtrResult)
678 : {
679 : nsresult rv;
680 : rv = nsSupportsArray::Create(NULL, NS_GET_IID(nsISupportsArray),
681 1746 : (void**)aInstancePtrResult);
682 1746 : return rv;
683 : }
684 :
685 : class nsArrayEnumerator : public nsISimpleEnumerator
686 : {
687 : public:
688 : // nsISupports interface
689 : NS_DECL_ISUPPORTS
690 :
691 : // nsISimpleEnumerator interface
692 : NS_IMETHOD HasMoreElements(bool* aResult);
693 : NS_IMETHOD GetNext(nsISupports** aResult);
694 :
695 : // nsArrayEnumerator methods
696 : nsArrayEnumerator(nsISupportsArray* aValueArray);
697 :
698 : private:
699 : ~nsArrayEnumerator(void);
700 :
701 : protected:
702 : nsISupportsArray* mValueArray;
703 : PRInt32 mIndex;
704 : };
705 :
706 19 : nsArrayEnumerator::nsArrayEnumerator(nsISupportsArray* aValueArray)
707 : : mValueArray(aValueArray),
708 19 : mIndex(0)
709 : {
710 19 : NS_IF_ADDREF(mValueArray);
711 19 : }
712 :
713 19 : nsArrayEnumerator::~nsArrayEnumerator(void)
714 : {
715 19 : NS_IF_RELEASE(mValueArray);
716 19 : }
717 :
718 114 : NS_IMPL_ISUPPORTS1(nsArrayEnumerator, nsISimpleEnumerator)
719 :
720 : NS_IMETHODIMP
721 368 : nsArrayEnumerator::HasMoreElements(bool* aResult)
722 : {
723 368 : NS_PRECONDITION(aResult != 0, "null ptr");
724 368 : if (! aResult)
725 0 : return NS_ERROR_NULL_POINTER;
726 :
727 368 : if (!mValueArray) {
728 0 : *aResult = false;
729 0 : return NS_OK;
730 : }
731 :
732 : PRUint32 cnt;
733 368 : nsresult rv = mValueArray->Count(&cnt);
734 368 : if (NS_FAILED(rv)) return rv;
735 368 : *aResult = (mIndex < (PRInt32) cnt);
736 368 : return NS_OK;
737 : }
738 :
739 : NS_IMETHODIMP
740 349 : nsArrayEnumerator::GetNext(nsISupports** aResult)
741 : {
742 349 : NS_PRECONDITION(aResult != 0, "null ptr");
743 349 : if (! aResult)
744 0 : return NS_ERROR_NULL_POINTER;
745 :
746 349 : if (!mValueArray) {
747 0 : *aResult = nsnull;
748 0 : return NS_OK;
749 : }
750 :
751 : PRUint32 cnt;
752 349 : nsresult rv = mValueArray->Count(&cnt);
753 349 : if (NS_FAILED(rv)) return rv;
754 349 : if (mIndex >= (PRInt32) cnt)
755 0 : return NS_ERROR_UNEXPECTED;
756 :
757 349 : *aResult = mValueArray->ElementAt(mIndex++);
758 349 : return NS_OK;
759 : }
760 :
761 : nsresult
762 19 : NS_NewArrayEnumerator(nsISimpleEnumerator* *result,
763 : nsISupportsArray* array)
764 : {
765 19 : nsArrayEnumerator* enumer = new nsArrayEnumerator(array);
766 19 : if (enumer == nsnull)
767 0 : return NS_ERROR_OUT_OF_MEMORY;
768 19 : *result = enumer;
769 19 : NS_ADDREF(*result);
770 19 : return NS_OK;
771 : }
|