Back to index

lightning-sunbird  0.9+nobinonly
nsSupportsArray.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   Scott Collins <scc@mozilla.org>: |do_QueryElementAt|
00024  *   Pierre Phaneuf <pp@ludusdesign.com>
00025  *
00026  * Alternatively, the contents of this file may be used under the terms of
00027  * either of the GNU General Public License Version 2 or later (the "GPL"),
00028  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00029  * in which case the provisions of the GPL or the LGPL are applicable instead
00030  * of those above. If you wish to allow use of your version of this file only
00031  * under the terms of either the GPL or the LGPL, and not to allow others to
00032  * use your version of this file under the terms of the MPL, indicate your
00033  * decision by deleting the provisions above and replace them with the notice
00034  * and other provisions required by the GPL or the LGPL. If you do not delete
00035  * the provisions above, a recipient may use your version of this file under
00036  * the terms of any one of the MPL, the GPL or the LGPL.
00037  *
00038  * ***** END LICENSE BLOCK ***** */
00039 
00040 #include <string.h>
00041 #include "prbit.h"
00042 #include "nsSupportsArray.h"
00043 #include "nsSupportsArrayEnumerator.h"
00044 #include "nsAString.h"
00045 #include "nsIObjectInputStream.h"
00046 #include "nsIObjectOutputStream.h"
00047 
00048 #if DEBUG_SUPPORTSARRAY
00049 #define MAXSUPPORTS 20
00050 
00051 class SupportsStats {
00052 public:
00053   SupportsStats();
00054   ~SupportsStats();
00055 
00056 };
00057 
00058 static int sizesUsed; // number of the elements of the arrays used
00059 static int sizesAlloced[MAXSUPPORTS]; // sizes of the allocations.  sorted
00060 static int NumberOfSize[MAXSUPPORTS]; // number of this allocation size (1 per array)
00061 static int AllocedOfSize[MAXSUPPORTS]; // number of this allocation size (each size for array used)
00062 static int GrowInPlace[MAXSUPPORTS];
00063 
00064 // these are per-allocation
00065 static int MaxElements[3000];
00066 
00067 // very evil
00068 #define ADD_TO_STATS(x,size) do {int i; for (i = 0; i < sizesUsed; i++) \
00069                                   { \
00070                                     if (sizesAlloced[i] == (int)(size)) \
00071                                     { ((x)[i])++; break; } \
00072                                   } \
00073                                   if (i >= sizesUsed && sizesUsed < MAXSUPPORTS) \
00074                                   { sizesAlloced[sizesUsed] = (size); \
00075                                     ((x)[sizesUsed++])++; break; \
00076                                   } \
00077                                 } while (0);
00078 
00079 #define SUB_FROM_STATS(x,size) do {int i; for (i = 0; i < sizesUsed; i++) \
00080                                     { \
00081                                       if (sizesAlloced[i] == (int)(size)) \
00082                                       { ((x)[i])--; break; } \
00083                                     } \
00084                                   } while (0);
00085 
00086 
00087 SupportsStats::SupportsStats()
00088 {
00089   sizesUsed = 1;
00090   sizesAlloced[0] = 0;
00091 }
00092 
00093 SupportsStats::~SupportsStats()
00094 {
00095   int i;
00096   for (i = 0; i < sizesUsed; i++)
00097   {
00098     printf("Size %d:\n",sizesAlloced[i]);
00099     printf("\tNumber of SupportsArrays this size (max):     %d\n",NumberOfSize[i]);
00100     printf("\tNumber of allocations this size (total):  %d\n",AllocedOfSize[i]);
00101     printf("\tNumber of GrowsInPlace this size (total): %d\n",GrowInPlace[i]);
00102   }
00103   printf("Max Size of SupportsArray:\n");
00104   for (i = 0; i < (int)(sizeof(MaxElements)/sizeof(MaxElements[0])); i++)
00105   {
00106     if (MaxElements[i])
00107       printf("\t%d: %d\n",i,MaxElements[i]);
00108   }
00109 }
00110 
00111 // Just so constructor/destructor get called
00112 SupportsStats gSupportsStats;
00113 #endif
00114 
00115 nsresult
00116 nsQueryElementAt::operator()( const nsIID& aIID, void** aResult ) const
00117   {
00118     nsresult status = mCollection
00119                         ? mCollection->QueryElementAt(mIndex, aIID, aResult)
00120                         : NS_ERROR_NULL_POINTER;
00121 
00122     if ( mErrorPtr )
00123       *mErrorPtr = status;
00124 
00125     return status;
00126   }
00127 
00128 static const PRInt32 kGrowArrayBy = 8;
00129 static const PRInt32 kLinearThreshold = 16 * sizeof(nsISupports *);
00130 
00131 nsSupportsArray::nsSupportsArray()
00132 {
00133   mArray = mAutoArray;
00134   mArraySize = kAutoArraySize;
00135   mCount = 0;
00136 #if DEBUG_SUPPORTSARRAY
00137   mMaxCount = 0;
00138   mMaxSize = 0;
00139   ADD_TO_STATS(NumberOfSize,kAutoArraySize*sizeof(mArray[0]));
00140   MaxElements[0]++;
00141 #endif
00142 }
00143 
00144 nsSupportsArray::~nsSupportsArray()
00145 {
00146   DeleteArray();
00147 }
00148 
00149 PRBool nsSupportsArray::GrowArrayBy(PRInt32 aGrowBy)
00150 {
00151   // We have to grow the array. Grow by kGrowArrayBy slots if we're smaller
00152   // than kLinearThreshold bytes, or a power of two if we're larger.
00153   // This is much more efficient with most memory allocators, especially
00154   // if it's very large, or of the allocator is binned.
00155   if (aGrowBy < kGrowArrayBy)
00156     aGrowBy = kGrowArrayBy;
00157 
00158   PRUint32 newCount = mArraySize + aGrowBy;  // Minimum increase
00159   PRUint32 newSize = sizeof(mArray[0]) * newCount;
00160 
00161   if (newSize >= (PRUint32) kLinearThreshold)
00162   {
00163     // newCount includes enough space for at least kGrowArrayBy new slots.
00164     // Select the next power-of-two size in bytes above that if newSize is
00165     // not a power of two.
00166     if (newSize & (newSize - 1))
00167       newSize = PR_BIT(PR_CeilingLog2(newSize));
00168 
00169     newCount = newSize / sizeof(mArray[0]);
00170   }
00171   // XXX This would be far more efficient in many allocators if we used
00172   // XXX PR_Realloc(), etc
00173   nsISupports** oldArray = mArray;
00174 
00175   mArray = new nsISupports*[newCount];
00176   if (!mArray) {                    // ran out of memory
00177     mArray = oldArray;
00178     return PR_FALSE;
00179   }
00180   mArraySize = newCount;
00181 
00182 #if DEBUG_SUPPORTSARRAY
00183   if (oldArray == mArray) // can't happen without use of realloc
00184     ADD_TO_STATS(GrowInPlace,mCount);
00185   ADD_TO_STATS(AllocedOfSize,mArraySize*sizeof(mArray[0]));
00186   if (mArraySize > mMaxSize)
00187   {
00188     ADD_TO_STATS(NumberOfSize,mArraySize*sizeof(mArray[0]));
00189     if (oldArray != &(mAutoArray[0]))
00190       SUB_FROM_STATS(NumberOfSize,mCount*sizeof(mArray[0]));
00191     mMaxSize = mArraySize;
00192   }
00193 #endif
00194   if (oldArray) {                   // need to move old data
00195     if (0 < mCount) {
00196       ::memcpy(mArray, oldArray, mCount * sizeof(nsISupports*));
00197     }
00198     if (oldArray != &(mAutoArray[0])) {
00199       delete[] oldArray;
00200     }
00201   }
00202 
00203   return PR_TRUE;
00204 }
00205 
00206 NS_METHOD
00207 nsSupportsArray::Create(nsISupports *aOuter, REFNSIID aIID, void **aResult)
00208 {
00209   if (aOuter)
00210     return NS_ERROR_NO_AGGREGATION;
00211 
00212   nsCOMPtr<nsISupportsArray> it = new nsSupportsArray();
00213   if (!it)
00214     return NS_ERROR_OUT_OF_MEMORY;
00215 
00216   return it->QueryInterface(aIID, aResult);
00217 }
00218 
00219 NS_IMPL_THREADSAFE_ISUPPORTS3(nsSupportsArray, nsISupportsArray, nsICollection, nsISerializable)
00220 
00221 NS_IMETHODIMP
00222 nsSupportsArray::Read(nsIObjectInputStream *aStream)
00223 {
00224   nsresult rv;
00225 
00226   PRUint32 newArraySize;
00227   rv = aStream->Read32(&newArraySize);
00228 
00229   if (newArraySize <= kAutoArraySize) {
00230     if (mArray != mAutoArray) {
00231       delete[] mArray;
00232       mArray = mAutoArray;
00233     }
00234     newArraySize = kAutoArraySize;
00235   }
00236   else {
00237     if (newArraySize <= mArraySize) {
00238       // Keep non-default-size mArray, it's more than big enough.
00239       newArraySize = mArraySize;
00240     }
00241     else {
00242       nsISupports** array = new nsISupports*[newArraySize];
00243       if (!array)
00244         return NS_ERROR_OUT_OF_MEMORY;
00245       if (mArray != mAutoArray)
00246         delete[] mArray;
00247       mArray = array;
00248     }
00249   }
00250   mArraySize = newArraySize;
00251 
00252   rv = aStream->Read32(&mCount);
00253   if (NS_FAILED(rv)) return rv;
00254 
00255   NS_ASSERTION(mCount <= mArraySize, "overlarge mCount!");
00256   if (mCount > mArraySize)
00257     mCount = mArraySize;
00258 
00259   for (PRUint32 i = 0; i < mCount; i++) {
00260     rv = aStream->ReadObject(PR_TRUE, &mArray[i]);
00261     if (NS_FAILED(rv)) return rv;
00262   }
00263 
00264   return NS_OK;
00265 }
00266 
00267 NS_IMETHODIMP
00268 nsSupportsArray::Write(nsIObjectOutputStream *aStream)
00269 {
00270   nsresult rv;
00271 
00272   rv = aStream->Write32(mArraySize);
00273   if (NS_FAILED(rv)) return rv;
00274 
00275   rv = aStream->Write32(mCount);
00276   if (NS_FAILED(rv)) return rv;
00277 
00278   for (PRUint32 i = 0; i < mCount; i++) {
00279     rv = aStream->WriteObject(mArray[i], PR_TRUE);
00280     if (NS_FAILED(rv)) return rv;
00281   }
00282 
00283   return NS_OK;
00284 }
00285 
00286 void nsSupportsArray::DeleteArray(void)
00287 {
00288   Clear();
00289   if (mArray != &(mAutoArray[0])) {
00290     delete[] mArray;
00291     mArray = mAutoArray;
00292     mArraySize = kAutoArraySize;
00293   }
00294 }
00295 
00296 
00297 NS_IMETHODIMP_(PRBool)
00298 nsSupportsArray::Equals(const nsISupportsArray* aOther)
00299 {
00300   if (aOther) {
00301     PRUint32 countOther;
00302     nsISupportsArray* other = NS_CONST_CAST(nsISupportsArray*, aOther);
00303     nsresult rv = other->Count(&countOther);
00304     if (NS_FAILED( rv ))
00305       return PR_FALSE;
00306 
00307     if (mCount == countOther) {
00308       PRUint32 index = mCount;
00309       nsCOMPtr<nsISupports> otherElem;
00310       while (index--) {
00311         if (NS_FAILED(other->GetElementAt(index, getter_AddRefs(otherElem))))
00312           return PR_FALSE;
00313         if (mArray[index] != otherElem)
00314           return PR_FALSE;
00315       }
00316       return PR_TRUE;
00317     }
00318   }
00319   return PR_FALSE;
00320 }
00321 
00322 NS_IMETHODIMP_(nsISupports*)
00323 nsSupportsArray::ElementAt(PRUint32 aIndex)
00324 {
00325   if (aIndex < mCount) {
00326     nsISupports*  element = mArray[aIndex];
00327     NS_IF_ADDREF(element);
00328     return element;
00329   }
00330   return 0;
00331 }
00332 
00333 NS_IMETHODIMP_(PRInt32)
00334 nsSupportsArray::IndexOf(const nsISupports* aPossibleElement)
00335 {
00336   return IndexOfStartingAt(aPossibleElement, 0);
00337 }
00338 
00339 NS_IMETHODIMP_(PRInt32)
00340 nsSupportsArray::IndexOfStartingAt(const nsISupports* aPossibleElement,
00341                                    PRUint32 aStartIndex)
00342 {
00343   if (aStartIndex < mCount) {
00344     const nsISupports** start = (const nsISupports**)mArray;  // work around goofy compiler behavior
00345     const nsISupports** ep = (start + aStartIndex);
00346     const nsISupports** end = (start + mCount);
00347     while (ep < end) {
00348       if (aPossibleElement == *ep) {
00349         return (ep - start);
00350       }
00351       ep++;
00352     }
00353   }
00354   return -1;
00355 }
00356 
00357 NS_IMETHODIMP_(PRInt32)
00358 nsSupportsArray::LastIndexOf(const nsISupports* aPossibleElement)
00359 {
00360   if (0 < mCount) {
00361     const nsISupports** start = (const nsISupports**)mArray;  // work around goofy compiler behavior
00362     const nsISupports** ep = (start + mCount);
00363     while (start <= --ep) {
00364       if (aPossibleElement == *ep) {
00365         return (ep - start);
00366       }
00367     }
00368   }
00369   return -1;
00370 }
00371 
00372 NS_IMETHODIMP_(PRBool)
00373 nsSupportsArray::InsertElementAt(nsISupports* aElement, PRUint32 aIndex)
00374 {
00375   if (aIndex <= mCount) {
00376     if (mArraySize < (mCount + 1)) {
00377       // need to grow the array
00378       if (!GrowArrayBy(1))
00379         return PR_FALSE;
00380     }
00381 
00382     // Could be slightly more efficient if GrowArrayBy knew about the
00383     // split, but the difference is trivial.
00384     PRUint32 slide = (mCount - aIndex);
00385     if (0 < slide) {
00386       ::memmove(mArray + aIndex + 1, mArray + aIndex, slide * sizeof(nsISupports*));
00387     }
00388 
00389     mArray[aIndex] = aElement;
00390     NS_IF_ADDREF(aElement);
00391     mCount++;
00392 
00393 #if DEBUG_SUPPORTSARRAY
00394     if (mCount > mMaxCount &&
00395         mCount < (PRInt32)(sizeof(MaxElements)/sizeof(MaxElements[0])))
00396     {
00397       MaxElements[mCount]++;
00398       MaxElements[mMaxCount]--;
00399       mMaxCount = mCount;
00400     }
00401 #endif
00402     return PR_TRUE;
00403   }
00404   return PR_FALSE;
00405 }
00406 
00407 NS_IMETHODIMP_(PRBool)
00408 nsSupportsArray::InsertElementsAt(nsISupportsArray* aElements, PRUint32 aIndex)
00409 {
00410   if (!aElements) {
00411     return PR_FALSE;
00412   }
00413   PRUint32 countElements;
00414   if (NS_FAILED( aElements->Count( &countElements ) ))
00415     return PR_FALSE;
00416 
00417   if (aIndex <= mCount) {
00418     if (mArraySize < (mCount + countElements)) {
00419       // need to grow the array
00420       if (!GrowArrayBy(countElements))
00421         return PR_FALSE;
00422     }
00423 
00424     // Could be slightly more efficient if GrowArrayBy knew about the
00425     // split, but the difference is trivial.
00426     PRUint32 slide = (mCount - aIndex);
00427     if (0 < slide) {
00428       ::memmove(mArray + aIndex + countElements, mArray + aIndex,
00429                 slide * sizeof(nsISupports*));
00430     }
00431 
00432     for (PRUint32 i = 0; i < countElements; ++i, ++mCount) {
00433       // use GetElementAt to copy and do AddRef for us
00434       if (NS_FAILED( aElements->GetElementAt( i, mArray + aIndex + i) ))
00435         return PR_FALSE;
00436     }
00437 
00438 #if DEBUG_SUPPORTSARRAY
00439     if (mCount > mMaxCount &&
00440         mCount < (PRInt32)(sizeof(MaxElements)/sizeof(MaxElements[0])))
00441     {
00442       MaxElements[mCount]++;
00443       MaxElements[mMaxCount]--;
00444       mMaxCount = mCount;
00445     }
00446 #endif
00447     return PR_TRUE;
00448   }
00449   return PR_FALSE;
00450 }
00451 
00452 NS_IMETHODIMP_(PRBool)
00453 nsSupportsArray::ReplaceElementAt(nsISupports* aElement, PRUint32 aIndex)
00454 {
00455   if (aIndex < mCount) {
00456     NS_IF_ADDREF(aElement);  // addref first in case it's the same object!
00457     NS_IF_RELEASE(mArray[aIndex]);
00458     mArray[aIndex] = aElement;
00459     return PR_TRUE;
00460   }
00461   return PR_FALSE;
00462 }
00463 
00464 NS_IMETHODIMP_(PRBool)
00465 nsSupportsArray::RemoveElementsAt(PRUint32 aIndex, PRUint32 aCount)
00466 {
00467   if (aIndex + aCount <= mCount) {
00468     for (PRUint32 i = 0; i < aCount; i++)
00469       NS_IF_RELEASE(mArray[aIndex+i]);
00470     mCount -= aCount;
00471     PRInt32 slide = (mCount - aIndex);
00472     if (0 < slide) {
00473       ::memmove(mArray + aIndex, mArray + aIndex + aCount,
00474                 slide * sizeof(nsISupports*));
00475     }
00476     return PR_TRUE;
00477   }
00478   return PR_FALSE;
00479 }
00480 
00481 NS_IMETHODIMP_(PRBool)
00482 nsSupportsArray::RemoveElement(const nsISupports* aElement, PRUint32 aStartIndex)
00483 {
00484   PRInt32 theIndex = IndexOfStartingAt(aElement,aStartIndex);
00485   if (theIndex >= 0)
00486     return RemoveElementAt(theIndex);
00487 
00488   return PR_FALSE;
00489 }
00490 
00491 NS_IMETHODIMP_(PRBool)
00492 nsSupportsArray::RemoveLastElement(const nsISupports* aElement)
00493 {
00494   PRInt32 theIndex = LastIndexOf(aElement);
00495   if (theIndex >= 0)
00496     return RemoveElementAt(theIndex);
00497 
00498   return PR_FALSE;
00499 }
00500 
00501 NS_IMETHODIMP_(PRBool)
00502 nsSupportsArray::MoveElement(PRInt32 aFrom, PRInt32 aTo)
00503 {
00504   nsISupports *tempElement;
00505 
00506   if (aTo == aFrom)
00507     return PR_TRUE;
00508 
00509   if (aTo < 0 || aFrom < 0 ||
00510       (PRUint32) aTo >= mCount || (PRUint32) aFrom >= mCount)
00511   {
00512     // can't extend the array when moving an element.  Also catches mImpl = null
00513     return PR_FALSE;
00514   }
00515   tempElement = mArray[aFrom];
00516 
00517   if (aTo < aFrom)
00518   {
00519     // Moving one element closer to the head; the elements inbetween move down
00520     ::memmove(mArray + aTo + 1, mArray + aTo,
00521               (aFrom-aTo) * sizeof(mArray[0]));
00522     mArray[aTo] = tempElement;
00523   }
00524   else // already handled aFrom == aTo
00525   {
00526     // Moving one element closer to the tail; the elements inbetween move up
00527     ::memmove(mArray + aFrom, mArray + aFrom + 1,
00528               (aTo-aFrom) * sizeof(mArray[0]));
00529     mArray[aTo] = tempElement;
00530   }
00531 
00532   return PR_TRUE;
00533 }
00534 
00535 NS_IMETHODIMP
00536 nsSupportsArray::Clear(void)
00537 {
00538   if (0 < mCount) {
00539     do {
00540       --mCount;
00541       NS_IF_RELEASE(mArray[mCount]);
00542     } while (0 != mCount);
00543   }
00544   return NS_OK;
00545 }
00546 
00547 NS_IMETHODIMP
00548 nsSupportsArray::Compact(void)
00549 {
00550 #if DEBUG_SUPPORTSARRAY
00551   PRUint32 oldArraySize = mArraySize;
00552 #endif
00553   if ((mArraySize != mCount) && (kAutoArraySize < mArraySize)) {
00554     nsISupports** oldArray = mArray;
00555     if (mCount <= kAutoArraySize) {
00556       mArray = mAutoArray;
00557       mArraySize = kAutoArraySize;
00558     }
00559     else {
00560       mArray = new nsISupports*[mCount];
00561       if (!mArray) {
00562         mArray = oldArray;
00563         return NS_OK;
00564       }
00565       mArraySize = mCount;
00566     }
00567 #if DEBUG_SUPPORTSARRAY
00568     if (oldArray == mArray &&
00569         oldArray != &(mAutoArray[0])) // can't happen without use of realloc
00570       ADD_TO_STATS(GrowInPlace,oldArraySize);
00571     if (oldArray != &(mAutoArray[0]))
00572       ADD_TO_STATS(AllocedOfSize,mArraySize*sizeof(mArray[0]));
00573 #endif
00574     ::memcpy(mArray, oldArray, mCount * sizeof(nsISupports*));
00575     delete[] oldArray;
00576   }
00577   return NS_OK;
00578 }
00579 
00580 NS_IMETHODIMP_(PRBool)
00581 nsSupportsArray::SizeTo(PRInt32 aSize)
00582 {
00583 #if DEBUG_SUPPORTSARRAY
00584   PRUint32 oldArraySize = mArraySize;
00585 #endif
00586   NS_ASSERTION(aSize >= 0, "negative aSize!");
00587 
00588   // XXX for aSize < mCount we could resize to mCount
00589   if (mArraySize == (PRUint32) aSize || (PRUint32) aSize < mCount)
00590     return PR_TRUE;     // nothing to do
00591 
00592   // switch back to autoarray if possible
00593   nsISupports** oldArray = mArray;
00594   if ((PRUint32) aSize <= kAutoArraySize) {
00595     mArray = mAutoArray;
00596     mArraySize = kAutoArraySize;
00597   }
00598   else {
00599     mArray = new nsISupports*[aSize];
00600     if (!mArray) {
00601       mArray = oldArray;
00602       return PR_FALSE;
00603     }
00604     mArraySize = aSize;
00605   }
00606 #if DEBUG_SUPPORTSARRAY
00607   if (oldArray == mArray &&
00608       oldArray != &(mAutoArray[0])) // can't happen without use of realloc
00609     ADD_TO_STATS(GrowInPlace,oldArraySize);
00610   if (oldArray != &(mAutoArray[0]))
00611     ADD_TO_STATS(AllocedOfSize,mArraySize*sizeof(mArray[0]));
00612 #endif
00613   ::memcpy(mArray, oldArray, mCount * sizeof(nsISupports*));
00614   if (oldArray != mAutoArray)
00615     delete[] oldArray;
00616 
00617   return PR_TRUE;
00618 }
00619 
00620 NS_IMETHODIMP_(PRBool)
00621 nsSupportsArray::EnumerateForwards(nsISupportsArrayEnumFunc aFunc, void* aData)
00622 {
00623   PRInt32 aIndex = -1;
00624   PRBool  running = PR_TRUE;
00625 
00626   while (running && (++aIndex < (PRInt32)mCount)) {
00627     running = (*aFunc)(mArray[aIndex], aData);
00628   }
00629   return running;
00630 }
00631 
00632 NS_IMETHODIMP_(PRBool)
00633 nsSupportsArray::EnumerateBackwards(nsISupportsArrayEnumFunc aFunc, void* aData)
00634 {
00635   PRUint32 aIndex = mCount;
00636   PRBool  running = PR_TRUE;
00637 
00638   while (running && (0 < aIndex--)) {
00639     running = (*aFunc)(mArray[aIndex], aData);
00640   }
00641   return running;
00642 }
00643 
00644 NS_IMETHODIMP
00645 nsSupportsArray::Enumerate(nsIEnumerator* *result)
00646 {
00647   nsSupportsArrayEnumerator* e = new nsSupportsArrayEnumerator(this);
00648   if (!e)
00649     return NS_ERROR_OUT_OF_MEMORY;
00650   *result = e;
00651   NS_ADDREF(e);
00652   return NS_OK;
00653 }
00654 
00655 static PRBool
00656 CopyElement(nsISupports* aElement, void *aData)
00657 {
00658   nsresult rv;
00659   nsISupportsArray* newArray = (nsISupportsArray*)aData;
00660   rv = newArray->AppendElement(aElement);
00661   return NS_SUCCEEDED(rv);
00662 }
00663 
00664 NS_IMETHODIMP
00665 nsSupportsArray::Clone(nsISupportsArray* *result)
00666 {
00667   nsresult rv;
00668   nsISupportsArray* newArray;
00669   rv = NS_NewISupportsArray(&newArray);
00670   PRBool ok = EnumerateForwards(CopyElement, newArray);
00671   if (!ok) return NS_ERROR_OUT_OF_MEMORY;
00672   *result = newArray;
00673   return NS_OK;
00674 }
00675 
00676 NS_COM nsresult
00677 NS_NewISupportsArray(nsISupportsArray** aInstancePtrResult)
00678 {
00679   nsresult rv;
00680   rv = nsSupportsArray::Create(NULL, NS_GET_IID(nsISupportsArray),
00681                                (void**)aInstancePtrResult);
00682   return rv;
00683 }
00684