LCOV - app.info - xpcom/glue/nsVoidArray.cpp

LCOV - code coverage report
| Current view: | directory - xpcom/glue - nsVoidArray.cpp (source / functions) |  | Found | Hit | Coverage |
| Test: | app.info | Lines: | 386 | 73 | 18.9 %
| Date: | 2012-04-21 | Functions: | 45 | 10 | 22.2 %

           1                 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; c-file-offsets: ((substatement-open . 0)) -*- */
           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                 :  *
          24                 :  * Alternatively, the contents of this file may be used under the terms of
          25                 :  * either of the GNU General Public License Version 2 or later (the "GPL"),
          26                 :  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
          27                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
          28                 :  * of those above. If you wish to allow use of your version of this file only
          29                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
          30                 :  * use your version of this file under the terms of the MPL, indicate your
          31                 :  * decision by deleting the provisions above and replace them with the notice
          32                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
          33                 :  * the provisions above, a recipient may use your version of this file under
          34                 :  * the terms of any one of the MPL, the GPL or the LGPL.
          35                 :  *
          36                 :  * ***** END LICENSE BLOCK ***** */
          37                 :
          38                 : #include <stdlib.h>
          39                 :
          40                 : #include "nsVoidArray.h"
          41                 : #include "nsQuickSort.h"
          42                 : #include "prbit.h"
          43                 : #include "nsISupportsImpl.h" // for nsTraceRefcnt
          44                 : #include "nsAlgorithm.h"
          45                 :
          46                 : /**
          47                 :  * Grow the array by at least this many elements at a time.
          48                 :  */
          49                 : static const PRInt32 kMinGrowArrayBy = 8;
          50                 : static const PRInt32 kMaxGrowArrayBy = 1024;
          51                 : static const PRInt32 kAutoClearCompactSizeFactor = 4;
          52                 :
          53                 : /**
          54                 :  * This is the threshold (in bytes) of the mImpl struct, past which
          55                 :  * we'll force the array to grow geometrically
          56                 :  */
          57                 : static const PRInt32 kLinearThreshold = 24 * sizeof(void *);
          58                 :
          59                 : /**
          60                 :  * Compute the number of bytes requires for the mImpl struct that will
          61                 :  * hold |n| elements.
          62                 :  */
          63                 : #define SIZEOF_IMPL(n_) (sizeof(Impl) + sizeof(void *) * ((n_) - 1))
          64                 :
          65                 :
          66                 : /**
          67                 :  * Compute the number of elements that an mImpl struct of |n| bytes
          68                 :  * will hold.
          69                 :  */
          70                 : #define CAPACITYOF_IMPL(n_) ((((n_) - sizeof(Impl)) / sizeof(void *)) + 1)
          71                 :
          72                 : #if DEBUG_VOIDARRAY
          73                 : #define MAXVOID 10
          74                 :
          75                 : class VoidStats {
          76                 : public:
          77                 :   VoidStats();
          78                 :   ~VoidStats();
          79                 :
          80                 : };
          81                 :
          82                 : static int sizesUsed; // number of the elements of the arrays used
          83                 : static int sizesAlloced[MAXVOID]; // sizes of the allocations.  sorted
          84                 : static int NumberOfSize[MAXVOID]; // number of this allocation size (1 per array)
          85                 : static int AllocedOfSize[MAXVOID]; // number of this allocation size (each size for array used)
          86                 : static int MaxAuto[MAXVOID];      // AutoArrays that maxed out at this size
          87                 : static int GrowInPlace[MAXVOID];  // arrays this size that grew in-place via realloc
          88                 :
          89                 : // these are per-allocation
          90                 : static int MaxElements[2000];     // # of arrays that maxed out at each size.
          91                 :
          92                 : // statistics macros
          93                 : #define ADD_TO_STATS(x,size) do {int i; for (i = 0; i < sizesUsed; i++) \
          94                 :                                   { \
          95                 :                                     if (sizesAlloced[i] == (int)(size)) \
          96                 :                                     { ((x)[i])++; break; } \
          97                 :                                   } \
          98                 :                                   if (i >= sizesUsed && sizesUsed < MAXVOID) \
          99                 :                                   { sizesAlloced[sizesUsed] = (size); \
         100                 :                                     ((x)[sizesUsed++])++; break; \
         101                 :                                   } \
         102                 :                                 } while (0)
         103                 :
         104                 : #define SUB_FROM_STATS(x,size) do {int i; for (i = 0; i < sizesUsed; i++) \
         105                 :                                     { \
         106                 :                                       if (sizesAlloced[i] == (int)(size)) \
         107                 :                                       { ((x)[i])--; break; } \
         108                 :                                     } \
         109                 :                                   } while (0)
         110                 :
         111                 :
         112                 : VoidStats::VoidStats()
         113                 : {
         114                 :   sizesUsed = 1;
         115                 :   sizesAlloced[0] = 0;
         116                 : }
         117                 :
         118                 : VoidStats::~VoidStats()
         119                 : {
         120                 :   int i;
         121                 :   for (i = 0; i < sizesUsed; i++)
         122                 :   {
         123                 :     printf("Size %d:\n",sizesAlloced[i]);
         124                 :     printf("\tNumber of VoidArrays this size (max):     %d\n",NumberOfSize[i]-MaxAuto[i]);
         125                 :     printf("\tNumber of AutoVoidArrays this size (max): %d\n",MaxAuto[i]);
         126                 :     printf("\tNumber of allocations this size (total):  %d\n",AllocedOfSize[i]);
         127                 :     printf("\tNumber of GrowsInPlace this size (total): %d\n",GrowInPlace[i]);
         128                 :   }
         129                 :   printf("Max Size of VoidArray:\n");
         130                 :   for (i = 0; i < (int)(sizeof(MaxElements)/sizeof(MaxElements[0])); i++)
         131                 :   {
         132                 :     if (MaxElements[i])
         133                 :       printf("\t%d: %d\n",i,MaxElements[i]);
         134                 :   }
         135                 : }
         136                 :
         137                 : // Just so constructor/destructor's get called
         138                 : VoidStats gVoidStats;
         139                 : #endif
         140                 :
         141                 : void
         142            2736 : nsVoidArray::SetArray(Impl *newImpl, PRInt32 aSize, PRInt32 aCount,
         143                 :                       bool aOwner, bool aHasAuto)
         144                 : {
         145                 :   // old mImpl has been realloced and so we don't free/delete it
         146            2736 :   NS_PRECONDITION(newImpl, "can't set size");
         147            2736 :   mImpl = newImpl;
         148            2736 :   mImpl->mCount = aCount;
         149                 :   mImpl->mBits = static_cast<PRUint32>(aSize & kArraySizeMask) |
         150                 :                  (aOwner ? kArrayOwnerMask : 0) |
         151            2736 :                  (aHasAuto ? kArrayHasAutoBufferMask : 0);
         152            2736 : }
         153                 :
         154                 : // This does all allocation/reallocation of the array.
         155                 : // It also will compact down to N - good for things that might grow a lot
         156                 : // at times,  but usually are smaller, like JS deferred GC releases.
         157            1368 : bool nsVoidArray::SizeTo(PRInt32 aSize)
         158                 : {
         159            1368 :   PRUint32 oldsize = GetArraySize();
         160            1368 :   bool isOwner = IsArrayOwner();
         161            1368 :   bool hasAuto = HasAutoBuffer();
         162                 :
         163            1368 :   if (aSize == (PRInt32) oldsize)
         164               0 :     return true; // no change
         165                 :
         166            1368 :   if (aSize <= 0)
         167                 :   {
         168                 :     // free the array if allocated
         169               0 :     if (mImpl)
         170                 :     {
         171               0 :       if (isOwner)
         172                 :       {
         173               0 :         free(reinterpret_cast<char *>(mImpl));
         174               0 :         if (hasAuto) {
         175               0 :           static_cast<nsAutoVoidArray*>(this)->ResetToAutoBuffer();
         176                 :         }
         177                 :         else {
         178               0 :           mImpl = nsnull;
         179                 :         }
         180                 :       }
         181                 :       else
         182                 :       {
         183               0 :         mImpl->mCount = 0; // nsAutoVoidArray
         184                 :       }
         185                 :     }
         186               0 :     return true;
         187                 :   }
         188                 :
         189            1368 :   if (mImpl && isOwner)
         190                 :   {
         191                 :     // We currently own an array impl. Resize it appropriately.
         192               0 :     if (aSize < mImpl->mCount)
         193                 :     {
         194                 :       // XXX Note: we could also just resize to mCount
         195               0 :       return true;  // can't make it that small, ignore request
         196                 :     }
         197                 :
         198               0 :     char* bytes = (char *) realloc(mImpl,SIZEOF_IMPL(aSize));
         199               0 :     Impl* newImpl = reinterpret_cast<Impl*>(bytes);
         200               0 :     if (!newImpl)
         201               0 :       return false;
         202                 :
         203                 : #if DEBUG_VOIDARRAY
         204                 :     if (mImpl == newImpl)
         205                 :       ADD_TO_STATS(GrowInPlace,oldsize);
         206                 :     ADD_TO_STATS(AllocedOfSize,SIZEOF_IMPL(aSize));
         207                 :     if (aSize > mMaxSize)
         208                 :     {
         209                 :       ADD_TO_STATS(NumberOfSize,SIZEOF_IMPL(aSize));
         210                 :       if (oldsize)
         211                 :         SUB_FROM_STATS(NumberOfSize,oldsize);
         212                 :       mMaxSize = aSize;
         213                 :       if (mIsAuto)
         214                 :       {
         215                 :         ADD_TO_STATS(MaxAuto,SIZEOF_IMPL(aSize));
         216                 :         SUB_FROM_STATS(MaxAuto,oldsize);
         217                 :       }
         218                 :     }
         219                 : #endif
         220               0 :     SetArray(newImpl, aSize, newImpl->mCount, true, hasAuto);
         221               0 :     return true;
         222                 :   }
         223                 :
         224            1368 :   if ((PRUint32) aSize < oldsize) {
         225                 :     // No point in allocating if it won't free the current Impl anyway.
         226               0 :     return true;
         227                 :   }
         228                 :
         229                 :   // just allocate an array
         230                 :   // allocate the exact size requested
         231            1368 :   char* bytes = (char *) malloc(SIZEOF_IMPL(aSize));
         232            1368 :   Impl* newImpl = reinterpret_cast<Impl*>(bytes);
         233            1368 :   if (!newImpl)
         234               0 :     return false;
         235                 :
         236                 : #if DEBUG_VOIDARRAY
         237                 :   ADD_TO_STATS(AllocedOfSize,SIZEOF_IMPL(aSize));
         238                 :   if (aSize > mMaxSize)
         239                 :   {
         240                 :     ADD_TO_STATS(NumberOfSize,SIZEOF_IMPL(aSize));
         241                 :     if (oldsize && !mImpl)
         242                 :       SUB_FROM_STATS(NumberOfSize,oldsize);
         243                 :     mMaxSize = aSize;
         244                 :   }
         245                 : #endif
         246            1368 :   if (mImpl)
         247                 :   {
         248                 : #if DEBUG_VOIDARRAY
         249                 :     ADD_TO_STATS(MaxAuto,SIZEOF_IMPL(aSize));
         250                 :     SUB_FROM_STATS(MaxAuto,0);
         251                 :     SUB_FROM_STATS(NumberOfSize,0);
         252                 :     mIsAuto = true;
         253                 : #endif
         254                 :     // We must be growing an nsAutoVoidArray - copy since we didn't
         255                 :     // realloc.
         256                 :     memcpy(newImpl->mArray, mImpl->mArray,
         257               0 :                   mImpl->mCount * sizeof(mImpl->mArray[0]));
         258                 :   }
         259                 :
         260            1368 :   SetArray(newImpl, aSize, mImpl ? mImpl->mCount : 0, true, hasAuto);
         261                 :   // no memset; handled later in ReplaceElementAt if needed
         262            1368 :   return true;
         263                 : }
         264                 :
         265            1368 : bool nsVoidArray::GrowArrayBy(PRInt32 aGrowBy)
         266                 : {
         267                 :   // We have to grow the array. Grow by kMinGrowArrayBy slots if we're
         268                 :   // smaller than kLinearThreshold bytes, or a power of two if we're
         269                 :   // larger.  This is much more efficient with most memory allocators,
         270                 :   // especially if it's very large, or of the allocator is binned.
         271            1368 :   if (aGrowBy < kMinGrowArrayBy)
         272            1368 :     aGrowBy = kMinGrowArrayBy;
         273                 :
         274            1368 :   PRUint32 newCapacity = GetArraySize() + aGrowBy;  // Minimum increase
         275            1368 :   PRUint32 newSize = SIZEOF_IMPL(newCapacity);
         276                 :
         277            1368 :   if (newSize >= (PRUint32) kLinearThreshold)
         278                 :   {
         279                 :     // newCount includes enough space for at least kMinGrowArrayBy new
         280                 :     // slots. Select the next power-of-two size in bytes above or
         281                 :     // equal to that.
         282                 :     // Also, limit the increase in size to about a VM page or two.
         283               0 :     if (GetArraySize() >= kMaxGrowArrayBy)
         284                 :     {
         285               0 :       newCapacity = GetArraySize() + NS_MAX(kMaxGrowArrayBy,aGrowBy);
         286               0 :       newSize = SIZEOF_IMPL(newCapacity);
         287                 :     }
         288                 :     else
         289                 :     {
         290               0 :       PR_CEILING_LOG2(newSize, newSize);
         291               0 :       newCapacity = CAPACITYOF_IMPL(PR_BIT(newSize));
         292                 :     }
         293                 :   }
         294                 :   // frees old mImpl IF this succeeds
         295            1368 :   if (!SizeTo(newCapacity))
         296               0 :     return false;
         297                 :
         298            1368 :   return true;
         299                 : }
         300                 :
         301            2736 : nsVoidArray::nsVoidArray()
         302            2736 :   : mImpl(nsnull)
         303                 : {
         304            2736 :   MOZ_COUNT_CTOR(nsVoidArray);
         305                 : #if DEBUG_VOIDARRAY
         306                 :   mMaxCount = 0;
         307                 :   mMaxSize = 0;
         308                 :   mIsAuto = false;
         309                 :   ADD_TO_STATS(NumberOfSize,0);
         310                 :   MaxElements[0]++;
         311                 : #endif
         312            2736 : }
         313                 :
         314               0 : nsVoidArray::nsVoidArray(PRInt32 aCount)
         315               0 :   : mImpl(nsnull)
         316                 : {
         317               0 :   MOZ_COUNT_CTOR(nsVoidArray);
         318                 : #if DEBUG_VOIDARRAY
         319                 :   mMaxCount = 0;
         320                 :   mMaxSize = 0;
         321                 :   mIsAuto = false;
         322                 :   MaxElements[0]++;
         323                 : #endif
         324               0 :   SizeTo(aCount);
         325               0 : }
         326                 :
         327            1368 : nsVoidArray& nsVoidArray::operator=(const nsVoidArray& other)
         328                 : {
         329            1368 :   PRInt32 otherCount = other.Count();
         330            1368 :   PRInt32 maxCount = GetArraySize();
         331            1368 :   if (otherCount)
         332                 :   {
         333            1368 :     if (otherCount > maxCount)
         334                 :     {
         335                 :       // frees old mImpl IF this succeeds
         336               0 :       if (!GrowArrayBy(otherCount-maxCount))
         337               0 :         return *this;      // XXX The allocation failed - don't do anything
         338                 :
         339               0 :       memcpy(mImpl->mArray, other.mImpl->mArray, otherCount * sizeof(mImpl->mArray[0]));
         340               0 :       mImpl->mCount = otherCount;
         341                 :     }
         342                 :     else
         343                 :     {
         344                 :       // the old array can hold the new array
         345            1368 :       memcpy(mImpl->mArray, other.mImpl->mArray, otherCount * sizeof(mImpl->mArray[0]));
         346            1368 :       mImpl->mCount = otherCount;
         347                 :       // if it shrank a lot, compact it anyways
         348            1368 :       if ((otherCount*2) < maxCount && maxCount > 100)
         349                 :       {
         350               0 :         Compact();  // shrank by at least 50 entries
         351                 :       }
         352                 :     }
         353                 : #if DEBUG_VOIDARRAY
         354                 :      if (mImpl->mCount > mMaxCount &&
         355                 :          mImpl->mCount < (PRInt32)(sizeof(MaxElements)/sizeof(MaxElements[0])))
         356                 :      {
         357                 :        MaxElements[mImpl->mCount]++;
         358                 :        MaxElements[mMaxCount]--;
         359                 :        mMaxCount = mImpl->mCount;
         360                 :      }
         361                 : #endif
         362                 :   }
         363                 :   else
         364                 :   {
         365                 :     // Why do we drop the buffer here when we don't in Clear()?
         366               0 :     SizeTo(0);
         367                 :   }
         368                 :
         369            1368 :   return *this;
         370                 : }
         371                 :
         372            2736 : nsVoidArray::~nsVoidArray()
         373                 : {
         374            2736 :   MOZ_COUNT_DTOR(nsVoidArray);
         375            2736 :   if (mImpl && IsArrayOwner())
         376            1368 :     free(reinterpret_cast<char*>(mImpl));
         377            2736 : }
         378                 :
         379               0 : bool nsVoidArray::SetCount(PRInt32 aNewCount)
         380                 : {
         381               0 :   NS_ASSERTION(aNewCount >= 0,"SetCount(negative index)");
         382               0 :   if (aNewCount < 0)
         383               0 :     return false;
         384                 :
         385               0 :   if (aNewCount == 0)
         386                 :   {
         387               0 :     Clear();
         388               0 :     return true;
         389                 :   }
         390                 :
         391               0 :   if (PRUint32(aNewCount) > PRUint32(GetArraySize()))
         392                 :   {
         393               0 :     PRInt32 oldCount = Count();
         394               0 :     PRInt32 growDelta = aNewCount - oldCount;
         395                 :
         396                 :     // frees old mImpl IF this succeeds
         397               0 :     if (!GrowArrayBy(growDelta))
         398               0 :       return false;
         399                 :   }
         400                 :
         401               0 :   if (aNewCount > mImpl->mCount)
         402                 :   {
         403                 :     // Make sure that new entries added to the array by this
         404                 :     // SetCount are cleared to 0.  Some users of this assume that.
         405                 :     // This code means we don't have to memset when we allocate an array.
         406               0 :     memset(&mImpl->mArray[mImpl->mCount], 0,
         407               0 :            (aNewCount - mImpl->mCount) * sizeof(mImpl->mArray[0]));
         408                 :   }
         409                 :
         410               0 :   mImpl->mCount = aNewCount;
         411                 :
         412                 : #if DEBUG_VOIDARRAY
         413                 :   if (mImpl->mCount > mMaxCount &&
         414                 :       mImpl->mCount < (PRInt32)(sizeof(MaxElements)/sizeof(MaxElements[0])))
         415                 :   {
         416                 :     MaxElements[mImpl->mCount]++;
         417                 :     MaxElements[mMaxCount]--;
         418                 :     mMaxCount = mImpl->mCount;
         419                 :   }
         420                 : #endif
         421                 :
         422               0 :   return true;
         423                 : }
         424                 :
         425               0 : PRInt32 nsVoidArray::IndexOf(void* aPossibleElement) const
         426                 : {
         427               0 :   if (mImpl)
         428                 :   {
         429               0 :     void** ap = mImpl->mArray;
         430               0 :     void** end = ap + mImpl->mCount;
         431               0 :     while (ap < end)
         432                 :     {
         433               0 :       if (*ap == aPossibleElement)
         434                 :       {
         435               0 :         return ap - mImpl->mArray;
         436                 :       }
         437               0 :       ap++;
         438                 :     }
         439                 :   }
         440               0 :   return -1;
         441                 : }
         442                 :
         443            1368 : bool nsVoidArray::InsertElementAt(void* aElement, PRInt32 aIndex)
         444                 : {
         445            1368 :   PRInt32 oldCount = Count();
         446            1368 :   NS_ASSERTION(aIndex >= 0,"InsertElementAt(negative index)");
         447            1368 :   if (PRUint32(aIndex) > PRUint32(oldCount))
         448                 :   {
         449                 :     // An invalid index causes the insertion to fail
         450                 :     // Invalid indexes are ones that add more than one entry to the
         451                 :     // array (i.e., they can append).
         452               0 :     return false;
         453                 :   }
         454                 :
         455            1368 :   if (oldCount >= GetArraySize())
         456                 :   {
         457            1368 :     if (!GrowArrayBy(1))
         458               0 :       return false;
         459                 :   }
         460                 :   // else the array is already large enough
         461                 :
         462            1368 :   PRInt32 slide = oldCount - aIndex;
         463            1368 :   if (0 != slide)
         464                 :   {
         465                 :     // Slide data over to make room for the insertion
         466               0 :     memmove(mImpl->mArray + aIndex + 1, mImpl->mArray + aIndex,
         467               0 :             slide * sizeof(mImpl->mArray[0]));
         468                 :   }
         469                 :
         470            1368 :   mImpl->mArray[aIndex] = aElement;
         471            1368 :   mImpl->mCount++;
         472                 :
         473                 : #if DEBUG_VOIDARRAY
         474                 :   if (mImpl->mCount > mMaxCount &&
         475                 :       mImpl->mCount < (PRInt32)(sizeof(MaxElements)/sizeof(MaxElements[0])))
         476                 :   {
         477                 :     MaxElements[mImpl->mCount]++;
         478                 :     MaxElements[mMaxCount]--;
         479                 :     mMaxCount = mImpl->mCount;
         480                 :   }
         481                 : #endif
         482                 :
         483            1368 :   return true;
         484                 : }
         485                 :
         486               0 : bool nsVoidArray::InsertElementsAt(const nsVoidArray& other, PRInt32 aIndex)
         487                 : {
         488               0 :   PRInt32 oldCount = Count();
         489               0 :   PRInt32 otherCount = other.Count();
         490                 :
         491               0 :   NS_ASSERTION(aIndex >= 0,"InsertElementsAt(negative index)");
         492               0 :   if (PRUint32(aIndex) > PRUint32(oldCount))
         493                 :   {
         494                 :     // An invalid index causes the insertion to fail
         495                 :     // Invalid indexes are ones that are more than one entry past the end of
         496                 :     // the array (i.e., they can append).
         497               0 :     return false;
         498                 :   }
         499                 :
         500               0 :   if (oldCount + otherCount > GetArraySize())
         501                 :   {
         502               0 :     if (!GrowArrayBy(otherCount))
         503               0 :       return false;;
         504                 :   }
         505                 :   // else the array is already large enough
         506                 :
         507               0 :   PRInt32 slide = oldCount - aIndex;
         508               0 :   if (0 != slide)
         509                 :   {
         510                 :     // Slide data over to make room for the insertion
         511               0 :     memmove(mImpl->mArray + aIndex + otherCount, mImpl->mArray + aIndex,
         512               0 :             slide * sizeof(mImpl->mArray[0]));
         513                 :   }
         514                 :
         515               0 :   for (PRInt32 i = 0; i < otherCount; i++)
         516                 :   {
         517                 :     // copy all the elements (destroys aIndex)
         518               0 :     mImpl->mArray[aIndex++] = other.mImpl->mArray[i];
         519               0 :     mImpl->mCount++;
         520                 :   }
         521                 :
         522                 : #if DEBUG_VOIDARRAY
         523                 :   if (mImpl->mCount > mMaxCount &&
         524                 :       mImpl->mCount < (PRInt32)(sizeof(MaxElements)/sizeof(MaxElements[0])))
         525                 :   {
         526                 :     MaxElements[mImpl->mCount]++;
         527                 :     MaxElements[mMaxCount]--;
         528                 :     mMaxCount = mImpl->mCount;
         529                 :   }
         530                 : #endif
         531                 :
         532               0 :   return true;
         533                 : }
         534                 :
         535               0 : bool nsVoidArray::ReplaceElementAt(void* aElement, PRInt32 aIndex)
         536                 : {
         537               0 :   NS_ASSERTION(aIndex >= 0,"ReplaceElementAt(negative index)");
         538               0 :   if (aIndex < 0)
         539               0 :     return false;
         540                 :
         541                 :   // Unlike InsertElementAt, ReplaceElementAt can implicitly add more
         542                 :   // than just the one element to the array.
         543               0 :   if (PRUint32(aIndex) >= PRUint32(GetArraySize()))
         544                 :   {
         545               0 :     PRInt32 oldCount = Count();
         546               0 :     PRInt32 requestedCount = aIndex + 1;
         547               0 :     PRInt32 growDelta = requestedCount - oldCount;
         548                 :
         549                 :     // frees old mImpl IF this succeeds
         550               0 :     if (!GrowArrayBy(growDelta))
         551               0 :       return false;
         552                 :   }
         553                 :
         554               0 :   mImpl->mArray[aIndex] = aElement;
         555               0 :   if (aIndex >= mImpl->mCount)
         556                 :   {
         557                 :     // Make sure that any entries implicitly added to the array by this
         558                 :     // ReplaceElementAt are cleared to 0.  Some users of this assume that.
         559                 :     // This code means we don't have to memset when we allocate an array.
         560               0 :     if (aIndex > mImpl->mCount) // note: not >=
         561                 :     {
         562                 :       // For example, if mCount is 2, and we do a ReplaceElementAt for
         563                 :       // element[5], then we need to set three entries ([2], [3], and [4])
         564                 :       // to 0.
         565               0 :       memset(&mImpl->mArray[mImpl->mCount], 0,
         566               0 :              (aIndex - mImpl->mCount) * sizeof(mImpl->mArray[0]));
         567                 :     }
         568                 :
         569               0 :      mImpl->mCount = aIndex + 1;
         570                 :
         571                 : #if DEBUG_VOIDARRAY
         572                 :      if (mImpl->mCount > mMaxCount &&
         573                 :          mImpl->mCount < (PRInt32)(sizeof(MaxElements)/sizeof(MaxElements[0])))
         574                 :      {
         575                 :        MaxElements[mImpl->mCount]++;
         576                 :        MaxElements[mMaxCount]--;
         577                 :        mMaxCount = mImpl->mCount;
         578                 :      }
         579                 : #endif
         580                 :   }
         581                 :
         582               0 :   return true;
         583                 : }
         584                 :
         585                 : // useful for doing LRU arrays
         586               0 : bool nsVoidArray::MoveElement(PRInt32 aFrom, PRInt32 aTo)
         587                 : {
         588                 :   void *tempElement;
         589                 :
         590               0 :   if (aTo == aFrom)
         591               0 :     return true;
         592                 :
         593               0 :   NS_ASSERTION(aTo >= 0 && aFrom >= 0,"MoveElement(negative index)");
         594               0 :   if (aTo >= Count() || aFrom >= Count())
         595                 :   {
         596                 :     // can't extend the array when moving an element.  Also catches mImpl = null
         597               0 :     return false;
         598                 :   }
         599               0 :   tempElement = mImpl->mArray[aFrom];
         600                 :
         601               0 :   if (aTo < aFrom)
         602                 :   {
         603                 :     // Moving one element closer to the head; the elements inbetween move down
         604               0 :     memmove(mImpl->mArray + aTo + 1, mImpl->mArray + aTo,
         605               0 :             (aFrom-aTo) * sizeof(mImpl->mArray[0]));
         606               0 :     mImpl->mArray[aTo] = tempElement;
         607                 :   }
         608                 :   else // already handled aFrom == aTo
         609                 :   {
         610                 :     // Moving one element closer to the tail; the elements inbetween move up
         611               0 :     memmove(mImpl->mArray + aFrom, mImpl->mArray + aFrom + 1,
         612               0 :             (aTo-aFrom) * sizeof(mImpl->mArray[0]));
         613               0 :     mImpl->mArray[aTo] = tempElement;
         614                 :   }
         615                 :
         616               0 :   return true;
         617                 : }
         618                 :
         619               0 : bool nsVoidArray::RemoveElementsAt(PRInt32 aIndex, PRInt32 aCount)
         620                 : {
         621               0 :   PRInt32 oldCount = Count();
         622               0 :   NS_ASSERTION(aIndex >= 0,"RemoveElementsAt(negative index)");
         623               0 :   if (PRUint32(aIndex) >= PRUint32(oldCount))
         624                 :   {
         625                 :     // An invalid index causes the replace to fail
         626               0 :     return false;
         627                 :   }
         628                 :   // Limit to available entries starting at aIndex
         629               0 :   if (aCount + aIndex > oldCount)
         630               0 :     aCount = oldCount - aIndex;
         631                 :
         632                 :   // We don't need to move any elements if we're removing the
         633                 :   // last element in the array
         634               0 :   if (aIndex < (oldCount - aCount))
         635                 :   {
         636               0 :     memmove(mImpl->mArray + aIndex, mImpl->mArray + aIndex + aCount,
         637               0 :             (oldCount - (aIndex + aCount)) * sizeof(mImpl->mArray[0]));
         638                 :   }
         639                 :
         640               0 :   mImpl->mCount -= aCount;
         641               0 :   return true;
         642                 : }
         643                 :
         644               0 : bool nsVoidArray::RemoveElement(void* aElement)
         645                 : {
         646               0 :   PRInt32 theIndex = IndexOf(aElement);
         647               0 :   if (theIndex != -1)
         648               0 :     return RemoveElementAt(theIndex);
         649                 :
         650               0 :   return false;
         651                 : }
         652                 :
         653            1368 : void nsVoidArray::Clear()
         654                 : {
         655            1368 :   if (mImpl)
         656                 :   {
         657            1368 :     mImpl->mCount = 0;
         658                 :     // We don't have to free on Clear, but if we have a built-in buffer,
         659                 :     // it's worth considering.
         660            1368 :     if (HasAutoBuffer() && IsArrayOwner() &&
         661               0 :         GetArraySize() > kAutoClearCompactSizeFactor * kAutoBufSize) {
         662               0 :       SizeTo(0);
         663                 :     }
         664                 :   }
         665            1368 : }
         666                 :
         667               0 : void nsVoidArray::Compact()
         668                 : {
         669               0 :   if (mImpl)
         670                 :   {
         671                 :     // XXX NOTE: this is quite inefficient in many cases if we're only
         672                 :     // compacting by a little, but some callers care more about memory use.
         673               0 :     PRInt32 count = Count();
         674               0 :     if (HasAutoBuffer() && count <= kAutoBufSize)
         675                 :     {
         676               0 :       Impl* oldImpl = mImpl;
         677               0 :       static_cast<nsAutoVoidArray*>(this)->ResetToAutoBuffer();
         678                 :       memcpy(mImpl->mArray, oldImpl->mArray,
         679               0 :              count * sizeof(mImpl->mArray[0]));
         680               0 :       free(reinterpret_cast<char *>(oldImpl));
         681                 :     }
         682               0 :     else if (GetArraySize() > count)
         683                 :     {
         684               0 :       SizeTo(Count());
         685                 :     }
         686                 :   }
         687               0 : }
         688                 :
         689                 : // Needed because we want to pass the pointer to the item in the array
         690                 : // to the comparator function, not a pointer to the pointer in the array.
         691                 : struct VoidArrayComparatorContext {
         692                 :   nsVoidArrayComparatorFunc mComparatorFunc;
         693                 :   void* mData;
         694                 : };
         695                 :
         696                 : static int
         697               0 : VoidArrayComparator(const void* aElement1, const void* aElement2, void* aData)
         698                 : {
         699               0 :   VoidArrayComparatorContext* ctx = static_cast<VoidArrayComparatorContext*>(aData);
         700                 :   return (*ctx->mComparatorFunc)(*static_cast<void* const*>(aElement1),
         701                 :                                  *static_cast<void* const*>(aElement2),
         702               0 :                                   ctx->mData);
         703                 : }
         704                 :
         705               0 : void nsVoidArray::Sort(nsVoidArrayComparatorFunc aFunc, void* aData)
         706                 : {
         707               0 :   if (mImpl && mImpl->mCount > 1)
         708                 :   {
         709               0 :     VoidArrayComparatorContext ctx = {aFunc, aData};
         710                 :     NS_QuickSort(mImpl->mArray, mImpl->mCount, sizeof(mImpl->mArray[0]),
         711               0 :                  VoidArrayComparator, &ctx);
         712                 :   }
         713               0 : }
         714                 :
         715            1368 : bool nsVoidArray::EnumerateForwards(nsVoidArrayEnumFunc aFunc, void* aData)
         716                 : {
         717            1368 :   PRInt32 index = -1;
         718            1368 :   bool    running = true;
         719                 :
         720            1368 :   if (mImpl) {
         721            4104 :     while (running && (++index < mImpl->mCount)) {
         722            1368 :       running = (*aFunc)(mImpl->mArray[index], aData);
         723                 :     }
         724                 :   }
         725            1368 :   return running;
         726                 : }
         727                 :
         728               0 : bool nsVoidArray::EnumerateForwards(nsVoidArrayEnumFuncConst aFunc,
         729                 :                                     void* aData) const
         730                 : {
         731               0 :   PRInt32 index = -1;
         732               0 :   bool    running = true;
         733                 :
         734               0 :   if (mImpl) {
         735               0 :     while (running && (++index < mImpl->mCount)) {
         736               0 :       running = (*aFunc)(mImpl->mArray[index], aData);
         737                 :     }
         738                 :   }
         739               0 :   return running;
         740                 : }
         741                 :
         742               0 : bool nsVoidArray::EnumerateBackwards(nsVoidArrayEnumFunc aFunc, void* aData)
         743                 : {
         744               0 :   bool    running = true;
         745                 :
         746               0 :   if (mImpl)
         747                 :   {
         748               0 :     PRInt32 index = Count();
         749               0 :     while (running && (0 <= --index))
         750                 :     {
         751               0 :       running = (*aFunc)(mImpl->mArray[index], aData);
         752                 :     }
         753                 :   }
         754               0 :   return running;
         755                 : }
         756                 :
         757                 : struct SizeOfElementIncludingThisData
         758                 : {
         759                 :   size_t mSize;
         760                 :   nsVoidArraySizeOfElementIncludingThisFunc mSizeOfElementIncludingThis;
         761                 :   nsMallocSizeOfFun mMallocSizeOf;
         762                 :   void *mData;      // the arg passed by the user
         763                 : };
         764                 :
         765                 : static bool
         766               0 : SizeOfElementIncludingThisEnumerator(const void *aElement, void *aData)
         767                 : {
         768               0 :   SizeOfElementIncludingThisData *d = (SizeOfElementIncludingThisData *)aData;
         769               0 :   d->mSize += d->mSizeOfElementIncludingThis(aElement, d->mMallocSizeOf, d->mData);
         770               0 :   return true;
         771                 : }
         772                 :
         773                 : size_t
         774               0 : nsVoidArray::SizeOfExcludingThis(
         775                 :   nsVoidArraySizeOfElementIncludingThisFunc aSizeOfElementIncludingThis,
         776                 :   nsMallocSizeOfFun aMallocSizeOf, void* aData) const
         777                 : {
         778               0 :   size_t n = 0;
         779                 :   // Measure the element storage.
         780               0 :   if (mImpl) {
         781               0 :     n += aMallocSizeOf(mImpl);
         782                 :   }
         783                 :   // Measure things pointed to by the elements.
         784               0 :   if (aSizeOfElementIncludingThis) {
         785                 :     SizeOfElementIncludingThisData data2 =
         786               0 :       { 0, aSizeOfElementIncludingThis, aMallocSizeOf, aData };
         787               0 :     EnumerateForwards(SizeOfElementIncludingThisEnumerator, &data2);
         788               0 :     n += data2.mSize;
         789                 :   }
         790               0 :   return n;
         791                 : }
         792                 :
         793                 : //----------------------------------------------------------------
         794                 : // nsAutoVoidArray
         795                 :
         796            1368 : nsAutoVoidArray::nsAutoVoidArray()
         797            1368 :   : nsVoidArray()
         798                 : {
         799                 :   // Don't need to clear it.  Some users just call ReplaceElementAt(),
         800                 :   // but we'll clear it at that time if needed to save CPU cycles.
         801                 : #if DEBUG_VOIDARRAY
         802                 :   mIsAuto = true;
         803                 :   ADD_TO_STATS(MaxAuto,0);
         804                 : #endif
         805            1368 :   ResetToAutoBuffer();
         806            1368 : }
         807                 :
         808                 : //----------------------------------------------------------------------
         809                 : // NOTE: nsSmallVoidArray elements MUST all have the low bit as 0.
         810                 : // This means that normally it's only used for pointers, and in particular
         811                 : // structures or objects.
         812               0 : nsSmallVoidArray::~nsSmallVoidArray()
         813                 : {
         814               0 :   if (HasSingle())
         815                 :   {
         816                 :     // Have to null out mImpl before the nsVoidArray dtor runs.
         817               0 :     mImpl = nsnull;
         818                 :   }
         819               0 : }
         820                 :
         821                 : nsSmallVoidArray&
         822               0 : nsSmallVoidArray::operator=(nsSmallVoidArray& other)
         823                 : {
         824               0 :   PRInt32 count = other.Count();
         825               0 :   switch (count) {
         826                 :     case 0:
         827               0 :       Clear();
         828               0 :       break;
         829                 :     case 1:
         830               0 :       Clear();
         831               0 :       AppendElement(other.ElementAt(0));
         832               0 :       break;
         833                 :     default:
         834               0 :       if (GetArraySize() >= count || SizeTo(count)) {
         835               0 :         *AsArray() = *other.AsArray();
         836                 :       }
         837                 :   }
         838                 :
         839               0 :   return *this;
         840                 : }
         841                 :
         842                 : PRInt32
         843               0 : nsSmallVoidArray::GetArraySize() const
         844                 : {
         845               0 :   if (HasSingle()) {
         846               0 :     return 1;
         847                 :   }
         848                 :
         849               0 :   return AsArray()->GetArraySize();
         850                 : }
         851                 :
         852                 : PRInt32
         853               0 : nsSmallVoidArray::Count() const
         854                 : {
         855               0 :   if (HasSingle()) {
         856               0 :     return 1;
         857                 :   }
         858                 :
         859               0 :   return AsArray()->Count();
         860                 : }
         861                 :
         862                 : void*
         863               0 : nsSmallVoidArray::FastElementAt(PRInt32 aIndex) const
         864                 : {
         865               0 :   NS_ASSERTION(0 <= aIndex && aIndex < Count(), "nsSmallVoidArray::FastElementAt: index out of range");
         866                 :
         867               0 :   if (HasSingle()) {
         868               0 :     return GetSingle();
         869                 :   }
         870                 :
         871               0 :   return AsArray()->FastElementAt(aIndex);
         872                 : }
         873                 :
         874                 : PRInt32
         875               0 : nsSmallVoidArray::IndexOf(void* aPossibleElement) const
         876                 : {
         877               0 :   if (HasSingle()) {
         878               0 :     return aPossibleElement == GetSingle() ? 0 : -1;
         879                 :   }
         880                 :
         881               0 :   return AsArray()->IndexOf(aPossibleElement);
         882                 : }
         883                 :
         884                 : bool
         885               0 : nsSmallVoidArray::InsertElementAt(void* aElement, PRInt32 aIndex)
         886                 : {
         887               0 :   NS_ASSERTION(!(NS_PTR_TO_INT32(aElement) & 0x1),
         888                 :                "Attempt to add element with 0x1 bit set to nsSmallVoidArray");
         889                 :
         890               0 :   if (aIndex == 0 && IsEmpty()) {
         891               0 :     SetSingle(aElement);
         892                 :
         893               0 :     return true;
         894                 :   }
         895                 :
         896               0 :   if (!EnsureArray()) {
         897               0 :     return false;
         898                 :   }
         899                 :
         900               0 :   return AsArray()->InsertElementAt(aElement, aIndex);
         901                 : }
         902                 :
         903               0 : bool nsSmallVoidArray::InsertElementsAt(const nsVoidArray &aOther, PRInt32 aIndex)
         904                 : {
         905                 : #ifdef DEBUG
         906               0 :   for (int i = 0; i < aOther.Count(); i++) {
         907               0 :     NS_ASSERTION(!(NS_PTR_TO_INT32(aOther.ElementAt(i)) & 0x1),
         908                 :                  "Attempt to add element with 0x1 bit set to nsSmallVoidArray");
         909                 :   }
         910                 : #endif
         911                 :
         912               0 :   if (aIndex == 0 && IsEmpty() && aOther.Count() == 1) {
         913               0 :     SetSingle(aOther.FastElementAt(0));
         914                 :
         915               0 :     return true;
         916                 :   }
         917                 :
         918               0 :   if (!EnsureArray()) {
         919               0 :     return false;
         920                 :   }
         921                 :
         922               0 :   return AsArray()->InsertElementsAt(aOther, aIndex);
         923                 : }
         924                 :
         925                 : bool
         926               0 : nsSmallVoidArray::ReplaceElementAt(void* aElement, PRInt32 aIndex)
         927                 : {
         928               0 :   NS_ASSERTION(!(NS_PTR_TO_INT32(aElement) & 0x1),
         929                 :                "Attempt to add element with 0x1 bit set to nsSmallVoidArray");
         930                 :
         931               0 :   if (aIndex == 0 && (IsEmpty() || HasSingle())) {
         932               0 :     SetSingle(aElement);
         933                 :
         934               0 :     return true;
         935                 :   }
         936                 :
         937               0 :   if (!EnsureArray()) {
         938               0 :     return false;
         939                 :   }
         940                 :
         941               0 :   return AsArray()->ReplaceElementAt(aElement, aIndex);
         942                 : }
         943                 :
         944                 : bool
         945               0 : nsSmallVoidArray::AppendElement(void* aElement)
         946                 : {
         947               0 :   NS_ASSERTION(!(NS_PTR_TO_INT32(aElement) & 0x1),
         948                 :                "Attempt to add element with 0x1 bit set to nsSmallVoidArray");
         949                 :
         950               0 :   if (IsEmpty()) {
         951               0 :     SetSingle(aElement);
         952                 :
         953               0 :     return true;
         954                 :   }
         955                 :
         956               0 :   if (!EnsureArray()) {
         957               0 :     return false;
         958                 :   }
         959                 :
         960               0 :   return AsArray()->AppendElement(aElement);
         961                 : }
         962                 :
         963                 : bool
         964               0 : nsSmallVoidArray::RemoveElement(void* aElement)
         965                 : {
         966               0 :   if (HasSingle()) {
         967               0 :     if (aElement == GetSingle()) {
         968               0 :       mImpl = nsnull;
         969               0 :       return true;
         970                 :     }
         971                 :
         972               0 :     return false;
         973                 :   }
         974                 :
         975               0 :   return AsArray()->RemoveElement(aElement);
         976                 : }
         977                 :
         978                 : bool
         979               0 : nsSmallVoidArray::RemoveElementAt(PRInt32 aIndex)
         980                 : {
         981               0 :   if (HasSingle()) {
         982               0 :     if (aIndex == 0) {
         983               0 :       mImpl = nsnull;
         984                 :
         985               0 :       return true;
         986                 :     }
         987                 :
         988               0 :     return false;
         989                 :   }
         990                 :
         991               0 :   return AsArray()->RemoveElementAt(aIndex);
         992                 : }
         993                 :
         994                 : bool
         995               0 : nsSmallVoidArray::RemoveElementsAt(PRInt32 aIndex, PRInt32 aCount)
         996                 : {
         997               0 :   if (HasSingle()) {
         998               0 :     if (aIndex == 0) {
         999               0 :       if (aCount > 0) {
        1000               0 :         mImpl = nsnull;
        1001                 :       }
        1002                 :
        1003               0 :       return true;
        1004                 :     }
        1005                 :
        1006               0 :     return false;
        1007                 :   }
        1008                 :
        1009               0 :   return AsArray()->RemoveElementsAt(aIndex, aCount);
        1010                 : }
        1011                 :
        1012                 : void
        1013               0 : nsSmallVoidArray::Clear()
        1014                 : {
        1015               0 :   if (HasSingle()) {
        1016               0 :     mImpl = nsnull;
        1017                 :   }
        1018                 :   else {
        1019               0 :     AsArray()->Clear();
        1020                 :   }
        1021               0 : }
        1022                 :
        1023                 : bool
        1024               0 : nsSmallVoidArray::SizeTo(PRInt32 aMin)
        1025                 : {
        1026               0 :   if (!HasSingle()) {
        1027               0 :     return AsArray()->SizeTo(aMin);
        1028                 :   }
        1029                 :
        1030               0 :   if (aMin <= 0) {
        1031               0 :     mImpl = nsnull;
        1032                 :
        1033               0 :     return true;
        1034                 :   }
        1035                 :
        1036               0 :   if (aMin == 1) {
        1037               0 :     return true;
        1038                 :   }
        1039                 :
        1040               0 :   void* single = GetSingle();
        1041               0 :   mImpl = nsnull;
        1042               0 :   if (!AsArray()->SizeTo(aMin)) {
        1043               0 :     SetSingle(single);
        1044                 :
        1045               0 :     return false;
        1046                 :   }
        1047                 :
        1048               0 :   AsArray()->AppendElement(single);
        1049                 :
        1050               0 :   return true;
        1051                 : }
        1052                 :
        1053                 : void
        1054               0 : nsSmallVoidArray::Compact()
        1055                 : {
        1056               0 :   if (!HasSingle()) {
        1057               0 :     AsArray()->Compact();
        1058                 :   }
        1059               0 : }
        1060                 :
        1061                 : void
        1062               0 : nsSmallVoidArray::Sort(nsVoidArrayComparatorFunc aFunc, void* aData)
        1063                 : {
        1064               0 :   if (!HasSingle()) {
        1065               0 :     AsArray()->Sort(aFunc,aData);
        1066                 :   }
        1067               0 : }
        1068                 :
        1069                 : bool
        1070               0 : nsSmallVoidArray::EnumerateForwards(nsVoidArrayEnumFunc aFunc, void* aData)
        1071                 : {
        1072               0 :   if (HasSingle()) {
        1073               0 :     return (*aFunc)(GetSingle(), aData);
        1074                 :   }
        1075               0 :   return AsArray()->EnumerateForwards(aFunc,aData);
        1076                 : }
        1077                 :
        1078                 : bool
        1079               0 : nsSmallVoidArray::EnumerateBackwards(nsVoidArrayEnumFunc aFunc, void* aData)
        1080                 : {
        1081               0 :   if (HasSingle()) {
        1082               0 :     return (*aFunc)(GetSingle(), aData);
        1083                 :   }
        1084               0 :   return AsArray()->EnumerateBackwards(aFunc,aData);
        1085                 : }
        1086                 :
        1087                 : bool
        1088               0 : nsSmallVoidArray::EnsureArray()
        1089                 : {
        1090               0 :   if (!HasSingle()) {
        1091               0 :     return true;
        1092                 :   }
        1093                 :
        1094               0 :   void* single = GetSingle();
        1095               0 :   mImpl = nsnull;
        1096               0 :   if (!AsArray()->AppendElement(single)) {
        1097               0 :     SetSingle(single);
        1098                 :
        1099               0 :     return false;
        1100                 :   }
        1101                 :
        1102               0 :   return true;
        1103                 : }

Generated by: LCOV version 1.7