xpcom/glue/nsTArray.h

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

     1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     2 /* vim:set ts=2 sw=2 sts=2 et cindent: */
     3 /* This Source Code Form is subject to the terms of the Mozilla Public
     4  * License, v. 2.0. If a copy of the MPL was not distributed with this
     5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     7 #ifndef nsTArray_h__
     8 #define nsTArray_h__
    10 #include "nsTArrayForwardDeclare.h"
    11 #include "mozilla/Alignment.h"
    12 #include "mozilla/Assertions.h"
    13 #include "mozilla/MemoryReporting.h"
    14 #include "mozilla/TypeTraits.h"
    16 #include <string.h>
    18 #include "nsCycleCollectionNoteChild.h"
    19 #include "nsAlgorithm.h"
    20 #include "nscore.h"
    21 #include "nsQuickSort.h"
    22 #include "nsDebug.h"
    23 #include "nsISupportsImpl.h"
    24 #include <new>
    26 namespace JS {
    27 template <class T>
    28 class Heap;
    29 } /* namespace JS */
    31 class nsRegion;
    32 class nsIntRegion;
    34 //
    35 // nsTArray is a resizable array class, like std::vector.
    36 //
    37 // Unlike std::vector, which follows C++'s construction/destruction rules,
    38 // nsTArray assumes that your "T" can be memmoved()'ed safely.
    39 //
    40 // The public classes defined in this header are
    41 //
    42 //   nsTArray<T>,
    43 //   FallibleTArray<T>,
    44 //   nsAutoTArray<T, N>, and
    45 //   AutoFallibleTArray<T, N>.
    46 //
    47 // nsTArray and nsAutoTArray are infallible; if one tries to make an allocation
    48 // which fails, it crashes the program.  In contrast, FallibleTArray and
    49 // AutoFallibleTArray are fallible; if you use one of these classes, you must
    50 // check the return values of methods such as Append() which may allocate.  If
    51 // in doubt, choose an infallible type.
    52 //
    53 // InfallibleTArray and AutoInfallibleTArray are aliases for nsTArray and
    54 // nsAutoTArray.
    55 //
    56 // If you just want to declare the nsTArray types (e.g., if you're in a header
    57 // file and don't need the full nsTArray definitions) consider including
    58 // nsTArrayForwardDeclare.h instead of nsTArray.h.
    59 //
    60 // The template parameter (i.e., T in nsTArray<T>) specifies the type of the
    61 // elements and has the following requirements:
    62 //
    63 //   T MUST be safely memmove()'able.
    64 //   T MUST define a copy-constructor.
    65 //   T MAY define operator< for sorting.
    66 //   T MAY define operator== for searching.
    67 //
    68 // (Note that the memmove requirement may be relaxed for certain types - see
    69 // nsTArray_CopyChooser below.)
    70 //
    71 // For methods taking a Comparator instance, the Comparator must be a class
    72 // defining the following methods:
    73 //
    74 //   class Comparator {
    75 //     public:
    76 //       /** @return True if the elements are equals; false otherwise. */
    77 //       bool Equals(const elem_type& a, const Item& b) const;
    78 //
    79 //       /** @return True if (a < b); false otherwise. */
    80 //       bool LessThan(const elem_type& a, const Item& b) const;
    81 //   };
    82 //
    83 // The Equals method is used for searching, and the LessThan method is used for
    84 // searching and sorting.  The |Item| type above can be arbitrary, but must
    85 // match the Item type passed to the sort or search function.
    86 //
    89 //
    90 // nsTArrayFallibleResult and nsTArrayInfallibleResult types are proxy types
    91 // which are used because you cannot use a templated type which is bound to
    92 // void as an argument to a void function.  In order to work around that, we
    93 // encode either a void or a boolean inside these proxy objects, and pass them
    94 // to the aforementioned function instead, and then use the type information to
    95 // decide what to do in the function.
    96 //
    97 // Note that public nsTArray methods should never return a proxy type.  Such
    98 // types are only meant to be used in the internal nsTArray helper methods.
    99 // Public methods returning non-proxy types cannot be called from other
   100 // nsTArray members.
   101 //
   102 struct nsTArrayFallibleResult
   103 {
   104   // Note: allows implicit conversions from and to bool
   105   nsTArrayFallibleResult(bool result)
   106     : mResult(result)
   107   {}
   109   operator bool() {
   110     return mResult;
   111   }
   113 private:
   114   bool mResult;
   115 };
   117 struct nsTArrayInfallibleResult
   118 {
   119 };
   121 //
   122 // nsTArray*Allocators must all use the same |free()|, to allow swap()'ing
   123 // between fallible and infallible variants.
   124 //
   126 struct nsTArrayFallibleAllocatorBase
   127 {
   128   typedef bool ResultType;
   129   typedef nsTArrayFallibleResult ResultTypeProxy;
   131   static ResultType Result(ResultTypeProxy result) {
   132     return result;
   133   }
   135   static bool Successful(ResultTypeProxy result) {
   136     return result;
   137   }
   139   static ResultTypeProxy SuccessResult() {
   140     return true;
   141   }
   143   static ResultTypeProxy FailureResult() {
   144     return false;
   145   }
   147   static ResultType ConvertBoolToResultType(bool aValue) {
   148     return aValue;
   149   }
   150 };
   152 struct nsTArrayInfallibleAllocatorBase
   153 {
   154   typedef void ResultType;
   155   typedef nsTArrayInfallibleResult ResultTypeProxy;
   157   static ResultType Result(ResultTypeProxy result) {
   158   }
   160   static bool Successful(ResultTypeProxy) {
   161     return true;
   162   }
   164   static ResultTypeProxy SuccessResult() {
   165     return ResultTypeProxy();
   166   }
   168   static ResultTypeProxy FailureResult() {
   169     NS_RUNTIMEABORT("Infallible nsTArray should never fail");
   170     return ResultTypeProxy();
   171   }
   173   static ResultType ConvertBoolToResultType(bool aValue) {
   174     if (!aValue) {
   175       NS_RUNTIMEABORT("infallible nsTArray should never convert false to ResultType");
   176     }
   177   }
   178 };
   180 #if defined(MOZALLOC_HAVE_XMALLOC)
   181 #include "mozilla/mozalloc_abort.h"
   183 struct nsTArrayFallibleAllocator : nsTArrayFallibleAllocatorBase
   184 {
   185   static void* Malloc(size_t size) {
   186     return moz_malloc(size);
   187   }
   189   static void* Realloc(void* ptr, size_t size) {
   190     return moz_realloc(ptr, size);
   191   }
   193   static void Free(void* ptr) {
   194     moz_free(ptr);
   195   }
   197   static void SizeTooBig(size_t) {
   198   }
   199 };
   201 struct nsTArrayInfallibleAllocator : nsTArrayInfallibleAllocatorBase
   202 {
   203   static void* Malloc(size_t size) {
   204     return moz_xmalloc(size);
   205   }
   207   static void* Realloc(void* ptr, size_t size) {
   208     return moz_xrealloc(ptr, size);
   209   }
   211   static void Free(void* ptr) {
   212     moz_free(ptr);
   213   }
   215   static void SizeTooBig(size_t size) {
   216     NS_ABORT_OOM(size);
   217   }
   218 };
   220 #else
   221 #include <stdlib.h>
   223 struct nsTArrayFallibleAllocator : nsTArrayFallibleAllocatorBase
   224 {
   225   static void* Malloc(size_t size) {
   226     return malloc(size);
   227   }
   229   static void* Realloc(void* ptr, size_t size) {
   230     return realloc(ptr, size);
   231   }
   233   static void Free(void* ptr) {
   234     free(ptr);
   235   }
   237   static void SizeTooBig(size_t) {
   238   }
   239 };
   241 struct nsTArrayInfallibleAllocator : nsTArrayInfallibleAllocatorBase
   242 {
   243   static void* Malloc(size_t size) {
   244     void* ptr = malloc(size);
   245     if (MOZ_UNLIKELY(!ptr)) {
   246       NS_ABORT_OOM(size);
   247     }
   248     return ptr;
   249   }
   251   static void* Realloc(void* ptr, size_t size) {
   252     void* newptr = realloc(ptr, size);
   253     if (MOZ_UNLIKELY(!ptr && size)) {
   254       NS_ABORT_OOM(size);
   255     }
   256     return newptr;
   257   }
   259   static void Free(void* ptr) {
   260     free(ptr);
   261   }
   263   static void SizeTooBig(size_t size) {
   264     NS_ABORT_OOM(size);
   265   }
   266 };
   268 #endif
   270 // nsTArray_base stores elements into the space allocated beyond
   271 // sizeof(*this).  This is done to minimize the size of the nsTArray
   272 // object when it is empty.
   273 struct NS_COM_GLUE nsTArrayHeader
   274 {
   275   static nsTArrayHeader sEmptyHdr;
   277   uint32_t mLength;
   278   uint32_t mCapacity : 31;
   279   uint32_t mIsAutoArray : 1;
   280 };
   282 // This class provides a SafeElementAt method to nsTArray<T*> which does
   283 // not take a second default value parameter.
   284 template <class E, class Derived>
   285 struct nsTArray_SafeElementAtHelper
   286 {
   287   typedef E*       elem_type;
   288   typedef uint32_t index_type;
   290   // No implementation is provided for these two methods, and that is on
   291   // purpose, since we don't support these functions on non-pointer type
   292   // instantiations.
   293   elem_type& SafeElementAt(index_type i);
   294   const elem_type& SafeElementAt(index_type i) const;
   295 };
   297 template <class E, class Derived>
   298 struct nsTArray_SafeElementAtHelper<E*, Derived>
   299 {
   300   typedef E*       elem_type;
   301   typedef uint32_t index_type;
   303   elem_type SafeElementAt(index_type i) {
   304     return static_cast<Derived*> (this)->SafeElementAt(i, nullptr);
   305   }
   307   const elem_type SafeElementAt(index_type i) const {
   308     return static_cast<const Derived*> (this)->SafeElementAt(i, nullptr);
   309   }
   310 };
   312 // E is the base type that the smart pointer is templated over; the
   313 // smart pointer can act as E*.
   314 template <class E, class Derived>
   315 struct nsTArray_SafeElementAtSmartPtrHelper
   316 {
   317   typedef E*       elem_type;
   318   typedef uint32_t index_type;
   320   elem_type SafeElementAt(index_type i) {
   321     return static_cast<Derived*> (this)->SafeElementAt(i, nullptr);
   322   }
   324   const elem_type SafeElementAt(index_type i) const {
   325     return static_cast<const Derived*> (this)->SafeElementAt(i, nullptr);
   326   }
   327 };
   329 template <class T> class nsCOMPtr;
   331 template <class E, class Derived>
   332 struct nsTArray_SafeElementAtHelper<nsCOMPtr<E>, Derived> :
   333   public nsTArray_SafeElementAtSmartPtrHelper<E, Derived>
   334 {
   335 };
   337 template <class T> class nsRefPtr;
   339 template <class E, class Derived>
   340 struct nsTArray_SafeElementAtHelper<nsRefPtr<E>, Derived> :
   341   public nsTArray_SafeElementAtSmartPtrHelper<E, Derived>
   342 {
   343 };
   345 //
   346 // This class serves as a base class for nsTArray.  It shouldn't be used
   347 // directly.  It holds common implementation code that does not depend on the
   348 // element type of the nsTArray.
   349 //
   350 template<class Alloc, class Copy>
   351 class nsTArray_base
   352 {
   353   // Allow swapping elements with |nsTArray_base|s created using a
   354   // different allocator.  This is kosher because all allocators use
   355   // the same free().
   356   template<class Allocator, class Copier>
   357   friend class nsTArray_base;
   359 protected:
   360   typedef nsTArrayHeader Header;
   362 public:
   363   typedef uint32_t size_type;
   364   typedef uint32_t index_type;
   366   // @return The number of elements in the array.
   367   size_type Length() const {
   368     return mHdr->mLength;
   369   }
   371   // @return True if the array is empty or false otherwise.
   372   bool IsEmpty() const {
   373     return Length() == 0;
   374   }
   376   // @return The number of elements that can fit in the array without forcing
   377   // the array to be re-allocated.  The length of an array is always less
   378   // than or equal to its capacity.
   379   size_type Capacity() const {
   380     return mHdr->mCapacity;
   381   }
   383 #ifdef DEBUG
   384   void* DebugGetHeader() const {
   385     return mHdr;
   386   }
   387 #endif
   389 protected:
   390   nsTArray_base();
   392   ~nsTArray_base();
   394   // Resize the storage if necessary to achieve the requested capacity.
   395   // @param capacity     The requested number of array elements.
   396   // @param elemSize     The size of an array element.
   397   // @return False if insufficient memory is available; true otherwise.
   398   typename Alloc::ResultTypeProxy EnsureCapacity(size_type capacity, size_type elemSize);
   400   // Resize the storage to the minimum required amount.
   401   // @param elemSize     The size of an array element.
   402   // @param elemAlign    The alignment in bytes of an array element.
   403   void ShrinkCapacity(size_type elemSize, size_t elemAlign);
   405   // This method may be called to resize a "gap" in the array by shifting
   406   // elements around.  It updates mLength appropriately.  If the resulting
   407   // array has zero elements, then the array's memory is free'd.
   408   // @param start        The starting index of the gap.
   409   // @param oldLen       The current length of the gap.
   410   // @param newLen       The desired length of the gap.
   411   // @param elemSize     The size of an array element.
   412   // @param elemAlign    The alignment in bytes of an array element.
   413   void ShiftData(index_type start, size_type oldLen, size_type newLen,
   414                  size_type elemSize, size_t elemAlign);
   416   // This method increments the length member of the array's header.
   417   // Note that mHdr may actually be sEmptyHdr in the case where a
   418   // zero-length array is inserted into our array. But then n should
   419   // always be 0.
   420   void IncrementLength(uint32_t n) {
   421     if (mHdr == EmptyHdr()) {
   422       if (MOZ_UNLIKELY(n != 0)) {
   423         // Writing a non-zero length to the empty header would be extremely bad.
   424         MOZ_CRASH();
   425       }
   426     } else {
   427       mHdr->mLength += n;
   428     }
   429   }
   431   // This method inserts blank slots into the array.
   432   // @param index the place to insert the new elements. This must be no
   433   //              greater than the current length of the array.
   434   // @param count the number of slots to insert
   435   // @param elementSize the size of an array element.
   436   // @param elemAlign the alignment in bytes of an array element.
   437   bool InsertSlotsAt(index_type index, size_type count,
   438                        size_type elementSize, size_t elemAlign);
   440 protected:
   441   template<class Allocator>
   442   typename Alloc::ResultTypeProxy
   443   SwapArrayElements(nsTArray_base<Allocator, Copy>& other,
   444                     size_type elemSize,
   445                     size_t elemAlign);
   447   // This is an RAII class used in SwapArrayElements.
   448   class IsAutoArrayRestorer {
   449     public:
   450       IsAutoArrayRestorer(nsTArray_base<Alloc, Copy> &array, size_t elemAlign);
   451       ~IsAutoArrayRestorer();
   453     private:
   454       nsTArray_base<Alloc, Copy> &mArray;
   455       size_t mElemAlign;
   456       bool mIsAuto;
   457   };
   459   // Helper function for SwapArrayElements. Ensures that if the array
   460   // is an nsAutoTArray that it doesn't use the built-in buffer.
   461   bool EnsureNotUsingAutoArrayBuffer(size_type elemSize);
   463   // Returns true if this nsTArray is an nsAutoTArray with a built-in buffer.
   464   bool IsAutoArray() const {
   465     return mHdr->mIsAutoArray;
   466   }
   468   // Returns a Header for the built-in buffer of this nsAutoTArray.
   469   Header* GetAutoArrayBuffer(size_t elemAlign) {
   470     MOZ_ASSERT(IsAutoArray(), "Should be an auto array to call this");
   471     return GetAutoArrayBufferUnsafe(elemAlign);
   472   }
   473   const Header* GetAutoArrayBuffer(size_t elemAlign) const {
   474     MOZ_ASSERT(IsAutoArray(), "Should be an auto array to call this");
   475     return GetAutoArrayBufferUnsafe(elemAlign);
   476   }
   478   // Returns a Header for the built-in buffer of this nsAutoTArray, but doesn't
   479   // assert that we are an nsAutoTArray.
   480   Header* GetAutoArrayBufferUnsafe(size_t elemAlign) {
   481     return const_cast<Header*>(static_cast<const nsTArray_base<Alloc, Copy>*>(this)->
   482                                GetAutoArrayBufferUnsafe(elemAlign));
   483   }
   484   const Header* GetAutoArrayBufferUnsafe(size_t elemAlign) const;
   486   // Returns true if this is an nsAutoTArray and it currently uses the
   487   // built-in buffer to store its elements.
   488   bool UsesAutoArrayBuffer() const;
   490   // The array's elements (prefixed with a Header).  This pointer is never
   491   // null.  If the array is empty, then this will point to sEmptyHdr.
   492   Header *mHdr;
   494   Header* Hdr() const {
   495     return mHdr;
   496   }
   498   Header** PtrToHdr() {
   499     return &mHdr;
   500   }
   502   static Header* EmptyHdr() {
   503     return &Header::sEmptyHdr;
   504   }
   505 };
   507 //
   508 // This class defines convenience functions for element specific operations.
   509 // Specialize this template if necessary.
   510 //
   511 template<class E>
   512 class nsTArrayElementTraits
   513 {
   514 public:
   515   // Invoke the default constructor in place.
   516   static inline void Construct(E *e) {
   517     // Do NOT call "E()"! That triggers C++ "default initialization"
   518     // which zeroes out POD ("plain old data") types such as regular
   519     // ints.  We don't want that because it can be a performance issue
   520     // and people don't expect it; nsTArray should work like a regular
   521     // C/C++ array in this respect.
   522     new (static_cast<void *>(e)) E;
   523   }
   524   // Invoke the copy-constructor in place.
   525   template<class A>
   526   static inline void Construct(E *e, const A &arg) {
   527     typedef typename mozilla::RemoveCV<E>::Type E_NoCV;
   528     typedef typename mozilla::RemoveCV<A>::Type A_NoCV;
   529     static_assert(!mozilla::IsSame<E_NoCV*, A_NoCV>::value,
   530                   "For safety, we disallow constructing nsTArray<E> elements "
   531                   "from E* pointers. See bug 960591.");
   532     new (static_cast<void *>(e)) E(arg);
   533   }
   534   // Invoke the destructor in place.
   535   static inline void Destruct(E *e) {
   536     e->~E();
   537   }
   538 };
   540 // The default comparator used by nsTArray
   541 template<class A, class B>
   542 class nsDefaultComparator
   543 {
   544 public:
   545   bool Equals(const A& a, const B& b) const {
   546     return a == b;
   547   }
   548   bool LessThan(const A& a, const B& b) const {
   549     return a < b;
   550   }
   551 };
   553 template <class E> class InfallibleTArray;
   554 template <class E> class FallibleTArray;
   556 template<bool IsPod, bool IsSameType>
   557 struct AssignRangeAlgorithm {
   558   template<class Item, class ElemType, class IndexType, class SizeType>
   559   static void implementation(ElemType* elements, IndexType start,
   560                              SizeType count, const Item *values) {
   561     ElemType *iter = elements + start, *end = iter + count;
   562     for (; iter != end; ++iter, ++values)
   563       nsTArrayElementTraits<ElemType>::Construct(iter, *values);
   564   }
   565 };
   567 template<>
   568 struct AssignRangeAlgorithm<true, true> {
   569   template<class Item, class ElemType, class IndexType, class SizeType>
   570   static void implementation(ElemType* elements, IndexType start,
   571                              SizeType count, const Item *values) {
   572     memcpy(elements + start, values, count * sizeof(ElemType));
   573   }
   574 };
   576 //
   577 // Normally elements are copied with memcpy and memmove, but for some element
   578 // types that is problematic.  The nsTArray_CopyChooser template class can be
   579 // specialized to ensure that copying calls constructors and destructors
   580 // instead, as is done below for JS::Heap<E> elements.
   581 //
   583 //
   584 // A class that defines how to copy elements using memcpy/memmove.
   585 //
   586 struct nsTArray_CopyWithMemutils
   587 {
   588   const static bool allowRealloc = true;
   590   static void CopyElements(void* dest, const void* src, size_t count, size_t elemSize) {
   591     memcpy(dest, src, count * elemSize);
   592   }
   594   static void CopyHeaderAndElements(void* dest, const void* src, size_t count, size_t elemSize) {
   595     memcpy(dest, src, sizeof(nsTArrayHeader) + count * elemSize);
   596   }
   598   static void MoveElements(void* dest, const void* src, size_t count, size_t elemSize) {
   599     memmove(dest, src, count * elemSize);
   600   }
   601 };
   603 //
   604 // A template class that defines how to copy elements calling their constructors
   605 // and destructors appropriately.
   606 //
   607 template <class ElemType>
   608 struct nsTArray_CopyWithConstructors
   609 {
   610   typedef nsTArrayElementTraits<ElemType> traits;
   612   const static bool allowRealloc = false;
   614   static void CopyElements(void* dest, void* src, size_t count, size_t elemSize) {
   615     ElemType* destElem = static_cast<ElemType*>(dest);
   616     ElemType* srcElem = static_cast<ElemType*>(src);
   617     ElemType* destElemEnd = destElem + count;
   618 #ifdef DEBUG
   619     ElemType* srcElemEnd = srcElem + count;
   620     MOZ_ASSERT(srcElemEnd <= destElem || srcElemEnd > destElemEnd);
   621 #endif
   622     while (destElem != destElemEnd) {
   623       traits::Construct(destElem, *srcElem);
   624       traits::Destruct(srcElem);
   625       ++destElem;
   626       ++srcElem;
   627     }
   628   }
   630   static void CopyHeaderAndElements(void* dest, void* src, size_t count, size_t elemSize) {
   631     nsTArrayHeader* destHeader = static_cast<nsTArrayHeader*>(dest);
   632     nsTArrayHeader* srcHeader = static_cast<nsTArrayHeader*>(src);
   633     *destHeader = *srcHeader;
   634     CopyElements(static_cast<uint8_t*>(dest) + sizeof(nsTArrayHeader),
   635                  static_cast<uint8_t*>(src) + sizeof(nsTArrayHeader),
   636                  count, elemSize);
   637   }
   639   static void MoveElements(void* dest, void* src, size_t count, size_t elemSize) {
   640     ElemType* destElem = static_cast<ElemType*>(dest);
   641     ElemType* srcElem = static_cast<ElemType*>(src);
   642     ElemType* destElemEnd = destElem + count;
   643     ElemType* srcElemEnd = srcElem + count;
   644     if (destElem == srcElem) {
   645       return;  // In practice, we don't do this.
   646     } else if (srcElemEnd > destElem && srcElemEnd < destElemEnd) {
   647       while (destElemEnd != destElem) {
   648         --destElemEnd;
   649         --srcElemEnd;
   650         traits::Construct(destElemEnd, *srcElemEnd);
   651         traits::Destruct(srcElem);
   652       }
   653     } else {
   654       CopyElements(dest, src, count, elemSize);
   655     }
   656   }
   657 };
   659 //
   660 // The default behaviour is to use memcpy/memmove for everything.
   661 //
   662 template <class E>
   663 struct nsTArray_CopyChooser {
   664   typedef nsTArray_CopyWithMemutils Type;
   665 };
   667 //
   668 // Some classes require constructors/destructors to be called, so they are
   669 // specialized here.
   670 //
   671 template <class E>
   672 struct nsTArray_CopyChooser<JS::Heap<E> > {
   673   typedef nsTArray_CopyWithConstructors<JS::Heap<E> > Type;
   674 };
   676 template<>
   677 struct nsTArray_CopyChooser<nsRegion> {
   678   typedef nsTArray_CopyWithConstructors<nsRegion> Type;
   679 };
   681 template<>
   682 struct nsTArray_CopyChooser<nsIntRegion> {
   683   typedef nsTArray_CopyWithConstructors<nsIntRegion> Type;
   684 };
   686 //
   687 // Base class for nsTArray_Impl that is templated on element type and derived
   688 // nsTArray_Impl class, to allow extra conversions to be added for specific
   689 // types.
   690 //
   691 template <class E, class Derived>
   692 struct nsTArray_TypedBase : public nsTArray_SafeElementAtHelper<E, Derived> {};
   694 //
   695 // Specialization of nsTArray_TypedBase for arrays containing JS::Heap<E>
   696 // elements.
   697 //
   698 // These conversions are safe because JS::Heap<E> and E share the same
   699 // representation, and since the result of the conversions are const references
   700 // we won't miss any barriers.
   701 //
   702 // The static_cast is necessary to obtain the correct address for the derived
   703 // class since we are a base class used in multiple inheritance.
   704 //
   705 template <class E, class Derived>
   706 struct nsTArray_TypedBase<JS::Heap<E>, Derived>
   707  : public nsTArray_SafeElementAtHelper<JS::Heap<E>, Derived>
   708 {
   709   operator const nsTArray<E>& () {
   710     static_assert(sizeof(E) == sizeof(JS::Heap<E>),
   711                   "JS::Heap<E> must be binary compatible with E.");
   712     Derived* self = static_cast<Derived*>(this);
   713     return *reinterpret_cast<nsTArray<E> *>(self);
   714   }
   716   operator const FallibleTArray<E>& () {
   717     Derived* self = static_cast<Derived*>(this);
   718     return *reinterpret_cast<FallibleTArray<E> *>(self);
   719   }
   720 };
   723 //
   724 // nsTArray_Impl contains most of the guts supporting nsTArray, FallibleTArray,
   725 // nsAutoTArray, and AutoFallibleTArray.
   726 //
   727 // The only situation in which you might need to use nsTArray_Impl in your code
   728 // is if you're writing code which mutates a TArray which may or may not be
   729 // infallible.
   730 //
   731 // Code which merely reads from a TArray which may or may not be infallible can
   732 // simply cast the TArray to |const nsTArray&|; both fallible and infallible
   733 // TArrays can be cast to |const nsTArray&|.
   734 //
   735 template<class E, class Alloc>
   736 class nsTArray_Impl : public nsTArray_base<Alloc, typename nsTArray_CopyChooser<E>::Type>,
   737                       public nsTArray_TypedBase<E, nsTArray_Impl<E, Alloc> >
   738 {
   739 public:
   740   typedef typename nsTArray_CopyChooser<E>::Type     copy_type;
   741   typedef nsTArray_base<Alloc, copy_type>            base_type;
   742   typedef typename base_type::size_type              size_type;
   743   typedef typename base_type::index_type             index_type;
   744   typedef E                                          elem_type;
   745   typedef nsTArray_Impl<E, Alloc>                    self_type;
   746   typedef nsTArrayElementTraits<E>                   elem_traits;
   747   typedef nsTArray_SafeElementAtHelper<E, self_type> safeelementat_helper_type;
   749   using safeelementat_helper_type::SafeElementAt;
   750   using base_type::EmptyHdr;
   752   // A special value that is used to indicate an invalid or unknown index
   753   // into the array.
   754   enum {
   755     NoIndex = index_type(-1)
   756   };
   758   using base_type::Length;
   760   //
   761   // Finalization method
   762   //
   764   ~nsTArray_Impl() { Clear(); }
   766   //
   767   // Initialization methods
   768   //
   770   nsTArray_Impl() {}
   772   // Initialize this array and pre-allocate some number of elements.
   773   explicit nsTArray_Impl(size_type capacity) {
   774     SetCapacity(capacity);
   775   }
   777   // The array's copy-constructor performs a 'deep' copy of the given array.
   778   // @param other  The array object to copy.
   779   //
   780   // It's very important that we declare this method as taking |const
   781   // self_type&| as opposed to taking |const nsTArray_Impl<E, OtherAlloc>| for
   782   // an arbitrary OtherAlloc.
   783   //
   784   // If we don't declare a constructor taking |const self_type&|, C++ generates
   785   // a copy-constructor for this class which merely copies the object's
   786   // members, which is obviously wrong.
   787   //
   788   // You can pass an nsTArray_Impl<E, OtherAlloc> to this method because
   789   // nsTArray_Impl<E, X> can be cast to const nsTArray_Impl<E, Y>&.  So the
   790   // effect on the API is the same as if we'd declared this method as taking
   791   // |const nsTArray_Impl<E, OtherAlloc>&|.
   792   explicit nsTArray_Impl(const self_type& other) {
   793     AppendElements(other);
   794   }
   796   // Allow converting to a const array with a different kind of allocator,
   797   // Since the allocator doesn't matter for const arrays
   798   template<typename Allocator>
   799   operator const nsTArray_Impl<E, Allocator>&() const {
   800     return *reinterpret_cast<const nsTArray_Impl<E, Allocator>*>(this);
   801   }
   802   // And we have to do this for our subclasses too
   803   operator const nsTArray<E>&() const {
   804     return *reinterpret_cast<const InfallibleTArray<E>*>(this);
   805   }
   806   operator const FallibleTArray<E>&() const {
   807     return *reinterpret_cast<const FallibleTArray<E>*>(this);
   808   }
   810   // The array's assignment operator performs a 'deep' copy of the given
   811   // array.  It is optimized to reuse existing storage if possible.
   812   // @param other  The array object to copy.
   813   self_type& operator=(const self_type& other) {
   814     ReplaceElementsAt(0, Length(), other.Elements(), other.Length());
   815     return *this;
   816   }
   818   // Return true if this array has the same length and the same
   819   // elements as |other|.
   820   template<typename Allocator>
   821   bool operator==(const nsTArray_Impl<E, Allocator>& other) const {
   822     size_type len = Length();
   823     if (len != other.Length())
   824       return false;
   826     // XXX std::equal would be as fast or faster here
   827     for (index_type i = 0; i < len; ++i)
   828       if (!(operator[](i) == other[i]))
   829         return false;
   831     return true;
   832   }
   834   // Return true if this array does not have the same length and the same
   835   // elements as |other|.
   836   bool operator!=(const self_type& other) const {
   837     return !operator==(other);
   838   }
   840   template<typename Allocator>
   841   self_type& operator=(const nsTArray_Impl<E, Allocator>& other) {
   842     ReplaceElementsAt(0, Length(), other.Elements(), other.Length());
   843     return *this;
   844   }
   846   // @return The amount of memory used by this nsTArray_Impl, excluding
   847   // sizeof(*this).
   848   size_t SizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const {
   849     if (this->UsesAutoArrayBuffer() || Hdr() == EmptyHdr())
   850       return 0;
   851     return mallocSizeOf(this->Hdr());
   852   }
   854   // @return The amount of memory used by this nsTArray_Impl, including
   855   // sizeof(*this).
   856   size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const {
   857     return mallocSizeOf(this) + SizeOfExcludingThis(mallocSizeOf);
   858   }
   860   //
   861   // Accessor methods
   862   //
   864   // This method provides direct access to the array elements.
   865   // @return A pointer to the first element of the array.  If the array is
   866   // empty, then this pointer must not be dereferenced.
   867   elem_type* Elements() {
   868     return reinterpret_cast<elem_type *>(Hdr() + 1);
   869   }
   871   // This method provides direct, readonly access to the array elements.
   872   // @return A pointer to the first element of the array.  If the array is
   873   // empty, then this pointer must not be dereferenced.
   874   const elem_type* Elements() const {
   875     return reinterpret_cast<const elem_type *>(Hdr() + 1);
   876   }
   878   // This method provides direct access to the i'th element of the array.
   879   // The given index must be within the array bounds.
   880   // @param i  The index of an element in the array.
   881   // @return   A reference to the i'th element of the array.
   882   elem_type& ElementAt(index_type i) {
   883     MOZ_ASSERT(i < Length(), "invalid array index");
   884     return Elements()[i];
   885   }
   887   // This method provides direct, readonly access to the i'th element of the
   888   // array.  The given index must be within the array bounds.
   889   // @param i  The index of an element in the array.
   890   // @return   A const reference to the i'th element of the array.
   891   const elem_type& ElementAt(index_type i) const {
   892     MOZ_ASSERT(i < Length(), "invalid array index");
   893     return Elements()[i];
   894   }
   896   // This method provides direct access to the i'th element of the array in
   897   // a bounds safe manner. If the requested index is out of bounds the
   898   // provided default value is returned.
   899   // @param i  The index of an element in the array.
   900   // @param def The value to return if the index is out of bounds.
   901   elem_type& SafeElementAt(index_type i, elem_type& def) {
   902     return i < Length() ? Elements()[i] : def;
   903   }
   905   // This method provides direct access to the i'th element of the array in
   906   // a bounds safe manner. If the requested index is out of bounds the
   907   // provided default value is returned.
   908   // @param i  The index of an element in the array.
   909   // @param def The value to return if the index is out of bounds.
   910   const elem_type& SafeElementAt(index_type i, const elem_type& def) const {
   911     return i < Length() ? Elements()[i] : def;
   912   }
   914   // Shorthand for ElementAt(i)
   915   elem_type& operator[](index_type i) {
   916     return ElementAt(i);
   917   }
   919   // Shorthand for ElementAt(i)
   920   const elem_type& operator[](index_type i) const {
   921     return ElementAt(i);
   922   }
   924   // Shorthand for ElementAt(length - 1)
   925   elem_type& LastElement() {
   926     return ElementAt(Length() - 1);
   927   }
   929   // Shorthand for ElementAt(length - 1)
   930   const elem_type& LastElement() const {
   931     return ElementAt(Length() - 1);
   932   }
   934   // Shorthand for SafeElementAt(length - 1, def)
   935   elem_type& SafeLastElement(elem_type& def) {
   936     return SafeElementAt(Length() - 1, def);
   937   }
   939   // Shorthand for SafeElementAt(length - 1, def)
   940   const elem_type& SafeLastElement(const elem_type& def) const {
   941     return SafeElementAt(Length() - 1, def);
   942   }
   944   //
   945   // Search methods
   946   //
   948   // This method searches for the first element in this array that is equal
   949   // to the given element.
   950   // @param item   The item to search for.
   951   // @param comp   The Comparator used to determine element equality.
   952   // @return       true if the element was found.
   953   template<class Item, class Comparator>
   954   bool Contains(const Item& item, const Comparator& comp) const {
   955     return IndexOf(item, 0, comp) != NoIndex;
   956   }
   958   // This method searches for the first element in this array that is equal
   959   // to the given element.  This method assumes that 'operator==' is defined
   960   // for elem_type.
   961   // @param item   The item to search for.
   962   // @return       true if the element was found.
   963   template<class Item>
   964   bool Contains(const Item& item) const {
   965     return IndexOf(item) != NoIndex;
   966   }
   968   // This method searches for the offset of the first element in this
   969   // array that is equal to the given element.
   970   // @param item   The item to search for.
   971   // @param start  The index to start from.
   972   // @param comp   The Comparator used to determine element equality.
   973   // @return       The index of the found element or NoIndex if not found.
   974   template<class Item, class Comparator>
   975   index_type IndexOf(const Item& item, index_type start,
   976                      const Comparator& comp) const {
   977     const elem_type* iter = Elements() + start, *end = Elements() + Length();
   978     for (; iter != end; ++iter) {
   979       if (comp.Equals(*iter, item))
   980         return index_type(iter - Elements());
   981     }
   982     return NoIndex;
   983   }
   985   // This method searches for the offset of the first element in this
   986   // array that is equal to the given element.  This method assumes
   987   // that 'operator==' is defined for elem_type.
   988   // @param item   The item to search for.
   989   // @param start  The index to start from.
   990   // @return       The index of the found element or NoIndex if not found.
   991   template<class Item>
   992   index_type IndexOf(const Item& item, index_type start = 0) const {
   993     return IndexOf(item, start, nsDefaultComparator<elem_type, Item>());
   994   }
   996   // This method searches for the offset of the last element in this
   997   // array that is equal to the given element.
   998   // @param item   The item to search for.
   999   // @param start  The index to start from.  If greater than or equal to the
  1000   //               length of the array, then the entire array is searched.
  1001   // @param comp   The Comparator used to determine element equality.
  1002   // @return       The index of the found element or NoIndex if not found.
  1003   template<class Item, class Comparator>
  1004   index_type LastIndexOf(const Item& item, index_type start,
  1005                          const Comparator& comp) const {
  1006     size_type endOffset = start >= Length() ? Length() : start + 1;
  1007     const elem_type* end = Elements() - 1, *iter = end + endOffset;
  1008     for (; iter != end; --iter) {
  1009       if (comp.Equals(*iter, item))
  1010         return index_type(iter - Elements());
  1012     return NoIndex;
  1015   // This method searches for the offset of the last element in this
  1016   // array that is equal to the given element.  This method assumes
  1017   // that 'operator==' is defined for elem_type.
  1018   // @param item   The item to search for.
  1019   // @param start  The index to start from.  If greater than or equal to the
  1020   //               length of the array, then the entire array is searched.
  1021   // @return       The index of the found element or NoIndex if not found.
  1022   template<class Item>
  1023   index_type LastIndexOf(const Item& item,
  1024                          index_type start = NoIndex) const {
  1025     return LastIndexOf(item, start, nsDefaultComparator<elem_type, Item>());
  1028   // This method searches for the offset for the element in this array
  1029   // that is equal to the given element. The array is assumed to be sorted.
  1030   // @param item   The item to search for.
  1031   // @param comp   The Comparator used.
  1032   // @return       The index of the found element or NoIndex if not found.
  1033   template<class Item, class Comparator>
  1034   index_type BinaryIndexOf(const Item& item, const Comparator& comp) const {
  1035     index_type low = 0, high = Length();
  1036     while (high > low) {
  1037       index_type mid = (high + low) >> 1;
  1038       if (comp.Equals(ElementAt(mid), item))
  1039         return mid;
  1040       if (comp.LessThan(ElementAt(mid), item))
  1041         low = mid + 1;
  1042       else
  1043         high = mid;
  1045     return NoIndex;
  1048   // This method searches for the offset for the element in this array
  1049   // that is equal to the given element. The array is assumed to be sorted.
  1050   // This method assumes that 'operator==' and 'operator<' are defined.
  1051   // @param item   The item to search for.
  1052   // @return       The index of the found element or NoIndex if not found.
  1053   template<class Item>
  1054   index_type BinaryIndexOf(const Item& item) const {
  1055     return BinaryIndexOf(item, nsDefaultComparator<elem_type, Item>());
  1058   //
  1059   // Mutation methods
  1060   //
  1061   // This method call the destructor on each element of the array, empties it,
  1062   // but does not shrink the array's capacity.
  1063   // See also SetLengthAndRetainStorage.
  1064   // Make sure to call Compact() if needed to avoid keeping a huge array
  1065   // around.
  1066   void ClearAndRetainStorage() {
  1067     if (base_type::mHdr == EmptyHdr()) {
  1068       return;
  1071     DestructRange(0, Length());
  1072     base_type::mHdr->mLength = 0;
  1075   // This method modifies the length of the array, but unlike SetLength
  1076   // it doesn't deallocate/reallocate the current internal storage.
  1077   // The new length MUST be shorter than or equal to the current capacity.
  1078   // If the new length is larger than the existing length of the array,
  1079   // then new elements will be constructed using elem_type's default
  1080   // constructor.  If shorter, elements will be destructed and removed.
  1081   // See also ClearAndRetainStorage.
  1082   // @param newLen  The desired length of this array.
  1083   void SetLengthAndRetainStorage(size_type newLen) {
  1084     MOZ_ASSERT(newLen <= base_type::Capacity());
  1085     size_type oldLen = Length();
  1086     if (newLen > oldLen) {
  1087       InsertElementsAt(oldLen, newLen - oldLen);
  1088       return;
  1090     if (newLen < oldLen) {
  1091       DestructRange(newLen, oldLen - newLen);
  1092       base_type::mHdr->mLength = newLen;
  1096   // This method replaces a range of elements in this array.
  1097   // @param start     The starting index of the elements to replace.
  1098   // @param count     The number of elements to replace.  This may be zero to
  1099   //                  insert elements without removing any existing elements.
  1100   // @param array     The values to copy into this array.  Must be non-null,
  1101   //                  and these elements must not already exist in the array
  1102   //                  being modified.
  1103   // @param arrayLen  The number of values to copy into this array.
  1104   // @return          A pointer to the new elements in the array, or null if
  1105   //                  the operation failed due to insufficient memory.
  1106   template<class Item>
  1107   elem_type *ReplaceElementsAt(index_type start, size_type count,
  1108                                const Item* array, size_type arrayLen) {
  1109     // Adjust memory allocation up-front to catch errors.
  1110     if (!Alloc::Successful(this->EnsureCapacity(Length() + arrayLen - count, sizeof(elem_type))))
  1111       return nullptr;
  1112     DestructRange(start, count);
  1113     this->ShiftData(start, count, arrayLen, sizeof(elem_type), MOZ_ALIGNOF(elem_type));
  1114     AssignRange(start, arrayLen, array);
  1115     return Elements() + start;
  1118   // A variation on the ReplaceElementsAt method defined above.
  1119   template<class Item>
  1120   elem_type *ReplaceElementsAt(index_type start, size_type count,
  1121                                const nsTArray<Item>& array) {
  1122     return ReplaceElementsAt(start, count, array.Elements(), array.Length());
  1125   // A variation on the ReplaceElementsAt method defined above.
  1126   template<class Item>
  1127   elem_type *ReplaceElementsAt(index_type start, size_type count,
  1128                                const Item& item) {
  1129     return ReplaceElementsAt(start, count, &item, 1);
  1132   // A variation on the ReplaceElementsAt method defined above.
  1133   template<class Item>
  1134   elem_type *ReplaceElementAt(index_type index, const Item& item) {
  1135     return ReplaceElementsAt(index, 1, &item, 1);
  1138   // A variation on the ReplaceElementsAt method defined above.
  1139   template<class Item>
  1140   elem_type *InsertElementsAt(index_type index, const Item* array,
  1141                               size_type arrayLen) {
  1142     return ReplaceElementsAt(index, 0, array, arrayLen);
  1145   // A variation on the ReplaceElementsAt method defined above.
  1146   template<class Item, class Allocator>
  1147   elem_type *InsertElementsAt(index_type index, const nsTArray_Impl<Item, Allocator>& array) {
  1148     return ReplaceElementsAt(index, 0, array.Elements(), array.Length());
  1151   // A variation on the ReplaceElementsAt method defined above.
  1152   template<class Item>
  1153   elem_type *InsertElementAt(index_type index, const Item& item) {
  1154     return ReplaceElementsAt(index, 0, &item, 1);
  1157   // Insert a new element without copy-constructing. This is useful to avoid
  1158   // temporaries.
  1159   // @return A pointer to the newly inserted element, or null on OOM.
  1160   elem_type* InsertElementAt(index_type index) {
  1161     if (!Alloc::Successful(this->EnsureCapacity(Length() + 1, sizeof(elem_type))))
  1162       return nullptr;
  1163     this->ShiftData(index, 0, 1, sizeof(elem_type), MOZ_ALIGNOF(elem_type));
  1164     elem_type *elem = Elements() + index;
  1165     elem_traits::Construct(elem);
  1166     return elem;
  1169   // This method searches for the smallest index of an element that is strictly
  1170   // greater than |item|.  If |item| is inserted at this index, the array will
  1171   // remain sorted and |item| would come after all elements that are equal to
  1172   // it.  If |item| is greater than or equal to all elements in the array, the
  1173   // array length is returned.
  1174   //
  1175   // Note that consumers who want to know whether there are existing items equal
  1176   // to |item| in the array can just check that the return value here is > 0 and
  1177   // indexing into the previous slot gives something equal to |item|.
  1178   //
  1179   //
  1180   // @param item   The item to search for.
  1181   // @param comp   The Comparator used.
  1182   // @return        The index of greatest element <= to |item|
  1183   // @precondition The array is sorted
  1184   template<class Item, class Comparator>
  1185   index_type
  1186   IndexOfFirstElementGt(const Item& item,
  1187                         const Comparator& comp) const {
  1188     // invariant: low <= [idx] <= high
  1189     index_type low = 0, high = Length();
  1190     while (high > low) {
  1191       index_type mid = (high + low) >> 1;
  1192       // Comparators are not required to provide a LessThan(Item&, elem_type),
  1193       // so we can't do comp.LessThan(item, ElementAt(mid)).
  1194       if (comp.LessThan(ElementAt(mid), item) ||
  1195           comp.Equals(ElementAt(mid), item)) {
  1196         // item >= ElementAt(mid), so our desired index is at least mid+1.
  1197         low = mid + 1;
  1198       } else {
  1199         // item < ElementAt(mid).  Our desired index is therefore at most mid.
  1200         high = mid;
  1203     MOZ_ASSERT(high == low);
  1204     return low;
  1207   // A variation on the IndexOfFirstElementGt method defined above.
  1208   template<class Item>
  1209   index_type
  1210   IndexOfFirstElementGt(const Item& item) const {
  1211     return IndexOfFirstElementGt(item, nsDefaultComparator<elem_type, Item>());
  1214   // Inserts |item| at such an index to guarantee that if the array
  1215   // was previously sorted, it will remain sorted after this
  1216   // insertion.
  1217   template<class Item, class Comparator>
  1218   elem_type *InsertElementSorted(const Item& item, const Comparator& comp) {
  1219     index_type index = IndexOfFirstElementGt(item, comp);
  1220     return InsertElementAt(index, item);
  1223   // A variation on the InsertElementSorted method defined above.
  1224   template<class Item>
  1225   elem_type *InsertElementSorted(const Item& item) {
  1226     return InsertElementSorted(item, nsDefaultComparator<elem_type, Item>());
  1229   // This method appends elements to the end of this array.
  1230   // @param array     The elements to append to this array.
  1231   // @param arrayLen  The number of elements to append to this array.
  1232   // @return          A pointer to the new elements in the array, or null if
  1233   //                  the operation failed due to insufficient memory.
  1234   template<class Item>
  1235   elem_type *AppendElements(const Item* array, size_type arrayLen) {
  1236     if (!Alloc::Successful(this->EnsureCapacity(Length() + arrayLen, sizeof(elem_type))))
  1237       return nullptr;
  1238     index_type len = Length();
  1239     AssignRange(len, arrayLen, array);
  1240     this->IncrementLength(arrayLen);
  1241     return Elements() + len;
  1244   // A variation on the AppendElements method defined above.
  1245   template<class Item, class Allocator>
  1246   elem_type *AppendElements(const nsTArray_Impl<Item, Allocator>& array) {
  1247     return AppendElements(array.Elements(), array.Length());
  1250   // A variation on the AppendElements method defined above.
  1251   template<class Item>
  1252   elem_type *AppendElement(const Item& item) {
  1253     return AppendElements(&item, 1);
  1256   // Append new elements without copy-constructing. This is useful to avoid
  1257   // temporaries.
  1258   // @return A pointer to the newly appended elements, or null on OOM.
  1259   elem_type *AppendElements(size_type count) {
  1260     if (!Alloc::Successful(this->EnsureCapacity(Length() + count, sizeof(elem_type))))
  1261       return nullptr;
  1262     elem_type *elems = Elements() + Length();
  1263     size_type i;
  1264     for (i = 0; i < count; ++i) {
  1265       elem_traits::Construct(elems + i);
  1267     this->IncrementLength(count);
  1268     return elems;
  1271   // Append a new element without copy-constructing. This is useful to avoid
  1272   // temporaries.
  1273   // @return A pointer to the newly appended element, or null on OOM.
  1274   elem_type *AppendElement() {
  1275     return AppendElements(1);
  1278   // Move all elements from another array to the end of this array without
  1279   // calling copy constructors or destructors.
  1280   // @return A pointer to the newly appended elements, or null on OOM.
  1281   template<class Item, class Allocator>
  1282   elem_type *MoveElementsFrom(nsTArray_Impl<Item, Allocator>& array) {
  1283     MOZ_ASSERT(&array != this, "argument must be different array");
  1284     index_type len = Length();
  1285     index_type otherLen = array.Length();
  1286     if (!Alloc::Successful(this->EnsureCapacity(len + otherLen, sizeof(elem_type))))
  1287       return nullptr;
  1288     copy_type::CopyElements(Elements() + len, array.Elements(), otherLen, sizeof(elem_type));
  1289     this->IncrementLength(otherLen);
  1290     array.ShiftData(0, otherLen, 0, sizeof(elem_type), MOZ_ALIGNOF(elem_type));
  1291     return Elements() + len;
  1294   // This method removes a range of elements from this array.
  1295   // @param start  The starting index of the elements to remove.
  1296   // @param count  The number of elements to remove.
  1297   void RemoveElementsAt(index_type start, size_type count) {
  1298     MOZ_ASSERT(count == 0 || start < Length(), "Invalid start index");
  1299     MOZ_ASSERT(start + count <= Length(), "Invalid length");
  1300     // Check that the previous assert didn't overflow
  1301     MOZ_ASSERT(start <= start + count, "Start index plus length overflows");
  1302     DestructRange(start, count);
  1303     this->ShiftData(start, count, 0, sizeof(elem_type), MOZ_ALIGNOF(elem_type));
  1306   // A variation on the RemoveElementsAt method defined above.
  1307   void RemoveElementAt(index_type index) {
  1308     RemoveElementsAt(index, 1);
  1311   // A variation on the RemoveElementsAt method defined above.
  1312   void Clear() {
  1313     RemoveElementsAt(0, Length());
  1316   // This helper function combines IndexOf with RemoveElementAt to "search
  1317   // and destroy" the first element that is equal to the given element.
  1318   // @param item  The item to search for.
  1319   // @param comp  The Comparator used to determine element equality.
  1320   // @return true if the element was found
  1321   template<class Item, class Comparator>
  1322   bool RemoveElement(const Item& item, const Comparator& comp) {
  1323     index_type i = IndexOf(item, 0, comp);
  1324     if (i == NoIndex)
  1325       return false;
  1327     RemoveElementAt(i);
  1328     return true;
  1331   // A variation on the RemoveElement method defined above that assumes
  1332   // that 'operator==' is defined for elem_type.
  1333   template<class Item>
  1334   bool RemoveElement(const Item& item) {
  1335     return RemoveElement(item, nsDefaultComparator<elem_type, Item>());
  1338   // This helper function combines IndexOfFirstElementGt with
  1339   // RemoveElementAt to "search and destroy" the last element that
  1340   // is equal to the given element.
  1341   // @param item  The item to search for.
  1342   // @param comp  The Comparator used to determine element equality.
  1343   // @return true if the element was found
  1344   template<class Item, class Comparator>
  1345   bool RemoveElementSorted(const Item& item, const Comparator& comp) {
  1346     index_type index = IndexOfFirstElementGt(item, comp);
  1347     if (index > 0 && comp.Equals(ElementAt(index - 1), item)) {
  1348       RemoveElementAt(index - 1);
  1349       return true;
  1351     return false;
  1354   // A variation on the RemoveElementSorted method defined above.
  1355   template<class Item>
  1356   bool RemoveElementSorted(const Item& item) {
  1357     return RemoveElementSorted(item, nsDefaultComparator<elem_type, Item>());
  1360   // This method causes the elements contained in this array and the given
  1361   // array to be swapped.
  1362   template<class Allocator>
  1363   typename Alloc::ResultType
  1364   SwapElements(nsTArray_Impl<E, Allocator>& other) {
  1365     return Alloc::Result(this->SwapArrayElements(other, sizeof(elem_type),
  1366                                                  MOZ_ALIGNOF(elem_type)));
  1369   //
  1370   // Allocation
  1371   //
  1373   // This method may increase the capacity of this array object by the
  1374   // specified amount.  This method may be called in advance of several
  1375   // AppendElement operations to minimize heap re-allocations.  This method
  1376   // will not reduce the number of elements in this array.
  1377   // @param capacity  The desired capacity of this array.
  1378   // @return True if the operation succeeded; false if we ran out of memory
  1379   typename Alloc::ResultType SetCapacity(size_type capacity) {
  1380     return Alloc::Result(this->EnsureCapacity(capacity, sizeof(elem_type)));
  1383   // This method modifies the length of the array.  If the new length is
  1384   // larger than the existing length of the array, then new elements will be
  1385   // constructed using elem_type's default constructor.  Otherwise, this call
  1386   // removes elements from the array (see also RemoveElementsAt).
  1387   // @param newLen  The desired length of this array.
  1388   // @return        True if the operation succeeded; false otherwise.
  1389   // See also TruncateLength if the new length is guaranteed to be
  1390   // smaller than the old.
  1391   typename Alloc::ResultType SetLength(size_type newLen) {
  1392     size_type oldLen = Length();
  1393     if (newLen > oldLen) {
  1394       return Alloc::ConvertBoolToResultType(InsertElementsAt(oldLen, newLen - oldLen) != nullptr);
  1397     TruncateLength(newLen);
  1398     return Alloc::ConvertBoolToResultType(true);
  1401   // This method modifies the length of the array, but may only be
  1402   // called when the new length is shorter than the old.  It can
  1403   // therefore be called when elem_type has no default constructor,
  1404   // unlike SetLength.  It removes elements from the array (see also
  1405   // RemoveElementsAt).
  1406   // @param newLen  The desired length of this array.
  1407   void TruncateLength(size_type newLen) {
  1408     size_type oldLen = Length();
  1409     NS_ABORT_IF_FALSE(newLen <= oldLen,
  1410                       "caller should use SetLength instead");
  1411     RemoveElementsAt(newLen, oldLen - newLen);
  1414   // This method ensures that the array has length at least the given
  1415   // length.  If the current length is shorter than the given length,
  1416   // then new elements will be constructed using elem_type's default
  1417   // constructor.
  1418   // @param minLen  The desired minimum length of this array.
  1419   // @return        True if the operation succeeded; false otherwise.
  1420 typename Alloc::ResultType EnsureLengthAtLeast(size_type minLen) {
  1421     size_type oldLen = Length();
  1422     if (minLen > oldLen) {
  1423       return Alloc::ConvertBoolToResultType(!!InsertElementsAt(oldLen, minLen - oldLen));
  1425     return Alloc::ConvertBoolToResultType(true);
  1428   // This method inserts elements into the array, constructing
  1429   // them using elem_type's default constructor.
  1430   // @param index the place to insert the new elements. This must be no
  1431   //              greater than the current length of the array.
  1432   // @param count the number of elements to insert
  1433   elem_type *InsertElementsAt(index_type index, size_type count) {
  1434     if (!base_type::InsertSlotsAt(index, count, sizeof(elem_type), MOZ_ALIGNOF(elem_type))) {
  1435       return nullptr;
  1438     // Initialize the extra array elements
  1439     elem_type *iter = Elements() + index, *end = iter + count;
  1440     for (; iter != end; ++iter) {
  1441       elem_traits::Construct(iter);
  1444     return Elements() + index;
  1447   // This method inserts elements into the array, constructing them
  1448   // elem_type's copy constructor (or whatever one-arg constructor
  1449   // happens to match the Item type).
  1450   // @param index the place to insert the new elements. This must be no
  1451   //              greater than the current length of the array.
  1452   // @param count the number of elements to insert.
  1453   // @param item the value to use when constructing the new elements.
  1454   template<class Item>
  1455   elem_type *InsertElementsAt(index_type index, size_type count,
  1456                               const Item& item) {
  1457     if (!base_type::InsertSlotsAt(index, count, sizeof(elem_type), MOZ_ALIGNOF(elem_type))) {
  1458       return nullptr;
  1461     // Initialize the extra array elements
  1462     elem_type *iter = Elements() + index, *end = iter + count;
  1463     for (; iter != end; ++iter) {
  1464       elem_traits::Construct(iter, item);
  1467     return Elements() + index;
  1470   // This method may be called to minimize the memory used by this array.
  1471   void Compact() {
  1472     ShrinkCapacity(sizeof(elem_type), MOZ_ALIGNOF(elem_type));
  1475   //
  1476   // Sorting
  1477   //
  1479   // This function is meant to be used with the NS_QuickSort function.  It
  1480   // maps the callback API expected by NS_QuickSort to the Comparator API
  1481   // used by nsTArray_Impl.  See nsTArray_Impl::Sort.
  1482   template<class Comparator>
  1483   static int Compare(const void* e1, const void* e2, void *data) {
  1484     const Comparator* c = reinterpret_cast<const Comparator*>(data);
  1485     const elem_type* a = static_cast<const elem_type*>(e1);
  1486     const elem_type* b = static_cast<const elem_type*>(e2);
  1487     return c->LessThan(*a, *b) ? -1 : (c->Equals(*a, *b) ? 0 : 1);
  1490   // This method sorts the elements of the array.  It uses the LessThan
  1491   // method defined on the given Comparator object to collate elements.
  1492   // @param comp The Comparator used to collate elements.
  1493   template<class Comparator>
  1494   void Sort(const Comparator& comp) {
  1495     NS_QuickSort(Elements(), Length(), sizeof(elem_type),
  1496                  Compare<Comparator>, const_cast<Comparator*>(&comp));
  1499   // A variation on the Sort method defined above that assumes that
  1500   // 'operator<' is defined for elem_type.
  1501   void Sort() {
  1502     Sort(nsDefaultComparator<elem_type, elem_type>());
  1505   //
  1506   // Binary Heap
  1507   //
  1509   // Sorts the array into a binary heap.
  1510   // @param comp The Comparator used to create the heap
  1511   template<class Comparator>
  1512   void MakeHeap(const Comparator& comp) {
  1513     if (!Length()) {
  1514       return;
  1516     index_type index = (Length() - 1) / 2;
  1517     do {
  1518       SiftDown(index, comp);
  1519     } while (index--);
  1522   // A variation on the MakeHeap method defined above.
  1523   void MakeHeap() {
  1524     MakeHeap(nsDefaultComparator<elem_type, elem_type>());
  1527   // Adds an element to the heap
  1528   // @param item The item to add
  1529   // @param comp The Comparator used to sift-up the item
  1530   template<class Item, class Comparator>
  1531   elem_type *PushHeap(const Item& item, const Comparator& comp) {
  1532     if (!base_type::InsertSlotsAt(Length(), 1, sizeof(elem_type), MOZ_ALIGNOF(elem_type))) {
  1533       return nullptr;
  1535     // Sift up the new node
  1536     elem_type *elem = Elements();
  1537     index_type index = Length() - 1;
  1538     index_type parent_index = (index - 1) / 2;
  1539     while (index && comp.LessThan(elem[parent_index], item)) {
  1540       elem[index] = elem[parent_index];
  1541       index = parent_index;
  1542       parent_index = (index - 1) / 2;
  1544     elem[index] = item;
  1545     return &elem[index];
  1548   // A variation on the PushHeap method defined above.
  1549   template<class Item>
  1550   elem_type *PushHeap(const Item& item) {
  1551     return PushHeap(item, nsDefaultComparator<elem_type, Item>());
  1554   // Delete the root of the heap and restore the heap
  1555   // @param comp The Comparator used to restore the heap
  1556   template<class Comparator>
  1557   void PopHeap(const Comparator& comp) {
  1558     if (!Length()) {
  1559       return;
  1561     index_type last_index = Length() - 1;
  1562     elem_type *elem = Elements();
  1563     elem[0] = elem[last_index];
  1564     TruncateLength(last_index);
  1565     if (Length()) {
  1566       SiftDown(0, comp);
  1570   // A variation on the PopHeap method defined above.
  1571   void PopHeap() {
  1572     PopHeap(nsDefaultComparator<elem_type, elem_type>());
  1575 protected:
  1576   using base_type::Hdr;
  1577   using base_type::ShrinkCapacity;
  1579   // This method invokes elem_type's destructor on a range of elements.
  1580   // @param start  The index of the first element to destroy.
  1581   // @param count  The number of elements to destroy.
  1582   void DestructRange(index_type start, size_type count) {
  1583     elem_type *iter = Elements() + start, *end = iter + count;
  1584     for (; iter != end; ++iter) {
  1585       elem_traits::Destruct(iter);
  1589   // This method invokes elem_type's copy-constructor on a range of elements.
  1590   // @param start   The index of the first element to construct.
  1591   // @param count   The number of elements to construct.
  1592   // @param values  The array of elements to copy.
  1593   template<class Item>
  1594   void AssignRange(index_type start, size_type count,
  1595                    const Item *values) {
  1596     AssignRangeAlgorithm<mozilla::IsPod<Item>::value,
  1597                          mozilla::IsSame<Item, elem_type>::value>
  1598       ::implementation(Elements(), start, count, values);
  1601   // This method sifts an item down to its proper place in a binary heap
  1602   // @param index The index of the node to start sifting down from
  1603   // @param comp  The Comparator used to sift down
  1604   template<class Comparator>
  1605   void SiftDown(index_type index, const Comparator& comp) {
  1606     elem_type *elem = Elements();
  1607     elem_type item = elem[index];
  1608     index_type end = Length() - 1;
  1609     while ((index * 2) < end) {
  1610       const index_type left = (index * 2) + 1;
  1611       const index_type right = (index * 2) + 2;
  1612       const index_type parent_index = index;
  1613       if (comp.LessThan(item, elem[left])) {
  1614         if (left < end &&
  1615             comp.LessThan(elem[left], elem[right])) {
  1616           index = right;
  1617         } else {
  1618           index = left;
  1620       } else if (left < end &&
  1621                  comp.LessThan(item, elem[right])) {
  1622         index = right;
  1623       } else {
  1624         break;
  1626       elem[parent_index] = elem[index];
  1628     elem[index] = item;
  1630 };
  1632 template <typename E, typename Alloc>
  1633 inline void
  1634 ImplCycleCollectionUnlink(nsTArray_Impl<E, Alloc>& aField)
  1636   aField.Clear();
  1639 template <typename E, typename Alloc>
  1640 inline void
  1641 ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& aCallback,
  1642                             nsTArray_Impl<E, Alloc>& aField,
  1643                             const char* aName,
  1644                             uint32_t aFlags = 0)
  1646   aFlags |= CycleCollectionEdgeNameArrayFlag;
  1647   uint32_t length = aField.Length();
  1648   for (uint32_t i = 0; i < length; ++i) {
  1649     ImplCycleCollectionTraverse(aCallback, aField[i], aName, aFlags);
  1653 //
  1654 // nsTArray is an infallible vector class.  See the comment at the top of this
  1655 // file for more details.
  1656 //
  1657 template <class E>
  1658 class nsTArray : public nsTArray_Impl<E, nsTArrayInfallibleAllocator>
  1660 public:
  1661   typedef nsTArray_Impl<E, nsTArrayInfallibleAllocator> base_type;
  1662   typedef nsTArray<E>                                   self_type;
  1663   typedef typename base_type::size_type                 size_type;
  1665   nsTArray() {}
  1666   explicit nsTArray(size_type capacity) : base_type(capacity) {}
  1667   explicit nsTArray(const nsTArray& other) : base_type(other) {}
  1669   template<class Allocator>
  1670   explicit nsTArray(const nsTArray_Impl<E, Allocator>& other) : base_type(other) {}
  1671 };
  1673 //
  1674 // FallibleTArray is a fallible vector class.
  1675 //
  1676 template <class E>
  1677 class FallibleTArray : public nsTArray_Impl<E, nsTArrayFallibleAllocator>
  1679 public:
  1680   typedef nsTArray_Impl<E, nsTArrayFallibleAllocator>   base_type;
  1681   typedef FallibleTArray<E>                             self_type;
  1682   typedef typename base_type::size_type                 size_type;
  1684   FallibleTArray() {}
  1685   explicit FallibleTArray(size_type capacity) : base_type(capacity) {}
  1686   explicit FallibleTArray(const FallibleTArray<E>& other) : base_type(other) {}
  1688   template<class Allocator>
  1689   explicit FallibleTArray(const nsTArray_Impl<E, Allocator>& other) : base_type(other) {}
  1690 };
  1692 //
  1693 // nsAutoArrayBase is a base class for AutoFallibleTArray and nsAutoTArray.
  1694 // You shouldn't use this class directly.
  1695 //
  1696 template <class TArrayBase, uint32_t N>
  1697 class nsAutoArrayBase : public TArrayBase
  1699 public:
  1700   typedef nsAutoArrayBase<TArrayBase, N> self_type;
  1701   typedef TArrayBase base_type;
  1702   typedef typename base_type::Header Header;
  1703   typedef typename base_type::elem_type elem_type;
  1705   template<typename Allocator>
  1706   self_type& operator=(const nsTArray_Impl<elem_type, Allocator>& other) {
  1707     base_type::operator=(other);
  1708     return *this;
  1711 protected:
  1712   nsAutoArrayBase() {
  1713     Init();
  1716   // We need this constructor because nsAutoTArray and friends all have
  1717   // implicit copy-constructors.  If we don't have this method, those
  1718   // copy-constructors will call nsAutoArrayBase's implicit copy-constructor,
  1719   // which won't call Init() and set up the auto buffer!
  1720   nsAutoArrayBase(const self_type &aOther) {
  1721     Init();
  1722     this->AppendElements(aOther);
  1725 private:
  1726   // nsTArray_base casts itself as an nsAutoArrayBase in order to get a pointer
  1727   // to mAutoBuf.
  1728   template<class Allocator, class Copier>
  1729   friend class nsTArray_base;
  1731   void Init() {
  1732     static_assert(MOZ_ALIGNOF(elem_type) <= 8,
  1733                   "can't handle alignments greater than 8, "
  1734                   "see nsTArray_base::UsesAutoArrayBuffer()");
  1735     // Temporary work around for VS2012 RC compiler crash
  1736     Header** phdr = base_type::PtrToHdr();
  1737     *phdr = reinterpret_cast<Header*>(&mAutoBuf);
  1738     (*phdr)->mLength = 0;
  1739     (*phdr)->mCapacity = N;
  1740     (*phdr)->mIsAutoArray = 1;
  1742     MOZ_ASSERT(base_type::GetAutoArrayBuffer(MOZ_ALIGNOF(elem_type)) ==
  1743                reinterpret_cast<Header*>(&mAutoBuf),
  1744                "GetAutoArrayBuffer needs to be fixed");
  1747   // Declare mAutoBuf aligned to the maximum of the header's alignment and
  1748   // elem_type's alignment.  We need to use a union rather than
  1749   // MOZ_ALIGNED_DECL because GCC is picky about what goes into
  1750   // __attribute__((aligned(foo))).
  1751   union {
  1752     char mAutoBuf[sizeof(nsTArrayHeader) + N * sizeof(elem_type)];
  1753     // Do the max operation inline to ensure that it is a compile-time constant.
  1754     mozilla::AlignedElem<(MOZ_ALIGNOF(Header) > MOZ_ALIGNOF(elem_type))
  1755                          ? MOZ_ALIGNOF(Header) : MOZ_ALIGNOF(elem_type)> mAlign;
  1756   };
  1757 };
  1759 //
  1760 // nsAutoTArray<E, N> is an infallible vector class with N elements of inline
  1761 // storage.  If you try to store more than N elements inside an
  1762 // nsAutoTArray<E, N>, we'll call malloc() and store them all on the heap.
  1763 //
  1764 // Note that you can cast an nsAutoTArray<E, N> to
  1765 // |const AutoFallibleTArray<E, N>&|.
  1766 //
  1767 template<class E, uint32_t N>
  1768 class nsAutoTArray : public nsAutoArrayBase<nsTArray<E>, N>
  1770   typedef nsAutoTArray<E, N> self_type;
  1771   typedef nsAutoArrayBase<nsTArray<E>, N> Base;
  1773 public:
  1774   nsAutoTArray() {}
  1776   template<typename Allocator>
  1777   explicit nsAutoTArray(const nsTArray_Impl<E, Allocator>& other) {
  1778     Base::AppendElements(other);
  1781   operator const AutoFallibleTArray<E, N>&() const {
  1782     return *reinterpret_cast<const AutoFallibleTArray<E, N>*>(this);
  1784 };
  1786 //
  1787 // AutoFallibleTArray<E, N> is a fallible vector class with N elements of
  1788 // inline storage.
  1789 //
  1790 template<class E, uint32_t N>
  1791 class AutoFallibleTArray : public nsAutoArrayBase<FallibleTArray<E>, N>
  1793   typedef AutoFallibleTArray<E, N> self_type;
  1794   typedef nsAutoArrayBase<FallibleTArray<E>, N> Base;
  1796 public:
  1797   AutoFallibleTArray() {}
  1799   template<typename Allocator>
  1800   explicit AutoFallibleTArray(const nsTArray_Impl<E, Allocator>& other) {
  1801     Base::AppendElements(other);
  1804   operator const nsAutoTArray<E, N>&() const {
  1805     return *reinterpret_cast<const nsAutoTArray<E, N>*>(this);
  1807 };
  1809 // Assert that nsAutoTArray doesn't have any extra padding inside.
  1810 //
  1811 // It's important that the data stored in this auto array takes up a multiple of
  1812 // 8 bytes; e.g. nsAutoTArray<uint32_t, 1> wouldn't work.  Since nsAutoTArray
  1813 // contains a pointer, its size must be a multiple of alignof(void*).  (This is
  1814 // because any type may be placed into an array, and there's no padding between
  1815 // elements of an array.)  The compiler pads the end of the structure to
  1816 // enforce this rule.
  1817 //
  1818 // If we used nsAutoTArray<uint32_t, 1> below, this assertion would fail on a
  1819 // 64-bit system, where the compiler inserts 4 bytes of padding at the end of
  1820 // the auto array to make its size a multiple of alignof(void*) == 8 bytes.
  1822 static_assert(sizeof(nsAutoTArray<uint32_t, 2>) ==
  1823               sizeof(void*) + sizeof(nsTArrayHeader) + sizeof(uint32_t) * 2,
  1824               "nsAutoTArray shouldn't contain any extra padding, "
  1825               "see the comment");
  1827 // Definitions of nsTArray_Impl methods
  1828 #include "nsTArray-inl.h"
  1830 #endif  // nsTArray_h__

mercurial