Bug 455527 - In some cases Embedding startup crashes if gAppData == null. r=benjamin.
[mozilla-central.git] / xpcom / ds / nsSupportsArray.cpp
blobf1b092537de53ea7ae797798701b142e66fe4b42
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
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/
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.
15 * The Original Code is mozilla.org code.
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.
22 * Contributor(s):
23 * Scott Collins <scc@mozilla.org>: |do_QueryElementAt|
24 * Pierre Phaneuf <pp@ludusdesign.com>
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.
38 * ***** END LICENSE BLOCK ***** */
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"
48 #if DEBUG_SUPPORTSARRAY
49 #define MAXSUPPORTS 20
51 class SupportsStats {
52 public:
53 SupportsStats();
54 ~SupportsStats();
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];
64 // these are per-allocation
65 static int MaxElements[3000];
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);
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);
87 SupportsStats::SupportsStats()
89 sizesUsed = 1;
90 sizesAlloced[0] = 0;
93 SupportsStats::~SupportsStats()
95 int i;
96 for (i = 0; i < sizesUsed; i++)
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]);
103 printf("Max Size of SupportsArray:\n");
104 for (i = 0; i < (int)(sizeof(MaxElements)/sizeof(MaxElements[0])); i++)
106 if (MaxElements[i])
107 printf("\t%d: %d\n",i,MaxElements[i]);
111 // Just so constructor/destructor get called
112 SupportsStats gSupportsStats;
113 #endif
115 nsresult
116 nsQueryElementAt::operator()( const nsIID& aIID, void** aResult ) const
118 nsresult status = mCollection
119 ? mCollection->QueryElementAt(mIndex, aIID, aResult)
120 : NS_ERROR_NULL_POINTER;
122 if ( mErrorPtr )
123 *mErrorPtr = status;
125 return status;
128 static const PRInt32 kGrowArrayBy = 8;
129 static const PRInt32 kLinearThreshold = 16 * sizeof(nsISupports *);
131 nsSupportsArray::nsSupportsArray()
133 mArray = mAutoArray;
134 mArraySize = kAutoArraySize;
135 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
144 nsSupportsArray::~nsSupportsArray()
146 DeleteArray();
149 PRBool nsSupportsArray::GrowArrayBy(PRInt32 aGrowBy)
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 if (aGrowBy < kGrowArrayBy)
156 aGrowBy = kGrowArrayBy;
158 PRUint32 newCount = mArraySize + aGrowBy; // Minimum increase
159 PRUint32 newSize = sizeof(mArray[0]) * newCount;
161 if (newSize >= (PRUint32) kLinearThreshold)
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 if (newSize & (newSize - 1))
167 newSize = PR_BIT(PR_CeilingLog2(newSize));
169 newCount = newSize / sizeof(mArray[0]);
171 // XXX This would be far more efficient in many allocators if we used
172 // XXX PR_Realloc(), etc
173 nsISupports** oldArray = mArray;
175 mArray = new nsISupports*[newCount];
176 if (!mArray) { // ran out of memory
177 mArray = oldArray;
178 return PR_FALSE;
180 mArraySize = newCount;
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)
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;
193 #endif
194 if (oldArray) { // need to move old data
195 if (0 < mCount) {
196 ::memcpy(mArray, oldArray, mCount * sizeof(nsISupports*));
198 if (oldArray != &(mAutoArray[0])) {
199 delete[] oldArray;
203 return PR_TRUE;
206 NS_METHOD
207 nsSupportsArray::Create(nsISupports *aOuter, REFNSIID aIID, void **aResult)
209 if (aOuter)
210 return NS_ERROR_NO_AGGREGATION;
212 nsCOMPtr<nsISupportsArray> it = new nsSupportsArray();
213 if (!it)
214 return NS_ERROR_OUT_OF_MEMORY;
216 return it->QueryInterface(aIID, aResult);
219 NS_IMPL_THREADSAFE_ISUPPORTS3(nsSupportsArray, nsISupportsArray, nsICollection, nsISerializable)
221 NS_IMETHODIMP
222 nsSupportsArray::Read(nsIObjectInputStream *aStream)
224 nsresult rv;
226 PRUint32 newArraySize;
227 rv = aStream->Read32(&newArraySize);
229 if (newArraySize <= kAutoArraySize) {
230 if (mArray != mAutoArray) {
231 delete[] mArray;
232 mArray = mAutoArray;
234 newArraySize = kAutoArraySize;
236 else {
237 if (newArraySize <= mArraySize) {
238 // Keep non-default-size mArray, it's more than big enough.
239 newArraySize = mArraySize;
241 else {
242 nsISupports** array = new nsISupports*[newArraySize];
243 if (!array)
244 return NS_ERROR_OUT_OF_MEMORY;
245 if (mArray != mAutoArray)
246 delete[] mArray;
247 mArray = array;
250 mArraySize = newArraySize;
252 rv = aStream->Read32(&mCount);
253 if (NS_FAILED(rv)) return rv;
255 NS_ASSERTION(mCount <= mArraySize, "overlarge mCount!");
256 if (mCount > mArraySize)
257 mCount = mArraySize;
259 for (PRUint32 i = 0; i < mCount; i++) {
260 rv = aStream->ReadObject(PR_TRUE, &mArray[i]);
261 if (NS_FAILED(rv)) return rv;
264 return NS_OK;
267 NS_IMETHODIMP
268 nsSupportsArray::Write(nsIObjectOutputStream *aStream)
270 nsresult rv;
272 rv = aStream->Write32(mArraySize);
273 if (NS_FAILED(rv)) return rv;
275 rv = aStream->Write32(mCount);
276 if (NS_FAILED(rv)) return rv;
278 for (PRUint32 i = 0; i < mCount; i++) {
279 rv = aStream->WriteObject(mArray[i], PR_TRUE);
280 if (NS_FAILED(rv)) return rv;
283 return NS_OK;
286 void nsSupportsArray::DeleteArray(void)
288 Clear();
289 if (mArray != &(mAutoArray[0])) {
290 delete[] mArray;
291 mArray = mAutoArray;
292 mArraySize = kAutoArraySize;
297 NS_IMETHODIMP_(PRBool)
298 nsSupportsArray::Equals(const nsISupportsArray* aOther)
300 if (aOther) {
301 PRUint32 countOther;
302 nsISupportsArray* other = const_cast<nsISupportsArray*>(aOther);
303 nsresult rv = other->Count(&countOther);
304 if (NS_FAILED( rv ))
305 return PR_FALSE;
307 if (mCount == countOther) {
308 PRUint32 index = mCount;
309 nsCOMPtr<nsISupports> otherElem;
310 while (index--) {
311 if (NS_FAILED(other->GetElementAt(index, getter_AddRefs(otherElem))))
312 return PR_FALSE;
313 if (mArray[index] != otherElem)
314 return PR_FALSE;
316 return PR_TRUE;
319 return PR_FALSE;
322 NS_IMETHODIMP_(nsISupports*)
323 nsSupportsArray::ElementAt(PRUint32 aIndex)
325 if (aIndex < mCount) {
326 nsISupports* element = mArray[aIndex];
327 NS_IF_ADDREF(element);
328 return element;
330 return 0;
333 NS_IMETHODIMP_(PRInt32)
334 nsSupportsArray::IndexOf(const nsISupports* aPossibleElement)
336 return IndexOfStartingAt(aPossibleElement, 0);
339 NS_IMETHODIMP_(PRInt32)
340 nsSupportsArray::IndexOfStartingAt(const nsISupports* aPossibleElement,
341 PRUint32 aStartIndex)
343 if (aStartIndex < mCount) {
344 const nsISupports** start = (const nsISupports**)mArray; // work around goofy compiler behavior
345 const nsISupports** ep = (start + aStartIndex);
346 const nsISupports** end = (start + mCount);
347 while (ep < end) {
348 if (aPossibleElement == *ep) {
349 return (ep - start);
351 ep++;
354 return -1;
357 NS_IMETHODIMP_(PRInt32)
358 nsSupportsArray::LastIndexOf(const nsISupports* aPossibleElement)
360 if (0 < mCount) {
361 const nsISupports** start = (const nsISupports**)mArray; // work around goofy compiler behavior
362 const nsISupports** ep = (start + mCount);
363 while (start <= --ep) {
364 if (aPossibleElement == *ep) {
365 return (ep - start);
369 return -1;
372 NS_IMETHODIMP_(PRBool)
373 nsSupportsArray::InsertElementAt(nsISupports* aElement, PRUint32 aIndex)
375 if (aIndex <= mCount) {
376 if (mArraySize < (mCount + 1)) {
377 // need to grow the array
378 if (!GrowArrayBy(1))
379 return PR_FALSE;
382 // Could be slightly more efficient if GrowArrayBy knew about the
383 // split, but the difference is trivial.
384 PRUint32 slide = (mCount - aIndex);
385 if (0 < slide) {
386 ::memmove(mArray + aIndex + 1, mArray + aIndex, slide * sizeof(nsISupports*));
389 mArray[aIndex] = aElement;
390 NS_IF_ADDREF(aElement);
391 mCount++;
393 #if DEBUG_SUPPORTSARRAY
394 if (mCount > mMaxCount &&
395 mCount < (PRInt32)(sizeof(MaxElements)/sizeof(MaxElements[0])))
397 MaxElements[mCount]++;
398 MaxElements[mMaxCount]--;
399 mMaxCount = mCount;
401 #endif
402 return PR_TRUE;
404 return PR_FALSE;
407 NS_IMETHODIMP_(PRBool)
408 nsSupportsArray::InsertElementsAt(nsISupportsArray* aElements, PRUint32 aIndex)
410 if (!aElements) {
411 return PR_FALSE;
413 PRUint32 countElements;
414 if (NS_FAILED( aElements->Count( &countElements ) ))
415 return PR_FALSE;
417 if (aIndex <= mCount) {
418 if (mArraySize < (mCount + countElements)) {
419 // need to grow the array
420 if (!GrowArrayBy(countElements))
421 return PR_FALSE;
424 // Could be slightly more efficient if GrowArrayBy knew about the
425 // split, but the difference is trivial.
426 PRUint32 slide = (mCount - aIndex);
427 if (0 < slide) {
428 ::memmove(mArray + aIndex + countElements, mArray + aIndex,
429 slide * sizeof(nsISupports*));
432 for (PRUint32 i = 0; i < countElements; ++i, ++mCount) {
433 // use GetElementAt to copy and do AddRef for us
434 if (NS_FAILED( aElements->GetElementAt( i, mArray + aIndex + i) ))
435 return PR_FALSE;
438 #if DEBUG_SUPPORTSARRAY
439 if (mCount > mMaxCount &&
440 mCount < (PRInt32)(sizeof(MaxElements)/sizeof(MaxElements[0])))
442 MaxElements[mCount]++;
443 MaxElements[mMaxCount]--;
444 mMaxCount = mCount;
446 #endif
447 return PR_TRUE;
449 return PR_FALSE;
452 NS_IMETHODIMP_(PRBool)
453 nsSupportsArray::ReplaceElementAt(nsISupports* aElement, PRUint32 aIndex)
455 if (aIndex < mCount) {
456 NS_IF_ADDREF(aElement); // addref first in case it's the same object!
457 NS_IF_RELEASE(mArray[aIndex]);
458 mArray[aIndex] = aElement;
459 return PR_TRUE;
461 return PR_FALSE;
464 NS_IMETHODIMP_(PRBool)
465 nsSupportsArray::RemoveElementsAt(PRUint32 aIndex, PRUint32 aCount)
467 if (aIndex + aCount <= mCount) {
468 for (PRUint32 i = 0; i < aCount; i++)
469 NS_IF_RELEASE(mArray[aIndex+i]);
470 mCount -= aCount;
471 PRInt32 slide = (mCount - aIndex);
472 if (0 < slide) {
473 ::memmove(mArray + aIndex, mArray + aIndex + aCount,
474 slide * sizeof(nsISupports*));
476 return PR_TRUE;
478 return PR_FALSE;
481 NS_IMETHODIMP_(PRBool)
482 nsSupportsArray::RemoveElement(const nsISupports* aElement, PRUint32 aStartIndex)
484 PRInt32 theIndex = IndexOfStartingAt(aElement,aStartIndex);
485 if (theIndex >= 0)
486 return RemoveElementAt(theIndex);
488 return PR_FALSE;
491 NS_IMETHODIMP_(PRBool)
492 nsSupportsArray::RemoveLastElement(const nsISupports* aElement)
494 PRInt32 theIndex = LastIndexOf(aElement);
495 if (theIndex >= 0)
496 return RemoveElementAt(theIndex);
498 return PR_FALSE;
501 NS_IMETHODIMP_(PRBool)
502 nsSupportsArray::MoveElement(PRInt32 aFrom, PRInt32 aTo)
504 nsISupports *tempElement;
506 if (aTo == aFrom)
507 return PR_TRUE;
509 if (aTo < 0 || aFrom < 0 ||
510 (PRUint32) aTo >= mCount || (PRUint32) aFrom >= mCount)
512 // can't extend the array when moving an element. Also catches mImpl = null
513 return PR_FALSE;
515 tempElement = mArray[aFrom];
517 if (aTo < aFrom)
519 // Moving one element closer to the head; the elements inbetween move down
520 ::memmove(mArray + aTo + 1, mArray + aTo,
521 (aFrom-aTo) * sizeof(mArray[0]));
522 mArray[aTo] = tempElement;
524 else // already handled aFrom == aTo
526 // Moving one element closer to the tail; the elements inbetween move up
527 ::memmove(mArray + aFrom, mArray + aFrom + 1,
528 (aTo-aFrom) * sizeof(mArray[0]));
529 mArray[aTo] = tempElement;
532 return PR_TRUE;
535 NS_IMETHODIMP
536 nsSupportsArray::Clear(void)
538 if (0 < mCount) {
539 do {
540 --mCount;
541 NS_IF_RELEASE(mArray[mCount]);
542 } while (0 != mCount);
544 return NS_OK;
547 NS_IMETHODIMP
548 nsSupportsArray::Compact(void)
550 #if DEBUG_SUPPORTSARRAY
551 PRUint32 oldArraySize = mArraySize;
552 #endif
553 if ((mArraySize != mCount) && (kAutoArraySize < mArraySize)) {
554 nsISupports** oldArray = mArray;
555 if (mCount <= kAutoArraySize) {
556 mArray = mAutoArray;
557 mArraySize = kAutoArraySize;
559 else {
560 mArray = new nsISupports*[mCount];
561 if (!mArray) {
562 mArray = oldArray;
563 return NS_OK;
565 mArraySize = mCount;
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 ::memcpy(mArray, oldArray, mCount * sizeof(nsISupports*));
575 delete[] oldArray;
577 return NS_OK;
580 NS_IMETHODIMP_(PRBool)
581 nsSupportsArray::SizeTo(PRInt32 aSize)
583 #if DEBUG_SUPPORTSARRAY
584 PRUint32 oldArraySize = mArraySize;
585 #endif
586 NS_ASSERTION(aSize >= 0, "negative aSize!");
588 // XXX for aSize < mCount we could resize to mCount
589 if (mArraySize == (PRUint32) aSize || (PRUint32) aSize < mCount)
590 return PR_TRUE; // nothing to do
592 // switch back to autoarray if possible
593 nsISupports** oldArray = mArray;
594 if ((PRUint32) aSize <= kAutoArraySize) {
595 mArray = mAutoArray;
596 mArraySize = kAutoArraySize;
598 else {
599 mArray = new nsISupports*[aSize];
600 if (!mArray) {
601 mArray = oldArray;
602 return PR_FALSE;
604 mArraySize = aSize;
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 ::memcpy(mArray, oldArray, mCount * sizeof(nsISupports*));
614 if (oldArray != mAutoArray)
615 delete[] oldArray;
617 return PR_TRUE;
620 NS_IMETHODIMP_(PRBool)
621 nsSupportsArray::EnumerateForwards(nsISupportsArrayEnumFunc aFunc, void* aData)
623 PRInt32 aIndex = -1;
624 PRBool running = PR_TRUE;
626 while (running && (++aIndex < (PRInt32)mCount)) {
627 running = (*aFunc)(mArray[aIndex], aData);
629 return running;
632 NS_IMETHODIMP_(PRBool)
633 nsSupportsArray::EnumerateBackwards(nsISupportsArrayEnumFunc aFunc, void* aData)
635 PRUint32 aIndex = mCount;
636 PRBool running = PR_TRUE;
638 while (running && (0 < aIndex--)) {
639 running = (*aFunc)(mArray[aIndex], aData);
641 return running;
644 NS_IMETHODIMP
645 nsSupportsArray::Enumerate(nsIEnumerator* *result)
647 nsSupportsArrayEnumerator* e = new nsSupportsArrayEnumerator(this);
648 if (!e)
649 return NS_ERROR_OUT_OF_MEMORY;
650 *result = e;
651 NS_ADDREF(e);
652 return NS_OK;
655 static PRBool
656 CopyElement(nsISupports* aElement, void *aData)
658 nsresult rv;
659 nsISupportsArray* newArray = (nsISupportsArray*)aData;
660 rv = newArray->AppendElement(aElement);
661 return NS_SUCCEEDED(rv);
664 NS_IMETHODIMP
665 nsSupportsArray::Clone(nsISupportsArray* *result)
667 nsresult rv;
668 nsISupportsArray* newArray;
669 rv = NS_NewISupportsArray(&newArray);
670 PRBool ok = EnumerateForwards(CopyElement, newArray);
671 if (!ok) return NS_ERROR_OUT_OF_MEMORY;
672 *result = newArray;
673 return NS_OK;
676 NS_COM nsresult
677 NS_NewISupportsArray(nsISupportsArray** aInstancePtrResult)
679 nsresult rv;
680 rv = nsSupportsArray::Create(NULL, NS_GET_IID(nsISupportsArray),
681 (void**)aInstancePtrResult);
682 return rv;
685 class nsArrayEnumerator : public nsISimpleEnumerator
687 public:
688 // nsISupports interface
689 NS_DECL_ISUPPORTS
691 // nsISimpleEnumerator interface
692 NS_IMETHOD HasMoreElements(PRBool* aResult);
693 NS_IMETHOD GetNext(nsISupports** aResult);
695 // nsArrayEnumerator methods
696 nsArrayEnumerator(nsISupportsArray* aValueArray);
698 private:
699 ~nsArrayEnumerator(void);
701 protected:
702 nsISupportsArray* mValueArray;
703 PRInt32 mIndex;
706 nsArrayEnumerator::nsArrayEnumerator(nsISupportsArray* aValueArray)
707 : mValueArray(aValueArray),
708 mIndex(0)
710 NS_IF_ADDREF(mValueArray);
713 nsArrayEnumerator::~nsArrayEnumerator(void)
715 NS_IF_RELEASE(mValueArray);
718 NS_IMPL_ISUPPORTS1(nsArrayEnumerator, nsISimpleEnumerator)
720 NS_IMETHODIMP
721 nsArrayEnumerator::HasMoreElements(PRBool* aResult)
723 NS_PRECONDITION(aResult != 0, "null ptr");
724 if (! aResult)
725 return NS_ERROR_NULL_POINTER;
727 if (!mValueArray) {
728 *aResult = PR_FALSE;
729 return NS_OK;
732 PRUint32 cnt;
733 nsresult rv = mValueArray->Count(&cnt);
734 if (NS_FAILED(rv)) return rv;
735 *aResult = (mIndex < (PRInt32) cnt);
736 return NS_OK;
739 NS_IMETHODIMP
740 nsArrayEnumerator::GetNext(nsISupports** aResult)
742 NS_PRECONDITION(aResult != 0, "null ptr");
743 if (! aResult)
744 return NS_ERROR_NULL_POINTER;
746 if (!mValueArray) {
747 *aResult = nsnull;
748 return NS_OK;
751 PRUint32 cnt;
752 nsresult rv = mValueArray->Count(&cnt);
753 if (NS_FAILED(rv)) return rv;
754 if (mIndex >= (PRInt32) cnt)
755 return NS_ERROR_UNEXPECTED;
757 *aResult = mValueArray->ElementAt(mIndex++);
758 return NS_OK;
761 nsresult
762 NS_NewArrayEnumerator(nsISimpleEnumerator* *result,
763 nsISupportsArray* array)
765 nsArrayEnumerator* enumer = new nsArrayEnumerator(array);
766 if (enumer == nsnull)
767 return NS_ERROR_OUT_OF_MEMORY;
768 *result = enumer;
769 NS_ADDREF(*result);
770 return NS_OK;