xpcom/glue/nsTArray.h

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/xpcom/glue/nsTArray.h	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,1830 @@
     1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     1.5 +/* vim:set ts=2 sw=2 sts=2 et cindent: */
     1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.9 +
    1.10 +#ifndef nsTArray_h__
    1.11 +#define nsTArray_h__
    1.12 +
    1.13 +#include "nsTArrayForwardDeclare.h"
    1.14 +#include "mozilla/Alignment.h"
    1.15 +#include "mozilla/Assertions.h"
    1.16 +#include "mozilla/MemoryReporting.h"
    1.17 +#include "mozilla/TypeTraits.h"
    1.18 +
    1.19 +#include <string.h>
    1.20 +
    1.21 +#include "nsCycleCollectionNoteChild.h"
    1.22 +#include "nsAlgorithm.h"
    1.23 +#include "nscore.h"
    1.24 +#include "nsQuickSort.h"
    1.25 +#include "nsDebug.h"
    1.26 +#include "nsISupportsImpl.h"
    1.27 +#include <new>
    1.28 +
    1.29 +namespace JS {
    1.30 +template <class T>
    1.31 +class Heap;
    1.32 +} /* namespace JS */
    1.33 +
    1.34 +class nsRegion;
    1.35 +class nsIntRegion;
    1.36 +
    1.37 +//
    1.38 +// nsTArray is a resizable array class, like std::vector.
    1.39 +//
    1.40 +// Unlike std::vector, which follows C++'s construction/destruction rules,
    1.41 +// nsTArray assumes that your "T" can be memmoved()'ed safely.
    1.42 +//
    1.43 +// The public classes defined in this header are
    1.44 +//
    1.45 +//   nsTArray<T>,
    1.46 +//   FallibleTArray<T>,
    1.47 +//   nsAutoTArray<T, N>, and
    1.48 +//   AutoFallibleTArray<T, N>.
    1.49 +//
    1.50 +// nsTArray and nsAutoTArray are infallible; if one tries to make an allocation
    1.51 +// which fails, it crashes the program.  In contrast, FallibleTArray and
    1.52 +// AutoFallibleTArray are fallible; if you use one of these classes, you must
    1.53 +// check the return values of methods such as Append() which may allocate.  If
    1.54 +// in doubt, choose an infallible type.
    1.55 +//
    1.56 +// InfallibleTArray and AutoInfallibleTArray are aliases for nsTArray and
    1.57 +// nsAutoTArray.
    1.58 +//
    1.59 +// If you just want to declare the nsTArray types (e.g., if you're in a header
    1.60 +// file and don't need the full nsTArray definitions) consider including
    1.61 +// nsTArrayForwardDeclare.h instead of nsTArray.h.
    1.62 +//
    1.63 +// The template parameter (i.e., T in nsTArray<T>) specifies the type of the
    1.64 +// elements and has the following requirements:
    1.65 +//
    1.66 +//   T MUST be safely memmove()'able.
    1.67 +//   T MUST define a copy-constructor.
    1.68 +//   T MAY define operator< for sorting.
    1.69 +//   T MAY define operator== for searching.
    1.70 +//
    1.71 +// (Note that the memmove requirement may be relaxed for certain types - see
    1.72 +// nsTArray_CopyChooser below.)
    1.73 +//
    1.74 +// For methods taking a Comparator instance, the Comparator must be a class
    1.75 +// defining the following methods:
    1.76 +//
    1.77 +//   class Comparator {
    1.78 +//     public:
    1.79 +//       /** @return True if the elements are equals; false otherwise. */
    1.80 +//       bool Equals(const elem_type& a, const Item& b) const;
    1.81 +//
    1.82 +//       /** @return True if (a < b); false otherwise. */
    1.83 +//       bool LessThan(const elem_type& a, const Item& b) const;
    1.84 +//   };
    1.85 +//
    1.86 +// The Equals method is used for searching, and the LessThan method is used for
    1.87 +// searching and sorting.  The |Item| type above can be arbitrary, but must
    1.88 +// match the Item type passed to the sort or search function.
    1.89 +//
    1.90 +
    1.91 +
    1.92 +//
    1.93 +// nsTArrayFallibleResult and nsTArrayInfallibleResult types are proxy types
    1.94 +// which are used because you cannot use a templated type which is bound to
    1.95 +// void as an argument to a void function.  In order to work around that, we
    1.96 +// encode either a void or a boolean inside these proxy objects, and pass them
    1.97 +// to the aforementioned function instead, and then use the type information to
    1.98 +// decide what to do in the function.
    1.99 +//
   1.100 +// Note that public nsTArray methods should never return a proxy type.  Such
   1.101 +// types are only meant to be used in the internal nsTArray helper methods.
   1.102 +// Public methods returning non-proxy types cannot be called from other
   1.103 +// nsTArray members.
   1.104 +//
   1.105 +struct nsTArrayFallibleResult
   1.106 +{
   1.107 +  // Note: allows implicit conversions from and to bool
   1.108 +  nsTArrayFallibleResult(bool result)
   1.109 +    : mResult(result)
   1.110 +  {}
   1.111 +
   1.112 +  operator bool() {
   1.113 +    return mResult;
   1.114 +  }
   1.115 +
   1.116 +private:
   1.117 +  bool mResult;
   1.118 +};
   1.119 +
   1.120 +struct nsTArrayInfallibleResult
   1.121 +{
   1.122 +};
   1.123 +
   1.124 +//
   1.125 +// nsTArray*Allocators must all use the same |free()|, to allow swap()'ing
   1.126 +// between fallible and infallible variants.
   1.127 +//
   1.128 +
   1.129 +struct nsTArrayFallibleAllocatorBase
   1.130 +{
   1.131 +  typedef bool ResultType;
   1.132 +  typedef nsTArrayFallibleResult ResultTypeProxy;
   1.133 +
   1.134 +  static ResultType Result(ResultTypeProxy result) {
   1.135 +    return result;
   1.136 +  }
   1.137 +
   1.138 +  static bool Successful(ResultTypeProxy result) {
   1.139 +    return result;
   1.140 +  }
   1.141 +
   1.142 +  static ResultTypeProxy SuccessResult() {
   1.143 +    return true;
   1.144 +  }
   1.145 +
   1.146 +  static ResultTypeProxy FailureResult() {
   1.147 +    return false;
   1.148 +  }
   1.149 +
   1.150 +  static ResultType ConvertBoolToResultType(bool aValue) {
   1.151 +    return aValue;
   1.152 +  }
   1.153 +};
   1.154 +
   1.155 +struct nsTArrayInfallibleAllocatorBase
   1.156 +{
   1.157 +  typedef void ResultType;
   1.158 +  typedef nsTArrayInfallibleResult ResultTypeProxy;
   1.159 +
   1.160 +  static ResultType Result(ResultTypeProxy result) {
   1.161 +  }
   1.162 +
   1.163 +  static bool Successful(ResultTypeProxy) {
   1.164 +    return true;
   1.165 +  }
   1.166 +
   1.167 +  static ResultTypeProxy SuccessResult() {
   1.168 +    return ResultTypeProxy();
   1.169 +  }
   1.170 +
   1.171 +  static ResultTypeProxy FailureResult() {
   1.172 +    NS_RUNTIMEABORT("Infallible nsTArray should never fail");
   1.173 +    return ResultTypeProxy();
   1.174 +  }
   1.175 +
   1.176 +  static ResultType ConvertBoolToResultType(bool aValue) {
   1.177 +    if (!aValue) {
   1.178 +      NS_RUNTIMEABORT("infallible nsTArray should never convert false to ResultType");
   1.179 +    }
   1.180 +  }
   1.181 +};
   1.182 +
   1.183 +#if defined(MOZALLOC_HAVE_XMALLOC)
   1.184 +#include "mozilla/mozalloc_abort.h"
   1.185 +
   1.186 +struct nsTArrayFallibleAllocator : nsTArrayFallibleAllocatorBase
   1.187 +{
   1.188 +  static void* Malloc(size_t size) {
   1.189 +    return moz_malloc(size);
   1.190 +  }
   1.191 +
   1.192 +  static void* Realloc(void* ptr, size_t size) {
   1.193 +    return moz_realloc(ptr, size);
   1.194 +  }
   1.195 +
   1.196 +  static void Free(void* ptr) {
   1.197 +    moz_free(ptr);
   1.198 +  }
   1.199 +
   1.200 +  static void SizeTooBig(size_t) {
   1.201 +  }
   1.202 +};
   1.203 +
   1.204 +struct nsTArrayInfallibleAllocator : nsTArrayInfallibleAllocatorBase
   1.205 +{
   1.206 +  static void* Malloc(size_t size) {
   1.207 +    return moz_xmalloc(size);
   1.208 +  }
   1.209 +
   1.210 +  static void* Realloc(void* ptr, size_t size) {
   1.211 +    return moz_xrealloc(ptr, size);
   1.212 +  }
   1.213 +
   1.214 +  static void Free(void* ptr) {
   1.215 +    moz_free(ptr);
   1.216 +  }
   1.217 +
   1.218 +  static void SizeTooBig(size_t size) {
   1.219 +    NS_ABORT_OOM(size);
   1.220 +  }
   1.221 +};
   1.222 +
   1.223 +#else
   1.224 +#include <stdlib.h>
   1.225 +
   1.226 +struct nsTArrayFallibleAllocator : nsTArrayFallibleAllocatorBase
   1.227 +{
   1.228 +  static void* Malloc(size_t size) {
   1.229 +    return malloc(size);
   1.230 +  }
   1.231 +
   1.232 +  static void* Realloc(void* ptr, size_t size) {
   1.233 +    return realloc(ptr, size);
   1.234 +  }
   1.235 +
   1.236 +  static void Free(void* ptr) {
   1.237 +    free(ptr);
   1.238 +  }
   1.239 +
   1.240 +  static void SizeTooBig(size_t) {
   1.241 +  }
   1.242 +};
   1.243 +
   1.244 +struct nsTArrayInfallibleAllocator : nsTArrayInfallibleAllocatorBase
   1.245 +{
   1.246 +  static void* Malloc(size_t size) {
   1.247 +    void* ptr = malloc(size);
   1.248 +    if (MOZ_UNLIKELY(!ptr)) {
   1.249 +      NS_ABORT_OOM(size);
   1.250 +    }
   1.251 +    return ptr;
   1.252 +  }
   1.253 +
   1.254 +  static void* Realloc(void* ptr, size_t size) {
   1.255 +    void* newptr = realloc(ptr, size);
   1.256 +    if (MOZ_UNLIKELY(!ptr && size)) {
   1.257 +      NS_ABORT_OOM(size);
   1.258 +    }
   1.259 +    return newptr;
   1.260 +  }
   1.261 +
   1.262 +  static void Free(void* ptr) {
   1.263 +    free(ptr);
   1.264 +  }
   1.265 +
   1.266 +  static void SizeTooBig(size_t size) {
   1.267 +    NS_ABORT_OOM(size);
   1.268 +  }
   1.269 +};
   1.270 +
   1.271 +#endif
   1.272 +
   1.273 +// nsTArray_base stores elements into the space allocated beyond
   1.274 +// sizeof(*this).  This is done to minimize the size of the nsTArray
   1.275 +// object when it is empty.
   1.276 +struct NS_COM_GLUE nsTArrayHeader
   1.277 +{
   1.278 +  static nsTArrayHeader sEmptyHdr;
   1.279 +
   1.280 +  uint32_t mLength;
   1.281 +  uint32_t mCapacity : 31;
   1.282 +  uint32_t mIsAutoArray : 1;
   1.283 +};
   1.284 +
   1.285 +// This class provides a SafeElementAt method to nsTArray<T*> which does
   1.286 +// not take a second default value parameter.
   1.287 +template <class E, class Derived>
   1.288 +struct nsTArray_SafeElementAtHelper
   1.289 +{
   1.290 +  typedef E*       elem_type;
   1.291 +  typedef uint32_t index_type;
   1.292 +
   1.293 +  // No implementation is provided for these two methods, and that is on
   1.294 +  // purpose, since we don't support these functions on non-pointer type
   1.295 +  // instantiations.
   1.296 +  elem_type& SafeElementAt(index_type i);
   1.297 +  const elem_type& SafeElementAt(index_type i) const;
   1.298 +};
   1.299 +
   1.300 +template <class E, class Derived>
   1.301 +struct nsTArray_SafeElementAtHelper<E*, Derived>
   1.302 +{
   1.303 +  typedef E*       elem_type;
   1.304 +  typedef uint32_t index_type;
   1.305 +
   1.306 +  elem_type SafeElementAt(index_type i) {
   1.307 +    return static_cast<Derived*> (this)->SafeElementAt(i, nullptr);
   1.308 +  }
   1.309 +
   1.310 +  const elem_type SafeElementAt(index_type i) const {
   1.311 +    return static_cast<const Derived*> (this)->SafeElementAt(i, nullptr);
   1.312 +  }
   1.313 +};
   1.314 +
   1.315 +// E is the base type that the smart pointer is templated over; the
   1.316 +// smart pointer can act as E*.
   1.317 +template <class E, class Derived>
   1.318 +struct nsTArray_SafeElementAtSmartPtrHelper
   1.319 +{
   1.320 +  typedef E*       elem_type;
   1.321 +  typedef uint32_t index_type;
   1.322 +
   1.323 +  elem_type SafeElementAt(index_type i) {
   1.324 +    return static_cast<Derived*> (this)->SafeElementAt(i, nullptr);
   1.325 +  }
   1.326 +
   1.327 +  const elem_type SafeElementAt(index_type i) const {
   1.328 +    return static_cast<const Derived*> (this)->SafeElementAt(i, nullptr);
   1.329 +  }
   1.330 +};
   1.331 +
   1.332 +template <class T> class nsCOMPtr;
   1.333 +
   1.334 +template <class E, class Derived>
   1.335 +struct nsTArray_SafeElementAtHelper<nsCOMPtr<E>, Derived> :
   1.336 +  public nsTArray_SafeElementAtSmartPtrHelper<E, Derived>
   1.337 +{
   1.338 +};
   1.339 +
   1.340 +template <class T> class nsRefPtr;
   1.341 +
   1.342 +template <class E, class Derived>
   1.343 +struct nsTArray_SafeElementAtHelper<nsRefPtr<E>, Derived> :
   1.344 +  public nsTArray_SafeElementAtSmartPtrHelper<E, Derived>
   1.345 +{
   1.346 +};
   1.347 +
   1.348 +//
   1.349 +// This class serves as a base class for nsTArray.  It shouldn't be used
   1.350 +// directly.  It holds common implementation code that does not depend on the
   1.351 +// element type of the nsTArray.
   1.352 +//
   1.353 +template<class Alloc, class Copy>
   1.354 +class nsTArray_base
   1.355 +{
   1.356 +  // Allow swapping elements with |nsTArray_base|s created using a
   1.357 +  // different allocator.  This is kosher because all allocators use
   1.358 +  // the same free().
   1.359 +  template<class Allocator, class Copier>
   1.360 +  friend class nsTArray_base;
   1.361 +
   1.362 +protected:
   1.363 +  typedef nsTArrayHeader Header;
   1.364 +
   1.365 +public:
   1.366 +  typedef uint32_t size_type;
   1.367 +  typedef uint32_t index_type;
   1.368 +
   1.369 +  // @return The number of elements in the array.
   1.370 +  size_type Length() const {
   1.371 +    return mHdr->mLength;
   1.372 +  }
   1.373 +
   1.374 +  // @return True if the array is empty or false otherwise.
   1.375 +  bool IsEmpty() const {
   1.376 +    return Length() == 0;
   1.377 +  }
   1.378 +
   1.379 +  // @return The number of elements that can fit in the array without forcing
   1.380 +  // the array to be re-allocated.  The length of an array is always less
   1.381 +  // than or equal to its capacity.
   1.382 +  size_type Capacity() const {
   1.383 +    return mHdr->mCapacity;
   1.384 +  }
   1.385 +
   1.386 +#ifdef DEBUG
   1.387 +  void* DebugGetHeader() const {
   1.388 +    return mHdr;
   1.389 +  }
   1.390 +#endif
   1.391 +
   1.392 +protected:
   1.393 +  nsTArray_base();
   1.394 +
   1.395 +  ~nsTArray_base();
   1.396 +
   1.397 +  // Resize the storage if necessary to achieve the requested capacity.
   1.398 +  // @param capacity     The requested number of array elements.
   1.399 +  // @param elemSize     The size of an array element.
   1.400 +  // @return False if insufficient memory is available; true otherwise.
   1.401 +  typename Alloc::ResultTypeProxy EnsureCapacity(size_type capacity, size_type elemSize);
   1.402 +
   1.403 +  // Resize the storage to the minimum required amount.
   1.404 +  // @param elemSize     The size of an array element.
   1.405 +  // @param elemAlign    The alignment in bytes of an array element.
   1.406 +  void ShrinkCapacity(size_type elemSize, size_t elemAlign);
   1.407 +
   1.408 +  // This method may be called to resize a "gap" in the array by shifting
   1.409 +  // elements around.  It updates mLength appropriately.  If the resulting
   1.410 +  // array has zero elements, then the array's memory is free'd.
   1.411 +  // @param start        The starting index of the gap.
   1.412 +  // @param oldLen       The current length of the gap.
   1.413 +  // @param newLen       The desired length of the gap.
   1.414 +  // @param elemSize     The size of an array element.
   1.415 +  // @param elemAlign    The alignment in bytes of an array element.
   1.416 +  void ShiftData(index_type start, size_type oldLen, size_type newLen,
   1.417 +                 size_type elemSize, size_t elemAlign);
   1.418 +
   1.419 +  // This method increments the length member of the array's header.
   1.420 +  // Note that mHdr may actually be sEmptyHdr in the case where a
   1.421 +  // zero-length array is inserted into our array. But then n should
   1.422 +  // always be 0.
   1.423 +  void IncrementLength(uint32_t n) {
   1.424 +    if (mHdr == EmptyHdr()) {
   1.425 +      if (MOZ_UNLIKELY(n != 0)) {
   1.426 +        // Writing a non-zero length to the empty header would be extremely bad.
   1.427 +        MOZ_CRASH();
   1.428 +      }
   1.429 +    } else {
   1.430 +      mHdr->mLength += n;
   1.431 +    }
   1.432 +  }
   1.433 +
   1.434 +  // This method inserts blank slots into the array.
   1.435 +  // @param index the place to insert the new elements. This must be no
   1.436 +  //              greater than the current length of the array.
   1.437 +  // @param count the number of slots to insert
   1.438 +  // @param elementSize the size of an array element.
   1.439 +  // @param elemAlign the alignment in bytes of an array element.
   1.440 +  bool InsertSlotsAt(index_type index, size_type count,
   1.441 +                       size_type elementSize, size_t elemAlign);
   1.442 +
   1.443 +protected:
   1.444 +  template<class Allocator>
   1.445 +  typename Alloc::ResultTypeProxy
   1.446 +  SwapArrayElements(nsTArray_base<Allocator, Copy>& other,
   1.447 +                    size_type elemSize,
   1.448 +                    size_t elemAlign);
   1.449 +
   1.450 +  // This is an RAII class used in SwapArrayElements.
   1.451 +  class IsAutoArrayRestorer {
   1.452 +    public:
   1.453 +      IsAutoArrayRestorer(nsTArray_base<Alloc, Copy> &array, size_t elemAlign);
   1.454 +      ~IsAutoArrayRestorer();
   1.455 +
   1.456 +    private:
   1.457 +      nsTArray_base<Alloc, Copy> &mArray;
   1.458 +      size_t mElemAlign;
   1.459 +      bool mIsAuto;
   1.460 +  };
   1.461 +
   1.462 +  // Helper function for SwapArrayElements. Ensures that if the array
   1.463 +  // is an nsAutoTArray that it doesn't use the built-in buffer.
   1.464 +  bool EnsureNotUsingAutoArrayBuffer(size_type elemSize);
   1.465 +
   1.466 +  // Returns true if this nsTArray is an nsAutoTArray with a built-in buffer.
   1.467 +  bool IsAutoArray() const {
   1.468 +    return mHdr->mIsAutoArray;
   1.469 +  }
   1.470 +
   1.471 +  // Returns a Header for the built-in buffer of this nsAutoTArray.
   1.472 +  Header* GetAutoArrayBuffer(size_t elemAlign) {
   1.473 +    MOZ_ASSERT(IsAutoArray(), "Should be an auto array to call this");
   1.474 +    return GetAutoArrayBufferUnsafe(elemAlign);
   1.475 +  }
   1.476 +  const Header* GetAutoArrayBuffer(size_t elemAlign) const {
   1.477 +    MOZ_ASSERT(IsAutoArray(), "Should be an auto array to call this");
   1.478 +    return GetAutoArrayBufferUnsafe(elemAlign);
   1.479 +  }
   1.480 +
   1.481 +  // Returns a Header for the built-in buffer of this nsAutoTArray, but doesn't
   1.482 +  // assert that we are an nsAutoTArray.
   1.483 +  Header* GetAutoArrayBufferUnsafe(size_t elemAlign) {
   1.484 +    return const_cast<Header*>(static_cast<const nsTArray_base<Alloc, Copy>*>(this)->
   1.485 +                               GetAutoArrayBufferUnsafe(elemAlign));
   1.486 +  }
   1.487 +  const Header* GetAutoArrayBufferUnsafe(size_t elemAlign) const;
   1.488 +
   1.489 +  // Returns true if this is an nsAutoTArray and it currently uses the
   1.490 +  // built-in buffer to store its elements.
   1.491 +  bool UsesAutoArrayBuffer() const;
   1.492 +
   1.493 +  // The array's elements (prefixed with a Header).  This pointer is never
   1.494 +  // null.  If the array is empty, then this will point to sEmptyHdr.
   1.495 +  Header *mHdr;
   1.496 +
   1.497 +  Header* Hdr() const {
   1.498 +    return mHdr;
   1.499 +  }
   1.500 +
   1.501 +  Header** PtrToHdr() {
   1.502 +    return &mHdr;
   1.503 +  }
   1.504 +
   1.505 +  static Header* EmptyHdr() {
   1.506 +    return &Header::sEmptyHdr;
   1.507 +  }
   1.508 +};
   1.509 +
   1.510 +//
   1.511 +// This class defines convenience functions for element specific operations.
   1.512 +// Specialize this template if necessary.
   1.513 +//
   1.514 +template<class E>
   1.515 +class nsTArrayElementTraits
   1.516 +{
   1.517 +public:
   1.518 +  // Invoke the default constructor in place.
   1.519 +  static inline void Construct(E *e) {
   1.520 +    // Do NOT call "E()"! That triggers C++ "default initialization"
   1.521 +    // which zeroes out POD ("plain old data") types such as regular
   1.522 +    // ints.  We don't want that because it can be a performance issue
   1.523 +    // and people don't expect it; nsTArray should work like a regular
   1.524 +    // C/C++ array in this respect.
   1.525 +    new (static_cast<void *>(e)) E;
   1.526 +  }
   1.527 +  // Invoke the copy-constructor in place.
   1.528 +  template<class A>
   1.529 +  static inline void Construct(E *e, const A &arg) {
   1.530 +    typedef typename mozilla::RemoveCV<E>::Type E_NoCV;
   1.531 +    typedef typename mozilla::RemoveCV<A>::Type A_NoCV;
   1.532 +    static_assert(!mozilla::IsSame<E_NoCV*, A_NoCV>::value,
   1.533 +                  "For safety, we disallow constructing nsTArray<E> elements "
   1.534 +                  "from E* pointers. See bug 960591.");
   1.535 +    new (static_cast<void *>(e)) E(arg);
   1.536 +  }
   1.537 +  // Invoke the destructor in place.
   1.538 +  static inline void Destruct(E *e) {
   1.539 +    e->~E();
   1.540 +  }
   1.541 +};
   1.542 +
   1.543 +// The default comparator used by nsTArray
   1.544 +template<class A, class B>
   1.545 +class nsDefaultComparator
   1.546 +{
   1.547 +public:
   1.548 +  bool Equals(const A& a, const B& b) const {
   1.549 +    return a == b;
   1.550 +  }
   1.551 +  bool LessThan(const A& a, const B& b) const {
   1.552 +    return a < b;
   1.553 +  }
   1.554 +};
   1.555 +
   1.556 +template <class E> class InfallibleTArray;
   1.557 +template <class E> class FallibleTArray;
   1.558 +
   1.559 +template<bool IsPod, bool IsSameType>
   1.560 +struct AssignRangeAlgorithm {
   1.561 +  template<class Item, class ElemType, class IndexType, class SizeType>
   1.562 +  static void implementation(ElemType* elements, IndexType start,
   1.563 +                             SizeType count, const Item *values) {
   1.564 +    ElemType *iter = elements + start, *end = iter + count;
   1.565 +    for (; iter != end; ++iter, ++values)
   1.566 +      nsTArrayElementTraits<ElemType>::Construct(iter, *values);
   1.567 +  }
   1.568 +};
   1.569 +
   1.570 +template<>
   1.571 +struct AssignRangeAlgorithm<true, true> {
   1.572 +  template<class Item, class ElemType, class IndexType, class SizeType>
   1.573 +  static void implementation(ElemType* elements, IndexType start,
   1.574 +                             SizeType count, const Item *values) {
   1.575 +    memcpy(elements + start, values, count * sizeof(ElemType));
   1.576 +  }
   1.577 +};
   1.578 +
   1.579 +//
   1.580 +// Normally elements are copied with memcpy and memmove, but for some element
   1.581 +// types that is problematic.  The nsTArray_CopyChooser template class can be
   1.582 +// specialized to ensure that copying calls constructors and destructors
   1.583 +// instead, as is done below for JS::Heap<E> elements.
   1.584 +//
   1.585 +
   1.586 +//
   1.587 +// A class that defines how to copy elements using memcpy/memmove.
   1.588 +//
   1.589 +struct nsTArray_CopyWithMemutils
   1.590 +{
   1.591 +  const static bool allowRealloc = true;
   1.592 +
   1.593 +  static void CopyElements(void* dest, const void* src, size_t count, size_t elemSize) {
   1.594 +    memcpy(dest, src, count * elemSize);
   1.595 +  }
   1.596 +
   1.597 +  static void CopyHeaderAndElements(void* dest, const void* src, size_t count, size_t elemSize) {
   1.598 +    memcpy(dest, src, sizeof(nsTArrayHeader) + count * elemSize);
   1.599 +  }
   1.600 +
   1.601 +  static void MoveElements(void* dest, const void* src, size_t count, size_t elemSize) {
   1.602 +    memmove(dest, src, count * elemSize);
   1.603 +  }
   1.604 +};
   1.605 +
   1.606 +//
   1.607 +// A template class that defines how to copy elements calling their constructors
   1.608 +// and destructors appropriately.
   1.609 +//
   1.610 +template <class ElemType>
   1.611 +struct nsTArray_CopyWithConstructors
   1.612 +{
   1.613 +  typedef nsTArrayElementTraits<ElemType> traits;
   1.614 +
   1.615 +  const static bool allowRealloc = false;
   1.616 +
   1.617 +  static void CopyElements(void* dest, void* src, size_t count, size_t elemSize) {
   1.618 +    ElemType* destElem = static_cast<ElemType*>(dest);
   1.619 +    ElemType* srcElem = static_cast<ElemType*>(src);
   1.620 +    ElemType* destElemEnd = destElem + count;
   1.621 +#ifdef DEBUG
   1.622 +    ElemType* srcElemEnd = srcElem + count;
   1.623 +    MOZ_ASSERT(srcElemEnd <= destElem || srcElemEnd > destElemEnd);
   1.624 +#endif
   1.625 +    while (destElem != destElemEnd) {
   1.626 +      traits::Construct(destElem, *srcElem);
   1.627 +      traits::Destruct(srcElem);
   1.628 +      ++destElem;
   1.629 +      ++srcElem;
   1.630 +    }
   1.631 +  }
   1.632 +
   1.633 +  static void CopyHeaderAndElements(void* dest, void* src, size_t count, size_t elemSize) {
   1.634 +    nsTArrayHeader* destHeader = static_cast<nsTArrayHeader*>(dest);
   1.635 +    nsTArrayHeader* srcHeader = static_cast<nsTArrayHeader*>(src);
   1.636 +    *destHeader = *srcHeader;
   1.637 +    CopyElements(static_cast<uint8_t*>(dest) + sizeof(nsTArrayHeader),
   1.638 +                 static_cast<uint8_t*>(src) + sizeof(nsTArrayHeader),
   1.639 +                 count, elemSize);
   1.640 +  }
   1.641 +
   1.642 +  static void MoveElements(void* dest, void* src, size_t count, size_t elemSize) {
   1.643 +    ElemType* destElem = static_cast<ElemType*>(dest);
   1.644 +    ElemType* srcElem = static_cast<ElemType*>(src);
   1.645 +    ElemType* destElemEnd = destElem + count;
   1.646 +    ElemType* srcElemEnd = srcElem + count;
   1.647 +    if (destElem == srcElem) {
   1.648 +      return;  // In practice, we don't do this.
   1.649 +    } else if (srcElemEnd > destElem && srcElemEnd < destElemEnd) {
   1.650 +      while (destElemEnd != destElem) {
   1.651 +        --destElemEnd;
   1.652 +        --srcElemEnd;
   1.653 +        traits::Construct(destElemEnd, *srcElemEnd);
   1.654 +        traits::Destruct(srcElem);
   1.655 +      }
   1.656 +    } else {
   1.657 +      CopyElements(dest, src, count, elemSize);
   1.658 +    }
   1.659 +  }
   1.660 +};
   1.661 +
   1.662 +//
   1.663 +// The default behaviour is to use memcpy/memmove for everything.
   1.664 +//
   1.665 +template <class E>
   1.666 +struct nsTArray_CopyChooser {
   1.667 +  typedef nsTArray_CopyWithMemutils Type;
   1.668 +};
   1.669 +
   1.670 +//
   1.671 +// Some classes require constructors/destructors to be called, so they are
   1.672 +// specialized here.
   1.673 +//
   1.674 +template <class E>
   1.675 +struct nsTArray_CopyChooser<JS::Heap<E> > {
   1.676 +  typedef nsTArray_CopyWithConstructors<JS::Heap<E> > Type;
   1.677 +};
   1.678 +
   1.679 +template<>
   1.680 +struct nsTArray_CopyChooser<nsRegion> {
   1.681 +  typedef nsTArray_CopyWithConstructors<nsRegion> Type;
   1.682 +};
   1.683 +
   1.684 +template<>
   1.685 +struct nsTArray_CopyChooser<nsIntRegion> {
   1.686 +  typedef nsTArray_CopyWithConstructors<nsIntRegion> Type;
   1.687 +};
   1.688 +
   1.689 +//
   1.690 +// Base class for nsTArray_Impl that is templated on element type and derived
   1.691 +// nsTArray_Impl class, to allow extra conversions to be added for specific
   1.692 +// types.
   1.693 +//
   1.694 +template <class E, class Derived>
   1.695 +struct nsTArray_TypedBase : public nsTArray_SafeElementAtHelper<E, Derived> {};
   1.696 +
   1.697 +//
   1.698 +// Specialization of nsTArray_TypedBase for arrays containing JS::Heap<E>
   1.699 +// elements.
   1.700 +//
   1.701 +// These conversions are safe because JS::Heap<E> and E share the same
   1.702 +// representation, and since the result of the conversions are const references
   1.703 +// we won't miss any barriers.
   1.704 +//
   1.705 +// The static_cast is necessary to obtain the correct address for the derived
   1.706 +// class since we are a base class used in multiple inheritance.
   1.707 +//
   1.708 +template <class E, class Derived>
   1.709 +struct nsTArray_TypedBase<JS::Heap<E>, Derived>
   1.710 + : public nsTArray_SafeElementAtHelper<JS::Heap<E>, Derived>
   1.711 +{
   1.712 +  operator const nsTArray<E>& () {
   1.713 +    static_assert(sizeof(E) == sizeof(JS::Heap<E>),
   1.714 +                  "JS::Heap<E> must be binary compatible with E.");
   1.715 +    Derived* self = static_cast<Derived*>(this);
   1.716 +    return *reinterpret_cast<nsTArray<E> *>(self);
   1.717 +  }
   1.718 +
   1.719 +  operator const FallibleTArray<E>& () {
   1.720 +    Derived* self = static_cast<Derived*>(this);
   1.721 +    return *reinterpret_cast<FallibleTArray<E> *>(self);
   1.722 +  }
   1.723 +};
   1.724 +
   1.725 +
   1.726 +//
   1.727 +// nsTArray_Impl contains most of the guts supporting nsTArray, FallibleTArray,
   1.728 +// nsAutoTArray, and AutoFallibleTArray.
   1.729 +//
   1.730 +// The only situation in which you might need to use nsTArray_Impl in your code
   1.731 +// is if you're writing code which mutates a TArray which may or may not be
   1.732 +// infallible.
   1.733 +//
   1.734 +// Code which merely reads from a TArray which may or may not be infallible can
   1.735 +// simply cast the TArray to |const nsTArray&|; both fallible and infallible
   1.736 +// TArrays can be cast to |const nsTArray&|.
   1.737 +//
   1.738 +template<class E, class Alloc>
   1.739 +class nsTArray_Impl : public nsTArray_base<Alloc, typename nsTArray_CopyChooser<E>::Type>,
   1.740 +                      public nsTArray_TypedBase<E, nsTArray_Impl<E, Alloc> >
   1.741 +{
   1.742 +public:
   1.743 +  typedef typename nsTArray_CopyChooser<E>::Type     copy_type;
   1.744 +  typedef nsTArray_base<Alloc, copy_type>            base_type;
   1.745 +  typedef typename base_type::size_type              size_type;
   1.746 +  typedef typename base_type::index_type             index_type;
   1.747 +  typedef E                                          elem_type;
   1.748 +  typedef nsTArray_Impl<E, Alloc>                    self_type;
   1.749 +  typedef nsTArrayElementTraits<E>                   elem_traits;
   1.750 +  typedef nsTArray_SafeElementAtHelper<E, self_type> safeelementat_helper_type;
   1.751 +
   1.752 +  using safeelementat_helper_type::SafeElementAt;
   1.753 +  using base_type::EmptyHdr;
   1.754 +
   1.755 +  // A special value that is used to indicate an invalid or unknown index
   1.756 +  // into the array.
   1.757 +  enum {
   1.758 +    NoIndex = index_type(-1)
   1.759 +  };
   1.760 +
   1.761 +  using base_type::Length;
   1.762 +
   1.763 +  //
   1.764 +  // Finalization method
   1.765 +  //
   1.766 +
   1.767 +  ~nsTArray_Impl() { Clear(); }
   1.768 +
   1.769 +  //
   1.770 +  // Initialization methods
   1.771 +  //
   1.772 +
   1.773 +  nsTArray_Impl() {}
   1.774 +
   1.775 +  // Initialize this array and pre-allocate some number of elements.
   1.776 +  explicit nsTArray_Impl(size_type capacity) {
   1.777 +    SetCapacity(capacity);
   1.778 +  }
   1.779 +
   1.780 +  // The array's copy-constructor performs a 'deep' copy of the given array.
   1.781 +  // @param other  The array object to copy.
   1.782 +  //
   1.783 +  // It's very important that we declare this method as taking |const
   1.784 +  // self_type&| as opposed to taking |const nsTArray_Impl<E, OtherAlloc>| for
   1.785 +  // an arbitrary OtherAlloc.
   1.786 +  //
   1.787 +  // If we don't declare a constructor taking |const self_type&|, C++ generates
   1.788 +  // a copy-constructor for this class which merely copies the object's
   1.789 +  // members, which is obviously wrong.
   1.790 +  //
   1.791 +  // You can pass an nsTArray_Impl<E, OtherAlloc> to this method because
   1.792 +  // nsTArray_Impl<E, X> can be cast to const nsTArray_Impl<E, Y>&.  So the
   1.793 +  // effect on the API is the same as if we'd declared this method as taking
   1.794 +  // |const nsTArray_Impl<E, OtherAlloc>&|.
   1.795 +  explicit nsTArray_Impl(const self_type& other) {
   1.796 +    AppendElements(other);
   1.797 +  }
   1.798 +
   1.799 +  // Allow converting to a const array with a different kind of allocator,
   1.800 +  // Since the allocator doesn't matter for const arrays
   1.801 +  template<typename Allocator>
   1.802 +  operator const nsTArray_Impl<E, Allocator>&() const {
   1.803 +    return *reinterpret_cast<const nsTArray_Impl<E, Allocator>*>(this);
   1.804 +  }
   1.805 +  // And we have to do this for our subclasses too
   1.806 +  operator const nsTArray<E>&() const {
   1.807 +    return *reinterpret_cast<const InfallibleTArray<E>*>(this);
   1.808 +  }
   1.809 +  operator const FallibleTArray<E>&() const {
   1.810 +    return *reinterpret_cast<const FallibleTArray<E>*>(this);
   1.811 +  }
   1.812 +
   1.813 +  // The array's assignment operator performs a 'deep' copy of the given
   1.814 +  // array.  It is optimized to reuse existing storage if possible.
   1.815 +  // @param other  The array object to copy.
   1.816 +  self_type& operator=(const self_type& other) {
   1.817 +    ReplaceElementsAt(0, Length(), other.Elements(), other.Length());
   1.818 +    return *this;
   1.819 +  }
   1.820 +
   1.821 +  // Return true if this array has the same length and the same
   1.822 +  // elements as |other|.
   1.823 +  template<typename Allocator>
   1.824 +  bool operator==(const nsTArray_Impl<E, Allocator>& other) const {
   1.825 +    size_type len = Length();
   1.826 +    if (len != other.Length())
   1.827 +      return false;
   1.828 +
   1.829 +    // XXX std::equal would be as fast or faster here
   1.830 +    for (index_type i = 0; i < len; ++i)
   1.831 +      if (!(operator[](i) == other[i]))
   1.832 +        return false;
   1.833 +
   1.834 +    return true;
   1.835 +  }
   1.836 +
   1.837 +  // Return true if this array does not have the same length and the same
   1.838 +  // elements as |other|.
   1.839 +  bool operator!=(const self_type& other) const {
   1.840 +    return !operator==(other);
   1.841 +  }
   1.842 +
   1.843 +  template<typename Allocator>
   1.844 +  self_type& operator=(const nsTArray_Impl<E, Allocator>& other) {
   1.845 +    ReplaceElementsAt(0, Length(), other.Elements(), other.Length());
   1.846 +    return *this;
   1.847 +  }
   1.848 +
   1.849 +  // @return The amount of memory used by this nsTArray_Impl, excluding
   1.850 +  // sizeof(*this).
   1.851 +  size_t SizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const {
   1.852 +    if (this->UsesAutoArrayBuffer() || Hdr() == EmptyHdr())
   1.853 +      return 0;
   1.854 +    return mallocSizeOf(this->Hdr());
   1.855 +  }
   1.856 +
   1.857 +  // @return The amount of memory used by this nsTArray_Impl, including
   1.858 +  // sizeof(*this).
   1.859 +  size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const {
   1.860 +    return mallocSizeOf(this) + SizeOfExcludingThis(mallocSizeOf);
   1.861 +  }
   1.862 +
   1.863 +  //
   1.864 +  // Accessor methods
   1.865 +  //
   1.866 +
   1.867 +  // This method provides direct access to the array elements.
   1.868 +  // @return A pointer to the first element of the array.  If the array is
   1.869 +  // empty, then this pointer must not be dereferenced.
   1.870 +  elem_type* Elements() {
   1.871 +    return reinterpret_cast<elem_type *>(Hdr() + 1);
   1.872 +  }
   1.873 +
   1.874 +  // This method provides direct, readonly access to the array elements.
   1.875 +  // @return A pointer to the first element of the array.  If the array is
   1.876 +  // empty, then this pointer must not be dereferenced.
   1.877 +  const elem_type* Elements() const {
   1.878 +    return reinterpret_cast<const elem_type *>(Hdr() + 1);
   1.879 +  }
   1.880 +
   1.881 +  // This method provides direct access to the i'th element of the array.
   1.882 +  // The given index must be within the array bounds.
   1.883 +  // @param i  The index of an element in the array.
   1.884 +  // @return   A reference to the i'th element of the array.
   1.885 +  elem_type& ElementAt(index_type i) {
   1.886 +    MOZ_ASSERT(i < Length(), "invalid array index");
   1.887 +    return Elements()[i];
   1.888 +  }
   1.889 +
   1.890 +  // This method provides direct, readonly access to the i'th element of the
   1.891 +  // array.  The given index must be within the array bounds.
   1.892 +  // @param i  The index of an element in the array.
   1.893 +  // @return   A const reference to the i'th element of the array.
   1.894 +  const elem_type& ElementAt(index_type i) const {
   1.895 +    MOZ_ASSERT(i < Length(), "invalid array index");
   1.896 +    return Elements()[i];
   1.897 +  }
   1.898 +
   1.899 +  // This method provides direct access to the i'th element of the array in
   1.900 +  // a bounds safe manner. If the requested index is out of bounds the
   1.901 +  // provided default value is returned.
   1.902 +  // @param i  The index of an element in the array.
   1.903 +  // @param def The value to return if the index is out of bounds.
   1.904 +  elem_type& SafeElementAt(index_type i, elem_type& def) {
   1.905 +    return i < Length() ? Elements()[i] : def;
   1.906 +  }
   1.907 +
   1.908 +  // This method provides direct access to the i'th element of the array in
   1.909 +  // a bounds safe manner. If the requested index is out of bounds the
   1.910 +  // provided default value is returned.
   1.911 +  // @param i  The index of an element in the array.
   1.912 +  // @param def The value to return if the index is out of bounds.
   1.913 +  const elem_type& SafeElementAt(index_type i, const elem_type& def) const {
   1.914 +    return i < Length() ? Elements()[i] : def;
   1.915 +  }
   1.916 +
   1.917 +  // Shorthand for ElementAt(i)
   1.918 +  elem_type& operator[](index_type i) {
   1.919 +    return ElementAt(i);
   1.920 +  }
   1.921 +
   1.922 +  // Shorthand for ElementAt(i)
   1.923 +  const elem_type& operator[](index_type i) const {
   1.924 +    return ElementAt(i);
   1.925 +  }
   1.926 +
   1.927 +  // Shorthand for ElementAt(length - 1)
   1.928 +  elem_type& LastElement() {
   1.929 +    return ElementAt(Length() - 1);
   1.930 +  }
   1.931 +
   1.932 +  // Shorthand for ElementAt(length - 1)
   1.933 +  const elem_type& LastElement() const {
   1.934 +    return ElementAt(Length() - 1);
   1.935 +  }
   1.936 +
   1.937 +  // Shorthand for SafeElementAt(length - 1, def)
   1.938 +  elem_type& SafeLastElement(elem_type& def) {
   1.939 +    return SafeElementAt(Length() - 1, def);
   1.940 +  }
   1.941 +
   1.942 +  // Shorthand for SafeElementAt(length - 1, def)
   1.943 +  const elem_type& SafeLastElement(const elem_type& def) const {
   1.944 +    return SafeElementAt(Length() - 1, def);
   1.945 +  }
   1.946 +
   1.947 +  //
   1.948 +  // Search methods
   1.949 +  //
   1.950 +
   1.951 +  // This method searches for the first element in this array that is equal
   1.952 +  // to the given element.
   1.953 +  // @param item   The item to search for.
   1.954 +  // @param comp   The Comparator used to determine element equality.
   1.955 +  // @return       true if the element was found.
   1.956 +  template<class Item, class Comparator>
   1.957 +  bool Contains(const Item& item, const Comparator& comp) const {
   1.958 +    return IndexOf(item, 0, comp) != NoIndex;
   1.959 +  }
   1.960 +
   1.961 +  // This method searches for the first element in this array that is equal
   1.962 +  // to the given element.  This method assumes that 'operator==' is defined
   1.963 +  // for elem_type.
   1.964 +  // @param item   The item to search for.
   1.965 +  // @return       true if the element was found.
   1.966 +  template<class Item>
   1.967 +  bool Contains(const Item& item) const {
   1.968 +    return IndexOf(item) != NoIndex;
   1.969 +  }
   1.970 +
   1.971 +  // This method searches for the offset of the first element in this
   1.972 +  // array that is equal to the given element.
   1.973 +  // @param item   The item to search for.
   1.974 +  // @param start  The index to start from.
   1.975 +  // @param comp   The Comparator used to determine element equality.
   1.976 +  // @return       The index of the found element or NoIndex if not found.
   1.977 +  template<class Item, class Comparator>
   1.978 +  index_type IndexOf(const Item& item, index_type start,
   1.979 +                     const Comparator& comp) const {
   1.980 +    const elem_type* iter = Elements() + start, *end = Elements() + Length();
   1.981 +    for (; iter != end; ++iter) {
   1.982 +      if (comp.Equals(*iter, item))
   1.983 +        return index_type(iter - Elements());
   1.984 +    }
   1.985 +    return NoIndex;
   1.986 +  }
   1.987 +
   1.988 +  // This method searches for the offset of the first element in this
   1.989 +  // array that is equal to the given element.  This method assumes
   1.990 +  // that 'operator==' is defined for elem_type.
   1.991 +  // @param item   The item to search for.
   1.992 +  // @param start  The index to start from.
   1.993 +  // @return       The index of the found element or NoIndex if not found.
   1.994 +  template<class Item>
   1.995 +  index_type IndexOf(const Item& item, index_type start = 0) const {
   1.996 +    return IndexOf(item, start, nsDefaultComparator<elem_type, Item>());
   1.997 +  }
   1.998 +
   1.999 +  // This method searches for the offset of the last element in this
  1.1000 +  // array that is equal to the given element.
  1.1001 +  // @param item   The item to search for.
  1.1002 +  // @param start  The index to start from.  If greater than or equal to the
  1.1003 +  //               length of the array, then the entire array is searched.
  1.1004 +  // @param comp   The Comparator used to determine element equality.
  1.1005 +  // @return       The index of the found element or NoIndex if not found.
  1.1006 +  template<class Item, class Comparator>
  1.1007 +  index_type LastIndexOf(const Item& item, index_type start,
  1.1008 +                         const Comparator& comp) const {
  1.1009 +    size_type endOffset = start >= Length() ? Length() : start + 1;
  1.1010 +    const elem_type* end = Elements() - 1, *iter = end + endOffset;
  1.1011 +    for (; iter != end; --iter) {
  1.1012 +      if (comp.Equals(*iter, item))
  1.1013 +        return index_type(iter - Elements());
  1.1014 +    }
  1.1015 +    return NoIndex;
  1.1016 +  }
  1.1017 +
  1.1018 +  // This method searches for the offset of the last element in this
  1.1019 +  // array that is equal to the given element.  This method assumes
  1.1020 +  // that 'operator==' is defined for elem_type.
  1.1021 +  // @param item   The item to search for.
  1.1022 +  // @param start  The index to start from.  If greater than or equal to the
  1.1023 +  //               length of the array, then the entire array is searched.
  1.1024 +  // @return       The index of the found element or NoIndex if not found.
  1.1025 +  template<class Item>
  1.1026 +  index_type LastIndexOf(const Item& item,
  1.1027 +                         index_type start = NoIndex) const {
  1.1028 +    return LastIndexOf(item, start, nsDefaultComparator<elem_type, Item>());
  1.1029 +  }
  1.1030 +
  1.1031 +  // This method searches for the offset for the element in this array
  1.1032 +  // that is equal to the given element. The array is assumed to be sorted.
  1.1033 +  // @param item   The item to search for.
  1.1034 +  // @param comp   The Comparator used.
  1.1035 +  // @return       The index of the found element or NoIndex if not found.
  1.1036 +  template<class Item, class Comparator>
  1.1037 +  index_type BinaryIndexOf(const Item& item, const Comparator& comp) const {
  1.1038 +    index_type low = 0, high = Length();
  1.1039 +    while (high > low) {
  1.1040 +      index_type mid = (high + low) >> 1;
  1.1041 +      if (comp.Equals(ElementAt(mid), item))
  1.1042 +        return mid;
  1.1043 +      if (comp.LessThan(ElementAt(mid), item))
  1.1044 +        low = mid + 1;
  1.1045 +      else
  1.1046 +        high = mid;
  1.1047 +    }
  1.1048 +    return NoIndex;
  1.1049 +  }
  1.1050 +
  1.1051 +  // This method searches for the offset for the element in this array
  1.1052 +  // that is equal to the given element. The array is assumed to be sorted.
  1.1053 +  // This method assumes that 'operator==' and 'operator<' are defined.
  1.1054 +  // @param item   The item to search for.
  1.1055 +  // @return       The index of the found element or NoIndex if not found.
  1.1056 +  template<class Item>
  1.1057 +  index_type BinaryIndexOf(const Item& item) const {
  1.1058 +    return BinaryIndexOf(item, nsDefaultComparator<elem_type, Item>());
  1.1059 +  }
  1.1060 +
  1.1061 +  //
  1.1062 +  // Mutation methods
  1.1063 +  //
  1.1064 +  // This method call the destructor on each element of the array, empties it,
  1.1065 +  // but does not shrink the array's capacity.
  1.1066 +  // See also SetLengthAndRetainStorage.
  1.1067 +  // Make sure to call Compact() if needed to avoid keeping a huge array
  1.1068 +  // around.
  1.1069 +  void ClearAndRetainStorage() {
  1.1070 +    if (base_type::mHdr == EmptyHdr()) {
  1.1071 +      return;
  1.1072 +    }
  1.1073 +
  1.1074 +    DestructRange(0, Length());
  1.1075 +    base_type::mHdr->mLength = 0;
  1.1076 +  }
  1.1077 +
  1.1078 +  // This method modifies the length of the array, but unlike SetLength
  1.1079 +  // it doesn't deallocate/reallocate the current internal storage.
  1.1080 +  // The new length MUST be shorter than or equal to the current capacity.
  1.1081 +  // If the new length is larger than the existing length of the array,
  1.1082 +  // then new elements will be constructed using elem_type's default
  1.1083 +  // constructor.  If shorter, elements will be destructed and removed.
  1.1084 +  // See also ClearAndRetainStorage.
  1.1085 +  // @param newLen  The desired length of this array.
  1.1086 +  void SetLengthAndRetainStorage(size_type newLen) {
  1.1087 +    MOZ_ASSERT(newLen <= base_type::Capacity());
  1.1088 +    size_type oldLen = Length();
  1.1089 +    if (newLen > oldLen) {
  1.1090 +      InsertElementsAt(oldLen, newLen - oldLen);
  1.1091 +      return;
  1.1092 +    }
  1.1093 +    if (newLen < oldLen) {
  1.1094 +      DestructRange(newLen, oldLen - newLen);
  1.1095 +      base_type::mHdr->mLength = newLen;
  1.1096 +    }
  1.1097 +  }
  1.1098 +
  1.1099 +  // This method replaces a range of elements in this array.
  1.1100 +  // @param start     The starting index of the elements to replace.
  1.1101 +  // @param count     The number of elements to replace.  This may be zero to
  1.1102 +  //                  insert elements without removing any existing elements.
  1.1103 +  // @param array     The values to copy into this array.  Must be non-null,
  1.1104 +  //                  and these elements must not already exist in the array
  1.1105 +  //                  being modified.
  1.1106 +  // @param arrayLen  The number of values to copy into this array.
  1.1107 +  // @return          A pointer to the new elements in the array, or null if
  1.1108 +  //                  the operation failed due to insufficient memory.
  1.1109 +  template<class Item>
  1.1110 +  elem_type *ReplaceElementsAt(index_type start, size_type count,
  1.1111 +                               const Item* array, size_type arrayLen) {
  1.1112 +    // Adjust memory allocation up-front to catch errors.
  1.1113 +    if (!Alloc::Successful(this->EnsureCapacity(Length() + arrayLen - count, sizeof(elem_type))))
  1.1114 +      return nullptr;
  1.1115 +    DestructRange(start, count);
  1.1116 +    this->ShiftData(start, count, arrayLen, sizeof(elem_type), MOZ_ALIGNOF(elem_type));
  1.1117 +    AssignRange(start, arrayLen, array);
  1.1118 +    return Elements() + start;
  1.1119 +  }
  1.1120 +
  1.1121 +  // A variation on the ReplaceElementsAt method defined above.
  1.1122 +  template<class Item>
  1.1123 +  elem_type *ReplaceElementsAt(index_type start, size_type count,
  1.1124 +                               const nsTArray<Item>& array) {
  1.1125 +    return ReplaceElementsAt(start, count, array.Elements(), array.Length());
  1.1126 +  }
  1.1127 +
  1.1128 +  // A variation on the ReplaceElementsAt method defined above.
  1.1129 +  template<class Item>
  1.1130 +  elem_type *ReplaceElementsAt(index_type start, size_type count,
  1.1131 +                               const Item& item) {
  1.1132 +    return ReplaceElementsAt(start, count, &item, 1);
  1.1133 +  }
  1.1134 +
  1.1135 +  // A variation on the ReplaceElementsAt method defined above.
  1.1136 +  template<class Item>
  1.1137 +  elem_type *ReplaceElementAt(index_type index, const Item& item) {
  1.1138 +    return ReplaceElementsAt(index, 1, &item, 1);
  1.1139 +  }
  1.1140 +
  1.1141 +  // A variation on the ReplaceElementsAt method defined above.
  1.1142 +  template<class Item>
  1.1143 +  elem_type *InsertElementsAt(index_type index, const Item* array,
  1.1144 +                              size_type arrayLen) {
  1.1145 +    return ReplaceElementsAt(index, 0, array, arrayLen);
  1.1146 +  }
  1.1147 +
  1.1148 +  // A variation on the ReplaceElementsAt method defined above.
  1.1149 +  template<class Item, class Allocator>
  1.1150 +  elem_type *InsertElementsAt(index_type index, const nsTArray_Impl<Item, Allocator>& array) {
  1.1151 +    return ReplaceElementsAt(index, 0, array.Elements(), array.Length());
  1.1152 +  }
  1.1153 +
  1.1154 +  // A variation on the ReplaceElementsAt method defined above.
  1.1155 +  template<class Item>
  1.1156 +  elem_type *InsertElementAt(index_type index, const Item& item) {
  1.1157 +    return ReplaceElementsAt(index, 0, &item, 1);
  1.1158 +  }
  1.1159 +
  1.1160 +  // Insert a new element without copy-constructing. This is useful to avoid
  1.1161 +  // temporaries.
  1.1162 +  // @return A pointer to the newly inserted element, or null on OOM.
  1.1163 +  elem_type* InsertElementAt(index_type index) {
  1.1164 +    if (!Alloc::Successful(this->EnsureCapacity(Length() + 1, sizeof(elem_type))))
  1.1165 +      return nullptr;
  1.1166 +    this->ShiftData(index, 0, 1, sizeof(elem_type), MOZ_ALIGNOF(elem_type));
  1.1167 +    elem_type *elem = Elements() + index;
  1.1168 +    elem_traits::Construct(elem);
  1.1169 +    return elem;
  1.1170 +  }
  1.1171 +
  1.1172 +  // This method searches for the smallest index of an element that is strictly
  1.1173 +  // greater than |item|.  If |item| is inserted at this index, the array will
  1.1174 +  // remain sorted and |item| would come after all elements that are equal to
  1.1175 +  // it.  If |item| is greater than or equal to all elements in the array, the
  1.1176 +  // array length is returned.
  1.1177 +  //
  1.1178 +  // Note that consumers who want to know whether there are existing items equal
  1.1179 +  // to |item| in the array can just check that the return value here is > 0 and
  1.1180 +  // indexing into the previous slot gives something equal to |item|.
  1.1181 +  //
  1.1182 +  //
  1.1183 +  // @param item   The item to search for.
  1.1184 +  // @param comp   The Comparator used.
  1.1185 +  // @return        The index of greatest element <= to |item|
  1.1186 +  // @precondition The array is sorted
  1.1187 +  template<class Item, class Comparator>
  1.1188 +  index_type
  1.1189 +  IndexOfFirstElementGt(const Item& item,
  1.1190 +                        const Comparator& comp) const {
  1.1191 +    // invariant: low <= [idx] <= high
  1.1192 +    index_type low = 0, high = Length();
  1.1193 +    while (high > low) {
  1.1194 +      index_type mid = (high + low) >> 1;
  1.1195 +      // Comparators are not required to provide a LessThan(Item&, elem_type),
  1.1196 +      // so we can't do comp.LessThan(item, ElementAt(mid)).
  1.1197 +      if (comp.LessThan(ElementAt(mid), item) ||
  1.1198 +          comp.Equals(ElementAt(mid), item)) {
  1.1199 +        // item >= ElementAt(mid), so our desired index is at least mid+1.
  1.1200 +        low = mid + 1;
  1.1201 +      } else {
  1.1202 +        // item < ElementAt(mid).  Our desired index is therefore at most mid.
  1.1203 +        high = mid;
  1.1204 +      }
  1.1205 +    }
  1.1206 +    MOZ_ASSERT(high == low);
  1.1207 +    return low;
  1.1208 +  }
  1.1209 +
  1.1210 +  // A variation on the IndexOfFirstElementGt method defined above.
  1.1211 +  template<class Item>
  1.1212 +  index_type
  1.1213 +  IndexOfFirstElementGt(const Item& item) const {
  1.1214 +    return IndexOfFirstElementGt(item, nsDefaultComparator<elem_type, Item>());
  1.1215 +  }
  1.1216 +
  1.1217 +  // Inserts |item| at such an index to guarantee that if the array
  1.1218 +  // was previously sorted, it will remain sorted after this
  1.1219 +  // insertion.
  1.1220 +  template<class Item, class Comparator>
  1.1221 +  elem_type *InsertElementSorted(const Item& item, const Comparator& comp) {
  1.1222 +    index_type index = IndexOfFirstElementGt(item, comp);
  1.1223 +    return InsertElementAt(index, item);
  1.1224 +  }
  1.1225 +
  1.1226 +  // A variation on the InsertElementSorted method defined above.
  1.1227 +  template<class Item>
  1.1228 +  elem_type *InsertElementSorted(const Item& item) {
  1.1229 +    return InsertElementSorted(item, nsDefaultComparator<elem_type, Item>());
  1.1230 +  }
  1.1231 +
  1.1232 +  // This method appends elements to the end of this array.
  1.1233 +  // @param array     The elements to append to this array.
  1.1234 +  // @param arrayLen  The number of elements to append to this array.
  1.1235 +  // @return          A pointer to the new elements in the array, or null if
  1.1236 +  //                  the operation failed due to insufficient memory.
  1.1237 +  template<class Item>
  1.1238 +  elem_type *AppendElements(const Item* array, size_type arrayLen) {
  1.1239 +    if (!Alloc::Successful(this->EnsureCapacity(Length() + arrayLen, sizeof(elem_type))))
  1.1240 +      return nullptr;
  1.1241 +    index_type len = Length();
  1.1242 +    AssignRange(len, arrayLen, array);
  1.1243 +    this->IncrementLength(arrayLen);
  1.1244 +    return Elements() + len;
  1.1245 +  }
  1.1246 +
  1.1247 +  // A variation on the AppendElements method defined above.
  1.1248 +  template<class Item, class Allocator>
  1.1249 +  elem_type *AppendElements(const nsTArray_Impl<Item, Allocator>& array) {
  1.1250 +    return AppendElements(array.Elements(), array.Length());
  1.1251 +  }
  1.1252 +
  1.1253 +  // A variation on the AppendElements method defined above.
  1.1254 +  template<class Item>
  1.1255 +  elem_type *AppendElement(const Item& item) {
  1.1256 +    return AppendElements(&item, 1);
  1.1257 +  }
  1.1258 +
  1.1259 +  // Append new elements without copy-constructing. This is useful to avoid
  1.1260 +  // temporaries.
  1.1261 +  // @return A pointer to the newly appended elements, or null on OOM.
  1.1262 +  elem_type *AppendElements(size_type count) {
  1.1263 +    if (!Alloc::Successful(this->EnsureCapacity(Length() + count, sizeof(elem_type))))
  1.1264 +      return nullptr;
  1.1265 +    elem_type *elems = Elements() + Length();
  1.1266 +    size_type i;
  1.1267 +    for (i = 0; i < count; ++i) {
  1.1268 +      elem_traits::Construct(elems + i);
  1.1269 +    }
  1.1270 +    this->IncrementLength(count);
  1.1271 +    return elems;
  1.1272 +  }
  1.1273 +
  1.1274 +  // Append a new element without copy-constructing. This is useful to avoid
  1.1275 +  // temporaries.
  1.1276 +  // @return A pointer to the newly appended element, or null on OOM.
  1.1277 +  elem_type *AppendElement() {
  1.1278 +    return AppendElements(1);
  1.1279 +  }
  1.1280 +
  1.1281 +  // Move all elements from another array to the end of this array without
  1.1282 +  // calling copy constructors or destructors.
  1.1283 +  // @return A pointer to the newly appended elements, or null on OOM.
  1.1284 +  template<class Item, class Allocator>
  1.1285 +  elem_type *MoveElementsFrom(nsTArray_Impl<Item, Allocator>& array) {
  1.1286 +    MOZ_ASSERT(&array != this, "argument must be different array");
  1.1287 +    index_type len = Length();
  1.1288 +    index_type otherLen = array.Length();
  1.1289 +    if (!Alloc::Successful(this->EnsureCapacity(len + otherLen, sizeof(elem_type))))
  1.1290 +      return nullptr;
  1.1291 +    copy_type::CopyElements(Elements() + len, array.Elements(), otherLen, sizeof(elem_type));
  1.1292 +    this->IncrementLength(otherLen);
  1.1293 +    array.ShiftData(0, otherLen, 0, sizeof(elem_type), MOZ_ALIGNOF(elem_type));
  1.1294 +    return Elements() + len;
  1.1295 +  }
  1.1296 +
  1.1297 +  // This method removes a range of elements from this array.
  1.1298 +  // @param start  The starting index of the elements to remove.
  1.1299 +  // @param count  The number of elements to remove.
  1.1300 +  void RemoveElementsAt(index_type start, size_type count) {
  1.1301 +    MOZ_ASSERT(count == 0 || start < Length(), "Invalid start index");
  1.1302 +    MOZ_ASSERT(start + count <= Length(), "Invalid length");
  1.1303 +    // Check that the previous assert didn't overflow
  1.1304 +    MOZ_ASSERT(start <= start + count, "Start index plus length overflows");
  1.1305 +    DestructRange(start, count);
  1.1306 +    this->ShiftData(start, count, 0, sizeof(elem_type), MOZ_ALIGNOF(elem_type));
  1.1307 +  }
  1.1308 +
  1.1309 +  // A variation on the RemoveElementsAt method defined above.
  1.1310 +  void RemoveElementAt(index_type index) {
  1.1311 +    RemoveElementsAt(index, 1);
  1.1312 +  }
  1.1313 +
  1.1314 +  // A variation on the RemoveElementsAt method defined above.
  1.1315 +  void Clear() {
  1.1316 +    RemoveElementsAt(0, Length());
  1.1317 +  }
  1.1318 +
  1.1319 +  // This helper function combines IndexOf with RemoveElementAt to "search
  1.1320 +  // and destroy" the first element that is equal to the given element.
  1.1321 +  // @param item  The item to search for.
  1.1322 +  // @param comp  The Comparator used to determine element equality.
  1.1323 +  // @return true if the element was found
  1.1324 +  template<class Item, class Comparator>
  1.1325 +  bool RemoveElement(const Item& item, const Comparator& comp) {
  1.1326 +    index_type i = IndexOf(item, 0, comp);
  1.1327 +    if (i == NoIndex)
  1.1328 +      return false;
  1.1329 +
  1.1330 +    RemoveElementAt(i);
  1.1331 +    return true;
  1.1332 +  }
  1.1333 +
  1.1334 +  // A variation on the RemoveElement method defined above that assumes
  1.1335 +  // that 'operator==' is defined for elem_type.
  1.1336 +  template<class Item>
  1.1337 +  bool RemoveElement(const Item& item) {
  1.1338 +    return RemoveElement(item, nsDefaultComparator<elem_type, Item>());
  1.1339 +  }
  1.1340 +
  1.1341 +  // This helper function combines IndexOfFirstElementGt with
  1.1342 +  // RemoveElementAt to "search and destroy" the last element that
  1.1343 +  // is equal to the given element.
  1.1344 +  // @param item  The item to search for.
  1.1345 +  // @param comp  The Comparator used to determine element equality.
  1.1346 +  // @return true if the element was found
  1.1347 +  template<class Item, class Comparator>
  1.1348 +  bool RemoveElementSorted(const Item& item, const Comparator& comp) {
  1.1349 +    index_type index = IndexOfFirstElementGt(item, comp);
  1.1350 +    if (index > 0 && comp.Equals(ElementAt(index - 1), item)) {
  1.1351 +      RemoveElementAt(index - 1);
  1.1352 +      return true;
  1.1353 +    }
  1.1354 +    return false;
  1.1355 +  }
  1.1356 +
  1.1357 +  // A variation on the RemoveElementSorted method defined above.
  1.1358 +  template<class Item>
  1.1359 +  bool RemoveElementSorted(const Item& item) {
  1.1360 +    return RemoveElementSorted(item, nsDefaultComparator<elem_type, Item>());
  1.1361 +  }
  1.1362 +
  1.1363 +  // This method causes the elements contained in this array and the given
  1.1364 +  // array to be swapped.
  1.1365 +  template<class Allocator>
  1.1366 +  typename Alloc::ResultType
  1.1367 +  SwapElements(nsTArray_Impl<E, Allocator>& other) {
  1.1368 +    return Alloc::Result(this->SwapArrayElements(other, sizeof(elem_type),
  1.1369 +                                                 MOZ_ALIGNOF(elem_type)));
  1.1370 +  }
  1.1371 +
  1.1372 +  //
  1.1373 +  // Allocation
  1.1374 +  //
  1.1375 +
  1.1376 +  // This method may increase the capacity of this array object by the
  1.1377 +  // specified amount.  This method may be called in advance of several
  1.1378 +  // AppendElement operations to minimize heap re-allocations.  This method
  1.1379 +  // will not reduce the number of elements in this array.
  1.1380 +  // @param capacity  The desired capacity of this array.
  1.1381 +  // @return True if the operation succeeded; false if we ran out of memory
  1.1382 +  typename Alloc::ResultType SetCapacity(size_type capacity) {
  1.1383 +    return Alloc::Result(this->EnsureCapacity(capacity, sizeof(elem_type)));
  1.1384 +  }
  1.1385 +
  1.1386 +  // This method modifies the length of the array.  If the new length is
  1.1387 +  // larger than the existing length of the array, then new elements will be
  1.1388 +  // constructed using elem_type's default constructor.  Otherwise, this call
  1.1389 +  // removes elements from the array (see also RemoveElementsAt).
  1.1390 +  // @param newLen  The desired length of this array.
  1.1391 +  // @return        True if the operation succeeded; false otherwise.
  1.1392 +  // See also TruncateLength if the new length is guaranteed to be
  1.1393 +  // smaller than the old.
  1.1394 +  typename Alloc::ResultType SetLength(size_type newLen) {
  1.1395 +    size_type oldLen = Length();
  1.1396 +    if (newLen > oldLen) {
  1.1397 +      return Alloc::ConvertBoolToResultType(InsertElementsAt(oldLen, newLen - oldLen) != nullptr);
  1.1398 +    }
  1.1399 +
  1.1400 +    TruncateLength(newLen);
  1.1401 +    return Alloc::ConvertBoolToResultType(true);
  1.1402 +  }
  1.1403 +
  1.1404 +  // This method modifies the length of the array, but may only be
  1.1405 +  // called when the new length is shorter than the old.  It can
  1.1406 +  // therefore be called when elem_type has no default constructor,
  1.1407 +  // unlike SetLength.  It removes elements from the array (see also
  1.1408 +  // RemoveElementsAt).
  1.1409 +  // @param newLen  The desired length of this array.
  1.1410 +  void TruncateLength(size_type newLen) {
  1.1411 +    size_type oldLen = Length();
  1.1412 +    NS_ABORT_IF_FALSE(newLen <= oldLen,
  1.1413 +                      "caller should use SetLength instead");
  1.1414 +    RemoveElementsAt(newLen, oldLen - newLen);
  1.1415 +  }
  1.1416 +
  1.1417 +  // This method ensures that the array has length at least the given
  1.1418 +  // length.  If the current length is shorter than the given length,
  1.1419 +  // then new elements will be constructed using elem_type's default
  1.1420 +  // constructor.
  1.1421 +  // @param minLen  The desired minimum length of this array.
  1.1422 +  // @return        True if the operation succeeded; false otherwise.
  1.1423 +typename Alloc::ResultType EnsureLengthAtLeast(size_type minLen) {
  1.1424 +    size_type oldLen = Length();
  1.1425 +    if (minLen > oldLen) {
  1.1426 +      return Alloc::ConvertBoolToResultType(!!InsertElementsAt(oldLen, minLen - oldLen));
  1.1427 +    }
  1.1428 +    return Alloc::ConvertBoolToResultType(true);
  1.1429 +  }
  1.1430 +
  1.1431 +  // This method inserts elements into the array, constructing
  1.1432 +  // them using elem_type's default constructor.
  1.1433 +  // @param index the place to insert the new elements. This must be no
  1.1434 +  //              greater than the current length of the array.
  1.1435 +  // @param count the number of elements to insert
  1.1436 +  elem_type *InsertElementsAt(index_type index, size_type count) {
  1.1437 +    if (!base_type::InsertSlotsAt(index, count, sizeof(elem_type), MOZ_ALIGNOF(elem_type))) {
  1.1438 +      return nullptr;
  1.1439 +    }
  1.1440 +
  1.1441 +    // Initialize the extra array elements
  1.1442 +    elem_type *iter = Elements() + index, *end = iter + count;
  1.1443 +    for (; iter != end; ++iter) {
  1.1444 +      elem_traits::Construct(iter);
  1.1445 +    }
  1.1446 +
  1.1447 +    return Elements() + index;
  1.1448 +  }
  1.1449 +
  1.1450 +  // This method inserts elements into the array, constructing them
  1.1451 +  // elem_type's copy constructor (or whatever one-arg constructor
  1.1452 +  // happens to match the Item type).
  1.1453 +  // @param index the place to insert the new elements. This must be no
  1.1454 +  //              greater than the current length of the array.
  1.1455 +  // @param count the number of elements to insert.
  1.1456 +  // @param item the value to use when constructing the new elements.
  1.1457 +  template<class Item>
  1.1458 +  elem_type *InsertElementsAt(index_type index, size_type count,
  1.1459 +                              const Item& item) {
  1.1460 +    if (!base_type::InsertSlotsAt(index, count, sizeof(elem_type), MOZ_ALIGNOF(elem_type))) {
  1.1461 +      return nullptr;
  1.1462 +    }
  1.1463 +
  1.1464 +    // Initialize the extra array elements
  1.1465 +    elem_type *iter = Elements() + index, *end = iter + count;
  1.1466 +    for (; iter != end; ++iter) {
  1.1467 +      elem_traits::Construct(iter, item);
  1.1468 +    }
  1.1469 +
  1.1470 +    return Elements() + index;
  1.1471 +  }
  1.1472 +
  1.1473 +  // This method may be called to minimize the memory used by this array.
  1.1474 +  void Compact() {
  1.1475 +    ShrinkCapacity(sizeof(elem_type), MOZ_ALIGNOF(elem_type));
  1.1476 +  }
  1.1477 +
  1.1478 +  //
  1.1479 +  // Sorting
  1.1480 +  //
  1.1481 +
  1.1482 +  // This function is meant to be used with the NS_QuickSort function.  It
  1.1483 +  // maps the callback API expected by NS_QuickSort to the Comparator API
  1.1484 +  // used by nsTArray_Impl.  See nsTArray_Impl::Sort.
  1.1485 +  template<class Comparator>
  1.1486 +  static int Compare(const void* e1, const void* e2, void *data) {
  1.1487 +    const Comparator* c = reinterpret_cast<const Comparator*>(data);
  1.1488 +    const elem_type* a = static_cast<const elem_type*>(e1);
  1.1489 +    const elem_type* b = static_cast<const elem_type*>(e2);
  1.1490 +    return c->LessThan(*a, *b) ? -1 : (c->Equals(*a, *b) ? 0 : 1);
  1.1491 +  }
  1.1492 +
  1.1493 +  // This method sorts the elements of the array.  It uses the LessThan
  1.1494 +  // method defined on the given Comparator object to collate elements.
  1.1495 +  // @param comp The Comparator used to collate elements.
  1.1496 +  template<class Comparator>
  1.1497 +  void Sort(const Comparator& comp) {
  1.1498 +    NS_QuickSort(Elements(), Length(), sizeof(elem_type),
  1.1499 +                 Compare<Comparator>, const_cast<Comparator*>(&comp));
  1.1500 +  }
  1.1501 +
  1.1502 +  // A variation on the Sort method defined above that assumes that
  1.1503 +  // 'operator<' is defined for elem_type.
  1.1504 +  void Sort() {
  1.1505 +    Sort(nsDefaultComparator<elem_type, elem_type>());
  1.1506 +  }
  1.1507 +
  1.1508 +  //
  1.1509 +  // Binary Heap
  1.1510 +  //
  1.1511 +
  1.1512 +  // Sorts the array into a binary heap.
  1.1513 +  // @param comp The Comparator used to create the heap
  1.1514 +  template<class Comparator>
  1.1515 +  void MakeHeap(const Comparator& comp) {
  1.1516 +    if (!Length()) {
  1.1517 +      return;
  1.1518 +    }
  1.1519 +    index_type index = (Length() - 1) / 2;
  1.1520 +    do {
  1.1521 +      SiftDown(index, comp);
  1.1522 +    } while (index--);
  1.1523 +  }
  1.1524 +
  1.1525 +  // A variation on the MakeHeap method defined above.
  1.1526 +  void MakeHeap() {
  1.1527 +    MakeHeap(nsDefaultComparator<elem_type, elem_type>());
  1.1528 +  }
  1.1529 +
  1.1530 +  // Adds an element to the heap
  1.1531 +  // @param item The item to add
  1.1532 +  // @param comp The Comparator used to sift-up the item
  1.1533 +  template<class Item, class Comparator>
  1.1534 +  elem_type *PushHeap(const Item& item, const Comparator& comp) {
  1.1535 +    if (!base_type::InsertSlotsAt(Length(), 1, sizeof(elem_type), MOZ_ALIGNOF(elem_type))) {
  1.1536 +      return nullptr;
  1.1537 +    }
  1.1538 +    // Sift up the new node
  1.1539 +    elem_type *elem = Elements();
  1.1540 +    index_type index = Length() - 1;
  1.1541 +    index_type parent_index = (index - 1) / 2;
  1.1542 +    while (index && comp.LessThan(elem[parent_index], item)) {
  1.1543 +      elem[index] = elem[parent_index];
  1.1544 +      index = parent_index;
  1.1545 +      parent_index = (index - 1) / 2;
  1.1546 +    }
  1.1547 +    elem[index] = item;
  1.1548 +    return &elem[index];
  1.1549 +  }
  1.1550 +
  1.1551 +  // A variation on the PushHeap method defined above.
  1.1552 +  template<class Item>
  1.1553 +  elem_type *PushHeap(const Item& item) {
  1.1554 +    return PushHeap(item, nsDefaultComparator<elem_type, Item>());
  1.1555 +  }
  1.1556 +
  1.1557 +  // Delete the root of the heap and restore the heap
  1.1558 +  // @param comp The Comparator used to restore the heap
  1.1559 +  template<class Comparator>
  1.1560 +  void PopHeap(const Comparator& comp) {
  1.1561 +    if (!Length()) {
  1.1562 +      return;
  1.1563 +    }
  1.1564 +    index_type last_index = Length() - 1;
  1.1565 +    elem_type *elem = Elements();
  1.1566 +    elem[0] = elem[last_index];
  1.1567 +    TruncateLength(last_index);
  1.1568 +    if (Length()) {
  1.1569 +      SiftDown(0, comp);
  1.1570 +    }
  1.1571 +  }
  1.1572 +
  1.1573 +  // A variation on the PopHeap method defined above.
  1.1574 +  void PopHeap() {
  1.1575 +    PopHeap(nsDefaultComparator<elem_type, elem_type>());
  1.1576 +  }
  1.1577 +
  1.1578 +protected:
  1.1579 +  using base_type::Hdr;
  1.1580 +  using base_type::ShrinkCapacity;
  1.1581 +
  1.1582 +  // This method invokes elem_type's destructor on a range of elements.
  1.1583 +  // @param start  The index of the first element to destroy.
  1.1584 +  // @param count  The number of elements to destroy.
  1.1585 +  void DestructRange(index_type start, size_type count) {
  1.1586 +    elem_type *iter = Elements() + start, *end = iter + count;
  1.1587 +    for (; iter != end; ++iter) {
  1.1588 +      elem_traits::Destruct(iter);
  1.1589 +    }
  1.1590 +  }
  1.1591 +
  1.1592 +  // This method invokes elem_type's copy-constructor on a range of elements.
  1.1593 +  // @param start   The index of the first element to construct.
  1.1594 +  // @param count   The number of elements to construct.
  1.1595 +  // @param values  The array of elements to copy.
  1.1596 +  template<class Item>
  1.1597 +  void AssignRange(index_type start, size_type count,
  1.1598 +                   const Item *values) {
  1.1599 +    AssignRangeAlgorithm<mozilla::IsPod<Item>::value,
  1.1600 +                         mozilla::IsSame<Item, elem_type>::value>
  1.1601 +      ::implementation(Elements(), start, count, values);
  1.1602 +  }
  1.1603 +
  1.1604 +  // This method sifts an item down to its proper place in a binary heap
  1.1605 +  // @param index The index of the node to start sifting down from
  1.1606 +  // @param comp  The Comparator used to sift down
  1.1607 +  template<class Comparator>
  1.1608 +  void SiftDown(index_type index, const Comparator& comp) {
  1.1609 +    elem_type *elem = Elements();
  1.1610 +    elem_type item = elem[index];
  1.1611 +    index_type end = Length() - 1;
  1.1612 +    while ((index * 2) < end) {
  1.1613 +      const index_type left = (index * 2) + 1;
  1.1614 +      const index_type right = (index * 2) + 2;
  1.1615 +      const index_type parent_index = index;
  1.1616 +      if (comp.LessThan(item, elem[left])) {
  1.1617 +        if (left < end &&
  1.1618 +            comp.LessThan(elem[left], elem[right])) {
  1.1619 +          index = right;
  1.1620 +        } else {
  1.1621 +          index = left;
  1.1622 +        }
  1.1623 +      } else if (left < end &&
  1.1624 +                 comp.LessThan(item, elem[right])) {
  1.1625 +        index = right;
  1.1626 +      } else {
  1.1627 +        break;
  1.1628 +      }
  1.1629 +      elem[parent_index] = elem[index];
  1.1630 +    }
  1.1631 +    elem[index] = item;
  1.1632 +  }
  1.1633 +};
  1.1634 +
  1.1635 +template <typename E, typename Alloc>
  1.1636 +inline void
  1.1637 +ImplCycleCollectionUnlink(nsTArray_Impl<E, Alloc>& aField)
  1.1638 +{
  1.1639 +  aField.Clear();
  1.1640 +}
  1.1641 +
  1.1642 +template <typename E, typename Alloc>
  1.1643 +inline void
  1.1644 +ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& aCallback,
  1.1645 +                            nsTArray_Impl<E, Alloc>& aField,
  1.1646 +                            const char* aName,
  1.1647 +                            uint32_t aFlags = 0)
  1.1648 +{
  1.1649 +  aFlags |= CycleCollectionEdgeNameArrayFlag;
  1.1650 +  uint32_t length = aField.Length();
  1.1651 +  for (uint32_t i = 0; i < length; ++i) {
  1.1652 +    ImplCycleCollectionTraverse(aCallback, aField[i], aName, aFlags);
  1.1653 +  }
  1.1654 +}
  1.1655 +
  1.1656 +//
  1.1657 +// nsTArray is an infallible vector class.  See the comment at the top of this
  1.1658 +// file for more details.
  1.1659 +//
  1.1660 +template <class E>
  1.1661 +class nsTArray : public nsTArray_Impl<E, nsTArrayInfallibleAllocator>
  1.1662 +{
  1.1663 +public:
  1.1664 +  typedef nsTArray_Impl<E, nsTArrayInfallibleAllocator> base_type;
  1.1665 +  typedef nsTArray<E>                                   self_type;
  1.1666 +  typedef typename base_type::size_type                 size_type;
  1.1667 +
  1.1668 +  nsTArray() {}
  1.1669 +  explicit nsTArray(size_type capacity) : base_type(capacity) {}
  1.1670 +  explicit nsTArray(const nsTArray& other) : base_type(other) {}
  1.1671 +
  1.1672 +  template<class Allocator>
  1.1673 +  explicit nsTArray(const nsTArray_Impl<E, Allocator>& other) : base_type(other) {}
  1.1674 +};
  1.1675 +
  1.1676 +//
  1.1677 +// FallibleTArray is a fallible vector class.
  1.1678 +//
  1.1679 +template <class E>
  1.1680 +class FallibleTArray : public nsTArray_Impl<E, nsTArrayFallibleAllocator>
  1.1681 +{
  1.1682 +public:
  1.1683 +  typedef nsTArray_Impl<E, nsTArrayFallibleAllocator>   base_type;
  1.1684 +  typedef FallibleTArray<E>                             self_type;
  1.1685 +  typedef typename base_type::size_type                 size_type;
  1.1686 +
  1.1687 +  FallibleTArray() {}
  1.1688 +  explicit FallibleTArray(size_type capacity) : base_type(capacity) {}
  1.1689 +  explicit FallibleTArray(const FallibleTArray<E>& other) : base_type(other) {}
  1.1690 +
  1.1691 +  template<class Allocator>
  1.1692 +  explicit FallibleTArray(const nsTArray_Impl<E, Allocator>& other) : base_type(other) {}
  1.1693 +};
  1.1694 +
  1.1695 +//
  1.1696 +// nsAutoArrayBase is a base class for AutoFallibleTArray and nsAutoTArray.
  1.1697 +// You shouldn't use this class directly.
  1.1698 +//
  1.1699 +template <class TArrayBase, uint32_t N>
  1.1700 +class nsAutoArrayBase : public TArrayBase
  1.1701 +{
  1.1702 +public:
  1.1703 +  typedef nsAutoArrayBase<TArrayBase, N> self_type;
  1.1704 +  typedef TArrayBase base_type;
  1.1705 +  typedef typename base_type::Header Header;
  1.1706 +  typedef typename base_type::elem_type elem_type;
  1.1707 +
  1.1708 +  template<typename Allocator>
  1.1709 +  self_type& operator=(const nsTArray_Impl<elem_type, Allocator>& other) {
  1.1710 +    base_type::operator=(other);
  1.1711 +    return *this;
  1.1712 +  }
  1.1713 +
  1.1714 +protected:
  1.1715 +  nsAutoArrayBase() {
  1.1716 +    Init();
  1.1717 +  }
  1.1718 +
  1.1719 +  // We need this constructor because nsAutoTArray and friends all have
  1.1720 +  // implicit copy-constructors.  If we don't have this method, those
  1.1721 +  // copy-constructors will call nsAutoArrayBase's implicit copy-constructor,
  1.1722 +  // which won't call Init() and set up the auto buffer!
  1.1723 +  nsAutoArrayBase(const self_type &aOther) {
  1.1724 +    Init();
  1.1725 +    this->AppendElements(aOther);
  1.1726 +  }
  1.1727 +
  1.1728 +private:
  1.1729 +  // nsTArray_base casts itself as an nsAutoArrayBase in order to get a pointer
  1.1730 +  // to mAutoBuf.
  1.1731 +  template<class Allocator, class Copier>
  1.1732 +  friend class nsTArray_base;
  1.1733 +
  1.1734 +  void Init() {
  1.1735 +    static_assert(MOZ_ALIGNOF(elem_type) <= 8,
  1.1736 +                  "can't handle alignments greater than 8, "
  1.1737 +                  "see nsTArray_base::UsesAutoArrayBuffer()");
  1.1738 +    // Temporary work around for VS2012 RC compiler crash
  1.1739 +    Header** phdr = base_type::PtrToHdr();
  1.1740 +    *phdr = reinterpret_cast<Header*>(&mAutoBuf);
  1.1741 +    (*phdr)->mLength = 0;
  1.1742 +    (*phdr)->mCapacity = N;
  1.1743 +    (*phdr)->mIsAutoArray = 1;
  1.1744 +
  1.1745 +    MOZ_ASSERT(base_type::GetAutoArrayBuffer(MOZ_ALIGNOF(elem_type)) ==
  1.1746 +               reinterpret_cast<Header*>(&mAutoBuf),
  1.1747 +               "GetAutoArrayBuffer needs to be fixed");
  1.1748 +  }
  1.1749 +
  1.1750 +  // Declare mAutoBuf aligned to the maximum of the header's alignment and
  1.1751 +  // elem_type's alignment.  We need to use a union rather than
  1.1752 +  // MOZ_ALIGNED_DECL because GCC is picky about what goes into
  1.1753 +  // __attribute__((aligned(foo))).
  1.1754 +  union {
  1.1755 +    char mAutoBuf[sizeof(nsTArrayHeader) + N * sizeof(elem_type)];
  1.1756 +    // Do the max operation inline to ensure that it is a compile-time constant.
  1.1757 +    mozilla::AlignedElem<(MOZ_ALIGNOF(Header) > MOZ_ALIGNOF(elem_type))
  1.1758 +                         ? MOZ_ALIGNOF(Header) : MOZ_ALIGNOF(elem_type)> mAlign;
  1.1759 +  };
  1.1760 +};
  1.1761 +
  1.1762 +//
  1.1763 +// nsAutoTArray<E, N> is an infallible vector class with N elements of inline
  1.1764 +// storage.  If you try to store more than N elements inside an
  1.1765 +// nsAutoTArray<E, N>, we'll call malloc() and store them all on the heap.
  1.1766 +//
  1.1767 +// Note that you can cast an nsAutoTArray<E, N> to
  1.1768 +// |const AutoFallibleTArray<E, N>&|.
  1.1769 +//
  1.1770 +template<class E, uint32_t N>
  1.1771 +class nsAutoTArray : public nsAutoArrayBase<nsTArray<E>, N>
  1.1772 +{
  1.1773 +  typedef nsAutoTArray<E, N> self_type;
  1.1774 +  typedef nsAutoArrayBase<nsTArray<E>, N> Base;
  1.1775 +
  1.1776 +public:
  1.1777 +  nsAutoTArray() {}
  1.1778 +
  1.1779 +  template<typename Allocator>
  1.1780 +  explicit nsAutoTArray(const nsTArray_Impl<E, Allocator>& other) {
  1.1781 +    Base::AppendElements(other);
  1.1782 +  }
  1.1783 +
  1.1784 +  operator const AutoFallibleTArray<E, N>&() const {
  1.1785 +    return *reinterpret_cast<const AutoFallibleTArray<E, N>*>(this);
  1.1786 +  }
  1.1787 +};
  1.1788 +
  1.1789 +//
  1.1790 +// AutoFallibleTArray<E, N> is a fallible vector class with N elements of
  1.1791 +// inline storage.
  1.1792 +//
  1.1793 +template<class E, uint32_t N>
  1.1794 +class AutoFallibleTArray : public nsAutoArrayBase<FallibleTArray<E>, N>
  1.1795 +{
  1.1796 +  typedef AutoFallibleTArray<E, N> self_type;
  1.1797 +  typedef nsAutoArrayBase<FallibleTArray<E>, N> Base;
  1.1798 +
  1.1799 +public:
  1.1800 +  AutoFallibleTArray() {}
  1.1801 +
  1.1802 +  template<typename Allocator>
  1.1803 +  explicit AutoFallibleTArray(const nsTArray_Impl<E, Allocator>& other) {
  1.1804 +    Base::AppendElements(other);
  1.1805 +  }
  1.1806 +
  1.1807 +  operator const nsAutoTArray<E, N>&() const {
  1.1808 +    return *reinterpret_cast<const nsAutoTArray<E, N>*>(this);
  1.1809 +  }
  1.1810 +};
  1.1811 +
  1.1812 +// Assert that nsAutoTArray doesn't have any extra padding inside.
  1.1813 +//
  1.1814 +// It's important that the data stored in this auto array takes up a multiple of
  1.1815 +// 8 bytes; e.g. nsAutoTArray<uint32_t, 1> wouldn't work.  Since nsAutoTArray
  1.1816 +// contains a pointer, its size must be a multiple of alignof(void*).  (This is
  1.1817 +// because any type may be placed into an array, and there's no padding between
  1.1818 +// elements of an array.)  The compiler pads the end of the structure to
  1.1819 +// enforce this rule.
  1.1820 +//
  1.1821 +// If we used nsAutoTArray<uint32_t, 1> below, this assertion would fail on a
  1.1822 +// 64-bit system, where the compiler inserts 4 bytes of padding at the end of
  1.1823 +// the auto array to make its size a multiple of alignof(void*) == 8 bytes.
  1.1824 +
  1.1825 +static_assert(sizeof(nsAutoTArray<uint32_t, 2>) ==
  1.1826 +              sizeof(void*) + sizeof(nsTArrayHeader) + sizeof(uint32_t) * 2,
  1.1827 +              "nsAutoTArray shouldn't contain any extra padding, "
  1.1828 +              "see the comment");
  1.1829 +
  1.1830 +// Definitions of nsTArray_Impl methods
  1.1831 +#include "nsTArray-inl.h"
  1.1832 +
  1.1833 +#endif  // nsTArray_h__

mercurial