mfbt/Vector.h

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/mfbt/Vector.h	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,1207 @@
     1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     1.5 +/* vim: set ts=8 sts=2 et sw=2 tw=80: */
     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 +/* A type/length-parametrized vector class. */
    1.11 +
    1.12 +#ifndef mozilla_Vector_h
    1.13 +#define mozilla_Vector_h
    1.14 +
    1.15 +#include "mozilla/Alignment.h"
    1.16 +#include "mozilla/AllocPolicy.h"
    1.17 +#include "mozilla/ArrayUtils.h" // for PointerRangeSize
    1.18 +#include "mozilla/Assertions.h"
    1.19 +#include "mozilla/Attributes.h"
    1.20 +#include "mozilla/MathAlgorithms.h"
    1.21 +#include "mozilla/MemoryReporting.h"
    1.22 +#include "mozilla/Move.h"
    1.23 +#include "mozilla/NullPtr.h"
    1.24 +#include "mozilla/ReentrancyGuard.h"
    1.25 +#include "mozilla/TemplateLib.h"
    1.26 +#include "mozilla/TypeTraits.h"
    1.27 +
    1.28 +#include <new> // for placement new
    1.29 +
    1.30 +/* Silence dire "bugs in previous versions of MSVC have been fixed" warnings */
    1.31 +#ifdef _MSC_VER
    1.32 +#pragma warning(push)
    1.33 +#pragma warning(disable:4345)
    1.34 +#endif
    1.35 +
    1.36 +namespace mozilla {
    1.37 +
    1.38 +template<typename T, size_t N, class AllocPolicy, class ThisVector>
    1.39 +class VectorBase;
    1.40 +
    1.41 +namespace detail {
    1.42 +
    1.43 +/*
    1.44 + * Check that the given capacity wastes the minimal amount of space if
    1.45 + * allocated on the heap.  This means that cap*sizeof(T) is as close to a
    1.46 + * power-of-two as possible.  growStorageBy() is responsible for ensuring
    1.47 + * this.
    1.48 + */
    1.49 +template<typename T>
    1.50 +static bool CapacityHasExcessSpace(size_t cap)
    1.51 +{
    1.52 +  size_t size = cap * sizeof(T);
    1.53 +  return RoundUpPow2(size) - size >= sizeof(T);
    1.54 +}
    1.55 +
    1.56 +/*
    1.57 + * This template class provides a default implementation for vector operations
    1.58 + * when the element type is not known to be a POD, as judged by IsPod.
    1.59 + */
    1.60 +template<typename T, size_t N, class AP, class ThisVector, bool IsPod>
    1.61 +struct VectorImpl
    1.62 +{
    1.63 +    /* Destroys constructed objects in the range [begin, end). */
    1.64 +    static inline void destroy(T* begin, T* end) {
    1.65 +      MOZ_ASSERT(begin <= end);
    1.66 +      for (T* p = begin; p < end; ++p)
    1.67 +        p->~T();
    1.68 +    }
    1.69 +
    1.70 +    /* Constructs objects in the uninitialized range [begin, end). */
    1.71 +    static inline void initialize(T* begin, T* end) {
    1.72 +      MOZ_ASSERT(begin <= end);
    1.73 +      for (T* p = begin; p < end; ++p)
    1.74 +        new(p) T();
    1.75 +    }
    1.76 +
    1.77 +    /*
    1.78 +     * Copy-constructs objects in the uninitialized range
    1.79 +     * [dst, dst+(srcend-srcbeg)) from the range [srcbeg, srcend).
    1.80 +     */
    1.81 +    template<typename U>
    1.82 +    static inline void copyConstruct(T* dst, const U* srcbeg, const U* srcend) {
    1.83 +      MOZ_ASSERT(srcbeg <= srcend);
    1.84 +      for (const U* p = srcbeg; p < srcend; ++p, ++dst)
    1.85 +        new(dst) T(*p);
    1.86 +    }
    1.87 +
    1.88 +    /*
    1.89 +     * Move-constructs objects in the uninitialized range
    1.90 +     * [dst, dst+(srcend-srcbeg)) from the range [srcbeg, srcend).
    1.91 +     */
    1.92 +    template<typename U>
    1.93 +    static inline void moveConstruct(T* dst, U* srcbeg, U* srcend) {
    1.94 +      MOZ_ASSERT(srcbeg <= srcend);
    1.95 +      for (U* p = srcbeg; p < srcend; ++p, ++dst)
    1.96 +        new(dst) T(Move(*p));
    1.97 +    }
    1.98 +
    1.99 +    /*
   1.100 +     * Copy-constructs objects in the uninitialized range [dst, dst+n) from the
   1.101 +     * same object u.
   1.102 +     */
   1.103 +    template<typename U>
   1.104 +    static inline void copyConstructN(T* dst, size_t n, const U& u) {
   1.105 +      for (T* end = dst + n; dst < end; ++dst)
   1.106 +        new(dst) T(u);
   1.107 +    }
   1.108 +
   1.109 +    /*
   1.110 +     * Grows the given buffer to have capacity newCap, preserving the objects
   1.111 +     * constructed in the range [begin, end) and updating v. Assumes that (1)
   1.112 +     * newCap has not overflowed, and (2) multiplying newCap by sizeof(T) will
   1.113 +     * not overflow.
   1.114 +     */
   1.115 +    static inline bool
   1.116 +    growTo(VectorBase<T, N, AP, ThisVector>& v, size_t newCap) {
   1.117 +      MOZ_ASSERT(!v.usingInlineStorage());
   1.118 +      MOZ_ASSERT(!CapacityHasExcessSpace<T>(newCap));
   1.119 +      T* newbuf = reinterpret_cast<T*>(v.malloc_(newCap * sizeof(T)));
   1.120 +      if (!newbuf)
   1.121 +        return false;
   1.122 +      T* dst = newbuf;
   1.123 +      T* src = v.beginNoCheck();
   1.124 +      for (; src < v.endNoCheck(); ++dst, ++src)
   1.125 +        new(dst) T(Move(*src));
   1.126 +      VectorImpl::destroy(v.beginNoCheck(), v.endNoCheck());
   1.127 +      v.free_(v.mBegin);
   1.128 +      v.mBegin = newbuf;
   1.129 +      /* v.mLength is unchanged. */
   1.130 +      v.mCapacity = newCap;
   1.131 +      return true;
   1.132 +    }
   1.133 +};
   1.134 +
   1.135 +/*
   1.136 + * This partial template specialization provides a default implementation for
   1.137 + * vector operations when the element type is known to be a POD, as judged by
   1.138 + * IsPod.
   1.139 + */
   1.140 +template<typename T, size_t N, class AP, class ThisVector>
   1.141 +struct VectorImpl<T, N, AP, ThisVector, true>
   1.142 +{
   1.143 +    static inline void destroy(T*, T*) {}
   1.144 +
   1.145 +    static inline void initialize(T* begin, T* end) {
   1.146 +      /*
   1.147 +       * You would think that memset would be a big win (or even break even)
   1.148 +       * when we know T is a POD. But currently it's not. This is probably
   1.149 +       * because |append| tends to be given small ranges and memset requires
   1.150 +       * a function call that doesn't get inlined.
   1.151 +       *
   1.152 +       * memset(begin, 0, sizeof(T) * (end-begin));
   1.153 +       */
   1.154 +      MOZ_ASSERT(begin <= end);
   1.155 +      for (T* p = begin; p < end; ++p)
   1.156 +        new(p) T();
   1.157 +    }
   1.158 +
   1.159 +    template<typename U>
   1.160 +    static inline void copyConstruct(T* dst, const U* srcbeg, const U* srcend) {
   1.161 +      /*
   1.162 +       * See above memset comment. Also, notice that copyConstruct is
   1.163 +       * currently templated (T != U), so memcpy won't work without
   1.164 +       * requiring T == U.
   1.165 +       *
   1.166 +       * memcpy(dst, srcbeg, sizeof(T) * (srcend - srcbeg));
   1.167 +       */
   1.168 +      MOZ_ASSERT(srcbeg <= srcend);
   1.169 +      for (const U* p = srcbeg; p < srcend; ++p, ++dst)
   1.170 +        *dst = *p;
   1.171 +    }
   1.172 +
   1.173 +    template<typename U>
   1.174 +    static inline void moveConstruct(T* dst, const U* srcbeg, const U* srcend) {
   1.175 +      copyConstruct(dst, srcbeg, srcend);
   1.176 +    }
   1.177 +
   1.178 +    static inline void copyConstructN(T* dst, size_t n, const T& t) {
   1.179 +      for (T* end = dst + n; dst < end; ++dst)
   1.180 +        *dst = t;
   1.181 +    }
   1.182 +
   1.183 +    static inline bool
   1.184 +    growTo(VectorBase<T, N, AP, ThisVector>& v, size_t newCap) {
   1.185 +      MOZ_ASSERT(!v.usingInlineStorage());
   1.186 +      MOZ_ASSERT(!CapacityHasExcessSpace<T>(newCap));
   1.187 +      size_t oldSize = sizeof(T) * v.mCapacity;
   1.188 +      size_t newSize = sizeof(T) * newCap;
   1.189 +      T* newbuf = reinterpret_cast<T*>(v.realloc_(v.mBegin, oldSize, newSize));
   1.190 +      if (!newbuf)
   1.191 +        return false;
   1.192 +      v.mBegin = newbuf;
   1.193 +      /* v.mLength is unchanged. */
   1.194 +      v.mCapacity = newCap;
   1.195 +      return true;
   1.196 +    }
   1.197 +};
   1.198 +
   1.199 +} // namespace detail
   1.200 +
   1.201 +/*
   1.202 + * A CRTP base class for vector-like classes.  Unless you really really want
   1.203 + * your own vector class -- and you almost certainly don't -- you should use
   1.204 + * mozilla::Vector instead!
   1.205 + *
   1.206 + * See mozilla::Vector for interface requirements.
   1.207 + */
   1.208 +template<typename T, size_t N, class AllocPolicy, class ThisVector>
   1.209 +class VectorBase : private AllocPolicy
   1.210 +{
   1.211 +    /* utilities */
   1.212 +
   1.213 +    static const bool sElemIsPod = IsPod<T>::value;
   1.214 +    typedef detail::VectorImpl<T, N, AllocPolicy, ThisVector, sElemIsPod> Impl;
   1.215 +    friend struct detail::VectorImpl<T, N, AllocPolicy, ThisVector, sElemIsPod>;
   1.216 +
   1.217 +    bool growStorageBy(size_t incr);
   1.218 +    bool convertToHeapStorage(size_t newCap);
   1.219 +
   1.220 +    /* magic constants */
   1.221 +
   1.222 +    static const int sMaxInlineBytes = 1024;
   1.223 +
   1.224 +    /* compute constants */
   1.225 +
   1.226 +    /*
   1.227 +     * Consider element size to be 1 for buffer sizing if there are 0 inline
   1.228 +     * elements.  This allows us to compile when the definition of the element
   1.229 +     * type is not visible here.
   1.230 +     *
   1.231 +     * Explicit specialization is only allowed at namespace scope, so in order
   1.232 +     * to keep everything here, we use a dummy template parameter with partial
   1.233 +     * specialization.
   1.234 +     */
   1.235 +    template<int M, int Dummy>
   1.236 +    struct ElemSize
   1.237 +    {
   1.238 +        static const size_t value = sizeof(T);
   1.239 +    };
   1.240 +    template<int Dummy>
   1.241 +    struct ElemSize<0, Dummy>
   1.242 +    {
   1.243 +        static const size_t value = 1;
   1.244 +    };
   1.245 +
   1.246 +    static const size_t sInlineCapacity =
   1.247 +      tl::Min<N, sMaxInlineBytes / ElemSize<N, 0>::value>::value;
   1.248 +
   1.249 +    /* Calculate inline buffer size; avoid 0-sized array. */
   1.250 +    static const size_t sInlineBytes =
   1.251 +      tl::Max<1, sInlineCapacity * ElemSize<N, 0>::value>::value;
   1.252 +
   1.253 +    /* member data */
   1.254 +
   1.255 +    /*
   1.256 +     * Pointer to the buffer, be it inline or heap-allocated. Only [mBegin,
   1.257 +     * mBegin + mLength) hold valid constructed T objects. The range [mBegin +
   1.258 +     * mLength, mBegin + mCapacity) holds uninitialized memory. The range
   1.259 +     * [mBegin + mLength, mBegin + mReserved) also holds uninitialized memory
   1.260 +     * previously allocated by a call to reserve().
   1.261 +     */
   1.262 +    T* mBegin;
   1.263 +
   1.264 +    /* Number of elements in the vector. */
   1.265 +    size_t mLength;
   1.266 +
   1.267 +    /* Max number of elements storable in the vector without resizing. */
   1.268 +    size_t mCapacity;
   1.269 +
   1.270 +#ifdef DEBUG
   1.271 +    /* Max elements of reserved or used space in this vector. */
   1.272 +    size_t mReserved;
   1.273 +#endif
   1.274 +
   1.275 +    /* Memory used for inline storage. */
   1.276 +    AlignedStorage<sInlineBytes> storage;
   1.277 +
   1.278 +#ifdef DEBUG
   1.279 +    friend class ReentrancyGuard;
   1.280 +    bool entered;
   1.281 +#endif
   1.282 +
   1.283 +    /* private accessors */
   1.284 +
   1.285 +    bool usingInlineStorage() const {
   1.286 +      return mBegin == const_cast<VectorBase*>(this)->inlineStorage();
   1.287 +    }
   1.288 +
   1.289 +    T* inlineStorage() {
   1.290 +      return static_cast<T*>(storage.addr());
   1.291 +    }
   1.292 +
   1.293 +    T* beginNoCheck() const {
   1.294 +      return mBegin;
   1.295 +    }
   1.296 +
   1.297 +    T* endNoCheck() {
   1.298 +      return mBegin + mLength;
   1.299 +    }
   1.300 +
   1.301 +    const T* endNoCheck() const {
   1.302 +      return mBegin + mLength;
   1.303 +    }
   1.304 +
   1.305 +#ifdef DEBUG
   1.306 +    size_t reserved() const {
   1.307 +      MOZ_ASSERT(mReserved <= mCapacity);
   1.308 +      MOZ_ASSERT(mLength <= mReserved);
   1.309 +      return mReserved;
   1.310 +    }
   1.311 +#endif
   1.312 +
   1.313 +    /* Append operations guaranteed to succeed due to pre-reserved space. */
   1.314 +    template<typename U> void internalAppend(U&& u);
   1.315 +    template<typename U, size_t O, class BP, class UV>
   1.316 +    void internalAppendAll(const VectorBase<U, O, BP, UV>& u);
   1.317 +    void internalAppendN(const T& t, size_t n);
   1.318 +    template<typename U> void internalAppend(const U* begin, size_t length);
   1.319 +
   1.320 +  public:
   1.321 +    static const size_t sMaxInlineStorage = N;
   1.322 +
   1.323 +    typedef T ElementType;
   1.324 +
   1.325 +    VectorBase(AllocPolicy = AllocPolicy());
   1.326 +    VectorBase(ThisVector&&); /* Move constructor. */
   1.327 +    ThisVector& operator=(ThisVector&&); /* Move assignment. */
   1.328 +    ~VectorBase();
   1.329 +
   1.330 +    /* accessors */
   1.331 +
   1.332 +    const AllocPolicy& allocPolicy() const {
   1.333 +      return *this;
   1.334 +    }
   1.335 +
   1.336 +    AllocPolicy& allocPolicy() {
   1.337 +      return *this;
   1.338 +    }
   1.339 +
   1.340 +    enum { InlineLength = N };
   1.341 +
   1.342 +    size_t length() const {
   1.343 +      return mLength;
   1.344 +    }
   1.345 +
   1.346 +    bool empty() const {
   1.347 +      return mLength == 0;
   1.348 +    }
   1.349 +
   1.350 +    size_t capacity() const {
   1.351 +      return mCapacity;
   1.352 +    }
   1.353 +
   1.354 +    T* begin() {
   1.355 +      MOZ_ASSERT(!entered);
   1.356 +      return mBegin;
   1.357 +    }
   1.358 +
   1.359 +    const T* begin() const {
   1.360 +      MOZ_ASSERT(!entered);
   1.361 +      return mBegin;
   1.362 +    }
   1.363 +
   1.364 +    T* end() {
   1.365 +      MOZ_ASSERT(!entered);
   1.366 +      return mBegin + mLength;
   1.367 +    }
   1.368 +
   1.369 +    const T* end() const {
   1.370 +      MOZ_ASSERT(!entered);
   1.371 +      return mBegin + mLength;
   1.372 +    }
   1.373 +
   1.374 +    T& operator[](size_t i) {
   1.375 +      MOZ_ASSERT(!entered);
   1.376 +      MOZ_ASSERT(i < mLength);
   1.377 +      return begin()[i];
   1.378 +    }
   1.379 +
   1.380 +    const T& operator[](size_t i) const {
   1.381 +      MOZ_ASSERT(!entered);
   1.382 +      MOZ_ASSERT(i < mLength);
   1.383 +      return begin()[i];
   1.384 +    }
   1.385 +
   1.386 +    T& back() {
   1.387 +      MOZ_ASSERT(!entered);
   1.388 +      MOZ_ASSERT(!empty());
   1.389 +      return *(end() - 1);
   1.390 +    }
   1.391 +
   1.392 +    const T& back() const {
   1.393 +      MOZ_ASSERT(!entered);
   1.394 +      MOZ_ASSERT(!empty());
   1.395 +      return *(end() - 1);
   1.396 +    }
   1.397 +
   1.398 +    class Range
   1.399 +    {
   1.400 +        friend class VectorBase;
   1.401 +        T* cur_;
   1.402 +        T* end_;
   1.403 +        Range(T* cur, T* end) : cur_(cur), end_(end) {
   1.404 +          MOZ_ASSERT(cur <= end);
   1.405 +        }
   1.406 +
   1.407 +      public:
   1.408 +        Range() {}
   1.409 +        bool empty() const { return cur_ == end_; }
   1.410 +        size_t remain() const { return PointerRangeSize(cur_, end_); }
   1.411 +        T& front() const { MOZ_ASSERT(!empty()); return *cur_; }
   1.412 +        void popFront() { MOZ_ASSERT(!empty()); ++cur_; }
   1.413 +        T popCopyFront() { MOZ_ASSERT(!empty()); return *cur_++; }
   1.414 +    };
   1.415 +
   1.416 +    Range all() {
   1.417 +      return Range(begin(), end());
   1.418 +    }
   1.419 +
   1.420 +    /* mutators */
   1.421 +
   1.422 +    /**
   1.423 +     * Given that the vector is empty and has no inline storage, grow to
   1.424 +     * |capacity|.
   1.425 +     */
   1.426 +    bool initCapacity(size_t request);
   1.427 +
   1.428 +    /**
   1.429 +     * If reserve(length() + N) succeeds, the N next appends are guaranteed to
   1.430 +     * succeed.
   1.431 +     */
   1.432 +    bool reserve(size_t request);
   1.433 +
   1.434 +    /**
   1.435 +     * Destroy elements in the range [end() - incr, end()). Does not deallocate
   1.436 +     * or unreserve storage for those elements.
   1.437 +     */
   1.438 +    void shrinkBy(size_t incr);
   1.439 +
   1.440 +    /** Grow the vector by incr elements. */
   1.441 +    bool growBy(size_t incr);
   1.442 +
   1.443 +    /** Call shrinkBy or growBy based on whether newSize > length(). */
   1.444 +    bool resize(size_t newLength);
   1.445 +
   1.446 +    /**
   1.447 +     * Increase the length of the vector, but don't initialize the new elements
   1.448 +     * -- leave them as uninitialized memory.
   1.449 +     */
   1.450 +    bool growByUninitialized(size_t incr);
   1.451 +    bool resizeUninitialized(size_t newLength);
   1.452 +
   1.453 +    /** Shorthand for shrinkBy(length()). */
   1.454 +    void clear();
   1.455 +
   1.456 +    /** Clears and releases any heap-allocated storage. */
   1.457 +    void clearAndFree();
   1.458 +
   1.459 +    /**
   1.460 +     * If true, appending |needed| elements won't reallocate elements storage.
   1.461 +     * This *doesn't* mean that infallibleAppend may be used!  You still must
   1.462 +     * reserve the extra space, even if this method indicates that appends won't
   1.463 +     * need to reallocate elements storage.
   1.464 +     */
   1.465 +    bool canAppendWithoutRealloc(size_t needed) const;
   1.466 +
   1.467 +    /** Potentially fallible append operations. */
   1.468 +
   1.469 +    /**
   1.470 +     * This can take either a T& or a T&&. Given a T&&, it moves |u| into the
   1.471 +     * vector, instead of copying it. If it fails, |u| is left unmoved. ("We are
   1.472 +     * not amused.")
   1.473 +     */
   1.474 +    template<typename U> bool append(U&& u);
   1.475 +
   1.476 +    template<typename U, size_t O, class BP, class UV>
   1.477 +    bool appendAll(const VectorBase<U, O, BP, UV>& u);
   1.478 +    bool appendN(const T& t, size_t n);
   1.479 +    template<typename U> bool append(const U* begin, const U* end);
   1.480 +    template<typename U> bool append(const U* begin, size_t length);
   1.481 +
   1.482 +    /*
   1.483 +     * Guaranteed-infallible append operations for use upon vectors whose
   1.484 +     * memory has been pre-reserved.  Don't use this if you haven't reserved the
   1.485 +     * memory!
   1.486 +     */
   1.487 +    template<typename U> void infallibleAppend(U&& u) {
   1.488 +      internalAppend(Forward<U>(u));
   1.489 +    }
   1.490 +    void infallibleAppendN(const T& t, size_t n) {
   1.491 +      internalAppendN(t, n);
   1.492 +    }
   1.493 +    template<typename U> void infallibleAppend(const U* aBegin, const U* aEnd) {
   1.494 +      internalAppend(aBegin, PointerRangeSize(aBegin, aEnd));
   1.495 +    }
   1.496 +    template<typename U> void infallibleAppend(const U* aBegin, size_t aLength) {
   1.497 +      internalAppend(aBegin, aLength);
   1.498 +    }
   1.499 +
   1.500 +    void popBack();
   1.501 +
   1.502 +    T popCopy();
   1.503 +
   1.504 +    /**
   1.505 +     * Transfers ownership of the internal buffer used by this vector to the
   1.506 +     * caller.  (It's the caller's responsibility to properly deallocate this
   1.507 +     * buffer, in accordance with this vector's AllocPolicy.)  After this call,
   1.508 +     * the vector is empty.  Since the returned buffer may need to be allocated
   1.509 +     * (if the elements are currently stored in-place), the call can fail,
   1.510 +     * returning nullptr.
   1.511 +     *
   1.512 +     * N.B. Although a T*, only the range [0, length()) is constructed.
   1.513 +     */
   1.514 +    T* extractRawBuffer();
   1.515 +
   1.516 +    /**
   1.517 +     * Transfer ownership of an array of objects into the vector.  The caller
   1.518 +     * must have allocated the array in accordance with this vector's
   1.519 +     * AllocPolicy.
   1.520 +     *
   1.521 +     * N.B. This call assumes that there are no uninitialized elements in the
   1.522 +     *      passed array.
   1.523 +     */
   1.524 +    void replaceRawBuffer(T* p, size_t length);
   1.525 +
   1.526 +    /**
   1.527 +     * Places |val| at position |p|, shifting existing elements from |p| onward
   1.528 +     * one position higher.  On success, |p| should not be reused because it'll
   1.529 +     * be a dangling pointer if reallocation of the vector storage occurred; the
   1.530 +     * return value should be used instead.  On failure, nullptr is returned.
   1.531 +     *
   1.532 +     * Example usage:
   1.533 +     *
   1.534 +     *   if (!(p = vec.insert(p, val)))
   1.535 +     *     <handle failure>
   1.536 +     *   <keep working with p>
   1.537 +     *
   1.538 +     * This is inherently a linear-time operation.  Be careful!
   1.539 +     */
   1.540 +    template<typename U>
   1.541 +    T* insert(T* p, U&& val);
   1.542 +
   1.543 +    /**
   1.544 +     * Removes the element |t|, which must fall in the bounds [begin, end),
   1.545 +     * shifting existing elements from |t + 1| onward one position lower.
   1.546 +     */
   1.547 +    void erase(T* t);
   1.548 +
   1.549 +    /**
   1.550 +     * Measure the size of the vector's heap-allocated storage.
   1.551 +     */
   1.552 +    size_t sizeOfExcludingThis(MallocSizeOf mallocSizeOf) const;
   1.553 +
   1.554 +    /**
   1.555 +     * Like sizeOfExcludingThis, but also measures the size of the vector
   1.556 +     * object (which must be heap-allocated) itself.
   1.557 +     */
   1.558 +    size_t sizeOfIncludingThis(MallocSizeOf mallocSizeOf) const;
   1.559 +
   1.560 +    void swap(ThisVector& other);
   1.561 +
   1.562 +  private:
   1.563 +    VectorBase(const VectorBase&) MOZ_DELETE;
   1.564 +    void operator=(const VectorBase&) MOZ_DELETE;
   1.565 +
   1.566 +    /* Move-construct/assign only from our derived class, ThisVector. */
   1.567 +    VectorBase(VectorBase&&) MOZ_DELETE;
   1.568 +    void operator=(VectorBase&&) MOZ_DELETE;
   1.569 +};
   1.570 +
   1.571 +/* This does the re-entrancy check plus several other sanity checks. */
   1.572 +#define MOZ_REENTRANCY_GUARD_ET_AL \
   1.573 +  ReentrancyGuard g(*this); \
   1.574 +  MOZ_ASSERT_IF(usingInlineStorage(), mCapacity == sInlineCapacity); \
   1.575 +  MOZ_ASSERT(reserved() <= mCapacity); \
   1.576 +  MOZ_ASSERT(mLength <= reserved()); \
   1.577 +  MOZ_ASSERT(mLength <= mCapacity)
   1.578 +
   1.579 +/* Vector Implementation */
   1.580 +
   1.581 +template<typename T, size_t N, class AP, class TV>
   1.582 +MOZ_ALWAYS_INLINE
   1.583 +VectorBase<T, N, AP, TV>::VectorBase(AP ap)
   1.584 +  : AP(ap),
   1.585 +    mLength(0),
   1.586 +    mCapacity(sInlineCapacity)
   1.587 +#ifdef DEBUG
   1.588 +  , mReserved(sInlineCapacity),
   1.589 +    entered(false)
   1.590 +#endif
   1.591 +{
   1.592 +  mBegin = static_cast<T*>(storage.addr());
   1.593 +}
   1.594 +
   1.595 +/* Move constructor. */
   1.596 +template<typename T, size_t N, class AllocPolicy, class TV>
   1.597 +MOZ_ALWAYS_INLINE
   1.598 +VectorBase<T, N, AllocPolicy, TV>::VectorBase(TV&& rhs)
   1.599 +  : AllocPolicy(Move(rhs))
   1.600 +#ifdef DEBUG
   1.601 +    , entered(false)
   1.602 +#endif
   1.603 +{
   1.604 +  mLength = rhs.mLength;
   1.605 +  mCapacity = rhs.mCapacity;
   1.606 +#ifdef DEBUG
   1.607 +  mReserved = rhs.mReserved;
   1.608 +#endif
   1.609 +
   1.610 +  if (rhs.usingInlineStorage()) {
   1.611 +    /* We can't move the buffer over in this case, so copy elements. */
   1.612 +    mBegin = static_cast<T*>(storage.addr());
   1.613 +    Impl::moveConstruct(mBegin, rhs.beginNoCheck(), rhs.endNoCheck());
   1.614 +    /*
   1.615 +     * Leave rhs's mLength, mBegin, mCapacity, and mReserved as they are.
   1.616 +     * The elements in its in-line storage still need to be destroyed.
   1.617 +     */
   1.618 +  } else {
   1.619 +    /*
   1.620 +     * Take src's buffer, and turn src into an empty vector using
   1.621 +     * in-line storage.
   1.622 +     */
   1.623 +    mBegin = rhs.mBegin;
   1.624 +    rhs.mBegin = static_cast<T*>(rhs.storage.addr());
   1.625 +    rhs.mCapacity = sInlineCapacity;
   1.626 +    rhs.mLength = 0;
   1.627 +#ifdef DEBUG
   1.628 +    rhs.mReserved = sInlineCapacity;
   1.629 +#endif
   1.630 +  }
   1.631 +}
   1.632 +
   1.633 +/* Move assignment. */
   1.634 +template<typename T, size_t N, class AP, class TV>
   1.635 +MOZ_ALWAYS_INLINE
   1.636 +TV&
   1.637 +VectorBase<T, N, AP, TV>::operator=(TV&& rhs)
   1.638 +{
   1.639 +  MOZ_ASSERT(this != &rhs, "self-move assignment is prohibited");
   1.640 +  TV* tv = static_cast<TV*>(this);
   1.641 +  tv->~TV();
   1.642 +  new(tv) TV(Move(rhs));
   1.643 +  return *tv;
   1.644 +}
   1.645 +
   1.646 +template<typename T, size_t N, class AP, class TV>
   1.647 +MOZ_ALWAYS_INLINE
   1.648 +VectorBase<T, N, AP, TV>::~VectorBase()
   1.649 +{
   1.650 +  MOZ_REENTRANCY_GUARD_ET_AL;
   1.651 +  Impl::destroy(beginNoCheck(), endNoCheck());
   1.652 +  if (!usingInlineStorage())
   1.653 +    this->free_(beginNoCheck());
   1.654 +}
   1.655 +
   1.656 +/*
   1.657 + * This function will create a new heap buffer with capacity newCap,
   1.658 + * move all elements in the inline buffer to this new buffer,
   1.659 + * and fail on OOM.
   1.660 + */
   1.661 +template<typename T, size_t N, class AP, class TV>
   1.662 +inline bool
   1.663 +VectorBase<T, N, AP, TV>::convertToHeapStorage(size_t newCap)
   1.664 +{
   1.665 +  MOZ_ASSERT(usingInlineStorage());
   1.666 +
   1.667 +  /* Allocate buffer. */
   1.668 +  MOZ_ASSERT(!detail::CapacityHasExcessSpace<T>(newCap));
   1.669 +  T* newBuf = reinterpret_cast<T*>(this->malloc_(newCap * sizeof(T)));
   1.670 +  if (!newBuf)
   1.671 +    return false;
   1.672 +
   1.673 +  /* Copy inline elements into heap buffer. */
   1.674 +  Impl::moveConstruct(newBuf, beginNoCheck(), endNoCheck());
   1.675 +  Impl::destroy(beginNoCheck(), endNoCheck());
   1.676 +
   1.677 +  /* Switch in heap buffer. */
   1.678 +  mBegin = newBuf;
   1.679 +  /* mLength is unchanged. */
   1.680 +  mCapacity = newCap;
   1.681 +  return true;
   1.682 +}
   1.683 +
   1.684 +template<typename T, size_t N, class AP, class TV>
   1.685 +MOZ_NEVER_INLINE bool
   1.686 +VectorBase<T, N, AP, TV>::growStorageBy(size_t incr)
   1.687 +{
   1.688 +  MOZ_ASSERT(mLength + incr > mCapacity);
   1.689 +  MOZ_ASSERT_IF(!usingInlineStorage(),
   1.690 +                !detail::CapacityHasExcessSpace<T>(mCapacity));
   1.691 +
   1.692 +  /*
   1.693 +   * When choosing a new capacity, its size should is as close to 2**N bytes
   1.694 +   * as possible.  2**N-sized requests are best because they are unlikely to
   1.695 +   * be rounded up by the allocator.  Asking for a 2**N number of elements
   1.696 +   * isn't as good, because if sizeof(T) is not a power-of-two that would
   1.697 +   * result in a non-2**N request size.
   1.698 +   */
   1.699 +
   1.700 +  size_t newCap;
   1.701 +
   1.702 +  if (incr == 1) {
   1.703 +    if (usingInlineStorage()) {
   1.704 +      /* This case occurs in ~70--80% of the calls to this function. */
   1.705 +      size_t newSize =
   1.706 +        tl::RoundUpPow2<(sInlineCapacity + 1) * sizeof(T)>::value;
   1.707 +      newCap = newSize / sizeof(T);
   1.708 +      goto convert;
   1.709 +    }
   1.710 +
   1.711 +    if (mLength == 0) {
   1.712 +      /* This case occurs in ~0--10% of the calls to this function. */
   1.713 +      newCap = 1;
   1.714 +      goto grow;
   1.715 +    }
   1.716 +
   1.717 +    /* This case occurs in ~15--20% of the calls to this function. */
   1.718 +
   1.719 +    /*
   1.720 +     * Will mLength * 4 *sizeof(T) overflow?  This condition limits a vector
   1.721 +     * to 1GB of memory on a 32-bit system, which is a reasonable limit.  It
   1.722 +     * also ensures that
   1.723 +     *
   1.724 +     *   static_cast<char*>(end()) - static_cast<char*>(begin())
   1.725 +     *
   1.726 +     * doesn't overflow ptrdiff_t (see bug 510319).
   1.727 +     */
   1.728 +    if (mLength & tl::MulOverflowMask<4 * sizeof(T)>::value) {
   1.729 +      this->reportAllocOverflow();
   1.730 +      return false;
   1.731 +    }
   1.732 +
   1.733 +    /*
   1.734 +     * If we reach here, the existing capacity will have a size that is already
   1.735 +     * as close to 2^N as sizeof(T) will allow.  Just double the capacity, and
   1.736 +     * then there might be space for one more element.
   1.737 +     */
   1.738 +    newCap = mLength * 2;
   1.739 +    if (detail::CapacityHasExcessSpace<T>(newCap))
   1.740 +      newCap += 1;
   1.741 +  } else {
   1.742 +    /* This case occurs in ~2% of the calls to this function. */
   1.743 +    size_t newMinCap = mLength + incr;
   1.744 +
   1.745 +    /* Did mLength + incr overflow?  Will newCap * sizeof(T) overflow? */
   1.746 +    if (newMinCap < mLength ||
   1.747 +        newMinCap & tl::MulOverflowMask<2 * sizeof(T)>::value)
   1.748 +    {
   1.749 +      this->reportAllocOverflow();
   1.750 +      return false;
   1.751 +    }
   1.752 +
   1.753 +    size_t newMinSize = newMinCap * sizeof(T);
   1.754 +    size_t newSize = RoundUpPow2(newMinSize);
   1.755 +    newCap = newSize / sizeof(T);
   1.756 +  }
   1.757 +
   1.758 +  if (usingInlineStorage()) {
   1.759 +  convert:
   1.760 +    return convertToHeapStorage(newCap);
   1.761 +  }
   1.762 +
   1.763 +grow:
   1.764 +  return Impl::growTo(*this, newCap);
   1.765 +}
   1.766 +
   1.767 +template<typename T, size_t N, class AP, class TV>
   1.768 +inline bool
   1.769 +VectorBase<T, N, AP, TV>::initCapacity(size_t request)
   1.770 +{
   1.771 +  MOZ_ASSERT(empty());
   1.772 +  MOZ_ASSERT(usingInlineStorage());
   1.773 +  if (request == 0)
   1.774 +    return true;
   1.775 +  T* newbuf = reinterpret_cast<T*>(this->malloc_(request * sizeof(T)));
   1.776 +  if (!newbuf)
   1.777 +    return false;
   1.778 +  mBegin = newbuf;
   1.779 +  mCapacity = request;
   1.780 +#ifdef DEBUG
   1.781 +  mReserved = request;
   1.782 +#endif
   1.783 +  return true;
   1.784 +}
   1.785 +
   1.786 +template<typename T, size_t N, class AP, class TV>
   1.787 +inline bool
   1.788 +VectorBase<T, N, AP, TV>::reserve(size_t request)
   1.789 +{
   1.790 +  MOZ_REENTRANCY_GUARD_ET_AL;
   1.791 +  if (request > mCapacity && !growStorageBy(request - mLength))
   1.792 +    return false;
   1.793 +
   1.794 +#ifdef DEBUG
   1.795 +  if (request > mReserved)
   1.796 +    mReserved = request;
   1.797 +  MOZ_ASSERT(mLength <= mReserved);
   1.798 +  MOZ_ASSERT(mReserved <= mCapacity);
   1.799 +#endif
   1.800 +  return true;
   1.801 +}
   1.802 +
   1.803 +template<typename T, size_t N, class AP, class TV>
   1.804 +inline void
   1.805 +VectorBase<T, N, AP, TV>::shrinkBy(size_t incr)
   1.806 +{
   1.807 +  MOZ_REENTRANCY_GUARD_ET_AL;
   1.808 +  MOZ_ASSERT(incr <= mLength);
   1.809 +  Impl::destroy(endNoCheck() - incr, endNoCheck());
   1.810 +  mLength -= incr;
   1.811 +}
   1.812 +
   1.813 +template<typename T, size_t N, class AP, class TV>
   1.814 +MOZ_ALWAYS_INLINE bool
   1.815 +VectorBase<T, N, AP, TV>::growBy(size_t incr)
   1.816 +{
   1.817 +  MOZ_REENTRANCY_GUARD_ET_AL;
   1.818 +  if (incr > mCapacity - mLength && !growStorageBy(incr))
   1.819 +    return false;
   1.820 +
   1.821 +  MOZ_ASSERT(mLength + incr <= mCapacity);
   1.822 +  T* newend = endNoCheck() + incr;
   1.823 +  Impl::initialize(endNoCheck(), newend);
   1.824 +  mLength += incr;
   1.825 +#ifdef DEBUG
   1.826 +  if (mLength > mReserved)
   1.827 +    mReserved = mLength;
   1.828 +#endif
   1.829 +  return true;
   1.830 +}
   1.831 +
   1.832 +template<typename T, size_t N, class AP, class TV>
   1.833 +MOZ_ALWAYS_INLINE bool
   1.834 +VectorBase<T, N, AP, TV>::growByUninitialized(size_t incr)
   1.835 +{
   1.836 +  MOZ_REENTRANCY_GUARD_ET_AL;
   1.837 +  if (incr > mCapacity - mLength && !growStorageBy(incr))
   1.838 +    return false;
   1.839 +
   1.840 +  MOZ_ASSERT(mLength + incr <= mCapacity);
   1.841 +  mLength += incr;
   1.842 +#ifdef DEBUG
   1.843 +  if (mLength > mReserved)
   1.844 +    mReserved = mLength;
   1.845 +#endif
   1.846 +  return true;
   1.847 +}
   1.848 +
   1.849 +template<typename T, size_t N, class AP, class TV>
   1.850 +inline bool
   1.851 +VectorBase<T, N, AP, TV>::resize(size_t newLength)
   1.852 +{
   1.853 +  size_t curLength = mLength;
   1.854 +  if (newLength > curLength)
   1.855 +    return growBy(newLength - curLength);
   1.856 +  shrinkBy(curLength - newLength);
   1.857 +  return true;
   1.858 +}
   1.859 +
   1.860 +template<typename T, size_t N, class AP, class TV>
   1.861 +MOZ_ALWAYS_INLINE bool
   1.862 +VectorBase<T, N, AP, TV>::resizeUninitialized(size_t newLength)
   1.863 +{
   1.864 +  size_t curLength = mLength;
   1.865 +  if (newLength > curLength)
   1.866 +    return growByUninitialized(newLength - curLength);
   1.867 +  shrinkBy(curLength - newLength);
   1.868 +  return true;
   1.869 +}
   1.870 +
   1.871 +template<typename T, size_t N, class AP, class TV>
   1.872 +inline void
   1.873 +VectorBase<T, N, AP, TV>::clear()
   1.874 +{
   1.875 +  MOZ_REENTRANCY_GUARD_ET_AL;
   1.876 +  Impl::destroy(beginNoCheck(), endNoCheck());
   1.877 +  mLength = 0;
   1.878 +}
   1.879 +
   1.880 +template<typename T, size_t N, class AP, class TV>
   1.881 +inline void
   1.882 +VectorBase<T, N, AP, TV>::clearAndFree()
   1.883 +{
   1.884 +  clear();
   1.885 +
   1.886 +  if (usingInlineStorage())
   1.887 +    return;
   1.888 +
   1.889 +  this->free_(beginNoCheck());
   1.890 +  mBegin = static_cast<T*>(storage.addr());
   1.891 +  mCapacity = sInlineCapacity;
   1.892 +#ifdef DEBUG
   1.893 +  mReserved = sInlineCapacity;
   1.894 +#endif
   1.895 +}
   1.896 +
   1.897 +template<typename T, size_t N, class AP, class TV>
   1.898 +inline bool
   1.899 +VectorBase<T, N, AP, TV>::canAppendWithoutRealloc(size_t needed) const
   1.900 +{
   1.901 +  return mLength + needed <= mCapacity;
   1.902 +}
   1.903 +
   1.904 +template<typename T, size_t N, class AP, class TV>
   1.905 +template<typename U, size_t O, class BP, class UV>
   1.906 +MOZ_ALWAYS_INLINE void
   1.907 +VectorBase<T, N, AP, TV>::internalAppendAll(const VectorBase<U, O, BP, UV>& other)
   1.908 +{
   1.909 +  internalAppend(other.begin(), other.length());
   1.910 +}
   1.911 +
   1.912 +template<typename T, size_t N, class AP, class TV>
   1.913 +template<typename U>
   1.914 +MOZ_ALWAYS_INLINE void
   1.915 +VectorBase<T, N, AP, TV>::internalAppend(U&& u)
   1.916 +{
   1.917 +  MOZ_ASSERT(mLength + 1 <= mReserved);
   1.918 +  MOZ_ASSERT(mReserved <= mCapacity);
   1.919 +  new(endNoCheck()) T(Forward<U>(u));
   1.920 +  ++mLength;
   1.921 +}
   1.922 +
   1.923 +template<typename T, size_t N, class AP, class TV>
   1.924 +MOZ_ALWAYS_INLINE bool
   1.925 +VectorBase<T, N, AP, TV>::appendN(const T& t, size_t needed)
   1.926 +{
   1.927 +  MOZ_REENTRANCY_GUARD_ET_AL;
   1.928 +  if (mLength + needed > mCapacity && !growStorageBy(needed))
   1.929 +    return false;
   1.930 +
   1.931 +#ifdef DEBUG
   1.932 +  if (mLength + needed > mReserved)
   1.933 +    mReserved = mLength + needed;
   1.934 +#endif
   1.935 +  internalAppendN(t, needed);
   1.936 +  return true;
   1.937 +}
   1.938 +
   1.939 +template<typename T, size_t N, class AP, class TV>
   1.940 +MOZ_ALWAYS_INLINE void
   1.941 +VectorBase<T, N, AP, TV>::internalAppendN(const T& t, size_t needed)
   1.942 +{
   1.943 +  MOZ_ASSERT(mLength + needed <= mReserved);
   1.944 +  MOZ_ASSERT(mReserved <= mCapacity);
   1.945 +  Impl::copyConstructN(endNoCheck(), needed, t);
   1.946 +  mLength += needed;
   1.947 +}
   1.948 +
   1.949 +template<typename T, size_t N, class AP, class TV>
   1.950 +template<typename U>
   1.951 +inline T*
   1.952 +VectorBase<T, N, AP, TV>::insert(T* p, U&& val)
   1.953 +{
   1.954 +  MOZ_ASSERT(begin() <= p);
   1.955 +  MOZ_ASSERT(p <= end());
   1.956 +  size_t pos = p - begin();
   1.957 +  MOZ_ASSERT(pos <= mLength);
   1.958 +  size_t oldLength = mLength;
   1.959 +  if (pos == oldLength) {
   1.960 +    if (!append(Forward<U>(val)))
   1.961 +      return nullptr;
   1.962 +  } else {
   1.963 +    T oldBack = Move(back());
   1.964 +    if (!append(Move(oldBack))) /* Dup the last element. */
   1.965 +      return nullptr;
   1.966 +    for (size_t i = oldLength; i > pos; --i)
   1.967 +      (*this)[i] = Move((*this)[i - 1]);
   1.968 +    (*this)[pos] = Forward<U>(val);
   1.969 +  }
   1.970 +  return begin() + pos;
   1.971 +}
   1.972 +
   1.973 +template<typename T, size_t N, class AP, class TV>
   1.974 +inline void
   1.975 +VectorBase<T, N, AP, TV>::erase(T* it)
   1.976 +{
   1.977 +  MOZ_ASSERT(begin() <= it);
   1.978 +  MOZ_ASSERT(it < end());
   1.979 +  while (it + 1 < end()) {
   1.980 +    *it = *(it + 1);
   1.981 +    ++it;
   1.982 +  }
   1.983 +    popBack();
   1.984 +}
   1.985 +
   1.986 +template<typename T, size_t N, class AP, class TV>
   1.987 +template<typename U>
   1.988 +MOZ_ALWAYS_INLINE bool
   1.989 +VectorBase<T, N, AP, TV>::append(const U* insBegin, const U* insEnd)
   1.990 +{
   1.991 +  MOZ_REENTRANCY_GUARD_ET_AL;
   1.992 +  size_t needed = PointerRangeSize(insBegin, insEnd);
   1.993 +  if (mLength + needed > mCapacity && !growStorageBy(needed))
   1.994 +    return false;
   1.995 +
   1.996 +#ifdef DEBUG
   1.997 +  if (mLength + needed > mReserved)
   1.998 +    mReserved = mLength + needed;
   1.999 +#endif
  1.1000 +  internalAppend(insBegin, needed);
  1.1001 +  return true;
  1.1002 +}
  1.1003 +
  1.1004 +template<typename T, size_t N, class AP, class TV>
  1.1005 +template<typename U>
  1.1006 +MOZ_ALWAYS_INLINE void
  1.1007 +VectorBase<T, N, AP, TV>::internalAppend(const U* insBegin, size_t insLength)
  1.1008 +{
  1.1009 +  MOZ_ASSERT(mLength + insLength <= mReserved);
  1.1010 +  MOZ_ASSERT(mReserved <= mCapacity);
  1.1011 +  Impl::copyConstruct(endNoCheck(), insBegin, insBegin + insLength);
  1.1012 +  mLength += insLength;
  1.1013 +}
  1.1014 +
  1.1015 +template<typename T, size_t N, class AP, class TV>
  1.1016 +template<typename U>
  1.1017 +MOZ_ALWAYS_INLINE bool
  1.1018 +VectorBase<T, N, AP, TV>::append(U&& u)
  1.1019 +{
  1.1020 +  MOZ_REENTRANCY_GUARD_ET_AL;
  1.1021 +  if (mLength == mCapacity && !growStorageBy(1))
  1.1022 +    return false;
  1.1023 +
  1.1024 +#ifdef DEBUG
  1.1025 +  if (mLength + 1 > mReserved)
  1.1026 +    mReserved = mLength + 1;
  1.1027 +#endif
  1.1028 +  internalAppend(Forward<U>(u));
  1.1029 +  return true;
  1.1030 +}
  1.1031 +
  1.1032 +template<typename T, size_t N, class AP, class TV>
  1.1033 +template<typename U, size_t O, class BP, class UV>
  1.1034 +MOZ_ALWAYS_INLINE bool
  1.1035 +VectorBase<T, N, AP, TV>::appendAll(const VectorBase<U, O, BP, UV>& other)
  1.1036 +{
  1.1037 +  return append(other.begin(), other.length());
  1.1038 +}
  1.1039 +
  1.1040 +template<typename T, size_t N, class AP, class TV>
  1.1041 +template<class U>
  1.1042 +MOZ_ALWAYS_INLINE bool
  1.1043 +VectorBase<T, N, AP, TV>::append(const U *insBegin, size_t insLength)
  1.1044 +{
  1.1045 +  return append(insBegin, insBegin + insLength);
  1.1046 +}
  1.1047 +
  1.1048 +template<typename T, size_t N, class AP, class TV>
  1.1049 +MOZ_ALWAYS_INLINE void
  1.1050 +VectorBase<T, N, AP, TV>::popBack()
  1.1051 +{
  1.1052 +  MOZ_REENTRANCY_GUARD_ET_AL;
  1.1053 +  MOZ_ASSERT(!empty());
  1.1054 +  --mLength;
  1.1055 +  endNoCheck()->~T();
  1.1056 +}
  1.1057 +
  1.1058 +template<typename T, size_t N, class AP, class TV>
  1.1059 +MOZ_ALWAYS_INLINE T
  1.1060 +VectorBase<T, N, AP, TV>::popCopy()
  1.1061 +{
  1.1062 +  T ret = back();
  1.1063 +  popBack();
  1.1064 +  return ret;
  1.1065 +}
  1.1066 +
  1.1067 +template<typename T, size_t N, class AP, class TV>
  1.1068 +inline T*
  1.1069 +VectorBase<T, N, AP, TV>::extractRawBuffer()
  1.1070 +{
  1.1071 +  T* ret;
  1.1072 +  if (usingInlineStorage()) {
  1.1073 +    ret = reinterpret_cast<T*>(this->malloc_(mLength * sizeof(T)));
  1.1074 +    if (!ret)
  1.1075 +      return nullptr;
  1.1076 +    Impl::copyConstruct(ret, beginNoCheck(), endNoCheck());
  1.1077 +    Impl::destroy(beginNoCheck(), endNoCheck());
  1.1078 +    /* mBegin, mCapacity are unchanged. */
  1.1079 +    mLength = 0;
  1.1080 +  } else {
  1.1081 +    ret = mBegin;
  1.1082 +    mBegin = static_cast<T*>(storage.addr());
  1.1083 +    mLength = 0;
  1.1084 +    mCapacity = sInlineCapacity;
  1.1085 +#ifdef DEBUG
  1.1086 +    mReserved = sInlineCapacity;
  1.1087 +#endif
  1.1088 +  }
  1.1089 +  return ret;
  1.1090 +}
  1.1091 +
  1.1092 +template<typename T, size_t N, class AP, class TV>
  1.1093 +inline void
  1.1094 +VectorBase<T, N, AP, TV>::replaceRawBuffer(T* p, size_t aLength)
  1.1095 +{
  1.1096 +  MOZ_REENTRANCY_GUARD_ET_AL;
  1.1097 +
  1.1098 +  /* Destroy what we have. */
  1.1099 +  Impl::destroy(beginNoCheck(), endNoCheck());
  1.1100 +  if (!usingInlineStorage())
  1.1101 +    this->free_(beginNoCheck());
  1.1102 +
  1.1103 +  /* Take in the new buffer. */
  1.1104 +  if (aLength <= sInlineCapacity) {
  1.1105 +    /*
  1.1106 +     * We convert to inline storage if possible, even though p might
  1.1107 +     * otherwise be acceptable.  Maybe this behaviour should be
  1.1108 +     * specifiable with an argument to this function.
  1.1109 +     */
  1.1110 +    mBegin = static_cast<T*>(storage.addr());
  1.1111 +    mLength = aLength;
  1.1112 +    mCapacity = sInlineCapacity;
  1.1113 +    Impl::moveConstruct(mBegin, p, p + aLength);
  1.1114 +    Impl::destroy(p, p + aLength);
  1.1115 +    this->free_(p);
  1.1116 +  } else {
  1.1117 +    mBegin = p;
  1.1118 +    mLength = aLength;
  1.1119 +    mCapacity = aLength;
  1.1120 +  }
  1.1121 +#ifdef DEBUG
  1.1122 +  mReserved = aLength;
  1.1123 +#endif
  1.1124 +}
  1.1125 +
  1.1126 +template<typename T, size_t N, class AP, class TV>
  1.1127 +inline size_t
  1.1128 +VectorBase<T, N, AP, TV>::sizeOfExcludingThis(MallocSizeOf mallocSizeOf) const
  1.1129 +{
  1.1130 +  return usingInlineStorage() ? 0 : mallocSizeOf(beginNoCheck());
  1.1131 +}
  1.1132 +
  1.1133 +template<typename T, size_t N, class AP, class TV>
  1.1134 +inline size_t
  1.1135 +VectorBase<T, N, AP, TV>::sizeOfIncludingThis(MallocSizeOf mallocSizeOf) const
  1.1136 +{
  1.1137 +  return mallocSizeOf(this) + sizeOfExcludingThis(mallocSizeOf);
  1.1138 +}
  1.1139 +
  1.1140 +template<typename T, size_t N, class AP, class TV>
  1.1141 +inline void
  1.1142 +VectorBase<T, N, AP, TV>::swap(TV& other)
  1.1143 +{
  1.1144 +  static_assert(N == 0,
  1.1145 +                "still need to implement this for N != 0");
  1.1146 +
  1.1147 +  // This only works when inline storage is always empty.
  1.1148 +  if (!usingInlineStorage() && other.usingInlineStorage()) {
  1.1149 +    other.mBegin = mBegin;
  1.1150 +    mBegin = inlineStorage();
  1.1151 +  } else if (usingInlineStorage() && !other.usingInlineStorage()) {
  1.1152 +    mBegin = other.mBegin;
  1.1153 +    other.mBegin = other.inlineStorage();
  1.1154 +  } else if (!usingInlineStorage() && !other.usingInlineStorage()) {
  1.1155 +    Swap(mBegin, other.mBegin);
  1.1156 +  } else {
  1.1157 +    // This case is a no-op, since we'd set both to use their inline storage.
  1.1158 +  }
  1.1159 +
  1.1160 +  Swap(mLength, other.mLength);
  1.1161 +  Swap(mCapacity, other.mCapacity);
  1.1162 +#ifdef DEBUG
  1.1163 +  Swap(mReserved, other.mReserved);
  1.1164 +#endif
  1.1165 +}
  1.1166 +
  1.1167 +/*
  1.1168 + * STL-like container providing a short-lived, dynamic buffer.  Vector calls the
  1.1169 + * constructors/destructors of all elements stored in its internal buffer, so
  1.1170 + * non-PODs may be safely used.  Additionally, Vector will store the first N
  1.1171 + * elements in-place before resorting to dynamic allocation.
  1.1172 + *
  1.1173 + * T requirements:
  1.1174 + *  - default and copy constructible, assignable, destructible
  1.1175 + *  - operations do not throw
  1.1176 + * N requirements:
  1.1177 + *  - any value, however, N is clamped to min/max values
  1.1178 + * AllocPolicy:
  1.1179 + *  - see "Allocation policies" in AllocPolicy.h (defaults to
  1.1180 + *    mozilla::MallocAllocPolicy)
  1.1181 + *
  1.1182 + * Vector is not reentrant: T member functions called during Vector member
  1.1183 + * functions must not call back into the same object!
  1.1184 + */
  1.1185 +template<typename T,
  1.1186 +         size_t MinInlineCapacity = 0,
  1.1187 +         class AllocPolicy = MallocAllocPolicy>
  1.1188 +class Vector
  1.1189 +  : public VectorBase<T,
  1.1190 +                      MinInlineCapacity,
  1.1191 +                      AllocPolicy,
  1.1192 +                      Vector<T, MinInlineCapacity, AllocPolicy> >
  1.1193 +{
  1.1194 +    typedef VectorBase<T, MinInlineCapacity, AllocPolicy, Vector> Base;
  1.1195 +
  1.1196 +  public:
  1.1197 +    Vector(AllocPolicy alloc = AllocPolicy()) : Base(alloc) {}
  1.1198 +    Vector(Vector&& vec) : Base(Move(vec)) {}
  1.1199 +    Vector& operator=(Vector&& vec) {
  1.1200 +      return Base::operator=(Move(vec));
  1.1201 +    }
  1.1202 +};
  1.1203 +
  1.1204 +} // namespace mozilla
  1.1205 +
  1.1206 +#ifdef _MSC_VER
  1.1207 +#pragma warning(pop)
  1.1208 +#endif
  1.1209 +
  1.1210 +#endif /* mozilla_Vector_h */

mercurial