LCOV - code coverage report
Current view: directory - xpcom/glue - nsVoidArray.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 386 140 36.3 %
Date: 2012-06-02 Functions: 45 16 35.6 %

       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            2806 : 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            2806 :   NS_PRECONDITION(newImpl, "can't set size");
     147            2806 :   mImpl = newImpl;
     148            2806 :   mImpl->mCount = aCount;
     149                 :   mImpl->mBits = static_cast<PRUint32>(aSize & kArraySizeMask) |
     150                 :                  (aOwner ? kArrayOwnerMask : 0) |
     151            2806 :                  (aHasAuto ? kArrayHasAutoBufferMask : 0);
     152            2806 : }
     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            1409 : bool nsVoidArray::SizeTo(PRInt32 aSize)
     158                 : {
     159            1409 :   PRUint32 oldsize = GetArraySize();
     160            1409 :   bool isOwner = IsArrayOwner();
     161            1409 :   bool hasAuto = HasAutoBuffer();
     162                 : 
     163            1409 :   if (aSize == (PRInt32) oldsize)
     164               0 :     return true; // no change
     165                 : 
     166            1409 :   if (aSize <= 0)
     167                 :   {
     168                 :     // free the array if allocated
     169               1 :     if (mImpl)
     170                 :     {
     171               1 :       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               1 :         mImpl->mCount = 0; // nsAutoVoidArray
     184                 :       }
     185                 :     }
     186               1 :     return true;
     187                 :   }
     188                 : 
     189            1408 :   if (mImpl && isOwner)
     190                 :   {
     191                 :     // We currently own an array impl. Resize it appropriately.
     192               7 :     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               7 :     char* bytes = (char *) realloc(mImpl,SIZEOF_IMPL(aSize));
     199               7 :     Impl* newImpl = reinterpret_cast<Impl*>(bytes);
     200               7 :     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               7 :     SetArray(newImpl, aSize, newImpl->mCount, true, hasAuto);
     221               7 :     return true;
     222                 :   }
     223                 : 
     224            1401 :   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            1401 :   char* bytes = (char *) malloc(SIZEOF_IMPL(aSize));
     232            1401 :   Impl* newImpl = reinterpret_cast<Impl*>(bytes);
     233            1401 :   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            1401 :   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               5 :                   mImpl->mCount * sizeof(mImpl->mArray[0]));
     258                 :   }
     259                 : 
     260            1401 :   SetArray(newImpl, aSize, mImpl ? mImpl->mCount : 0, true, hasAuto);
     261                 :   // no memset; handled later in ReplaceElementAt if needed
     262            1401 :   return true;
     263                 : }
     264                 : 
     265            1406 : 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            1406 :   if (aGrowBy < kMinGrowArrayBy)
     272            1401 :     aGrowBy = kMinGrowArrayBy;
     273                 : 
     274            1406 :   PRUint32 newCapacity = GetArraySize() + aGrowBy;  // Minimum increase
     275            1406 :   PRUint32 newSize = SIZEOF_IMPL(newCapacity);
     276                 : 
     277            1406 :   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               4 :     if (GetArraySize() >= kMaxGrowArrayBy)
     284                 :     {
     285               0 :       newCapacity = GetArraySize() + NS_MAX(kMaxGrowArrayBy,aGrowBy);
     286               0 :       newSize = SIZEOF_IMPL(newCapacity);
     287                 :     }
     288                 :     else
     289                 :     {
     290               4 :       PR_CEILING_LOG2(newSize, newSize);
     291               4 :       newCapacity = CAPACITYOF_IMPL(PR_BIT(newSize));
     292                 :     }
     293                 :   }
     294                 :   // frees old mImpl IF this succeeds
     295            1406 :   if (!SizeTo(newCapacity))
     296               0 :     return false;
     297                 : 
     298            1406 :   return true;
     299                 : }
     300                 : 
     301            2792 : nsVoidArray::nsVoidArray()
     302            2792 :   : mImpl(nsnull)
     303                 : {
     304            2792 :   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            2792 : }
     313                 : 
     314               2 : nsVoidArray::nsVoidArray(PRInt32 aCount)
     315               2 :   : mImpl(nsnull)
     316                 : {
     317               2 :   MOZ_COUNT_CTOR(nsVoidArray);
     318                 : #if DEBUG_VOIDARRAY
     319                 :   mMaxCount = 0;
     320                 :   mMaxSize = 0;
     321                 :   mIsAuto = false;
     322                 :   MaxElements[0]++;
     323                 : #endif
     324               2 :   SizeTo(aCount);
     325               2 : }
     326                 : 
     327            1395 : nsVoidArray& nsVoidArray::operator=(const nsVoidArray& other)
     328                 : {
     329            1395 :   PRInt32 otherCount = other.Count();
     330            1395 :   PRInt32 maxCount = GetArraySize();
     331            1395 :   if (otherCount)
     332                 :   {
     333            1394 :     if (otherCount > maxCount)
     334                 :     {
     335                 :       // frees old mImpl IF this succeeds
     336               3 :       if (!GrowArrayBy(otherCount-maxCount))
     337               0 :         return *this;      // XXX The allocation failed - don't do anything
     338                 : 
     339               3 :       memcpy(mImpl->mArray, other.mImpl->mArray, otherCount * sizeof(mImpl->mArray[0]));
     340               3 :       mImpl->mCount = otherCount;
     341                 :     }
     342                 :     else
     343                 :     {
     344                 :       // the old array can hold the new array
     345            1391 :       memcpy(mImpl->mArray, other.mImpl->mArray, otherCount * sizeof(mImpl->mArray[0]));
     346            1391 :       mImpl->mCount = otherCount;
     347                 :       // if it shrank a lot, compact it anyways
     348            1391 :       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               1 :     SizeTo(0);
     367                 :   }
     368                 : 
     369            1395 :   return *this;
     370                 : }
     371                 : 
     372            2794 : nsVoidArray::~nsVoidArray()
     373                 : {
     374            2794 :   MOZ_COUNT_DTOR(nsVoidArray);
     375            2794 :   if (mImpl && IsArrayOwner())
     376            1401 :     free(reinterpret_cast<char*>(mImpl));
     377            2794 : }
     378                 : 
     379               5 : bool nsVoidArray::SetCount(PRInt32 aNewCount)
     380                 : {
     381               5 :   NS_ASSERTION(aNewCount >= 0,"SetCount(negative index)");
     382               5 :   if (aNewCount < 0)
     383               0 :     return false;
     384                 : 
     385               5 :   if (aNewCount == 0)
     386                 :   {
     387               0 :     Clear();
     388               0 :     return true;
     389                 :   }
     390                 : 
     391               5 :   if (PRUint32(aNewCount) > PRUint32(GetArraySize()))
     392                 :   {
     393               2 :     PRInt32 oldCount = Count();
     394               2 :     PRInt32 growDelta = aNewCount - oldCount;
     395                 : 
     396                 :     // frees old mImpl IF this succeeds
     397               2 :     if (!GrowArrayBy(growDelta))
     398               0 :       return false;
     399                 :   }
     400                 : 
     401               5 :   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               3 :     memset(&mImpl->mArray[mImpl->mCount], 0,
     407               6 :            (aNewCount - mImpl->mCount) * sizeof(mImpl->mArray[0]));
     408                 :   }
     409                 : 
     410               5 :   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               5 :   return true;
     423                 : }
     424                 : 
     425              41 : PRInt32 nsVoidArray::IndexOf(void* aPossibleElement) const
     426                 : {
     427              41 :   if (mImpl)
     428                 :   {
     429              41 :     void** ap = mImpl->mArray;
     430              41 :     void** end = ap + mImpl->mCount;
     431             226 :     while (ap < end)
     432                 :     {
     433             145 :       if (*ap == aPossibleElement)
     434                 :       {
     435               1 :         return ap - mImpl->mArray;
     436                 :       }
     437             144 :       ap++;
     438                 :     }
     439                 :   }
     440              40 :   return -1;
     441                 : }
     442                 : 
     443            1470 : bool nsVoidArray::InsertElementAt(void* aElement, PRInt32 aIndex)
     444                 : {
     445            1470 :   PRInt32 oldCount = Count();
     446            1470 :   NS_ASSERTION(aIndex >= 0,"InsertElementAt(negative index)");
     447            1470 :   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            1470 :   if (oldCount >= GetArraySize())
     456                 :   {
     457            1401 :     if (!GrowArrayBy(1))
     458               0 :       return false;
     459                 :   }
     460                 :   // else the array is already large enough
     461                 : 
     462            1470 :   PRInt32 slide = oldCount - aIndex;
     463            1470 :   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            1470 :   mImpl->mArray[aIndex] = aElement;
     471            1470 :   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            1470 :   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              20 : bool nsVoidArray::ReplaceElementAt(void* aElement, PRInt32 aIndex)
     536                 : {
     537              20 :   NS_ASSERTION(aIndex >= 0,"ReplaceElementAt(negative index)");
     538              20 :   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              20 :   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              20 :   mImpl->mArray[aIndex] = aElement;
     555              20 :   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              20 :   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               4 : bool nsVoidArray::RemoveElementsAt(PRInt32 aIndex, PRInt32 aCount)
     620                 : {
     621               4 :   PRInt32 oldCount = Count();
     622               4 :   NS_ASSERTION(aIndex >= 0,"RemoveElementsAt(negative index)");
     623               4 :   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               4 :   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               4 :   if (aIndex < (oldCount - aCount))
     635                 :   {
     636               2 :     memmove(mImpl->mArray + aIndex, mImpl->mArray + aIndex + aCount,
     637               3 :             (oldCount - (aIndex + aCount)) * sizeof(mImpl->mArray[0]));
     638                 :   }
     639                 : 
     640               4 :   mImpl->mCount -= aCount;
     641               4 :   return true;
     642                 : }
     643                 : 
     644              41 : bool nsVoidArray::RemoveElement(void* aElement)
     645                 : {
     646              41 :   PRInt32 theIndex = IndexOf(aElement);
     647              41 :   if (theIndex != -1)
     648               1 :     return RemoveElementAt(theIndex);
     649                 : 
     650              40 :   return false;
     651                 : }
     652                 : 
     653            1395 : void nsVoidArray::Clear()
     654                 : {
     655            1395 :   if (mImpl)
     656                 :   {
     657            1395 :     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            1395 :     if (HasAutoBuffer() && IsArrayOwner() &&
     661               0 :         GetArraySize() > kAutoClearCompactSizeFactor * kAutoBufSize) {
     662               0 :       SizeTo(0);
     663                 :     }
     664                 :   }
     665            1395 : }
     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            1398 : bool nsVoidArray::EnumerateForwards(nsVoidArrayEnumFunc aFunc, void* aData)
     716                 : {
     717            1398 :   PRInt32 index = -1;
     718            1398 :   bool    running = true;
     719                 : 
     720            1398 :   if (mImpl) {
     721            4276 :     while (running && (++index < mImpl->mCount)) {
     722            1480 :       running = (*aFunc)(mImpl->mArray[index], aData);
     723                 :     }
     724                 :   }
     725            1398 :   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            1398 : nsAutoVoidArray::nsAutoVoidArray()
     797            1398 :   : 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            1398 :   ResetToAutoBuffer();
     806            1398 : }
     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