LCOV - code coverage report
Current view: top level - xpcom/ds - nsTArray.h (source / functions) Hit Total Coverage
Test: output.info Lines: 450 588 76.5 %
Date: 2017-07-14 16:53:18 Functions: 8743 42519 20.6 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
       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/. */
       6             : 
       7             : #ifndef nsTArray_h__
       8             : #define nsTArray_h__
       9             : 
      10             : #include "nsTArrayForwardDeclare.h"
      11             : #include "mozilla/Alignment.h"
      12             : #include "mozilla/ArrayIterator.h"
      13             : #include "mozilla/Assertions.h"
      14             : #include "mozilla/Attributes.h"
      15             : #include "mozilla/BinarySearch.h"
      16             : #include "mozilla/fallible.h"
      17             : #include "mozilla/MathAlgorithms.h"
      18             : #include "mozilla/MemoryReporting.h"
      19             : #include "mozilla/Move.h"
      20             : #include "mozilla/ReverseIterator.h"
      21             : #include "mozilla/TypeTraits.h"
      22             : #include "mozilla/Span.h"
      23             : 
      24             : #include <string.h>
      25             : 
      26             : #include "nsCycleCollectionNoteChild.h"
      27             : #include "nsAlgorithm.h"
      28             : #include "nscore.h"
      29             : #include "nsQuickSort.h"
      30             : #include "nsDebug.h"
      31             : #include "nsISupportsImpl.h"
      32             : #include "nsRegionFwd.h"
      33             : #include <functional>
      34             : #include <initializer_list>
      35             : #include <new>
      36             : 
      37             : namespace JS {
      38             : template<class T>
      39             : class Heap;
      40             : } /* namespace JS */
      41             : 
      42             : class nsRegion;
      43             : namespace mozilla {
      44             : namespace layers {
      45             : struct TileClient;
      46             : } // namespace layers
      47             : } // namespace mozilla
      48             : 
      49             : namespace mozilla {
      50             : struct SerializedStructuredCloneBuffer;
      51             : class SourceBufferTask;
      52             : } // namespace mozilla
      53             : 
      54             : namespace mozilla {
      55             : namespace dom {
      56             : namespace ipc {
      57             : class StructuredCloneData;
      58             : } // namespace ipc
      59             : } // namespace dom
      60             : } // namespace mozilla
      61             : 
      62             : namespace mozilla {
      63             : namespace dom {
      64             : class ClonedMessageData;
      65             : class MessagePortMessage;
      66             : namespace indexedDB {
      67             : struct StructuredCloneReadInfo;
      68             : class SerializedStructuredCloneReadInfo;
      69             : class ObjectStoreCursorResponse;
      70             : } // namespace indexedDB
      71             : } // namespace dom
      72             : } // namespace mozilla
      73             : 
      74             : class JSStructuredCloneData;
      75             : 
      76             : //
      77             : // nsTArray is a resizable array class, like std::vector.
      78             : //
      79             : // Unlike std::vector, which follows C++'s construction/destruction rules,
      80             : // nsTArray assumes that your "T" can be memmoved()'ed safely.
      81             : //
      82             : // The public classes defined in this header are
      83             : //
      84             : //   nsTArray<T>,
      85             : //   FallibleTArray<T>,
      86             : //   AutoTArray<T, N>, and
      87             : //
      88             : // nsTArray and AutoTArray are infallible by default. To opt-in to fallible
      89             : // behaviour, use the `mozilla::fallible` parameter and check the return value.
      90             : //
      91             : // If you just want to declare the nsTArray types (e.g., if you're in a header
      92             : // file and don't need the full nsTArray definitions) consider including
      93             : // nsTArrayForwardDeclare.h instead of nsTArray.h.
      94             : //
      95             : // The template parameter (i.e., T in nsTArray<T>) specifies the type of the
      96             : // elements and has the following requirements:
      97             : //
      98             : //   T MUST be safely memmove()'able.
      99             : //   T MUST define a copy-constructor.
     100             : //   T MAY define operator< for sorting.
     101             : //   T MAY define operator== for searching.
     102             : //
     103             : // (Note that the memmove requirement may be relaxed for certain types - see
     104             : // nsTArray_CopyChooser below.)
     105             : //
     106             : // For methods taking a Comparator instance, the Comparator must be a class
     107             : // defining the following methods:
     108             : //
     109             : //   class Comparator {
     110             : //     public:
     111             : //       /** @return True if the elements are equals; false otherwise. */
     112             : //       bool Equals(const elem_type& a, const Item& b) const;
     113             : //
     114             : //       /** @return True if (a < b); false otherwise. */
     115             : //       bool LessThan(const elem_type& a, const Item& b) const;
     116             : //   };
     117             : //
     118             : // The Equals method is used for searching, and the LessThan method is used for
     119             : // searching and sorting.  The |Item| type above can be arbitrary, but must
     120             : // match the Item type passed to the sort or search function.
     121             : //
     122             : 
     123             : 
     124             : //
     125             : // nsTArrayFallibleResult and nsTArrayInfallibleResult types are proxy types
     126             : // which are used because you cannot use a templated type which is bound to
     127             : // void as an argument to a void function.  In order to work around that, we
     128             : // encode either a void or a boolean inside these proxy objects, and pass them
     129             : // to the aforementioned function instead, and then use the type information to
     130             : // decide what to do in the function.
     131             : //
     132             : // Note that public nsTArray methods should never return a proxy type.  Such
     133             : // types are only meant to be used in the internal nsTArray helper methods.
     134             : // Public methods returning non-proxy types cannot be called from other
     135             : // nsTArray members.
     136             : //
     137             : struct nsTArrayFallibleResult
     138             : {
     139             :   // Note: allows implicit conversions from and to bool
     140        2650 :   MOZ_IMPLICIT nsTArrayFallibleResult(bool aResult) : mResult(aResult) {}
     141             : 
     142        1353 :   MOZ_IMPLICIT operator bool() { return mResult; }
     143             : 
     144             : private:
     145             :   bool mResult;
     146             : };
     147             : 
     148             : struct nsTArrayInfallibleResult
     149             : {
     150             : };
     151             : 
     152             : //
     153             : // nsTArray*Allocators must all use the same |free()|, to allow swap()'ing
     154             : // between fallible and infallible variants.
     155             : //
     156             : 
     157             : struct nsTArrayFallibleAllocatorBase
     158             : {
     159             :   typedef bool ResultType;
     160             :   typedef nsTArrayFallibleResult ResultTypeProxy;
     161             : 
     162         479 :   static ResultType Result(ResultTypeProxy aResult) { return aResult; }
     163         874 :   static bool Successful(ResultTypeProxy aResult) { return aResult; }
     164        2650 :   static ResultTypeProxy SuccessResult() { return true; }
     165           0 :   static ResultTypeProxy FailureResult() { return false; }
     166        1439 :   static ResultType ConvertBoolToResultType(bool aValue) { return aValue; }
     167             : };
     168             : 
     169             : struct nsTArrayInfallibleAllocatorBase
     170             : {
     171             :   typedef void ResultType;
     172             :   typedef nsTArrayInfallibleResult ResultTypeProxy;
     173             : 
     174       24748 :   static ResultType Result(ResultTypeProxy aResult) {}
     175      217762 :   static bool Successful(ResultTypeProxy) { return true; }
     176      243391 :   static ResultTypeProxy SuccessResult() { return ResultTypeProxy(); }
     177             : 
     178           0 :   static ResultTypeProxy FailureResult()
     179             :   {
     180           0 :     MOZ_CRASH("Infallible nsTArray should never fail");
     181             :     return ResultTypeProxy();
     182             :   }
     183             : 
     184        2746 :   static ResultType ConvertBoolToResultType(bool aValue)
     185             :   {
     186        2746 :     if (!aValue) {
     187           0 :       MOZ_CRASH("infallible nsTArray should never convert false to ResultType");
     188             :     }
     189        2746 :   }
     190             : };
     191             : 
     192             : struct nsTArrayFallibleAllocator : nsTArrayFallibleAllocatorBase
     193             : {
     194         997 :   static void* Malloc(size_t aSize) { return malloc(aSize); }
     195         323 :   static void* Realloc(void* aPtr, size_t aSize)
     196             :   {
     197         323 :     return realloc(aPtr, aSize);
     198             :   }
     199             : 
     200       11770 :   static void Free(void* aPtr) { free(aPtr); }
     201           0 :   static void SizeTooBig(size_t) {}
     202             : };
     203             : 
     204             : #if defined(MOZALLOC_HAVE_XMALLOC)
     205             : #include "mozilla/mozalloc_abort.h"
     206             : 
     207             : struct nsTArrayInfallibleAllocator : nsTArrayInfallibleAllocatorBase
     208             : {
     209       21468 :   static void* Malloc(size_t aSize) { return moz_xmalloc(aSize); }
     210       11688 :   static void* Realloc(void* aPtr, size_t aSize)
     211             :   {
     212       11688 :     return moz_xrealloc(aPtr, aSize);
     213             :   }
     214             : 
     215         333 :   static void Free(void* aPtr) { free(aPtr); }
     216           0 :   static void SizeTooBig(size_t aSize) { NS_ABORT_OOM(aSize); }
     217             : };
     218             : 
     219             : #else
     220             : #include <stdlib.h>
     221             : 
     222             : struct nsTArrayInfallibleAllocator : nsTArrayInfallibleAllocatorBase
     223             : {
     224             :   static void* Malloc(size_t aSize)
     225             :   {
     226             :     void* ptr = malloc(aSize);
     227             :     if (MOZ_UNLIKELY(!ptr)) {
     228             :       NS_ABORT_OOM(aSize);
     229             :     }
     230             :     return ptr;
     231             :   }
     232             : 
     233             :   static void* Realloc(void* aPtr, size_t aSize)
     234             :   {
     235             :     void* newptr = realloc(aPtr, aSize);
     236             :     if (MOZ_UNLIKELY(!newptr && aSize)) {
     237             :       NS_ABORT_OOM(aSize);
     238             :     }
     239             :     return newptr;
     240             :   }
     241             : 
     242             :   static void Free(void* aPtr) { free(aPtr); }
     243             :   static void SizeTooBig(size_t aSize) { NS_ABORT_OOM(aSize); }
     244             : };
     245             : 
     246             : #endif
     247             : 
     248             : // nsTArray_base stores elements into the space allocated beyond
     249             : // sizeof(*this).  This is done to minimize the size of the nsTArray
     250             : // object when it is empty.
     251             : struct nsTArrayHeader
     252             : {
     253             :   static nsTArrayHeader sEmptyHdr;
     254             : 
     255             :   uint32_t mLength;
     256             :   uint32_t mCapacity : 31;
     257             :   uint32_t mIsAutoArray : 1;
     258             : };
     259             : 
     260             : // This class provides a SafeElementAt method to nsTArray<T*> which does
     261             : // not take a second default value parameter.
     262             : template<class E, class Derived>
     263      124390 : struct nsTArray_SafeElementAtHelper
     264             : {
     265             :   typedef E*       elem_type;
     266             :   typedef size_t   index_type;
     267             : 
     268             :   // No implementation is provided for these two methods, and that is on
     269             :   // purpose, since we don't support these functions on non-pointer type
     270             :   // instantiations.
     271             :   elem_type& SafeElementAt(index_type aIndex);
     272             :   const elem_type& SafeElementAt(index_type aIndex) const;
     273             : };
     274             : 
     275             : template<class E, class Derived>
     276       44605 : struct nsTArray_SafeElementAtHelper<E*, Derived>
     277             : {
     278             :   typedef E*       elem_type;
     279             :   //typedef const E* const_elem_type;   XXX: see below
     280             :   typedef size_t   index_type;
     281             : 
     282        2632 :   elem_type SafeElementAt(index_type aIndex)
     283             :   {
     284        2632 :     return static_cast<Derived*>(this)->SafeElementAt(aIndex, nullptr);
     285             :   }
     286             : 
     287             :   // XXX: Probably should return const_elem_type, but callsites must be fixed.
     288             :   // Also, the use of const_elem_type for nsTArray<xpcGCCallback> in
     289             :   // xpcprivate.h causes build failures on Windows because xpcGCCallback is a
     290             :   // function pointer and MSVC doesn't like qualifying it with |const|.
     291           0 :   elem_type SafeElementAt(index_type aIndex) const
     292             :   {
     293           0 :     return static_cast<const Derived*>(this)->SafeElementAt(aIndex, nullptr);
     294             :   }
     295             : };
     296             : 
     297             : // E is the base type that the smart pointer is templated over; the
     298             : // smart pointer can act as E*.
     299             : template<class E, class Derived>
     300       17075 : struct nsTArray_SafeElementAtSmartPtrHelper
     301             : {
     302             :   typedef E*       elem_type;
     303             :   typedef const E* const_elem_type;
     304             :   typedef size_t   index_type;
     305             : 
     306          49 :   elem_type SafeElementAt(index_type aIndex)
     307             :   {
     308          49 :     return static_cast<Derived*>(this)->SafeElementAt(aIndex, nullptr);
     309             :   }
     310             : 
     311             :   // XXX: Probably should return const_elem_type, but callsites must be fixed.
     312           0 :   elem_type SafeElementAt(index_type aIndex) const
     313             :   {
     314           0 :     return static_cast<const Derived*>(this)->SafeElementAt(aIndex, nullptr);
     315             :   }
     316             : };
     317             : 
     318             : template<class T> class nsCOMPtr;
     319             : 
     320             : template<class E, class Derived>
     321        5855 : struct nsTArray_SafeElementAtHelper<nsCOMPtr<E>, Derived>
     322             :   : public nsTArray_SafeElementAtSmartPtrHelper<E, Derived>
     323             : {
     324             : };
     325             : 
     326             : template<class E, class Derived>
     327       11220 : struct nsTArray_SafeElementAtHelper<RefPtr<E>, Derived>
     328             :   : public nsTArray_SafeElementAtSmartPtrHelper<E, Derived>
     329             : {
     330             : };
     331             : 
     332             : namespace mozilla {
     333             : template<class T> class OwningNonNull;
     334             : } // namespace mozilla
     335             : 
     336             : template<class E, class Derived>
     337          13 : struct nsTArray_SafeElementAtHelper<mozilla::OwningNonNull<E>, Derived>
     338             : {
     339             :   typedef E*       elem_type;
     340             :   typedef const E* const_elem_type;
     341             :   typedef size_t   index_type;
     342             : 
     343           0 :   elem_type SafeElementAt(index_type aIndex)
     344             :   {
     345           0 :     if (aIndex < static_cast<Derived*>(this)->Length()) {
     346           0 :       return static_cast<Derived*>(this)->ElementAt(aIndex);
     347             :     }
     348           0 :     return nullptr;
     349             :   }
     350             : 
     351             :   // XXX: Probably should return const_elem_type, but callsites must be fixed.
     352             :   elem_type SafeElementAt(index_type aIndex) const
     353             :   {
     354             :     if (aIndex < static_cast<const Derived*>(this)->Length()) {
     355             :       return static_cast<const Derived*>(this)->ElementAt(aIndex);
     356             :     }
     357             :     return nullptr;
     358             :   }
     359             : };
     360             : 
     361             : // Servo bindings.
     362             : extern "C" void Gecko_EnsureTArrayCapacity(void* aArray,
     363             :                                            size_t aCapacity,
     364             :                                            size_t aElementSize);
     365             : extern "C" void Gecko_ClearPODTArray(void* aArray,
     366             :                                      size_t aElementSize,
     367             :                                      size_t aElementAlign);
     368             : 
     369             : MOZ_NORETURN MOZ_COLD void
     370             : InvalidArrayIndex_CRASH(size_t aIndex, size_t aLength);
     371             : 
     372             : //
     373             : // This class serves as a base class for nsTArray.  It shouldn't be used
     374             : // directly.  It holds common implementation code that does not depend on the
     375             : // element type of the nsTArray.
     376             : //
     377             : template<class Alloc, class Copy>
     378             : class nsTArray_base
     379             : {
     380             :   // Allow swapping elements with |nsTArray_base|s created using a
     381             :   // different allocator.  This is kosher because all allocators use
     382             :   // the same free().
     383             :   template<class Allocator, class Copier>
     384             :   friend class nsTArray_base;
     385             :   friend void Gecko_EnsureTArrayCapacity(void* aArray, size_t aCapacity,
     386             :                                          size_t aElemSize);
     387             :   friend void Gecko_ClearPODTArray(void* aTArray, size_t aElementSize,
     388             :                                    size_t aElementAlign);
     389             : 
     390             : protected:
     391             :   typedef nsTArrayHeader Header;
     392             : 
     393             : public:
     394             :   typedef size_t size_type;
     395             :   typedef size_t index_type;
     396             : 
     397             :   // @return The number of elements in the array.
     398     2538235 :   size_type Length() const { return mHdr->mLength; }
     399             : 
     400             :   // @return True if the array is empty or false otherwise.
     401      181999 :   bool IsEmpty() const { return Length() == 0; }
     402             : 
     403             :   // @return The number of elements that can fit in the array without forcing
     404             :   // the array to be re-allocated.  The length of an array is always less
     405             :   // than or equal to its capacity.
     406       22032 :   size_type Capacity() const {  return mHdr->mCapacity; }
     407             : 
     408             : #ifdef DEBUG
     409           0 :   void* DebugGetHeader() const { return mHdr; }
     410             : #endif
     411             : 
     412             : protected:
     413             :   nsTArray_base();
     414             : 
     415             :   ~nsTArray_base();
     416             : 
     417             :   // Resize the storage if necessary to achieve the requested capacity.
     418             :   // @param aCapacity The requested number of array elements.
     419             :   // @param aElemSize The size of an array element.
     420             :   // @return False if insufficient memory is available; true otherwise.
     421             :   template<typename ActualAlloc>
     422             :   typename ActualAlloc::ResultTypeProxy EnsureCapacity(size_type aCapacity,
     423             :                                                        size_type aElemSize);
     424             : 
     425             :   // Tries to resize the storage to the minimum required amount. If this fails,
     426             :   // the array is left as-is.
     427             :   // @param aElemSize  The size of an array element.
     428             :   // @param aElemAlign The alignment in bytes of an array element.
     429             :   void ShrinkCapacity(size_type aElemSize, size_t aElemAlign);
     430             : 
     431             :   // This method may be called to resize a "gap" in the array by shifting
     432             :   // elements around.  It updates mLength appropriately.  If the resulting
     433             :   // array has zero elements, then the array's memory is free'd.
     434             :   // @param aStart     The starting index of the gap.
     435             :   // @param aOldLen    The current length of the gap.
     436             :   // @param aNewLen    The desired length of the gap.
     437             :   // @param aElemSize  The size of an array element.
     438             :   // @param aElemAlign The alignment in bytes of an array element.
     439             :   template<typename ActualAlloc>
     440             :   void ShiftData(index_type aStart, size_type aOldLen, size_type aNewLen,
     441             :                  size_type aElemSize, size_t aElemAlign);
     442             : 
     443             :   // This method increments the length member of the array's header.
     444             :   // Note that mHdr may actually be sEmptyHdr in the case where a
     445             :   // zero-length array is inserted into our array. But then aNum should
     446             :   // always be 0.
     447      180279 :   void IncrementLength(size_t aNum)
     448             :   {
     449      180279 :     if (mHdr == EmptyHdr()) {
     450       12190 :       if (MOZ_UNLIKELY(aNum != 0)) {
     451             :         // Writing a non-zero length to the empty header would be extremely bad.
     452           0 :         MOZ_CRASH();
     453             :       }
     454             :     } else {
     455      168092 :       mHdr->mLength += aNum;
     456             :     }
     457      180282 :   }
     458             : 
     459             :   // This method inserts blank slots into the array.
     460             :   // @param aIndex the place to insert the new elements. This must be no
     461             :   //               greater than the current length of the array.
     462             :   // @param aCount the number of slots to insert
     463             :   // @param aElementSize the size of an array element.
     464             :   // @param aElemAlign the alignment in bytes of an array element.
     465             :   template<typename ActualAlloc>
     466             :   bool InsertSlotsAt(index_type aIndex, size_type aCount,
     467             :                      size_type aElementSize, size_t aElemAlign);
     468             : 
     469             :   template<typename ActualAlloc, class Allocator>
     470             :   typename ActualAlloc::ResultTypeProxy
     471             :   SwapArrayElements(nsTArray_base<Allocator, Copy>& aOther,
     472             :                     size_type aElemSize,
     473             :                     size_t aElemAlign);
     474             : 
     475             :   // This is an RAII class used in SwapArrayElements.
     476             :   class IsAutoArrayRestorer
     477             :   {
     478             :   public:
     479             :     IsAutoArrayRestorer(nsTArray_base<Alloc, Copy>& aArray, size_t aElemAlign);
     480             :     ~IsAutoArrayRestorer();
     481             : 
     482             :   private:
     483             :     nsTArray_base<Alloc, Copy>& mArray;
     484             :     size_t mElemAlign;
     485             :     bool mIsAuto;
     486             :   };
     487             : 
     488             :   // Helper function for SwapArrayElements. Ensures that if the array
     489             :   // is an AutoTArray that it doesn't use the built-in buffer.
     490             :   template<typename ActualAlloc>
     491             :   bool EnsureNotUsingAutoArrayBuffer(size_type aElemSize);
     492             : 
     493             :   // Returns true if this nsTArray is an AutoTArray with a built-in buffer.
     494      525301 :   bool IsAutoArray() const { return mHdr->mIsAutoArray; }
     495             : 
     496             :   // Returns a Header for the built-in buffer of this AutoTArray.
     497       74460 :   Header* GetAutoArrayBuffer(size_t aElemAlign)
     498             :   {
     499       74460 :     MOZ_ASSERT(IsAutoArray(), "Should be an auto array to call this");
     500       74460 :     return GetAutoArrayBufferUnsafe(aElemAlign);
     501             :   }
     502      387644 :   const Header* GetAutoArrayBuffer(size_t aElemAlign) const
     503             :   {
     504      387644 :     MOZ_ASSERT(IsAutoArray(), "Should be an auto array to call this");
     505      387644 :     return GetAutoArrayBufferUnsafe(aElemAlign);
     506             :   }
     507             : 
     508             :   // Returns a Header for the built-in buffer of this AutoTArray, but doesn't
     509             :   // assert that we are an AutoTArray.
     510       76282 :   Header* GetAutoArrayBufferUnsafe(size_t aElemAlign)
     511             :   {
     512             :     return const_cast<Header*>(static_cast<const nsTArray_base<Alloc, Copy>*>(
     513       76282 :       this)->GetAutoArrayBufferUnsafe(aElemAlign));
     514             :   }
     515             :   const Header* GetAutoArrayBufferUnsafe(size_t aElemAlign) const;
     516             : 
     517             :   // Returns true if this is an AutoTArray and it currently uses the
     518             :   // built-in buffer to store its elements.
     519             :   bool UsesAutoArrayBuffer() const;
     520             : 
     521             :   // The array's elements (prefixed with a Header).  This pointer is never
     522             :   // null.  If the array is empty, then this will point to sEmptyHdr.
     523             :   Header* mHdr;
     524             : 
     525     1753422 :   Header* Hdr() const { return mHdr; }
     526       72348 :   Header** PtrToHdr() { return &mHdr; }
     527      681886 :   static Header* EmptyHdr() { return &Header::sEmptyHdr; }
     528             : };
     529             : 
     530             : //
     531             : // This class defines convenience functions for element specific operations.
     532             : // Specialize this template if necessary.
     533             : //
     534             : template<class E>
     535             : class nsTArrayElementTraits
     536             : {
     537             : public:
     538             :   // Invoke the default constructor in place.
     539     1395010 :   static inline void Construct(E* aE)
     540             :   {
     541             :     // Do NOT call "E()"! That triggers C++ "default initialization"
     542             :     // which zeroes out POD ("plain old data") types such as regular
     543             :     // ints.  We don't want that because it can be a performance issue
     544             :     // and people don't expect it; nsTArray should work like a regular
     545             :     // C/C++ array in this respect.
     546     1395010 :     new (static_cast<void*>(aE)) E;
     547     1395010 :   }
     548             :   // Invoke the copy-constructor in place.
     549             :   template<class A>
     550      125730 :   static inline void Construct(E* aE, A&& aArg)
     551             :   {
     552             :     typedef typename mozilla::RemoveCV<E>::Type E_NoCV;
     553             :     typedef typename mozilla::RemoveCV<A>::Type A_NoCV;
     554             :     static_assert(!mozilla::IsSame<E_NoCV*, A_NoCV>::value,
     555             :                   "For safety, we disallow constructing nsTArray<E> elements "
     556             :                   "from E* pointers. See bug 960591.");
     557      125730 :     new (static_cast<void*>(aE)) E(mozilla::Forward<A>(aArg));
     558      125730 :   }
     559             :   // Invoke the destructor in place.
     560     1343886 :   static inline void Destruct(E* aE) { aE->~E(); }
     561             : };
     562             : 
     563             : // The default comparator used by nsTArray
     564             : template<class A, class B>
     565             : class nsDefaultComparator
     566             : {
     567             : public:
     568      291773 :   bool Equals(const A& aA, const B& aB) const { return aA == aB; }
     569       19881 :   bool LessThan(const A& aA, const B& aB) const { return aA < aB; }
     570             : };
     571             : 
     572             : template<bool IsPod, bool IsSameType>
     573             : struct AssignRangeAlgorithm
     574             : {
     575             :   template<class Item, class ElemType, class IndexType, class SizeType>
     576       19640 :   static void implementation(ElemType* aElements, IndexType aStart,
     577             :                              SizeType aCount, const Item* aValues)
     578             :   {
     579       19640 :     ElemType* iter = aElements + aStart;
     580       19640 :     ElemType* end = iter + aCount;
     581       27060 :     for (; iter != end; ++iter, ++aValues) {
     582        3710 :       nsTArrayElementTraits<ElemType>::Construct(iter, *aValues);
     583             :     }
     584       19640 :   }
     585             : };
     586             : 
     587             : template<>
     588             : struct AssignRangeAlgorithm<true, true>
     589             : {
     590             :   template<class Item, class ElemType, class IndexType, class SizeType>
     591        5052 :   static void implementation(ElemType* aElements, IndexType aStart,
     592             :                              SizeType aCount, const Item* aValues)
     593             :   {
     594        5052 :     memcpy(aElements + aStart, aValues, aCount * sizeof(ElemType));
     595        5052 :   }
     596             : };
     597             : 
     598             : //
     599             : // Normally elements are copied with memcpy and memmove, but for some element
     600             : // types that is problematic.  The nsTArray_CopyChooser template class can be
     601             : // specialized to ensure that copying calls constructors and destructors
     602             : // instead, as is done below for JS::Heap<E> elements.
     603             : //
     604             : 
     605             : //
     606             : // A class that defines how to copy elements using memcpy/memmove.
     607             : //
     608             : struct nsTArray_CopyWithMemutils
     609             : {
     610             :   const static bool allowRealloc = true;
     611             : 
     612        4531 :   static void MoveNonOverlappingRegionWithHeader(void* aDest, const void* aSrc,
     613             :                                                  size_t aCount, size_t aElemSize)
     614             :   {
     615        4531 :     memcpy(aDest, aSrc, sizeof(nsTArrayHeader) + aCount * aElemSize);
     616        4531 :   }
     617             : 
     618        2245 :   static void MoveOverlappingRegion(void* aDest, void* aSrc, size_t aCount,
     619             :                                     size_t aElemSize)
     620             :   {
     621        2245 :     memmove(aDest, aSrc, aCount * aElemSize);
     622        2245 :   }
     623             : 
     624       24905 :   static void MoveNonOverlappingRegion(void* aDest, void* aSrc, size_t aCount,
     625             :                                        size_t aElemSize)
     626             :   {
     627       24905 :     memcpy(aDest, aSrc, aCount * aElemSize);
     628       24905 :   }
     629             : };
     630             : 
     631             : //
     632             : // A template class that defines how to copy elements calling their constructors
     633             : // and destructors appropriately.
     634             : //
     635             : template<class ElemType>
     636             : struct nsTArray_CopyWithConstructors
     637             : {
     638             :   typedef nsTArrayElementTraits<ElemType> traits;
     639             : 
     640             :   const static bool allowRealloc = false;
     641             : 
     642          14 :   static void MoveNonOverlappingRegionWithHeader(void* aDest, void* aSrc, size_t aCount,
     643             :                                                  size_t aElemSize)
     644             :   {
     645          14 :     nsTArrayHeader* destHeader = static_cast<nsTArrayHeader*>(aDest);
     646          14 :     nsTArrayHeader* srcHeader = static_cast<nsTArrayHeader*>(aSrc);
     647          14 :     *destHeader = *srcHeader;
     648          14 :     MoveNonOverlappingRegion(static_cast<uint8_t*>(aDest) + sizeof(nsTArrayHeader),
     649             :                              static_cast<uint8_t*>(aSrc) + sizeof(nsTArrayHeader),
     650             :                              aCount, aElemSize);
     651          14 :   }
     652             : 
     653             :   // These functions are defined by analogy with memmove and memcpy.
     654             :   // What they actually do is slightly different: MoveOverlappingRegion
     655             :   // checks to see which direction the movement needs to take place,
     656             :   // whether from back-to-front of the range to be moved or from
     657             :   // front-to-back.  MoveNonOverlappingRegion assumes that moving
     658             :   // front-to-back is always valid.  So they're really more like
     659             :   // std::move{_backward,} in that respect.  We keep these names because
     660             :   // we think they read slightly better, and MoveNonOverlappingRegion is
     661             :   // only ever called on overlapping regions from MoveOverlappingRegion.
     662           0 :   static void MoveOverlappingRegion(void* aDest, void* aSrc, size_t aCount,
     663             :                                     size_t aElemSize)
     664             :   {
     665           0 :     ElemType* destElem = static_cast<ElemType*>(aDest);
     666           0 :     ElemType* srcElem = static_cast<ElemType*>(aSrc);
     667           0 :     ElemType* destElemEnd = destElem + aCount;
     668           0 :     ElemType* srcElemEnd = srcElem + aCount;
     669           0 :     if (destElem == srcElem) {
     670           0 :       return;  // In practice, we don't do this.
     671             :     }
     672             : 
     673             :     // Figure out whether to copy back-to-front or front-to-back.
     674           0 :     if (srcElemEnd > destElem && srcElemEnd < destElemEnd) {
     675           0 :       while (destElemEnd != destElem) {
     676           0 :         --destElemEnd;
     677           0 :         --srcElemEnd;
     678           0 :         traits::Construct(destElemEnd, mozilla::Move(*srcElemEnd));
     679           0 :         traits::Destruct(srcElemEnd);
     680             :       }
     681             :     } else {
     682           0 :       MoveNonOverlappingRegion(aDest, aSrc, aCount, aElemSize);
     683             :     }
     684             :   }
     685             : 
     686          14 :   static void MoveNonOverlappingRegion(void* aDest, void* aSrc, size_t aCount,
     687             :                                        size_t aElemSize)
     688             :   {
     689          14 :     ElemType* destElem = static_cast<ElemType*>(aDest);
     690          14 :     ElemType* srcElem = static_cast<ElemType*>(aSrc);
     691          14 :     ElemType* destElemEnd = destElem + aCount;
     692             : #ifdef DEBUG
     693          14 :     ElemType* srcElemEnd = srcElem + aCount;
     694          14 :     MOZ_ASSERT(srcElemEnd <= destElem || srcElemEnd > destElemEnd);
     695             : #endif
     696         120 :     while (destElem != destElemEnd) {
     697          53 :       traits::Construct(destElem, mozilla::Move(*srcElem));
     698          53 :       traits::Destruct(srcElem);
     699          53 :       ++destElem;
     700          53 :       ++srcElem;
     701             :     }
     702          14 :   }
     703             : };
     704             : 
     705             : //
     706             : // The default behaviour is to use memcpy/memmove for everything.
     707             : //
     708             : template<class E>
     709             : struct MOZ_NEEDS_MEMMOVABLE_TYPE nsTArray_CopyChooser
     710             : {
     711             :   typedef nsTArray_CopyWithMemutils Type;
     712             : };
     713             : 
     714             : //
     715             : // Some classes require constructors/destructors to be called, so they are
     716             : // specialized here.
     717             : //
     718             : #define DECLARE_USE_COPY_CONSTRUCTORS(T)                \
     719             :   template<>                                            \
     720             :   struct nsTArray_CopyChooser<T>                        \
     721             :   {                                                     \
     722             :     typedef nsTArray_CopyWithConstructors<T> Type;      \
     723             :   };
     724             : 
     725             : template<class E>
     726             : struct nsTArray_CopyChooser<JS::Heap<E>>
     727             : {
     728             :   typedef nsTArray_CopyWithConstructors<JS::Heap<E>> Type;
     729             : };
     730             : 
     731             : DECLARE_USE_COPY_CONSTRUCTORS(nsRegion)
     732             : DECLARE_USE_COPY_CONSTRUCTORS(nsIntRegion)
     733             : DECLARE_USE_COPY_CONSTRUCTORS(mozilla::layers::TileClient)
     734             : DECLARE_USE_COPY_CONSTRUCTORS(mozilla::SerializedStructuredCloneBuffer)
     735             : DECLARE_USE_COPY_CONSTRUCTORS(mozilla::dom::ipc::StructuredCloneData)
     736             : DECLARE_USE_COPY_CONSTRUCTORS(mozilla::dom::ClonedMessageData)
     737             : DECLARE_USE_COPY_CONSTRUCTORS(mozilla::dom::indexedDB::StructuredCloneReadInfo);
     738             : DECLARE_USE_COPY_CONSTRUCTORS(mozilla::dom::indexedDB::ObjectStoreCursorResponse)
     739             : DECLARE_USE_COPY_CONSTRUCTORS(mozilla::dom::indexedDB::SerializedStructuredCloneReadInfo);
     740             : DECLARE_USE_COPY_CONSTRUCTORS(JSStructuredCloneData)
     741             : DECLARE_USE_COPY_CONSTRUCTORS(mozilla::dom::MessagePortMessage)
     742             : DECLARE_USE_COPY_CONSTRUCTORS(mozilla::SourceBufferTask)
     743             : 
     744             : template<typename T>
     745             : struct nsTArray_CopyChooser<std::function<T>>
     746             : {
     747             :   typedef nsTArray_CopyWithConstructors<std::function<T>> Type;
     748             : };
     749             : 
     750             : 
     751             : //
     752             : // Base class for nsTArray_Impl that is templated on element type and derived
     753             : // nsTArray_Impl class, to allow extra conversions to be added for specific
     754             : // types.
     755             : //
     756             : template<class E, class Derived>
     757      186055 : struct nsTArray_TypedBase : public nsTArray_SafeElementAtHelper<E, Derived>
     758             : {
     759             : };
     760             : 
     761             : //
     762             : // Specialization of nsTArray_TypedBase for arrays containing JS::Heap<E>
     763             : // elements.
     764             : //
     765             : // These conversions are safe because JS::Heap<E> and E share the same
     766             : // representation, and since the result of the conversions are const references
     767             : // we won't miss any barriers.
     768             : //
     769             : // The static_cast is necessary to obtain the correct address for the derived
     770             : // class since we are a base class used in multiple inheritance.
     771             : //
     772             : template<class E, class Derived>
     773          28 : struct nsTArray_TypedBase<JS::Heap<E>, Derived>
     774             :   : public nsTArray_SafeElementAtHelper<JS::Heap<E>, Derived>
     775             : {
     776           7 :   operator const nsTArray<E>&()
     777             :   {
     778             :     static_assert(sizeof(E) == sizeof(JS::Heap<E>),
     779             :                   "JS::Heap<E> must be binary compatible with E.");
     780           7 :     Derived* self = static_cast<Derived*>(this);
     781           7 :     return *reinterpret_cast<nsTArray<E> *>(self);
     782             :   }
     783             : 
     784             :   operator const FallibleTArray<E>&()
     785             :   {
     786             :     Derived* self = static_cast<Derived*>(this);
     787             :     return *reinterpret_cast<FallibleTArray<E> *>(self);
     788             :   }
     789             : };
     790             : 
     791             : namespace detail {
     792             : 
     793             : template<class Item, class Comparator>
     794             : struct ItemComparatorEq
     795             : {
     796             :   const Item& mItem;
     797             :   const Comparator& mComp;
     798       26055 :   ItemComparatorEq(const Item& aItem, const Comparator& aComp)
     799             :     : mItem(aItem)
     800       26055 :     , mComp(aComp)
     801       26055 :   {}
     802             :   template<class T>
     803       23924 :   int operator()(const T& aElement) const {
     804       23924 :     if (mComp.Equals(aElement, mItem)) {
     805       10349 :       return 0;
     806             :     }
     807             : 
     808       13575 :     return mComp.LessThan(aElement, mItem) ? 1 : -1;
     809             :   }
     810             : };
     811             : 
     812             : template<class Item, class Comparator>
     813             : struct ItemComparatorFirstElementGT
     814             : {
     815             :   const Item& mItem;
     816             :   const Comparator& mComp;
     817        3920 :   ItemComparatorFirstElementGT(const Item& aItem, const Comparator& aComp)
     818             :     : mItem(aItem)
     819        3920 :     , mComp(aComp)
     820        3920 :   {}
     821             :   template<class T>
     822        6352 :   int operator()(const T& aElement) const {
     823       10400 :     if (mComp.LessThan(aElement, mItem) ||
     824        4048 :         mComp.Equals(aElement, mItem)) {
     825        3135 :       return 1;
     826             :     } else {
     827        3217 :       return -1;
     828             :     }
     829             :   }
     830             : };
     831             : 
     832             : } // namespace detail
     833             : 
     834             : //
     835             : // nsTArray_Impl contains most of the guts supporting nsTArray, FallibleTArray,
     836             : // AutoTArray.
     837             : //
     838             : // The only situation in which you might need to use nsTArray_Impl in your code
     839             : // is if you're writing code which mutates a TArray which may or may not be
     840             : // infallible.
     841             : //
     842             : // Code which merely reads from a TArray which may or may not be infallible can
     843             : // simply cast the TArray to |const nsTArray&|; both fallible and infallible
     844             : // TArrays can be cast to |const nsTArray&|.
     845             : //
     846             : template<class E, class Alloc>
     847             : class nsTArray_Impl
     848             :   : public nsTArray_base<Alloc, typename nsTArray_CopyChooser<E>::Type>
     849             :   , public nsTArray_TypedBase<E, nsTArray_Impl<E, Alloc>>
     850             : {
     851             : private:
     852             :   typedef nsTArrayFallibleAllocator FallibleAlloc;
     853             :   typedef nsTArrayInfallibleAllocator InfallibleAlloc;
     854             : 
     855             : public:
     856             :   typedef typename nsTArray_CopyChooser<E>::Type     copy_type;
     857             :   typedef nsTArray_base<Alloc, copy_type>            base_type;
     858             :   typedef typename base_type::size_type              size_type;
     859             :   typedef typename base_type::index_type             index_type;
     860             :   typedef E                                          elem_type;
     861             :   typedef nsTArray_Impl<E, Alloc>                    self_type;
     862             :   typedef nsTArrayElementTraits<E>                   elem_traits;
     863             :   typedef nsTArray_SafeElementAtHelper<E, self_type> safeelementat_helper_type;
     864             :   typedef mozilla::ArrayIterator<elem_type&, nsTArray<E>>       iterator;
     865             :   typedef mozilla::ArrayIterator<const elem_type&, nsTArray<E>> const_iterator;
     866             :   typedef mozilla::ReverseIterator<iterator>         reverse_iterator;
     867             :   typedef mozilla::ReverseIterator<const_iterator>   const_reverse_iterator;
     868             : 
     869             :   using safeelementat_helper_type::SafeElementAt;
     870             :   using base_type::EmptyHdr;
     871             : 
     872             :   // A special value that is used to indicate an invalid or unknown index
     873             :   // into the array.
     874             :   static const index_type NoIndex = index_type(-1);
     875             : 
     876             :   using base_type::Length;
     877             : 
     878             :   //
     879             :   // Finalization method
     880             :   //
     881             : 
     882      140846 :   ~nsTArray_Impl()
     883             :   {
     884      140846 :     if (!base_type::IsEmpty()) {
     885       33502 :       Clear();
     886             :     }
     887      140846 :   }
     888             : 
     889             :   //
     890             :   // Initialization methods
     891             :   //
     892             : 
     893      168057 :   nsTArray_Impl() {}
     894             : 
     895             :   // Initialize this array and pre-allocate some number of elements.
     896        1926 :   explicit nsTArray_Impl(size_type aCapacity) { SetCapacity(aCapacity); }
     897             : 
     898             :   // Initialize this array with an r-value.
     899             :   // Allow different types of allocators, since the allocator doesn't matter.
     900             :   template<typename Allocator>
     901        5185 :   explicit nsTArray_Impl(nsTArray_Impl<E, Allocator>&& aOther)
     902        5185 :   {
     903        5185 :     SwapElements(aOther);
     904        5185 :   }
     905             : 
     906             :   // The array's copy-constructor performs a 'deep' copy of the given array.
     907             :   // @param aOther The array object to copy.
     908             :   //
     909             :   // It's very important that we declare this method as taking |const
     910             :   // self_type&| as opposed to taking |const nsTArray_Impl<E, OtherAlloc>| for
     911             :   // an arbitrary OtherAlloc.
     912             :   //
     913             :   // If we don't declare a constructor taking |const self_type&|, C++ generates
     914             :   // a copy-constructor for this class which merely copies the object's
     915             :   // members, which is obviously wrong.
     916             :   //
     917             :   // You can pass an nsTArray_Impl<E, OtherAlloc> to this method because
     918             :   // nsTArray_Impl<E, X> can be cast to const nsTArray_Impl<E, Y>&.  So the
     919             :   // effect on the API is the same as if we'd declared this method as taking
     920             :   // |const nsTArray_Impl<E, OtherAlloc>&|.
     921       10726 :   explicit nsTArray_Impl(const self_type& aOther) { AppendElements(aOther); }
     922             : 
     923         189 :   explicit nsTArray_Impl(std::initializer_list<E> aIL) { AppendElements(aIL.begin(), aIL.size()); }
     924             :   // Allow converting to a const array with a different kind of allocator,
     925             :   // Since the allocator doesn't matter for const arrays
     926             :   template<typename Allocator>
     927           0 :   operator const nsTArray_Impl<E, Allocator>&() const
     928             :   {
     929           0 :     return *reinterpret_cast<const nsTArray_Impl<E, Allocator>*>(this);
     930             :   }
     931             :   // And we have to do this for our subclasses too
     932       74353 :   operator const nsTArray<E>&() const
     933             :   {
     934       74353 :     return *reinterpret_cast<const InfallibleTArray<E>*>(this);
     935             :   }
     936           0 :   operator const FallibleTArray<E>&() const
     937             :   {
     938           0 :     return *reinterpret_cast<const FallibleTArray<E>*>(this);
     939             :   }
     940             : 
     941             :   // The array's assignment operator performs a 'deep' copy of the given
     942             :   // array.  It is optimized to reuse existing storage if possible.
     943             :   // @param aOther The array object to copy.
     944        6541 :   self_type& operator=(const self_type& aOther)
     945             :   {
     946        6541 :     if (this != &aOther) {
     947        6541 :       ReplaceElementsAt(0, Length(), aOther.Elements(), aOther.Length());
     948             :     }
     949        6541 :     return *this;
     950             :   }
     951             : 
     952             :   // The array's move assignment operator steals the underlying data from
     953             :   // the other array.
     954             :   // @param other  The array object to move from.
     955         902 :   self_type& operator=(self_type&& aOther)
     956             :   {
     957         902 :     if (this != &aOther) {
     958         902 :       Clear();
     959         902 :       SwapElements(aOther);
     960             :     }
     961         902 :     return *this;
     962             :   }
     963             : 
     964             :   // Return true if this array has the same length and the same
     965             :   // elements as |aOther|.
     966             :   template<typename Allocator>
     967       11052 :   bool operator==(const nsTArray_Impl<E, Allocator>& aOther) const
     968             :   {
     969       11052 :     size_type len = Length();
     970       11052 :     if (len != aOther.Length()) {
     971         165 :       return false;
     972             :     }
     973             : 
     974             :     // XXX std::equal would be as fast or faster here
     975       11600 :     for (index_type i = 0; i < len; ++i) {
     976         731 :       if (!(operator[](i) == aOther[i])) {
     977          18 :         return false;
     978             :       }
     979             :     }
     980             : 
     981       10869 :     return true;
     982             :   }
     983             : 
     984             :   // Return true if this array does not have the same length and the same
     985             :   // elements as |aOther|.
     986        6013 :   bool operator!=(const self_type& aOther) const { return !operator==(aOther); }
     987             : 
     988             :   template<typename Allocator>
     989           0 :   self_type& operator=(const nsTArray_Impl<E, Allocator>& aOther)
     990             :   {
     991           0 :     ReplaceElementsAt(0, Length(), aOther.Elements(), aOther.Length());
     992           0 :     return *this;
     993             :   }
     994             : 
     995             :   template<typename Allocator>
     996             :   self_type& operator=(nsTArray_Impl<E, Allocator>&& aOther)
     997             :   {
     998             :     Clear();
     999             :     SwapElements(aOther);
    1000             :     return *this;
    1001             :   }
    1002             : 
    1003             :   // @return The amount of memory used by this nsTArray_Impl, excluding
    1004             :   // sizeof(*this). If you want to measure anything hanging off the array, you
    1005             :   // must iterate over the elements and measure them individually; hence the
    1006             :   // "Shallow" prefix.
    1007        5089 :   size_t ShallowSizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
    1008             :   {
    1009        5089 :     if (this->UsesAutoArrayBuffer() || Hdr() == EmptyHdr()) {
    1010        4782 :       return 0;
    1011             :     }
    1012         307 :     return aMallocSizeOf(this->Hdr());
    1013             :   }
    1014             : 
    1015             :   // @return The amount of memory used by this nsTArray_Impl, including
    1016             :   // sizeof(*this). If you want to measure anything hanging off the array, you
    1017             :   // must iterate over the elements and measure them individually; hence the
    1018             :   // "Shallow" prefix.
    1019           0 :   size_t ShallowSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
    1020             :   {
    1021           0 :     return aMallocSizeOf(this) + ShallowSizeOfExcludingThis(aMallocSizeOf);
    1022             :   }
    1023             : 
    1024             :   //
    1025             :   // Accessor methods
    1026             :   //
    1027             : 
    1028             :   // This method provides direct access to the array elements.
    1029             :   // @return A pointer to the first element of the array.  If the array is
    1030             :   // empty, then this pointer must not be dereferenced.
    1031     1264330 :   elem_type* Elements() { return reinterpret_cast<elem_type*>(Hdr() + 1); }
    1032             : 
    1033             :   // This method provides direct, readonly access to the array elements.
    1034             :   // @return A pointer to the first element of the array.  If the array is
    1035             :   // empty, then this pointer must not be dereferenced.
    1036      468339 :   const elem_type* Elements() const
    1037             :   {
    1038      468339 :     return reinterpret_cast<const elem_type*>(Hdr() + 1);
    1039             :   }
    1040             : 
    1041             :   // This method provides direct access to an element of the array. The given
    1042             :   // index must be within the array bounds.
    1043             :   // @param aIndex The index of an element in the array.
    1044             :   // @return A reference to the i'th element of the array.
    1045      908848 :   elem_type& ElementAt(index_type aIndex)
    1046             :   {
    1047      908848 :     if (MOZ_UNLIKELY(aIndex >= Length())) {
    1048           0 :       InvalidArrayIndex_CRASH(aIndex, Length());
    1049             :     }
    1050      908848 :     return Elements()[aIndex];
    1051             :   }
    1052             : 
    1053             :   // This method provides direct, readonly access to an element of the array
    1054             :   // The given index must be within the array bounds.
    1055             :   // @param aIndex The index of an element in the array.
    1056             :   // @return A const reference to the i'th element of the array.
    1057      173580 :   const elem_type& ElementAt(index_type aIndex) const
    1058             :   {
    1059      173580 :     if (MOZ_UNLIKELY(aIndex >= Length())) {
    1060           0 :       InvalidArrayIndex_CRASH(aIndex, Length());
    1061             :     }
    1062      173580 :     return Elements()[aIndex];
    1063             :   }
    1064             : 
    1065             :   // This method provides direct access to an element of the array in a bounds
    1066             :   // safe manner. If the requested index is out of bounds the provided default
    1067             :   // value is returned.
    1068             :   // @param aIndex The index of an element in the array.
    1069             :   // @param aDef   The value to return if the index is out of bounds.
    1070             :   elem_type& SafeElementAt(index_type aIndex, elem_type& aDef)
    1071             :   {
    1072             :     return aIndex < Length() ? Elements()[aIndex] : aDef;
    1073             :   }
    1074             : 
    1075             :   // This method provides direct access to an element of the array in a bounds
    1076             :   // safe manner. If the requested index is out of bounds the provided default
    1077             :   // value is returned.
    1078             :   // @param aIndex The index of an element in the array.
    1079             :   // @param aDef   The value to return if the index is out of bounds.
    1080        9234 :   const elem_type& SafeElementAt(index_type aIndex, const elem_type& aDef) const
    1081             :   {
    1082        9234 :     return aIndex < Length() ? Elements()[aIndex] : aDef;
    1083             :   }
    1084             : 
    1085             :   // Shorthand for ElementAt(aIndex)
    1086      872206 :   elem_type& operator[](index_type aIndex) { return ElementAt(aIndex); }
    1087             : 
    1088             :   // Shorthand for ElementAt(aIndex)
    1089      118422 :   const elem_type& operator[](index_type aIndex) const { return ElementAt(aIndex); }
    1090             : 
    1091             :   // Shorthand for ElementAt(length - 1)
    1092        2439 :   elem_type& LastElement() { return ElementAt(Length() - 1); }
    1093             : 
    1094             :   // Shorthand for ElementAt(length - 1)
    1095          16 :   const elem_type& LastElement() const { return ElementAt(Length() - 1); }
    1096             : 
    1097             :   // Shorthand for SafeElementAt(length - 1, def)
    1098             :   elem_type& SafeLastElement(elem_type& aDef)
    1099             :   {
    1100             :     return SafeElementAt(Length() - 1, aDef);
    1101             :   }
    1102             : 
    1103             :   // Shorthand for SafeElementAt(length - 1, def)
    1104        1223 :   const elem_type& SafeLastElement(const elem_type& aDef) const
    1105             :   {
    1106        1223 :     return SafeElementAt(Length() - 1, aDef);
    1107             :   }
    1108             : 
    1109             :   // Methods for range-based for loops.
    1110       14846 :   iterator begin() { return iterator(*this, 0); }
    1111       21138 :   const_iterator begin() const { return const_iterator(*this, 0); }
    1112             :   const_iterator cbegin() const { return begin(); }
    1113       17176 :   iterator end() { return iterator(*this, Length()); }
    1114       21138 :   const_iterator end() const { return const_iterator(*this, Length()); }
    1115             :   const_iterator cend() const { return end(); }
    1116             : 
    1117             :   // Methods for reverse iterating.
    1118        2564 :   reverse_iterator rbegin() { return reverse_iterator(end()); }
    1119         127 :   const_reverse_iterator rbegin() const { return const_reverse_iterator(end()); }
    1120             :   const_reverse_iterator crbegin() const { return rbegin(); }
    1121        2564 :   reverse_iterator rend() { return reverse_iterator(begin()); }
    1122         127 :   const_reverse_iterator rend() const { return const_reverse_iterator(begin()); }
    1123             :   const_reverse_iterator crend() const { return rend(); }
    1124             : 
    1125             :   // Span integration
    1126             : 
    1127           6 :   operator mozilla::Span<elem_type>()
    1128             :   {
    1129           6 :     return mozilla::Span<elem_type>(Elements(), Length());
    1130             :   }
    1131             : 
    1132           0 :   operator mozilla::Span<const elem_type>() const
    1133             :   {
    1134           0 :     return mozilla::Span<const elem_type>(Elements(), Length());
    1135             :   }
    1136             : 
    1137             :   //
    1138             :   // Search methods
    1139             :   //
    1140             : 
    1141             :   // This method searches for the first element in this array that is equal
    1142             :   // to the given element.
    1143             :   // @param aItem  The item to search for.
    1144             :   // @param aComp  The Comparator used to determine element equality.
    1145             :   // @return       true if the element was found.
    1146             :   template<class Item, class Comparator>
    1147           4 :   bool Contains(const Item& aItem, const Comparator& aComp) const
    1148             :   {
    1149           4 :     return IndexOf(aItem, 0, aComp) != NoIndex;
    1150             :   }
    1151             : 
    1152             :   // This method searches for the first element in this array that is equal
    1153             :   // to the given element.  This method assumes that 'operator==' is defined
    1154             :   // for elem_type.
    1155             :   // @param aItem  The item to search for.
    1156             :   // @return       true if the element was found.
    1157             :   template<class Item>
    1158       36781 :   bool Contains(const Item& aItem) const
    1159             :   {
    1160       36781 :     return IndexOf(aItem) != NoIndex;
    1161             :   }
    1162             : 
    1163             :   // This method searches for the offset of the first element in this
    1164             :   // array that is equal to the given element.
    1165             :   // @param aItem  The item to search for.
    1166             :   // @param aStart The index to start from.
    1167             :   // @param aComp  The Comparator used to determine element equality.
    1168             :   // @return       The index of the found element or NoIndex if not found.
    1169             :   template<class Item, class Comparator>
    1170       83738 :   index_type IndexOf(const Item& aItem, index_type aStart,
    1171             :                      const Comparator& aComp) const
    1172             :   {
    1173       83738 :     const elem_type* iter = Elements() + aStart;
    1174       83738 :     const elem_type* iend = Elements() + Length();
    1175      565904 :     for (; iter != iend; ++iter) {
    1176      288748 :       if (aComp.Equals(*iter, aItem)) {
    1177       47665 :         return index_type(iter - Elements());
    1178             :       }
    1179             :     }
    1180       36073 :     return NoIndex;
    1181             :   }
    1182             : 
    1183             :   // This method searches for the offset of the first element in this
    1184             :   // array that is equal to the given element.  This method assumes
    1185             :   // that 'operator==' is defined for elem_type.
    1186             :   // @param aItem  The item to search for.
    1187             :   // @param aStart The index to start from.
    1188             :   // @return       The index of the found element or NoIndex if not found.
    1189             :   template<class Item>
    1190       44277 :   index_type IndexOf(const Item& aItem, index_type aStart = 0) const
    1191             :   {
    1192       44277 :     return IndexOf(aItem, aStart, nsDefaultComparator<elem_type, Item>());
    1193             :   }
    1194             : 
    1195             :   // This method searches for the offset of the last element in this
    1196             :   // array that is equal to the given element.
    1197             :   // @param aItem  The item to search for.
    1198             :   // @param aStart The index to start from.  If greater than or equal to the
    1199             :   //               length of the array, then the entire array is searched.
    1200             :   // @param aComp  The Comparator used to determine element equality.
    1201             :   // @return       The index of the found element or NoIndex if not found.
    1202             :   template<class Item, class Comparator>
    1203           0 :   index_type LastIndexOf(const Item& aItem, index_type aStart,
    1204             :                          const Comparator& aComp) const
    1205             :   {
    1206           0 :     size_type endOffset = aStart >= Length() ? Length() : aStart + 1;
    1207           0 :     const elem_type* iend = Elements() - 1;
    1208           0 :     const elem_type* iter = iend + endOffset;
    1209           0 :     for (; iter != iend; --iter) {
    1210           0 :       if (aComp.Equals(*iter, aItem)) {
    1211           0 :         return index_type(iter - Elements());
    1212             :       }
    1213             :     }
    1214           0 :     return NoIndex;
    1215             :   }
    1216             : 
    1217             :   // This method searches for the offset of the last element in this
    1218             :   // array that is equal to the given element.  This method assumes
    1219             :   // that 'operator==' is defined for elem_type.
    1220             :   // @param aItem  The item to search for.
    1221             :   // @param aStart The index to start from.  If greater than or equal to the
    1222             :   //               length of the array, then the entire array is searched.
    1223             :   // @return       The index of the found element or NoIndex if not found.
    1224             :   template<class Item>
    1225           0 :   index_type LastIndexOf(const Item& aItem,
    1226             :                          index_type aStart = NoIndex) const
    1227             :   {
    1228           0 :     return LastIndexOf(aItem, aStart, nsDefaultComparator<elem_type, Item>());
    1229             :   }
    1230             : 
    1231             :   // This method searches for the offset for the element in this array
    1232             :   // that is equal to the given element. The array is assumed to be sorted.
    1233             :   // If there is more than one equivalent element, there is no guarantee
    1234             :   // on which one will be returned.
    1235             :   // @param aItem  The item to search for.
    1236             :   // @param aComp  The Comparator used.
    1237             :   // @return       The index of the found element or NoIndex if not found.
    1238             :   template<class Item, class Comparator>
    1239       26055 :   index_type BinaryIndexOf(const Item& aItem, const Comparator& aComp) const
    1240             :   {
    1241             :     using mozilla::BinarySearchIf;
    1242             :     typedef ::detail::ItemComparatorEq<Item, Comparator> Cmp;
    1243             : 
    1244             :     size_t index;
    1245       26055 :     bool found = BinarySearchIf(*this, 0, Length(), Cmp(aItem, aComp), &index);
    1246       26055 :     return found ? index : NoIndex;
    1247             :   }
    1248             : 
    1249             :   // This method searches for the offset for the element in this array
    1250             :   // that is equal to the given element. The array is assumed to be sorted.
    1251             :   // This method assumes that 'operator==' and 'operator<' are defined.
    1252             :   // @param aItem  The item to search for.
    1253             :   // @return       The index of the found element or NoIndex if not found.
    1254             :   template<class Item>
    1255         712 :   index_type BinaryIndexOf(const Item& aItem) const
    1256             :   {
    1257         712 :     return BinaryIndexOf(aItem, nsDefaultComparator<elem_type, Item>());
    1258             :   }
    1259             : 
    1260             :   //
    1261             :   // Mutation methods
    1262             :   //
    1263             : 
    1264             :   template<class Allocator, typename ActualAlloc = Alloc>
    1265          88 :   typename ActualAlloc::ResultType Assign(
    1266             :       const nsTArray_Impl<E, Allocator>& aOther)
    1267             :   {
    1268          88 :     return ActualAlloc::ConvertBoolToResultType(
    1269          88 :       !!ReplaceElementsAt<E, ActualAlloc>(0, Length(),
    1270          88 :                                           aOther.Elements(), aOther.Length()));
    1271             :   }
    1272             : 
    1273             :   template<class Allocator>
    1274             :   MOZ_MUST_USE
    1275          86 :   bool Assign(const nsTArray_Impl<E, Allocator>& aOther,
    1276             :               const mozilla::fallible_t&)
    1277             :   {
    1278          86 :     return Assign<Allocator, FallibleAlloc>(aOther);
    1279             :   }
    1280             : 
    1281             :   template<class Allocator>
    1282             :   void Assign(nsTArray_Impl<E, Allocator>&& aOther)
    1283             :   {
    1284             :     Clear();
    1285             :     SwapElements(aOther);
    1286             :   }
    1287             : 
    1288             :   // This method call the destructor on each element of the array, empties it,
    1289             :   // but does not shrink the array's capacity.
    1290             :   // See also SetLengthAndRetainStorage.
    1291             :   // Make sure to call Compact() if needed to avoid keeping a huge array
    1292             :   // around.
    1293         503 :   void ClearAndRetainStorage()
    1294             :   {
    1295         503 :     if (base_type::mHdr == EmptyHdr()) {
    1296           4 :       return;
    1297             :     }
    1298             : 
    1299         499 :     DestructRange(0, Length());
    1300         499 :     base_type::mHdr->mLength = 0;
    1301             :   }
    1302             : 
    1303             :   // This method modifies the length of the array, but unlike SetLength
    1304             :   // it doesn't deallocate/reallocate the current internal storage.
    1305             :   // The new length MUST be shorter than or equal to the current capacity.
    1306             :   // If the new length is larger than the existing length of the array,
    1307             :   // then new elements will be constructed using elem_type's default
    1308             :   // constructor.  If shorter, elements will be destructed and removed.
    1309             :   // See also ClearAndRetainStorage.
    1310             :   // @param aNewLen  The desired length of this array.
    1311        4620 :   void SetLengthAndRetainStorage(size_type aNewLen)
    1312             :   {
    1313        4620 :     MOZ_ASSERT(aNewLen <= base_type::Capacity());
    1314        4620 :     size_type oldLen = Length();
    1315        4620 :     if (aNewLen > oldLen) {
    1316          24 :       InsertElementsAt(oldLen, aNewLen - oldLen);
    1317          24 :       return;
    1318             :     }
    1319        4596 :     if (aNewLen < oldLen) {
    1320        4592 :       DestructRange(aNewLen, oldLen - aNewLen);
    1321        4592 :       base_type::mHdr->mLength = aNewLen;
    1322             :     }
    1323             :   }
    1324             : 
    1325             :   // This method replaces a range of elements in this array.
    1326             :   // @param aStart    The starting index of the elements to replace.
    1327             :   // @param aCount    The number of elements to replace.  This may be zero to
    1328             :   //                  insert elements without removing any existing elements.
    1329             :   // @param aArray    The values to copy into this array.  Must be non-null,
    1330             :   //                  and these elements must not already exist in the array
    1331             :   //                  being modified.
    1332             :   // @param aArrayLen The number of values to copy into this array.
    1333             :   // @return          A pointer to the new elements in the array, or null if
    1334             :   //                  the operation failed due to insufficient memory.
    1335             : protected:
    1336             :   template<class Item, typename ActualAlloc = Alloc>
    1337             :   elem_type* ReplaceElementsAt(index_type aStart, size_type aCount,
    1338             :                                const Item* aArray, size_type aArrayLen);
    1339             : 
    1340             : public:
    1341             : 
    1342             :   template<class Item>
    1343             :   MOZ_MUST_USE
    1344           0 :   elem_type* ReplaceElementsAt(index_type aStart, size_type aCount,
    1345             :                                const Item* aArray, size_type aArrayLen,
    1346             :                                const mozilla::fallible_t&)
    1347             :   {
    1348             :     return ReplaceElementsAt<Item, FallibleAlloc>(aStart, aCount,
    1349           0 :                                                   aArray, aArrayLen);
    1350             :   }
    1351             : 
    1352             :   // A variation on the ReplaceElementsAt method defined above.
    1353             : protected:
    1354             :   template<class Item, typename ActualAlloc = Alloc>
    1355           0 :   elem_type* ReplaceElementsAt(index_type aStart, size_type aCount,
    1356             :                                const nsTArray<Item>& aArray)
    1357             :   {
    1358           0 :     return ReplaceElementsAt<Item, ActualAlloc>(
    1359           0 :       aStart, aCount, aArray.Elements(), aArray.Length());
    1360             :   }
    1361             : 
    1362             :   template<class Item, typename ActualAlloc = Alloc>
    1363             :   elem_type* ReplaceElementsAt(index_type aStart,
    1364             :                                size_type aCount,
    1365             :                                mozilla::Span<const Item> aSpan)
    1366             :   {
    1367             :     return ReplaceElementsAt<Item, ActualAlloc>(
    1368             :       aStart, aCount, aSpan.Elements(), aSpan.Length());
    1369             :   }
    1370             : 
    1371             : public:
    1372             : 
    1373             :   template<class Item>
    1374             :   MOZ_MUST_USE
    1375             :   elem_type* ReplaceElementsAt(index_type aStart, size_type aCount,
    1376             :                                const nsTArray<Item>& aArray,
    1377             :                                const mozilla::fallible_t&)
    1378             :   {
    1379             :     return ReplaceElementsAt<Item, FallibleAlloc>(aStart, aCount, aArray);
    1380             :   }
    1381             : 
    1382             :   template<class Item>
    1383             :   MOZ_MUST_USE elem_type* ReplaceElementsAt(index_type aStart,
    1384             :                                             size_type aCount,
    1385             :                                             mozilla::Span<const Item> aSpan,
    1386             :                                             const mozilla::fallible_t&)
    1387             :   {
    1388             :     return ReplaceElementsAt<Item, FallibleAlloc>(aStart, aCount, aSpan);
    1389             :   }
    1390             : 
    1391             :   // A variation on the ReplaceElementsAt method defined above.
    1392             : protected:
    1393             :   template<class Item, typename ActualAlloc = Alloc>
    1394          24 :   elem_type* ReplaceElementsAt(index_type aStart, size_type aCount,
    1395             :                                const Item& aItem)
    1396             :   {
    1397          24 :     return ReplaceElementsAt<Item, ActualAlloc>(aStart, aCount, &aItem, 1);
    1398             :   }
    1399             : public:
    1400             : 
    1401             :   template<class Item>
    1402             :   MOZ_MUST_USE
    1403             :   elem_type* ReplaceElementsAt(index_type aStart, size_type aCount,
    1404             :                                const Item& aItem, const mozilla::fallible_t&)
    1405             :   {
    1406             :     return ReplaceElementsAt<Item, FallibleAlloc>(aStart, aCount, aItem);
    1407             :   }
    1408             : 
    1409             :   // A variation on the ReplaceElementsAt method defined above.
    1410             :   template<class Item>
    1411           4 :   elem_type* ReplaceElementAt(index_type aIndex, const Item& aItem)
    1412             :   {
    1413           4 :     return ReplaceElementsAt(aIndex, 1, &aItem, 1);
    1414             :   }
    1415             : 
    1416             :   // A variation on the ReplaceElementsAt method defined above.
    1417             : protected:
    1418             :   template<class Item, typename ActualAlloc = Alloc>
    1419           1 :   elem_type* InsertElementsAt(index_type aIndex, const Item* aArray,
    1420             :                               size_type aArrayLen)
    1421             :   {
    1422           1 :     return ReplaceElementsAt<Item, ActualAlloc>(aIndex, 0, aArray, aArrayLen);
    1423             :   }
    1424             : public:
    1425             : 
    1426             :   template<class Item>
    1427             :   MOZ_MUST_USE
    1428           0 :   elem_type* InsertElementsAt(index_type aIndex, const Item* aArray,
    1429             :                               size_type aArrayLen, const mozilla::fallible_t&)
    1430             :   {
    1431           0 :     return InsertElementsAt<Item, FallibleAlloc>(aIndex, aArray, aArrayLen);
    1432             :   }
    1433             : 
    1434             :   // A variation on the ReplaceElementsAt method defined above.
    1435             : protected:
    1436             :   template<class Item, class Allocator, typename ActualAlloc = Alloc>
    1437         764 :   elem_type* InsertElementsAt(index_type aIndex,
    1438             :                               const nsTArray_Impl<Item, Allocator>& aArray)
    1439             :   {
    1440         764 :     return ReplaceElementsAt<Item, ActualAlloc>(
    1441         764 :       aIndex, 0, aArray.Elements(), aArray.Length());
    1442             :   }
    1443             : 
    1444             :   template<class Item, typename ActualAlloc = Alloc>
    1445             :   elem_type* InsertElementsAt(index_type aIndex,
    1446             :                               mozilla::Span<const Item> aSpan)
    1447             :   {
    1448             :     return ReplaceElementsAt<Item, ActualAlloc>(
    1449             :       aIndex, 0, aSpan.Elements(), aSpan.Length());
    1450             :   }
    1451             : 
    1452             : public:
    1453             : 
    1454             :   template<class Item, class Allocator>
    1455             :   MOZ_MUST_USE
    1456           6 :   elem_type* InsertElementsAt(index_type aIndex,
    1457             :                               const nsTArray_Impl<Item, Allocator>& aArray,
    1458             :                               const mozilla::fallible_t&)
    1459             :   {
    1460           6 :     return InsertElementsAt<Item, Allocator, FallibleAlloc>(aIndex, aArray);
    1461             :   }
    1462             : 
    1463             :   template<class Item>
    1464             :   MOZ_MUST_USE elem_type* InsertElementsAt(index_type aIndex,
    1465             :                                            mozilla::Span<const Item> aSpan,
    1466             :                                            const mozilla::fallible_t&)
    1467             :   {
    1468             :     return InsertElementsAt<Item, FallibleAlloc>(aIndex, aSpan);
    1469             :   }
    1470             : 
    1471             :   // Insert a new element without copy-constructing. This is useful to avoid
    1472             :   // temporaries.
    1473             :   // @return A pointer to the newly inserted element, or null on OOM.
    1474             : protected:
    1475             :   template<typename ActualAlloc = Alloc>
    1476             :   elem_type* InsertElementAt(index_type aIndex);
    1477             : 
    1478             : public:
    1479             : 
    1480             :   MOZ_MUST_USE
    1481             :   elem_type* InsertElementAt(index_type aIndex, const mozilla::fallible_t&)
    1482             :   {
    1483             :     return InsertElementAt<FallibleAlloc>(aIndex);
    1484             :   }
    1485             : 
    1486             :   // Insert a new element, move constructing if possible.
    1487             : protected:
    1488             :   template<class Item, typename ActualAlloc = Alloc>
    1489             :   elem_type* InsertElementAt(index_type aIndex, Item&& aItem);
    1490             : 
    1491             : public:
    1492             : 
    1493             :   template<class Item>
    1494             :   MOZ_MUST_USE
    1495           0 :   elem_type* InsertElementAt(index_type aIndex, Item&& aItem,
    1496             :                              const mozilla::fallible_t&)
    1497             :   {
    1498           0 :     return InsertElementAt<Item, FallibleAlloc>(aIndex,
    1499           0 :                                                 mozilla::Forward<Item>(aItem));
    1500             :   }
    1501             : 
    1502             :   // Reconstruct the element at the given index, and return a pointer to the
    1503             :   // reconstructed element.  This will destroy the existing element and
    1504             :   // default-construct a new one, giving you a state much like what single-arg
    1505             :   // InsertElementAt(), or no-arg AppendElement() does, but without changing the
    1506             :   // length of the array.
    1507             :   //
    1508             :   // array[idx] = T()
    1509             :   //
    1510             :   // would accomplish the same thing as long as T has the appropriate moving
    1511             :   // operator=, but some types don't for various reasons.
    1512           0 :   elem_type* ReconstructElementAt(index_type aIndex)
    1513             :   {
    1514           0 :     elem_type* elem = &ElementAt(aIndex);
    1515           0 :     elem_traits::Destruct(elem);
    1516           0 :     elem_traits::Construct(elem);
    1517           0 :     return elem;
    1518             :   }
    1519             : 
    1520             :   // This method searches for the smallest index of an element that is strictly
    1521             :   // greater than |aItem|. If |aItem| is inserted at this index, the array will
    1522             :   // remain sorted and |aItem| would come after all elements that are equal to
    1523             :   // it. If |aItem| is greater than or equal to all elements in the array, the
    1524             :   // array length is returned.
    1525             :   //
    1526             :   // Note that consumers who want to know whether there are existing items equal
    1527             :   // to |aItem| in the array can just check that the return value here is > 0
    1528             :   // and indexing into the previous slot gives something equal to |aItem|.
    1529             :   //
    1530             :   //
    1531             :   // @param aItem  The item to search for.
    1532             :   // @param aComp  The Comparator used.
    1533             :   // @return        The index of greatest element <= to |aItem|
    1534             :   // @precondition The array is sorted
    1535             :   template<class Item, class Comparator>
    1536        3920 :   index_type IndexOfFirstElementGt(const Item& aItem,
    1537             :                                    const Comparator& aComp) const
    1538             :   {
    1539             :     using mozilla::BinarySearchIf;
    1540             :     typedef ::detail::ItemComparatorFirstElementGT<Item, Comparator> Cmp;
    1541             : 
    1542             :     size_t index;
    1543        3920 :     BinarySearchIf(*this, 0, Length(), Cmp(aItem, aComp), &index);
    1544        3920 :     return index;
    1545             :   }
    1546             : 
    1547             :   // A variation on the IndexOfFirstElementGt method defined above.
    1548             :   template<class Item>
    1549             :   index_type
    1550         732 :   IndexOfFirstElementGt(const Item& aItem) const
    1551             :   {
    1552         732 :     return IndexOfFirstElementGt(aItem, nsDefaultComparator<elem_type, Item>());
    1553             :   }
    1554             : 
    1555             :   // Inserts |aItem| at such an index to guarantee that if the array
    1556             :   // was previously sorted, it will remain sorted after this
    1557             :   // insertion.
    1558             : protected:
    1559             :   template<class Item, class Comparator, typename ActualAlloc = Alloc>
    1560        2447 :   elem_type* InsertElementSorted(Item&& aItem, const Comparator& aComp)
    1561             :   {
    1562        2447 :     index_type index = IndexOfFirstElementGt<Item, Comparator>(aItem, aComp);
    1563        2447 :     return InsertElementAt<Item, ActualAlloc>(
    1564        2447 :       index, mozilla::Forward<Item>(aItem));
    1565             :   }
    1566             : public:
    1567             : 
    1568             :   template<class Item, class Comparator>
    1569             :   MOZ_MUST_USE
    1570             :   elem_type* InsertElementSorted(Item&& aItem, const Comparator& aComp,
    1571             :                                  const mozilla::fallible_t&)
    1572             :   {
    1573             :     return InsertElementSorted<Item, Comparator, FallibleAlloc>(
    1574             :       mozilla::Forward<Item>(aItem), aComp);
    1575             :   }
    1576             : 
    1577             :   // A variation on the InsertElementSorted method defined above.
    1578             : protected:
    1579             :   template<class Item, typename ActualAlloc = Alloc>
    1580        2428 :   elem_type* InsertElementSorted(Item&& aItem)
    1581             :   {
    1582             :     nsDefaultComparator<elem_type, Item> comp;
    1583        2428 :     return InsertElementSorted<Item, decltype(comp), ActualAlloc>(
    1584        2428 :       mozilla::Forward<Item>(aItem), comp);
    1585             :   }
    1586             : public:
    1587             : 
    1588             :   template<class Item>
    1589             :   MOZ_MUST_USE
    1590          12 :   elem_type* InsertElementSorted(Item&& aItem, const mozilla::fallible_t&)
    1591             :   {
    1592          12 :     return InsertElementSorted<Item, FallibleAlloc>(
    1593          12 :       mozilla::Forward<Item>(aItem));
    1594             :   }
    1595             : 
    1596             :   // This method appends elements to the end of this array.
    1597             :   // @param aArray    The elements to append to this array.
    1598             :   // @param aArrayLen The number of elements to append to this array.
    1599             :   // @return          A pointer to the new elements in the array, or null if
    1600             :   //                  the operation failed due to insufficient memory.
    1601             : protected:
    1602             :   template<class Item, typename ActualAlloc = Alloc>
    1603             :   elem_type* AppendElements(const Item* aArray, size_type aArrayLen);
    1604             : 
    1605             :   template<class Item, typename ActualAlloc = Alloc>
    1606             :   elem_type* AppendElements(mozilla::Span<const Item> aSpan)
    1607             :   {
    1608             :     return AppendElements<Item, FallibleAlloc>(aSpan.Elements(),
    1609             :                                                aSpan.Length());
    1610             :   }
    1611             : 
    1612             :   template<class Item, size_t Length, typename ActualAlloc = Alloc>
    1613             :   elem_type* AppendElements(const mozilla::Array<Item, Length>& aArray)
    1614             :   {
    1615             :     return AppendElements<Item, ActualAlloc>(&aArray[0], Length);
    1616             :   }
    1617             : 
    1618             : public:
    1619             : 
    1620             :   template<class Item>
    1621             :   /* MOZ_MUST_USE */
    1622           0 :   elem_type* AppendElements(const Item* aArray, size_type aArrayLen,
    1623             :                             const mozilla::fallible_t&)
    1624             :   {
    1625           0 :     return AppendElements<Item, FallibleAlloc>(aArray, aArrayLen);
    1626             :   }
    1627             : 
    1628             :   template<class Item>
    1629             :   /* MOZ_MUST_USE */
    1630             :   elem_type* AppendElements(mozilla::Span<const Item> aSpan,
    1631             :                             const mozilla::fallible_t&)
    1632             :   {
    1633             :     return AppendElements<Item, FallibleAlloc>(aSpan.Elements(),
    1634             :                                                aSpan.Length());
    1635             :   }
    1636             : 
    1637             :   // A variation on the AppendElements method defined above.
    1638             : protected:
    1639             :   template<class Item, class Allocator, typename ActualAlloc = Alloc>
    1640       17062 :   elem_type* AppendElements(const nsTArray_Impl<Item, Allocator>& aArray)
    1641             :   {
    1642       17062 :     return AppendElements<Item, ActualAlloc>(aArray.Elements(), aArray.Length());
    1643             :   }
    1644             : public:
    1645             : 
    1646             :   template<class Item, class Allocator>
    1647             :   /* MOZ_MUST_USE */
    1648          35 :   elem_type* AppendElements(const nsTArray_Impl<Item, Allocator>& aArray,
    1649             :                             const mozilla::fallible_t&)
    1650             :   {
    1651          35 :     return AppendElements<Item, Allocator, FallibleAlloc>(aArray);
    1652             :   }
    1653             : 
    1654             :   // Move all elements from another array to the end of this array.
    1655             :   // @return A pointer to the newly appended elements, or null on OOM.
    1656             : protected:
    1657             :   template<class Item, class Allocator, typename ActualAlloc = Alloc>
    1658             :   elem_type* AppendElements(nsTArray_Impl<Item, Allocator>&& aArray);
    1659             : 
    1660             : public:
    1661             : 
    1662             :   template<class Item, class Allocator, typename ActualAlloc = Alloc>
    1663             :   /* MOZ_MUST_USE */
    1664             :   elem_type* AppendElements(nsTArray_Impl<Item, Allocator>&& aArray,
    1665             :                             const mozilla::fallible_t&)
    1666             :   {
    1667             :     return AppendElements<Item, Allocator>(mozilla::Move(aArray));
    1668             :   }
    1669             : 
    1670             :   // Append a new element, move constructing if possible.
    1671             : protected:
    1672             :   template<class Item, typename ActualAlloc = Alloc>
    1673             :   elem_type* AppendElement(Item&& aItem);
    1674             : 
    1675             : public:
    1676             : 
    1677             :   template<class Item>
    1678             :   /* MOZ_MUST_USE */
    1679         679 :   elem_type* AppendElement(Item&& aItem,
    1680             :                            const mozilla::fallible_t&)
    1681             :   {
    1682         679 :     return AppendElement<Item, FallibleAlloc>(mozilla::Forward<Item>(aItem));
    1683             :   }
    1684             : 
    1685             :   // Append new elements without copy-constructing. This is useful to avoid
    1686             :   // temporaries.
    1687             :   // @return A pointer to the newly appended elements, or null on OOM.
    1688             : protected:
    1689             :   template<typename ActualAlloc = Alloc>
    1690       44222 :   elem_type* AppendElements(size_type aCount) {
    1691       44222 :     if (!ActualAlloc::Successful(this->template EnsureCapacity<ActualAlloc>(
    1692       44222 :           Length() + aCount, sizeof(elem_type)))) {
    1693           0 :       return nullptr;
    1694             :     }
    1695       44222 :     elem_type* elems = Elements() + Length();
    1696             :     size_type i;
    1697     1098988 :     for (i = 0; i < aCount; ++i) {
    1698     1054766 :       elem_traits::Construct(elems + i);
    1699             :     }
    1700       44222 :     this->IncrementLength(aCount);
    1701       44222 :     return elems;
    1702             :   }
    1703             : public:
    1704             : 
    1705             :   /* MOZ_MUST_USE */
    1706          24 :   elem_type* AppendElements(size_type aCount,
    1707             :                             const mozilla::fallible_t&)
    1708             :   {
    1709          24 :     return AppendElements<FallibleAlloc>(aCount);
    1710             :   }
    1711             : 
    1712             :   // Append a new element without copy-constructing. This is useful to avoid
    1713             :   // temporaries.
    1714             :   // @return A pointer to the newly appended element, or null on OOM.
    1715             : protected:
    1716             :   template<typename ActualAlloc = Alloc>
    1717       43438 :   elem_type* AppendElement()
    1718             :   {
    1719       43438 :     return AppendElements<ActualAlloc>(1);
    1720             :   }
    1721             : public:
    1722             : 
    1723             :   /* MOZ_MUST_USE */
    1724          32 :   elem_type* AppendElement(const mozilla::fallible_t&)
    1725             :   {
    1726          32 :     return AppendElement<FallibleAlloc>();
    1727             :   }
    1728             : 
    1729             :   // This method removes a range of elements from this array.
    1730             :   // @param aStart The starting index of the elements to remove.
    1731             :   // @param aCount The number of elements to remove.
    1732             :   void RemoveElementsAt(index_type aStart, size_type aCount);
    1733             : 
    1734             :   // A variation on the RemoveElementsAt method defined above.
    1735        6377 :   void RemoveElementAt(index_type aIndex) { RemoveElementsAt(aIndex, 1); }
    1736             : 
    1737             :   // A variation on the RemoveElementsAt method defined above.
    1738       42235 :   void Clear() { RemoveElementsAt(0, Length()); }
    1739             : 
    1740             :   // This method removes elements based on the return value of the
    1741             :   // callback function aPredicate. If the function returns true for
    1742             :   // an element, the element is removed. aPredicate will be called
    1743             :   // for each element in order. It is not safe to access the array
    1744             :   // inside aPredicate.
    1745             :   template<typename Predicate>
    1746             :   void RemoveElementsBy(Predicate aPredicate);
    1747             : 
    1748             :   // This helper function combines IndexOf with RemoveElementAt to "search
    1749             :   // and destroy" the first element that is equal to the given element.
    1750             :   // @param aItem The item to search for.
    1751             :   // @param aComp The Comparator used to determine element equality.
    1752             :   // @return true if the element was found
    1753             :   template<class Item, class Comparator>
    1754       15846 :   bool RemoveElement(const Item& aItem, const Comparator& aComp)
    1755             :   {
    1756       15846 :     index_type i = IndexOf(aItem, 0, aComp);
    1757       15846 :     if (i == NoIndex) {
    1758       13305 :       return false;
    1759             :     }
    1760             : 
    1761        2541 :     RemoveElementAt(i);
    1762        2541 :     return true;
    1763             :   }
    1764             : 
    1765             :   // A variation on the RemoveElement method defined above that assumes
    1766             :   // that 'operator==' is defined for elem_type.
    1767             :   template<class Item>
    1768       15846 :   bool RemoveElement(const Item& aItem)
    1769             :   {
    1770       15846 :     return RemoveElement(aItem, nsDefaultComparator<elem_type, Item>());
    1771             :   }
    1772             : 
    1773             :   // This helper function combines IndexOfFirstElementGt with
    1774             :   // RemoveElementAt to "search and destroy" the last element that
    1775             :   // is equal to the given element.
    1776             :   // @param aItem The item to search for.
    1777             :   // @param aComp The Comparator used to determine element equality.
    1778             :   // @return true if the element was found
    1779             :   template<class Item, class Comparator>
    1780         594 :   bool RemoveElementSorted(const Item& aItem, const Comparator& aComp)
    1781             :   {
    1782         594 :     index_type index = IndexOfFirstElementGt(aItem, aComp);
    1783         594 :     if (index > 0 && aComp.Equals(ElementAt(index - 1), aItem)) {
    1784         594 :       RemoveElementAt(index - 1);
    1785         594 :       return true;
    1786             :     }
    1787           0 :     return false;
    1788             :   }
    1789             : 
    1790             :   // A variation on the RemoveElementSorted method defined above.
    1791             :   template<class Item>
    1792         594 :   bool RemoveElementSorted(const Item& aItem)
    1793             :   {
    1794         594 :     return RemoveElementSorted(aItem, nsDefaultComparator<elem_type, Item>());
    1795             :   }
    1796             : 
    1797             :   // This method causes the elements contained in this array and the given
    1798             :   // array to be swapped.
    1799             :   template<class Allocator>
    1800       20407 :   typename Alloc::ResultType SwapElements(nsTArray_Impl<E, Allocator>& aOther)
    1801             :   {
    1802       40814 :     return Alloc::Result(this->template SwapArrayElements<Alloc>(
    1803       40814 :       aOther, sizeof(elem_type), MOZ_ALIGNOF(elem_type)));
    1804             :   }
    1805             : 
    1806             :   //
    1807             :   // Allocation
    1808             :   //
    1809             : 
    1810             :   // This method may increase the capacity of this array object by the
    1811             :   // specified amount.  This method may be called in advance of several
    1812             :   // AppendElement operations to minimize heap re-allocations.  This method
    1813             :   // will not reduce the number of elements in this array.
    1814             :   // @param aCapacity The desired capacity of this array.
    1815             :   // @return True if the operation succeeded; false if we ran out of memory
    1816             : protected:
    1817             :   template<typename ActualAlloc = Alloc>
    1818        4819 :   typename ActualAlloc::ResultType SetCapacity(size_type aCapacity)
    1819             :   {
    1820        9159 :     return ActualAlloc::Result(this->template EnsureCapacity<ActualAlloc>(
    1821        9159 :       aCapacity, sizeof(elem_type)));
    1822             :   }
    1823             : public:
    1824             : 
    1825             :   MOZ_MUST_USE
    1826         479 :   bool SetCapacity(size_type aCapacity, const mozilla::fallible_t&)
    1827             :   {
    1828         479 :     return SetCapacity<FallibleAlloc>(aCapacity);
    1829             :   }
    1830             : 
    1831             :   // This method modifies the length of the array.  If the new length is
    1832             :   // larger than the existing length of the array, then new elements will be
    1833             :   // constructed using elem_type's default constructor.  Otherwise, this call
    1834             :   // removes elements from the array (see also RemoveElementsAt).
    1835             :   // @param aNewLen The desired length of this array.
    1836             :   // @return True if the operation succeeded; false otherwise.
    1837             :   // See also TruncateLength if the new length is guaranteed to be smaller than
    1838             :   // the old.
    1839             : protected:
    1840             :   template<typename ActualAlloc = Alloc>
    1841        3933 :   typename ActualAlloc::ResultType SetLength(size_type aNewLen)
    1842             :   {
    1843        3933 :     size_type oldLen = Length();
    1844        3933 :     if (aNewLen > oldLen) {
    1845        2006 :       return ActualAlloc::ConvertBoolToResultType(
    1846        4012 :         InsertElementsAt<ActualAlloc>(oldLen, aNewLen - oldLen) != nullptr);
    1847             :     }
    1848             : 
    1849        1927 :     TruncateLength(aNewLen);
    1850        1927 :     return ActualAlloc::ConvertBoolToResultType(true);
    1851             :   }
    1852             : public:
    1853             : 
    1854             :   MOZ_MUST_USE
    1855        1353 :   bool SetLength(size_type aNewLen, const mozilla::fallible_t&)
    1856             :   {
    1857        1353 :     return SetLength<FallibleAlloc>(aNewLen);
    1858             :   }
    1859             : 
    1860             :   // This method modifies the length of the array, but may only be
    1861             :   // called when the new length is shorter than the old.  It can
    1862             :   // therefore be called when elem_type has no default constructor,
    1863             :   // unlike SetLength.  It removes elements from the array (see also
    1864             :   // RemoveElementsAt).
    1865             :   // @param aNewLen The desired length of this array.
    1866        7747 :   void TruncateLength(size_type aNewLen)
    1867             :   {
    1868        7747 :     size_type oldLen = Length();
    1869        7747 :     MOZ_ASSERT(aNewLen <= oldLen,
    1870             :                "caller should use SetLength instead");
    1871        7747 :     RemoveElementsAt(aNewLen, oldLen - aNewLen);
    1872        7747 :   }
    1873             : 
    1874             :   // This method ensures that the array has length at least the given
    1875             :   // length.  If the current length is shorter than the given length,
    1876             :   // then new elements will be constructed using elem_type's default
    1877             :   // constructor.
    1878             :   // @param aMinLen The desired minimum length of this array.
    1879             :   // @return True if the operation succeeded; false otherwise.
    1880             : protected:
    1881             :   template<typename ActualAlloc = Alloc>
    1882         164 :   typename ActualAlloc::ResultType EnsureLengthAtLeast(size_type aMinLen)
    1883             :   {
    1884         164 :     size_type oldLen = Length();
    1885         164 :     if (aMinLen > oldLen) {
    1886          14 :       return ActualAlloc::ConvertBoolToResultType(
    1887          28 :         !!InsertElementsAt<ActualAlloc>(oldLen, aMinLen - oldLen));
    1888             :     }
    1889         150 :     return ActualAlloc::ConvertBoolToResultType(true);
    1890             :   }
    1891             : public:
    1892             : 
    1893             :   MOZ_MUST_USE
    1894             :   bool EnsureLengthAtLeast(size_type aMinLen, const mozilla::fallible_t&)
    1895             :   {
    1896             :     return EnsureLengthAtLeast<FallibleAlloc>(aMinLen);
    1897             :   }
    1898             : 
    1899             :   // This method inserts elements into the array, constructing
    1900             :   // them using elem_type's default constructor.
    1901             :   // @param aIndex the place to insert the new elements. This must be no
    1902             :   //               greater than the current length of the array.
    1903             :   // @param aCount the number of elements to insert
    1904             : protected:
    1905             :   template<typename ActualAlloc = Alloc>
    1906        2180 :   elem_type* InsertElementsAt(index_type aIndex, size_type aCount)
    1907             :   {
    1908        2180 :     if (!base_type::template InsertSlotsAt<ActualAlloc>(aIndex, aCount,
    1909             :                                                         sizeof(elem_type),
    1910             :                                                         MOZ_ALIGNOF(elem_type))) {
    1911           0 :       return nullptr;
    1912             :     }
    1913             : 
    1914             :     // Initialize the extra array elements
    1915        2180 :     elem_type* iter = Elements() + aIndex;
    1916        2180 :     elem_type* iend = iter + aCount;
    1917      682668 :     for (; iter != iend; ++iter) {
    1918      340244 :       elem_traits::Construct(iter);
    1919             :     }
    1920             : 
    1921        2180 :     return Elements() + aIndex;
    1922             :   }
    1923             : public:
    1924             : 
    1925             :   MOZ_MUST_USE
    1926         136 :   elem_type* InsertElementsAt(index_type aIndex, size_type aCount,
    1927             :                               const mozilla::fallible_t&)
    1928             :   {
    1929         136 :     return InsertElementsAt<FallibleAlloc>(aIndex, aCount);
    1930             :   }
    1931             : 
    1932             :   // This method inserts elements into the array, constructing them
    1933             :   // elem_type's copy constructor (or whatever one-arg constructor
    1934             :   // happens to match the Item type).
    1935             :   // @param aIndex the place to insert the new elements. This must be no
    1936             :   //               greater than the current length of the array.
    1937             :   // @param aCount the number of elements to insert.
    1938             :   // @param aItem the value to use when constructing the new elements.
    1939             : protected:
    1940             :   template<class Item, typename ActualAlloc = Alloc>
    1941             :   elem_type* InsertElementsAt(index_type aIndex, size_type aCount,
    1942             :                               const Item& aItem);
    1943             : 
    1944             : public:
    1945             : 
    1946             :   template<class Item>
    1947             :   MOZ_MUST_USE
    1948             :   elem_type* InsertElementsAt(index_type aIndex, size_type aCount,
    1949             :                               const Item& aItem, const mozilla::fallible_t&)
    1950             :   {
    1951             :     return InsertElementsAt<Item, FallibleAlloc>(aIndex, aCount, aItem);
    1952             :   }
    1953             : 
    1954             :   // This method may be called to minimize the memory used by this array.
    1955         749 :   void Compact()
    1956             :   {
    1957         749 :     ShrinkCapacity(sizeof(elem_type), MOZ_ALIGNOF(elem_type));
    1958         749 :   }
    1959             : 
    1960             :   //
    1961             :   // Sorting
    1962             :   //
    1963             : 
    1964             :   // This function is meant to be used with the NS_QuickSort function.  It
    1965             :   // maps the callback API expected by NS_QuickSort to the Comparator API
    1966             :   // used by nsTArray_Impl.  See nsTArray_Impl::Sort.
    1967             :   template<class Comparator>
    1968         645 :   static int Compare(const void* aE1, const void* aE2, void* aData)
    1969             :   {
    1970         645 :     const Comparator* c = reinterpret_cast<const Comparator*>(aData);
    1971         645 :     const elem_type* a = static_cast<const elem_type*>(aE1);
    1972         645 :     const elem_type* b = static_cast<const elem_type*>(aE2);
    1973         645 :     return c->LessThan(*a, *b) ? -1 : (c->Equals(*a, *b) ? 0 : 1);
    1974             :   }
    1975             : 
    1976             :   // This method sorts the elements of the array.  It uses the LessThan
    1977             :   // method defined on the given Comparator object to collate elements.
    1978             :   // @param aComp The Comparator used to collate elements.
    1979             :   template<class Comparator>
    1980          71 :   void Sort(const Comparator& aComp)
    1981             :   {
    1982          71 :     NS_QuickSort(Elements(), Length(), sizeof(elem_type),
    1983             :                  Compare<Comparator>, const_cast<Comparator*>(&aComp));
    1984          71 :   }
    1985             : 
    1986             :   // A variation on the Sort method defined above that assumes that
    1987             :   // 'operator<' is defined for elem_type.
    1988          27 :   void Sort() { Sort(nsDefaultComparator<elem_type, elem_type>()); }
    1989             : 
    1990             :   // This method reverses the array in place.
    1991           0 :   void Reverse()
    1992             :   {
    1993           0 :     elem_type* elements = Elements();
    1994           0 :     const size_type len = Length();
    1995           0 :     for (index_type i = 0, iend = len / 2; i < iend; ++i) {
    1996           0 :       mozilla::Swap(elements[i], elements[len - i - 1]);
    1997             :     }
    1998           0 :   }
    1999             : 
    2000             : protected:
    2001             :   using base_type::Hdr;
    2002             :   using base_type::ShrinkCapacity;
    2003             : 
    2004             :   // This method invokes elem_type's destructor on a range of elements.
    2005             :   // @param aStart The index of the first element to destroy.
    2006             :   // @param aCount The number of elements to destroy.
    2007       74324 :   void DestructRange(index_type aStart, size_type aCount)
    2008             :   {
    2009       74324 :     elem_type* iter = Elements() + aStart;
    2010       74324 :     elem_type *iend = iter + aCount;
    2011     2762790 :     for (; iter != iend; ++iter) {
    2012     1344233 :       elem_traits::Destruct(iter);
    2013             :     }
    2014       74324 :   }
    2015             : 
    2016             :   // This method invokes elem_type's copy-constructor on a range of elements.
    2017             :   // @param aStart  The index of the first element to construct.
    2018             :   // @param aCount  The number of elements to construct.
    2019             :   // @param aValues The array of elements to copy.
    2020             :   template<class Item>
    2021       24692 :   void AssignRange(index_type aStart, size_type aCount, const Item* aValues)
    2022             :   {
    2023       24692 :     AssignRangeAlgorithm<mozilla::IsPod<Item>::value,
    2024             :                          mozilla::IsSame<Item, elem_type>::value>
    2025       24692 :                          ::implementation(Elements(), aStart, aCount, aValues);
    2026       24692 :   }
    2027             : };
    2028             : 
    2029             : template<typename E, class Alloc>
    2030             : template<class Item, typename ActualAlloc>
    2031             : auto
    2032        7422 : nsTArray_Impl<E, Alloc>::ReplaceElementsAt(index_type aStart, size_type aCount,
    2033             :                                            const Item* aArray, size_type aArrayLen) -> elem_type*
    2034             : {
    2035        7422 :   if (MOZ_UNLIKELY(aStart > Length())) {
    2036           0 :     InvalidArrayIndex_CRASH(aStart, Length());
    2037             :   }
    2038             : 
    2039             :   // Adjust memory allocation up-front to catch errors.
    2040        7422 :   if (!ActualAlloc::Successful(this->template EnsureCapacity<ActualAlloc>(
    2041        7422 :         Length() + aArrayLen - aCount, sizeof(elem_type)))) {
    2042           0 :     return nullptr;
    2043             :   }
    2044        7422 :   DestructRange(aStart, aCount);
    2045        7422 :   this->template ShiftData<ActualAlloc>(aStart, aCount, aArrayLen,
    2046             :                                         sizeof(elem_type),
    2047             :                                         MOZ_ALIGNOF(elem_type));
    2048        7422 :   AssignRange(aStart, aArrayLen, aArray);
    2049        7422 :   return Elements() + aStart;
    2050             : }
    2051             : 
    2052             : template<typename E, class Alloc>
    2053             : void
    2054       61812 : nsTArray_Impl<E, Alloc>::RemoveElementsAt(index_type aStart, size_type aCount)
    2055             : {
    2056       61812 :   MOZ_ASSERT(aCount == 0 || aStart < Length(), "Invalid aStart index");
    2057       61812 :   MOZ_ASSERT(aStart + aCount <= Length(), "Invalid length");
    2058             :   // Check that the previous assert didn't overflow
    2059       61812 :   MOZ_ASSERT(aStart <= aStart + aCount, "Start index plus length overflows");
    2060       61812 :   DestructRange(aStart, aCount);
    2061       61812 :   this->template ShiftData<InfallibleAlloc>(aStart, aCount, 0,
    2062             :                                             sizeof(elem_type),
    2063             :                                             MOZ_ALIGNOF(elem_type));
    2064       61811 : }
    2065             : 
    2066             : template<typename E, class Alloc>
    2067             : template<typename Predicate>
    2068             : void
    2069          14 : nsTArray_Impl<E, Alloc>::RemoveElementsBy(Predicate aPredicate)
    2070             : {
    2071          14 :   if (base_type::mHdr == EmptyHdr()) {
    2072           0 :     return;
    2073             :   }
    2074             : 
    2075          14 :   index_type j = 0;
    2076          14 :   index_type len = Length();
    2077          30 :   for (index_type i = 0; i < len; ++i) {
    2078          16 :     if (aPredicate(Elements()[i])) {
    2079           1 :       elem_traits::Destruct(Elements() + i);
    2080             :     } else {
    2081          15 :       if (j < i) {
    2082           7 :         copy_type::MoveNonOverlappingRegion(Elements() + j, Elements() + i,
    2083             :                                             1, sizeof(elem_type));
    2084             :       }
    2085          15 :       ++j;
    2086             :     }
    2087             :   }
    2088          14 :   base_type::mHdr->mLength = j;
    2089             : }
    2090             : 
    2091             : template<typename E, class Alloc>
    2092             : template<class Item, typename ActualAlloc>
    2093             : auto
    2094           0 : nsTArray_Impl<E, Alloc>::InsertElementsAt(index_type aIndex, size_type aCount,
    2095             :                                           const Item& aItem) -> elem_type*
    2096             : {
    2097           0 :   if (!base_type::template InsertSlotsAt<ActualAlloc>(aIndex, aCount,
    2098             :                                                       sizeof(elem_type),
    2099             :                                                       MOZ_ALIGNOF(elem_type))) {
    2100           0 :     return nullptr;
    2101             :   }
    2102             : 
    2103             :   // Initialize the extra array elements
    2104           0 :   elem_type* iter = Elements() + aIndex;
    2105           0 :   elem_type* iend = iter + aCount;
    2106           0 :   for (; iter != iend; ++iter) {
    2107           0 :     elem_traits::Construct(iter, aItem);
    2108             :   }
    2109             : 
    2110           0 :   return Elements() + aIndex;
    2111             : }
    2112             : 
    2113             : template<typename E, class Alloc>
    2114             : template<typename ActualAlloc>
    2115             : auto
    2116           0 : nsTArray_Impl<E, Alloc>::InsertElementAt(index_type aIndex) -> elem_type*
    2117             : {
    2118           0 :   if (MOZ_UNLIKELY(aIndex > Length())) {
    2119           0 :     InvalidArrayIndex_CRASH(aIndex, Length());
    2120             :   }
    2121             : 
    2122           0 :   if (!ActualAlloc::Successful(this->template EnsureCapacity<ActualAlloc>(
    2123           0 :         Length() + 1, sizeof(elem_type)))) {
    2124           0 :     return nullptr;
    2125             :   }
    2126           0 :   this->template ShiftData<ActualAlloc>(aIndex, 0, 1, sizeof(elem_type),
    2127             :                                         MOZ_ALIGNOF(elem_type));
    2128           0 :   elem_type* elem = Elements() + aIndex;
    2129           0 :   elem_traits::Construct(elem);
    2130           0 :   return elem;
    2131             : }
    2132             : 
    2133             : template<typename E, class Alloc>
    2134             : template<class Item, typename ActualAlloc>
    2135             : auto
    2136        7098 : nsTArray_Impl<E, Alloc>::InsertElementAt(index_type aIndex, Item&& aItem) -> elem_type*
    2137             : {
    2138        7098 :   if (MOZ_UNLIKELY(aIndex > Length())) {
    2139           0 :     InvalidArrayIndex_CRASH(aIndex, Length());
    2140             :   }
    2141             : 
    2142        7098 :   if (!ActualAlloc::Successful(this->template EnsureCapacity<ActualAlloc>(
    2143        7098 :          Length() + 1, sizeof(elem_type)))) {
    2144           0 :     return nullptr;
    2145             :   }
    2146        7098 :   this->template ShiftData<ActualAlloc>(aIndex, 0, 1, sizeof(elem_type),
    2147             :                                         MOZ_ALIGNOF(elem_type));
    2148        7098 :   elem_type* elem = Elements() + aIndex;
    2149        7098 :   elem_traits::Construct(elem, mozilla::Forward<Item>(aItem));
    2150        7098 :   return elem;
    2151             : }
    2152             : 
    2153             : template<typename E, class Alloc>
    2154             : template<class Item, typename ActualAlloc>
    2155             : auto
    2156       17270 : nsTArray_Impl<E, Alloc>::AppendElements(const Item* aArray, size_type aArrayLen) -> elem_type*
    2157             : {
    2158       17270 :   if (!ActualAlloc::Successful(this->template EnsureCapacity<ActualAlloc>(
    2159       17270 :         Length() + aArrayLen, sizeof(elem_type)))) {
    2160           0 :     return nullptr;
    2161             :   }
    2162       17270 :   index_type len = Length();
    2163       17270 :   AssignRange(len, aArrayLen, aArray);
    2164       17270 :   this->IncrementLength(aArrayLen);
    2165       17270 :   return Elements() + len;
    2166             : }
    2167             : 
    2168             : template<typename E, class Alloc>
    2169             : template<class Item, class Allocator, typename ActualAlloc>
    2170             : auto
    2171          58 : nsTArray_Impl<E, Alloc>::AppendElements(nsTArray_Impl<Item, Allocator>&& aArray) -> elem_type*
    2172             : {
    2173          58 :   MOZ_ASSERT(&aArray != this, "argument must be different aArray");
    2174          58 :   if (Length() == 0) {
    2175          54 :     SwapElements<ActualAlloc>(aArray);
    2176          54 :     return Elements();
    2177             :   }
    2178             : 
    2179           4 :   index_type len = Length();
    2180           4 :   index_type otherLen = aArray.Length();
    2181           4 :   if (!Alloc::Successful(this->template EnsureCapacity<Alloc>(
    2182             :         len + otherLen, sizeof(elem_type)))) {
    2183           0 :     return nullptr;
    2184             :   }
    2185           4 :   copy_type::MoveNonOverlappingRegion(Elements() + len, aArray.Elements(), otherLen,
    2186             :                                       sizeof(elem_type));
    2187           4 :   this->IncrementLength(otherLen);
    2188           4 :   aArray.template ShiftData<Alloc>(0, otherLen, 0, sizeof(elem_type),
    2189             :                                    MOZ_ALIGNOF(elem_type));
    2190           4 :   return Elements() + len;
    2191             : }
    2192             : 
    2193             : template<typename E, class Alloc>
    2194             : template<class Item, typename ActualAlloc>
    2195             : auto
    2196      118768 : nsTArray_Impl<E, Alloc>::AppendElement(Item&& aItem) -> elem_type*
    2197             : {
    2198      118768 :   if (!ActualAlloc::Successful(this->template EnsureCapacity<ActualAlloc>(
    2199      118768 :          Length() + 1, sizeof(elem_type)))) {
    2200           0 :     return nullptr;
    2201             :   }
    2202      118768 :   elem_type* elem = Elements() + Length();
    2203      118768 :   elem_traits::Construct(elem, mozilla::Forward<Item>(aItem));
    2204      118768 :   this->IncrementLength(1);
    2205      118768 :   return elem;
    2206             : }
    2207             : 
    2208             : template<typename E, typename Alloc>
    2209             : inline void
    2210           0 : ImplCycleCollectionUnlink(nsTArray_Impl<E, Alloc>& aField)
    2211             : {
    2212           0 :   aField.Clear();
    2213           0 : }
    2214             : 
    2215             : template<typename E, typename Alloc>
    2216             : inline void
    2217          70 : ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& aCallback,
    2218             :                             nsTArray_Impl<E, Alloc>& aField,
    2219             :                             const char* aName,
    2220             :                             uint32_t aFlags = 0)
    2221             : {
    2222          70 :   aFlags |= CycleCollectionEdgeNameArrayFlag;
    2223          70 :   size_t length = aField.Length();
    2224          79 :   for (size_t i = 0; i < length; ++i) {
    2225           9 :     ImplCycleCollectionTraverse(aCallback, aField[i], aName, aFlags);
    2226             :   }
    2227          70 : }
    2228             : 
    2229             : //
    2230             : // nsTArray is an infallible vector class.  See the comment at the top of this
    2231             : // file for more details.
    2232             : //
    2233             : template<class E>
    2234      139902 : class nsTArray : public nsTArray_Impl<E, nsTArrayInfallibleAllocator>
    2235             : {
    2236             : public:
    2237             :   typedef nsTArray_Impl<E, nsTArrayInfallibleAllocator> base_type;
    2238             :   typedef nsTArray<E>                                   self_type;
    2239             :   typedef typename base_type::size_type                 size_type;
    2240             : 
    2241      166259 :   nsTArray() {}
    2242        1926 :   explicit nsTArray(size_type aCapacity) : base_type(aCapacity) {}
    2243       10726 :   explicit nsTArray(const nsTArray& aOther) : base_type(aOther) {}
    2244        5185 :   MOZ_IMPLICIT nsTArray(nsTArray&& aOther) : base_type(mozilla::Move(aOther)) {}
    2245         189 :   MOZ_IMPLICIT nsTArray(std::initializer_list<E> aIL) : base_type(aIL) {}
    2246             : 
    2247             :   template<class Allocator>
    2248           0 :   explicit nsTArray(const nsTArray_Impl<E, Allocator>& aOther)
    2249           0 :     : base_type(aOther)
    2250             :   {
    2251           0 :   }
    2252             :   template<class Allocator>
    2253             :   MOZ_IMPLICIT nsTArray(nsTArray_Impl<E, Allocator>&& aOther)
    2254             :     : base_type(mozilla::Move(aOther))
    2255             :   {
    2256             :   }
    2257             : 
    2258        6540 :   self_type& operator=(const self_type& aOther)
    2259             :   {
    2260        6540 :     base_type::operator=(aOther);
    2261        6540 :     return *this;
    2262             :   }
    2263             :   template<class Allocator>
    2264           1 :   self_type& operator=(const nsTArray_Impl<E, Allocator>& aOther)
    2265             :   {
    2266           1 :     base_type::operator=(aOther);
    2267           1 :     return *this;
    2268             :   }
    2269         902 :   self_type& operator=(self_type&& aOther)
    2270             :   {
    2271         902 :     base_type::operator=(mozilla::Move(aOther));
    2272         902 :     return *this;
    2273             :   }
    2274             :   template<class Allocator>
    2275             :   self_type& operator=(nsTArray_Impl<E, Allocator>&& aOther)
    2276             :   {
    2277             :     base_type::operator=(mozilla::Move(aOther));
    2278             :     return *this;
    2279             :   }
    2280             : 
    2281             :   using base_type::AppendElement;
    2282             :   using base_type::AppendElements;
    2283             :   using base_type::EnsureLengthAtLeast;
    2284             :   using base_type::InsertElementAt;
    2285             :   using base_type::InsertElementsAt;
    2286             :   using base_type::InsertElementSorted;
    2287             :   using base_type::ReplaceElementsAt;
    2288             :   using base_type::SetCapacity;
    2289             :   using base_type::SetLength;
    2290             : };
    2291             : 
    2292             : //
    2293             : // FallibleTArray is a fallible vector class.
    2294             : //
    2295             : template<class E>
    2296         945 : class FallibleTArray : public nsTArray_Impl<E, nsTArrayFallibleAllocator>
    2297             : {
    2298             : public:
    2299             :   typedef nsTArray_Impl<E, nsTArrayFallibleAllocator>   base_type;
    2300             :   typedef FallibleTArray<E>                             self_type;
    2301             :   typedef typename base_type::size_type                 size_type;
    2302             : 
    2303        1798 :   FallibleTArray() {}
    2304           0 :   explicit FallibleTArray(size_type aCapacity) : base_type(aCapacity) {}
    2305           0 :   explicit FallibleTArray(const FallibleTArray<E>& aOther) : base_type(aOther) {}
    2306           0 :   FallibleTArray(FallibleTArray<E>&& aOther)
    2307           0 :     : base_type(mozilla::Move(aOther))
    2308             :   {
    2309           0 :   }
    2310             : 
    2311             :   template<class Allocator>
    2312             :   explicit FallibleTArray(const nsTArray_Impl<E, Allocator>& aOther)
    2313             :     : base_type(aOther)
    2314             :   {
    2315             :   }
    2316             :   template<class Allocator>
    2317           0 :   explicit FallibleTArray(nsTArray_Impl<E, Allocator>&& aOther)
    2318           0 :     : base_type(mozilla::Move(aOther))
    2319             :   {
    2320           0 :   }
    2321             : 
    2322           0 :   self_type& operator=(const self_type& aOther)
    2323             :   {
    2324           0 :     base_type::operator=(aOther);
    2325           0 :     return *this;
    2326             :   }
    2327             :   template<class Allocator>
    2328             :   self_type& operator=(const nsTArray_Impl<E, Allocator>& aOther)
    2329             :   {
    2330             :     base_type::operator=(aOther);
    2331             :     return *this;
    2332             :   }
    2333           0 :   self_type& operator=(self_type&& aOther)
    2334             :   {
    2335           0 :     base_type::operator=(mozilla::Move(aOther));
    2336           0 :     return *this;
    2337             :   }
    2338             :   template<class Allocator>
    2339             :   self_type& operator=(nsTArray_Impl<E, Allocator>&& aOther)
    2340             :   {
    2341             :     base_type::operator=(mozilla::Move(aOther));
    2342             :     return *this;
    2343             :   }
    2344             : };
    2345             : 
    2346             : //
    2347             : // AutoTArray<E, N> is like nsTArray<E>, but with N elements of inline storage.
    2348             : // Storing more than N elements is fine, but it will cause a heap allocation.
    2349             : //
    2350             : template<class E, size_t N>
    2351       60109 : class MOZ_NON_MEMMOVABLE AutoTArray : public nsTArray<E>
    2352             : {
    2353             :   static_assert(N != 0, "AutoTArray<E, 0> should be specialized");
    2354             : public:
    2355             :   typedef AutoTArray<E, N> self_type;
    2356             :   typedef nsTArray<E> base_type;
    2357             :   typedef typename base_type::Header Header;
    2358             :   typedef typename base_type::elem_type elem_type;
    2359             : 
    2360       69296 :   AutoTArray()
    2361       69296 :   {
    2362       69296 :     Init();
    2363       69296 :   }
    2364             : 
    2365        1579 :   AutoTArray(const self_type& aOther)
    2366        1579 :   {
    2367        1579 :     Init();
    2368        1579 :     this->AppendElements(aOther);
    2369        1579 :   }
    2370             : 
    2371        1464 :   explicit AutoTArray(const base_type& aOther)
    2372        1464 :   {
    2373        1464 :     Init();
    2374        1464 :     this->AppendElements(aOther);
    2375        1464 :   }
    2376             : 
    2377           0 :   explicit AutoTArray(base_type&& aOther)
    2378           0 :   {
    2379           0 :     Init();
    2380           0 :     this->SwapElements(aOther);
    2381           0 :   }
    2382             : 
    2383             :   template<typename Allocator>
    2384             :   explicit AutoTArray(nsTArray_Impl<elem_type, Allocator>&& aOther)
    2385             :   {
    2386             :     Init();
    2387             :     this->SwapElements(aOther);
    2388             :   }
    2389             : 
    2390           0 :   MOZ_IMPLICIT AutoTArray(std::initializer_list<E> aIL)
    2391           0 :   {
    2392           0 :     Init();
    2393           0 :     this->AppendElements(aIL.begin(), aIL.size());
    2394           0 :   }
    2395             : 
    2396           0 :   self_type& operator=(const self_type& aOther)
    2397             :   {
    2398           0 :     base_type::operator=(aOther);
    2399           0 :     return *this;
    2400             :   }
    2401             : 
    2402             :   template<typename Allocator>
    2403           1 :   self_type& operator=(const nsTArray_Impl<elem_type, Allocator>& aOther)
    2404             :   {
    2405           1 :     base_type::operator=(aOther);
    2406           1 :     return *this;
    2407             :   }
    2408             : 
    2409             : private:
    2410             :   // nsTArray_base casts itself as an nsAutoArrayBase in order to get a pointer
    2411             :   // to mAutoBuf.
    2412             :   template<class Allocator, class Copier>
    2413             :   friend class nsTArray_base;
    2414             : 
    2415       72339 :   void Init()
    2416             :   {
    2417             :     static_assert(MOZ_ALIGNOF(elem_type) <= 8,
    2418             :                   "can't handle alignments greater than 8, "
    2419             :                   "see nsTArray_base::UsesAutoArrayBuffer()");
    2420             :     // Temporary work around for VS2012 RC compiler crash
    2421       72339 :     Header** phdr = base_type::PtrToHdr();
    2422       72339 :     *phdr = reinterpret_cast<Header*>(&mAutoBuf);
    2423       72339 :     (*phdr)->mLength = 0;
    2424       72339 :     (*phdr)->mCapacity = N;
    2425       72339 :     (*phdr)->mIsAutoArray = 1;
    2426             : 
    2427       72339 :     MOZ_ASSERT(base_type::GetAutoArrayBuffer(MOZ_ALIGNOF(elem_type)) ==
    2428             :                reinterpret_cast<Header*>(&mAutoBuf),
    2429             :                "GetAutoArrayBuffer needs to be fixed");
    2430       72339 :   }
    2431             : 
    2432             :   // Declare mAutoBuf aligned to the maximum of the header's alignment and
    2433             :   // elem_type's alignment.  We need to use a union rather than
    2434             :   // MOZ_ALIGNED_DECL because GCC is picky about what goes into
    2435             :   // __attribute__((aligned(foo))).
    2436             :   union
    2437             :   {
    2438             :     char mAutoBuf[sizeof(nsTArrayHeader) + N * sizeof(elem_type)];
    2439             :     // Do the max operation inline to ensure that it is a compile-time constant.
    2440             :     mozilla::AlignedElem<(MOZ_ALIGNOF(Header) > MOZ_ALIGNOF(elem_type)) ?
    2441             :                          MOZ_ALIGNOF(Header) : MOZ_ALIGNOF(elem_type)> mAlign;
    2442             :   };
    2443             : };
    2444             : 
    2445             : //
    2446             : // Specialization of AutoTArray<E, N> for the case where N == 0.
    2447             : // AutoTArray<E, 0> behaves exactly like nsTArray<E>, but without this
    2448             : // specialization, it stores a useless inline header.
    2449             : //
    2450             : // We do have many AutoTArray<E, 0> objects in memory: about 2,000 per tab as
    2451             : // of May 2014. These are typically not explicitly AutoTArray<E, 0> but rather
    2452             : // AutoTArray<E, N> for some value N depending on template parameters, in
    2453             : // generic code.
    2454             : //
    2455             : // For that reason, we optimize this case with the below partial specialization,
    2456             : // which ensures that AutoTArray<E, 0> is just like nsTArray<E>, without any
    2457             : // inline header overhead.
    2458             : //
    2459             : template<class E>
    2460        1396 : class AutoTArray<E, 0> : public nsTArray<E>
    2461             : {
    2462             : };
    2463             : 
    2464             : template<class E, size_t N>
    2465             : struct nsTArray_CopyChooser<AutoTArray<E, N>>
    2466             : {
    2467             :   typedef nsTArray_CopyWithConstructors<AutoTArray<E, N>> Type;
    2468             : };
    2469             : 
    2470             : // Span integration
    2471             : namespace mozilla {
    2472             : 
    2473             : template<class ElementType, class TArrayAlloc>
    2474             : Span<ElementType>
    2475           6 : MakeSpan(nsTArray_Impl<ElementType, TArrayAlloc>& aTArray)
    2476             : {
    2477           6 :   return aTArray;
    2478             : }
    2479             : 
    2480             : template<class ElementType, class TArrayAlloc>
    2481             : Span<const ElementType>
    2482             : MakeSpan(const nsTArray_Impl<ElementType, TArrayAlloc>& aTArray)
    2483             : {
    2484             :   return aTArray;
    2485             : }
    2486             : 
    2487             : } // namespace mozilla
    2488             : 
    2489             : // Assert that AutoTArray doesn't have any extra padding inside.
    2490             : //
    2491             : // It's important that the data stored in this auto array takes up a multiple of
    2492             : // 8 bytes; e.g. AutoTArray<uint32_t, 1> wouldn't work.  Since AutoTArray
    2493             : // contains a pointer, its size must be a multiple of alignof(void*).  (This is
    2494             : // because any type may be placed into an array, and there's no padding between
    2495             : // elements of an array.)  The compiler pads the end of the structure to
    2496             : // enforce this rule.
    2497             : //
    2498             : // If we used AutoTArray<uint32_t, 1> below, this assertion would fail on a
    2499             : // 64-bit system, where the compiler inserts 4 bytes of padding at the end of
    2500             : // the auto array to make its size a multiple of alignof(void*) == 8 bytes.
    2501             : 
    2502             : static_assert(sizeof(AutoTArray<uint32_t, 2>) ==
    2503             :               sizeof(void*) + sizeof(nsTArrayHeader) + sizeof(uint32_t) * 2,
    2504             :               "AutoTArray shouldn't contain any extra padding, "
    2505             :               "see the comment");
    2506             : 
    2507             : // Definitions of nsTArray_Impl methods
    2508             : #include "nsTArray-inl.h"
    2509             : 
    2510             : #endif  // nsTArray_h__

Generated by: LCOV version 1.13