1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 /* A type/length-parametrized vector class. */
9 #ifndef mozilla_Vector_h
10 #define mozilla_Vector_h
12 #include "mozilla/Alignment.h"
13 #include "mozilla/AllocPolicy.h"
14 #include "mozilla/Assertions.h"
15 #include "mozilla/Attributes.h"
16 #include "mozilla/MathAlgorithms.h"
17 #include "mozilla/MemoryReporting.h"
18 #include "mozilla/Move.h"
19 #include "mozilla/NullPtr.h"
20 #include "mozilla/ReentrancyGuard.h"
21 #include "mozilla/TemplateLib.h"
22 #include "mozilla/TypeTraits.h"
23 #include "mozilla/Util.h" // for PointerRangeSize
25 #include <new> // for placement new
27 /* Silence dire "bugs in previous versions of MSVC have been fixed" warnings */
30 #pragma warning(disable:4345)
35 template<typename T
, size_t N
, class AllocPolicy
, class ThisVector
>
41 * Check that the given capacity wastes the minimal amount of space if
42 * allocated on the heap. This means that cap*sizeof(T) is as close to a
43 * power-of-two as possible. growStorageBy() is responsible for ensuring
47 static bool CapacityHasExcessSpace(size_t cap
)
49 size_t size
= cap
* sizeof(T
);
50 return RoundUpPow2(size
) - size
>= sizeof(T
);
54 * This template class provides a default implementation for vector operations
55 * when the element type is not known to be a POD, as judged by IsPod.
57 template<typename T
, size_t N
, class AP
, class ThisVector
, bool IsPod
>
60 /* Destroys constructed objects in the range [begin, end). */
61 static inline void destroy(T
* begin
, T
* end
) {
62 for (T
* p
= begin
; p
< end
; ++p
)
66 /* Constructs objects in the uninitialized range [begin, end). */
67 static inline void initialize(T
* begin
, T
* end
) {
68 for (T
* p
= begin
; p
< end
; ++p
)
73 * Copy-constructs objects in the uninitialized range
74 * [dst, dst+(srcend-srcbeg)) from the range [srcbeg, srcend).
77 static inline void copyConstruct(T
* dst
, const U
* srcbeg
, const U
* srcend
) {
78 for (const U
* p
= srcbeg
; p
< srcend
; ++p
, ++dst
)
83 * Move-constructs objects in the uninitialized range
84 * [dst, dst+(srcend-srcbeg)) from the range [srcbeg, srcend).
87 static inline void moveConstruct(T
* dst
, U
* srcbeg
, U
* srcend
) {
88 for (U
* p
= srcbeg
; p
< srcend
; ++p
, ++dst
)
93 * Copy-constructs objects in the uninitialized range [dst, dst+n) from the
97 static inline void copyConstructN(T
* dst
, size_t n
, const U
& u
) {
98 for (T
* end
= dst
+ n
; dst
< end
; ++dst
)
103 * Grows the given buffer to have capacity newCap, preserving the objects
104 * constructed in the range [begin, end) and updating v. Assumes that (1)
105 * newCap has not overflowed, and (2) multiplying newCap by sizeof(T) will
109 growTo(VectorBase
<T
, N
, AP
, ThisVector
>& v
, size_t newCap
) {
110 MOZ_ASSERT(!v
.usingInlineStorage());
111 MOZ_ASSERT(!CapacityHasExcessSpace
<T
>(newCap
));
112 T
* newbuf
= reinterpret_cast<T
*>(v
.malloc_(newCap
* sizeof(T
)));
116 T
* src
= v
.beginNoCheck();
117 for (; src
< v
.endNoCheck(); ++dst
, ++src
)
118 new(dst
) T(Move(*src
));
119 VectorImpl::destroy(v
.beginNoCheck(), v
.endNoCheck());
122 /* v.mLength is unchanged. */
123 v
.mCapacity
= newCap
;
129 * This partial template specialization provides a default implementation for
130 * vector operations when the element type is known to be a POD, as judged by
133 template<typename T
, size_t N
, class AP
, class ThisVector
>
134 struct VectorImpl
<T
, N
, AP
, ThisVector
, true>
136 static inline void destroy(T
*, T
*) {}
138 static inline void initialize(T
* begin
, T
* end
) {
140 * You would think that memset would be a big win (or even break even)
141 * when we know T is a POD. But currently it's not. This is probably
142 * because |append| tends to be given small ranges and memset requires
143 * a function call that doesn't get inlined.
145 * memset(begin, 0, sizeof(T) * (end-begin));
147 for (T
* p
= begin
; p
< end
; ++p
)
152 static inline void copyConstruct(T
* dst
, const U
* srcbeg
, const U
* srcend
) {
154 * See above memset comment. Also, notice that copyConstruct is
155 * currently templated (T != U), so memcpy won't work without
158 * memcpy(dst, srcbeg, sizeof(T) * (srcend - srcbeg));
160 for (const U
* p
= srcbeg
; p
< srcend
; ++p
, ++dst
)
165 static inline void moveConstruct(T
* dst
, const U
* srcbeg
, const U
* srcend
) {
166 copyConstruct(dst
, srcbeg
, srcend
);
169 static inline void copyConstructN(T
* dst
, size_t n
, const T
& t
) {
170 for (T
* end
= dst
+ n
; dst
< end
; ++dst
)
175 growTo(VectorBase
<T
, N
, AP
, ThisVector
>& v
, size_t newCap
) {
176 MOZ_ASSERT(!v
.usingInlineStorage());
177 MOZ_ASSERT(!CapacityHasExcessSpace
<T
>(newCap
));
178 size_t oldSize
= sizeof(T
) * v
.mCapacity
;
179 size_t newSize
= sizeof(T
) * newCap
;
180 T
* newbuf
= reinterpret_cast<T
*>(v
.realloc_(v
.mBegin
, oldSize
, newSize
));
184 /* v.mLength is unchanged. */
185 v
.mCapacity
= newCap
;
190 } // namespace detail
193 * A CRTP base class for vector-like classes. Unless you really really want
194 * your own vector class -- and you almost certainly don't -- you should use
195 * mozilla::Vector instead!
197 * See mozilla::Vector for interface requirements.
199 template<typename T
, size_t N
, class AllocPolicy
, class ThisVector
>
200 class VectorBase
: private AllocPolicy
204 static const bool sElemIsPod
= IsPod
<T
>::value
;
205 typedef detail::VectorImpl
<T
, N
, AllocPolicy
, ThisVector
, sElemIsPod
> Impl
;
206 friend struct detail::VectorImpl
<T
, N
, AllocPolicy
, ThisVector
, sElemIsPod
>;
208 bool growStorageBy(size_t incr
);
209 bool convertToHeapStorage(size_t newCap
);
211 /* magic constants */
213 static const int sMaxInlineBytes
= 1024;
215 /* compute constants */
218 * Consider element size to be 1 for buffer sizing if there are 0 inline
219 * elements. This allows us to compile when the definition of the element
220 * type is not visible here.
222 * Explicit specialization is only allowed at namespace scope, so in order
223 * to keep everything here, we use a dummy template parameter with partial
226 template<int M
, int Dummy
>
229 static const size_t value
= sizeof(T
);
232 struct ElemSize
<0, Dummy
>
234 static const size_t value
= 1;
237 static const size_t sInlineCapacity
=
238 tl::Min
<N
, sMaxInlineBytes
/ ElemSize
<N
, 0>::value
>::value
;
240 /* Calculate inline buffer size; avoid 0-sized array. */
241 static const size_t sInlineBytes
=
242 tl::Max
<1, sInlineCapacity
* ElemSize
<N
, 0>::value
>::value
;
247 * Pointer to the buffer, be it inline or heap-allocated. Only [mBegin,
248 * mBegin + mLength) hold valid constructed T objects. The range [mBegin +
249 * mLength, mBegin + mCapacity) holds uninitialized memory. The range
250 * [mBegin + mLength, mBegin + mReserved) also holds uninitialized memory
251 * previously allocated by a call to reserve().
255 /* Number of elements in the vector. */
258 /* Max number of elements storable in the vector without resizing. */
262 /* Max elements of reserved or used space in this vector. */
266 /* Memory used for inline storage. */
267 AlignedStorage
<sInlineBytes
> storage
;
270 friend class ReentrancyGuard
;
274 /* private accessors */
276 bool usingInlineStorage() const {
277 return mBegin
== const_cast<VectorBase
*>(this)->inlineStorage();
281 return static_cast<T
*>(storage
.addr());
284 T
* beginNoCheck() const {
289 return mBegin
+ mLength
;
292 const T
* endNoCheck() const {
293 return mBegin
+ mLength
;
297 size_t reserved() const {
298 MOZ_ASSERT(mReserved
<= mCapacity
);
299 MOZ_ASSERT(mLength
<= mReserved
);
304 /* Append operations guaranteed to succeed due to pre-reserved space. */
305 template<typename U
> void internalAppend(U
&& u
);
306 template<typename U
, size_t O
, class BP
, class UV
>
307 void internalAppendAll(const VectorBase
<U
, O
, BP
, UV
>& u
);
308 void internalAppendN(const T
& t
, size_t n
);
309 template<typename U
> void internalAppend(const U
* begin
, size_t length
);
312 static const size_t sMaxInlineStorage
= N
;
314 typedef T ElementType
;
316 VectorBase(AllocPolicy
= AllocPolicy());
317 VectorBase(ThisVector
&&); /* Move constructor. */
318 ThisVector
& operator=(ThisVector
&&); /* Move assignment. */
323 const AllocPolicy
& allocPolicy() const {
327 AllocPolicy
& allocPolicy() {
331 enum { InlineLength
= N
};
333 size_t length() const {
341 size_t capacity() const {
346 MOZ_ASSERT(!entered
);
350 const T
* begin() const {
351 MOZ_ASSERT(!entered
);
356 MOZ_ASSERT(!entered
);
357 return mBegin
+ mLength
;
360 const T
* end() const {
361 MOZ_ASSERT(!entered
);
362 return mBegin
+ mLength
;
365 T
& operator[](size_t i
) {
366 MOZ_ASSERT(!entered
);
367 MOZ_ASSERT(i
< mLength
);
371 const T
& operator[](size_t i
) const {
372 MOZ_ASSERT(!entered
);
373 MOZ_ASSERT(i
< mLength
);
378 MOZ_ASSERT(!entered
);
379 MOZ_ASSERT(!empty());
383 const T
& back() const {
384 MOZ_ASSERT(!entered
);
385 MOZ_ASSERT(!empty());
391 friend class VectorBase
;
394 Range(T
* cur
, T
* end
) : cur_(cur
), end_(end
) {}
398 bool empty() const { return cur_
== end_
; }
399 size_t remain() const { return end_
- cur_
; }
400 T
& front() const { return *cur_
; }
401 void popFront() { MOZ_ASSERT(!empty()); ++cur_
; }
402 T
popCopyFront() { MOZ_ASSERT(!empty()); return *cur_
++; }
406 return Range(begin(), end());
412 * Given that the vector is empty and has no inline storage, grow to
415 bool initCapacity(size_t request
);
418 * If reserve(length() + N) succeeds, the N next appends are guaranteed to
421 bool reserve(size_t request
);
424 * Destroy elements in the range [end() - incr, end()). Does not deallocate
425 * or unreserve storage for those elements.
427 void shrinkBy(size_t incr
);
429 /** Grow the vector by incr elements. */
430 bool growBy(size_t incr
);
432 /** Call shrinkBy or growBy based on whether newSize > length(). */
433 bool resize(size_t newLength
);
436 * Increase the length of the vector, but don't initialize the new elements
437 * -- leave them as uninitialized memory.
439 bool growByUninitialized(size_t incr
);
440 bool resizeUninitialized(size_t newLength
);
442 /** Shorthand for shrinkBy(length()). */
445 /** Clears and releases any heap-allocated storage. */
449 * If true, appending |needed| elements won't reallocate elements storage.
450 * This *doesn't* mean that infallibleAppend may be used! You still must
451 * reserve the extra space, even if this method indicates that appends won't
452 * need to reallocate elements storage.
454 bool canAppendWithoutRealloc(size_t needed
) const;
456 /** Potentially fallible append operations. */
459 * This can take either a T& or a T&&. Given a T&&, it moves |u| into the
460 * vector, instead of copying it. If it fails, |u| is left unmoved. ("We are
463 template<typename U
> bool append(U
&& u
);
465 template<typename U
, size_t O
, class BP
, class UV
>
466 bool appendAll(const VectorBase
<U
, O
, BP
, UV
>& u
);
467 bool appendN(const T
& t
, size_t n
);
468 template<typename U
> bool append(const U
* begin
, const U
* end
);
469 template<typename U
> bool append(const U
* begin
, size_t length
);
472 * Guaranteed-infallible append operations for use upon vectors whose
473 * memory has been pre-reserved. Don't use this if you haven't reserved the
476 template<typename U
> void infallibleAppend(U
&& u
) {
477 internalAppend(Forward
<U
>(u
));
479 void infallibleAppendN(const T
& t
, size_t n
) {
480 internalAppendN(t
, n
);
482 template<typename U
> void infallibleAppend(const U
* aBegin
, const U
* aEnd
) {
483 internalAppend(aBegin
, PointerRangeSize(aBegin
, aEnd
));
485 template<typename U
> void infallibleAppend(const U
* aBegin
, size_t aLength
) {
486 internalAppend(aBegin
, aLength
);
494 * Transfers ownership of the internal buffer used by this vector to the
495 * caller. (It's the caller's responsibility to properly deallocate this
496 * buffer, in accordance with this vector's AllocPolicy.) After this call,
497 * the vector is empty. Since the returned buffer may need to be allocated
498 * (if the elements are currently stored in-place), the call can fail,
501 * N.B. Although a T*, only the range [0, length()) is constructed.
503 T
* extractRawBuffer();
506 * Transfer ownership of an array of objects into the vector. The caller
507 * must have allocated the array in accordance with this vector's
510 * N.B. This call assumes that there are no uninitialized elements in the
513 void replaceRawBuffer(T
* p
, size_t length
);
516 * Places |val| at position |p|, shifting existing elements from |p| onward
517 * one position higher. On success, |p| should not be reused because it'll
518 * be a dangling pointer if reallocation of the vector storage occurred; the
519 * return value should be used instead. On failure, nullptr is returned.
523 * if (!(p = vec.insert(p, val)))
525 * <keep working with p>
527 * This is inherently a linear-time operation. Be careful!
530 T
* insert(T
* p
, U
&& val
);
533 * Removes the element |t|, which must fall in the bounds [begin, end),
534 * shifting existing elements from |t + 1| onward one position lower.
539 * Measure the size of the vector's heap-allocated storage.
541 size_t sizeOfExcludingThis(MallocSizeOf mallocSizeOf
) const;
544 * Like sizeOfExcludingThis, but also measures the size of the vector
545 * object (which must be heap-allocated) itself.
547 size_t sizeOfIncludingThis(MallocSizeOf mallocSizeOf
) const;
549 void swap(ThisVector
& other
);
552 VectorBase(const VectorBase
&) MOZ_DELETE
;
553 void operator=(const VectorBase
&) MOZ_DELETE
;
555 /* Move-construct/assign only from our derived class, ThisVector. */
556 VectorBase(VectorBase
&&) MOZ_DELETE
;
557 void operator=(VectorBase
&&) MOZ_DELETE
;
560 /* This does the re-entrancy check plus several other sanity checks. */
561 #define MOZ_REENTRANCY_GUARD_ET_AL \
562 ReentrancyGuard g(*this); \
563 MOZ_ASSERT_IF(usingInlineStorage(), mCapacity == sInlineCapacity); \
564 MOZ_ASSERT(reserved() <= mCapacity); \
565 MOZ_ASSERT(mLength <= reserved()); \
566 MOZ_ASSERT(mLength <= mCapacity)
568 /* Vector Implementation */
570 template<typename T
, size_t N
, class AP
, class TV
>
572 VectorBase
<T
, N
, AP
, TV
>::VectorBase(AP ap
)
575 mCapacity(sInlineCapacity
)
577 , mReserved(sInlineCapacity
),
581 mBegin
= static_cast<T
*>(storage
.addr());
584 /* Move constructor. */
585 template<typename T
, size_t N
, class AllocPolicy
, class TV
>
587 VectorBase
<T
, N
, AllocPolicy
, TV
>::VectorBase(TV
&& rhs
)
588 : AllocPolicy(Move(rhs
))
593 mLength
= rhs
.mLength
;
594 mCapacity
= rhs
.mCapacity
;
596 mReserved
= rhs
.mReserved
;
599 if (rhs
.usingInlineStorage()) {
600 /* We can't move the buffer over in this case, so copy elements. */
601 mBegin
= static_cast<T
*>(storage
.addr());
602 Impl::moveConstruct(mBegin
, rhs
.beginNoCheck(), rhs
.endNoCheck());
604 * Leave rhs's mLength, mBegin, mCapacity, and mReserved as they are.
605 * The elements in its in-line storage still need to be destroyed.
609 * Take src's buffer, and turn src into an empty vector using
613 rhs
.mBegin
= static_cast<T
*>(rhs
.storage
.addr());
614 rhs
.mCapacity
= sInlineCapacity
;
617 rhs
.mReserved
= sInlineCapacity
;
622 /* Move assignment. */
623 template<typename T
, size_t N
, class AP
, class TV
>
626 VectorBase
<T
, N
, AP
, TV
>::operator=(TV
&& rhs
)
628 MOZ_ASSERT(this != &rhs
, "self-move assignment is prohibited");
629 TV
* tv
= static_cast<TV
*>(this);
631 new(tv
) TV(Move(rhs
));
635 template<typename T
, size_t N
, class AP
, class TV
>
637 VectorBase
<T
, N
, AP
, TV
>::~VectorBase()
639 MOZ_REENTRANCY_GUARD_ET_AL
;
640 Impl::destroy(beginNoCheck(), endNoCheck());
641 if (!usingInlineStorage())
642 this->free_(beginNoCheck());
646 * This function will create a new heap buffer with capacity newCap,
647 * move all elements in the inline buffer to this new buffer,
650 template<typename T
, size_t N
, class AP
, class TV
>
652 VectorBase
<T
, N
, AP
, TV
>::convertToHeapStorage(size_t newCap
)
654 MOZ_ASSERT(usingInlineStorage());
656 /* Allocate buffer. */
657 MOZ_ASSERT(!detail::CapacityHasExcessSpace
<T
>(newCap
));
658 T
* newBuf
= reinterpret_cast<T
*>(this->malloc_(newCap
* sizeof(T
)));
662 /* Copy inline elements into heap buffer. */
663 Impl::moveConstruct(newBuf
, beginNoCheck(), endNoCheck());
664 Impl::destroy(beginNoCheck(), endNoCheck());
666 /* Switch in heap buffer. */
668 /* mLength is unchanged. */
673 template<typename T
, size_t N
, class AP
, class TV
>
674 MOZ_NEVER_INLINE
bool
675 VectorBase
<T
, N
, AP
, TV
>::growStorageBy(size_t incr
)
677 MOZ_ASSERT(mLength
+ incr
> mCapacity
);
678 MOZ_ASSERT_IF(!usingInlineStorage(),
679 !detail::CapacityHasExcessSpace
<T
>(mCapacity
));
682 * When choosing a new capacity, its size should is as close to 2**N bytes
683 * as possible. 2**N-sized requests are best because they are unlikely to
684 * be rounded up by the allocator. Asking for a 2**N number of elements
685 * isn't as good, because if sizeof(T) is not a power-of-two that would
686 * result in a non-2**N request size.
692 if (usingInlineStorage()) {
693 /* This case occurs in ~70--80% of the calls to this function. */
695 tl::RoundUpPow2
<(sInlineCapacity
+ 1) * sizeof(T
)>::value
;
696 newCap
= newSize
/ sizeof(T
);
701 /* This case occurs in ~0--10% of the calls to this function. */
706 /* This case occurs in ~15--20% of the calls to this function. */
709 * Will mLength * 4 *sizeof(T) overflow? This condition limits a vector
710 * to 1GB of memory on a 32-bit system, which is a reasonable limit. It
713 * static_cast<char*>(end()) - static_cast<char*>(begin())
715 * doesn't overflow ptrdiff_t (see bug 510319).
717 if (mLength
& tl::MulOverflowMask
<4 * sizeof(T
)>::value
) {
718 this->reportAllocOverflow();
723 * If we reach here, the existing capacity will have a size that is already
724 * as close to 2^N as sizeof(T) will allow. Just double the capacity, and
725 * then there might be space for one more element.
727 newCap
= mLength
* 2;
728 if (detail::CapacityHasExcessSpace
<T
>(newCap
))
731 /* This case occurs in ~2% of the calls to this function. */
732 size_t newMinCap
= mLength
+ incr
;
734 /* Did mLength + incr overflow? Will newCap * sizeof(T) overflow? */
735 if (newMinCap
< mLength
||
736 newMinCap
& tl::MulOverflowMask
<2 * sizeof(T
)>::value
)
738 this->reportAllocOverflow();
742 size_t newMinSize
= newMinCap
* sizeof(T
);
743 size_t newSize
= RoundUpPow2(newMinSize
);
744 newCap
= newSize
/ sizeof(T
);
747 if (usingInlineStorage()) {
749 return convertToHeapStorage(newCap
);
753 return Impl::growTo(*this, newCap
);
756 template<typename T
, size_t N
, class AP
, class TV
>
758 VectorBase
<T
, N
, AP
, TV
>::initCapacity(size_t request
)
761 MOZ_ASSERT(usingInlineStorage());
764 T
* newbuf
= reinterpret_cast<T
*>(this->malloc_(request
* sizeof(T
)));
775 template<typename T
, size_t N
, class AP
, class TV
>
777 VectorBase
<T
, N
, AP
, TV
>::reserve(size_t request
)
779 MOZ_REENTRANCY_GUARD_ET_AL
;
780 if (request
> mCapacity
&& !growStorageBy(request
- mLength
))
784 if (request
> mReserved
)
786 MOZ_ASSERT(mLength
<= mReserved
);
787 MOZ_ASSERT(mReserved
<= mCapacity
);
792 template<typename T
, size_t N
, class AP
, class TV
>
794 VectorBase
<T
, N
, AP
, TV
>::shrinkBy(size_t incr
)
796 MOZ_REENTRANCY_GUARD_ET_AL
;
797 MOZ_ASSERT(incr
<= mLength
);
798 Impl::destroy(endNoCheck() - incr
, endNoCheck());
802 template<typename T
, size_t N
, class AP
, class TV
>
803 MOZ_ALWAYS_INLINE
bool
804 VectorBase
<T
, N
, AP
, TV
>::growBy(size_t incr
)
806 MOZ_REENTRANCY_GUARD_ET_AL
;
807 if (incr
> mCapacity
- mLength
&& !growStorageBy(incr
))
810 MOZ_ASSERT(mLength
+ incr
<= mCapacity
);
811 T
* newend
= endNoCheck() + incr
;
812 Impl::initialize(endNoCheck(), newend
);
815 if (mLength
> mReserved
)
821 template<typename T
, size_t N
, class AP
, class TV
>
822 MOZ_ALWAYS_INLINE
bool
823 VectorBase
<T
, N
, AP
, TV
>::growByUninitialized(size_t incr
)
825 MOZ_REENTRANCY_GUARD_ET_AL
;
826 if (incr
> mCapacity
- mLength
&& !growStorageBy(incr
))
829 MOZ_ASSERT(mLength
+ incr
<= mCapacity
);
832 if (mLength
> mReserved
)
838 template<typename T
, size_t N
, class AP
, class TV
>
840 VectorBase
<T
, N
, AP
, TV
>::resize(size_t newLength
)
842 size_t curLength
= mLength
;
843 if (newLength
> curLength
)
844 return growBy(newLength
- curLength
);
845 shrinkBy(curLength
- newLength
);
849 template<typename T
, size_t N
, class AP
, class TV
>
850 MOZ_ALWAYS_INLINE
bool
851 VectorBase
<T
, N
, AP
, TV
>::resizeUninitialized(size_t newLength
)
853 size_t curLength
= mLength
;
854 if (newLength
> curLength
)
855 return growByUninitialized(newLength
- curLength
);
856 shrinkBy(curLength
- newLength
);
860 template<typename T
, size_t N
, class AP
, class TV
>
862 VectorBase
<T
, N
, AP
, TV
>::clear()
864 MOZ_REENTRANCY_GUARD_ET_AL
;
865 Impl::destroy(beginNoCheck(), endNoCheck());
869 template<typename T
, size_t N
, class AP
, class TV
>
871 VectorBase
<T
, N
, AP
, TV
>::clearAndFree()
875 if (usingInlineStorage())
878 this->free_(beginNoCheck());
879 mBegin
= static_cast<T
*>(storage
.addr());
880 mCapacity
= sInlineCapacity
;
882 mReserved
= sInlineCapacity
;
886 template<typename T
, size_t N
, class AP
, class TV
>
888 VectorBase
<T
, N
, AP
, TV
>::canAppendWithoutRealloc(size_t needed
) const
890 return mLength
+ needed
<= mCapacity
;
893 template<typename T
, size_t N
, class AP
, class TV
>
894 template<typename U
, size_t O
, class BP
, class UV
>
895 MOZ_ALWAYS_INLINE
void
896 VectorBase
<T
, N
, AP
, TV
>::internalAppendAll(const VectorBase
<U
, O
, BP
, UV
>& other
)
898 internalAppend(other
.begin(), other
.length());
901 template<typename T
, size_t N
, class AP
, class TV
>
903 MOZ_ALWAYS_INLINE
void
904 VectorBase
<T
, N
, AP
, TV
>::internalAppend(U
&& u
)
906 MOZ_ASSERT(mLength
+ 1 <= mReserved
);
907 MOZ_ASSERT(mReserved
<= mCapacity
);
908 new(endNoCheck()) T(Forward
<U
>(u
));
912 template<typename T
, size_t N
, class AP
, class TV
>
913 MOZ_ALWAYS_INLINE
bool
914 VectorBase
<T
, N
, AP
, TV
>::appendN(const T
& t
, size_t needed
)
916 MOZ_REENTRANCY_GUARD_ET_AL
;
917 if (mLength
+ needed
> mCapacity
&& !growStorageBy(needed
))
921 if (mLength
+ needed
> mReserved
)
922 mReserved
= mLength
+ needed
;
924 internalAppendN(t
, needed
);
928 template<typename T
, size_t N
, class AP
, class TV
>
929 MOZ_ALWAYS_INLINE
void
930 VectorBase
<T
, N
, AP
, TV
>::internalAppendN(const T
& t
, size_t needed
)
932 MOZ_ASSERT(mLength
+ needed
<= mReserved
);
933 MOZ_ASSERT(mReserved
<= mCapacity
);
934 Impl::copyConstructN(endNoCheck(), needed
, t
);
938 template<typename T
, size_t N
, class AP
, class TV
>
941 VectorBase
<T
, N
, AP
, TV
>::insert(T
* p
, U
&& val
)
943 MOZ_ASSERT(begin() <= p
);
944 MOZ_ASSERT(p
<= end());
945 size_t pos
= p
- begin();
946 MOZ_ASSERT(pos
<= mLength
);
947 size_t oldLength
= mLength
;
948 if (pos
== oldLength
) {
949 if (!append(Forward
<U
>(val
)))
952 T oldBack
= Move(back());
953 if (!append(Move(oldBack
))) /* Dup the last element. */
955 for (size_t i
= oldLength
; i
> pos
; --i
)
956 (*this)[i
] = Move((*this)[i
- 1]);
957 (*this)[pos
] = Forward
<U
>(val
);
959 return begin() + pos
;
962 template<typename T
, size_t N
, class AP
, class TV
>
964 VectorBase
<T
, N
, AP
, TV
>::erase(T
* it
)
966 MOZ_ASSERT(begin() <= it
);
967 MOZ_ASSERT(it
< end());
968 while (it
+ 1 < end()) {
975 template<typename T
, size_t N
, class AP
, class TV
>
977 MOZ_ALWAYS_INLINE
bool
978 VectorBase
<T
, N
, AP
, TV
>::append(const U
* insBegin
, const U
* insEnd
)
980 MOZ_REENTRANCY_GUARD_ET_AL
;
981 size_t needed
= PointerRangeSize(insBegin
, insEnd
);
982 if (mLength
+ needed
> mCapacity
&& !growStorageBy(needed
))
986 if (mLength
+ needed
> mReserved
)
987 mReserved
= mLength
+ needed
;
989 internalAppend(insBegin
, needed
);
993 template<typename T
, size_t N
, class AP
, class TV
>
995 MOZ_ALWAYS_INLINE
void
996 VectorBase
<T
, N
, AP
, TV
>::internalAppend(const U
* insBegin
, size_t insLength
)
998 MOZ_ASSERT(mLength
+ insLength
<= mReserved
);
999 MOZ_ASSERT(mReserved
<= mCapacity
);
1000 Impl::copyConstruct(endNoCheck(), insBegin
, insBegin
+ insLength
);
1001 mLength
+= insLength
;
1004 template<typename T
, size_t N
, class AP
, class TV
>
1005 template<typename U
>
1006 MOZ_ALWAYS_INLINE
bool
1007 VectorBase
<T
, N
, AP
, TV
>::append(U
&& u
)
1009 MOZ_REENTRANCY_GUARD_ET_AL
;
1010 if (mLength
== mCapacity
&& !growStorageBy(1))
1014 if (mLength
+ 1 > mReserved
)
1015 mReserved
= mLength
+ 1;
1017 internalAppend(Forward
<U
>(u
));
1021 template<typename T
, size_t N
, class AP
, class TV
>
1022 template<typename U
, size_t O
, class BP
, class UV
>
1023 MOZ_ALWAYS_INLINE
bool
1024 VectorBase
<T
, N
, AP
, TV
>::appendAll(const VectorBase
<U
, O
, BP
, UV
>& other
)
1026 return append(other
.begin(), other
.length());
1029 template<typename T
, size_t N
, class AP
, class TV
>
1031 MOZ_ALWAYS_INLINE
bool
1032 VectorBase
<T
, N
, AP
, TV
>::append(const U
*insBegin
, size_t insLength
)
1034 return append(insBegin
, insBegin
+ insLength
);
1037 template<typename T
, size_t N
, class AP
, class TV
>
1038 MOZ_ALWAYS_INLINE
void
1039 VectorBase
<T
, N
, AP
, TV
>::popBack()
1041 MOZ_REENTRANCY_GUARD_ET_AL
;
1042 MOZ_ASSERT(!empty());
1047 template<typename T
, size_t N
, class AP
, class TV
>
1049 VectorBase
<T
, N
, AP
, TV
>::popCopy()
1056 template<typename T
, size_t N
, class AP
, class TV
>
1058 VectorBase
<T
, N
, AP
, TV
>::extractRawBuffer()
1061 if (usingInlineStorage()) {
1062 ret
= reinterpret_cast<T
*>(this->malloc_(mLength
* sizeof(T
)));
1065 Impl::copyConstruct(ret
, beginNoCheck(), endNoCheck());
1066 Impl::destroy(beginNoCheck(), endNoCheck());
1067 /* mBegin, mCapacity are unchanged. */
1071 mBegin
= static_cast<T
*>(storage
.addr());
1073 mCapacity
= sInlineCapacity
;
1075 mReserved
= sInlineCapacity
;
1081 template<typename T
, size_t N
, class AP
, class TV
>
1083 VectorBase
<T
, N
, AP
, TV
>::replaceRawBuffer(T
* p
, size_t aLength
)
1085 MOZ_REENTRANCY_GUARD_ET_AL
;
1087 /* Destroy what we have. */
1088 Impl::destroy(beginNoCheck(), endNoCheck());
1089 if (!usingInlineStorage())
1090 this->free_(beginNoCheck());
1092 /* Take in the new buffer. */
1093 if (aLength
<= sInlineCapacity
) {
1095 * We convert to inline storage if possible, even though p might
1096 * otherwise be acceptable. Maybe this behaviour should be
1097 * specifiable with an argument to this function.
1099 mBegin
= static_cast<T
*>(storage
.addr());
1101 mCapacity
= sInlineCapacity
;
1102 Impl::moveConstruct(mBegin
, p
, p
+ aLength
);
1103 Impl::destroy(p
, p
+ aLength
);
1108 mCapacity
= aLength
;
1111 mReserved
= aLength
;
1115 template<typename T
, size_t N
, class AP
, class TV
>
1117 VectorBase
<T
, N
, AP
, TV
>::sizeOfExcludingThis(MallocSizeOf mallocSizeOf
) const
1119 return usingInlineStorage() ? 0 : mallocSizeOf(beginNoCheck());
1122 template<typename T
, size_t N
, class AP
, class TV
>
1124 VectorBase
<T
, N
, AP
, TV
>::sizeOfIncludingThis(MallocSizeOf mallocSizeOf
) const
1126 return mallocSizeOf(this) + sizeOfExcludingThis(mallocSizeOf
);
1129 template<typename T
, size_t N
, class AP
, class TV
>
1131 VectorBase
<T
, N
, AP
, TV
>::swap(TV
& other
)
1133 static_assert(N
== 0,
1134 "still need to implement this for N != 0");
1136 // This only works when inline storage is always empty.
1137 if (!usingInlineStorage() && other
.usingInlineStorage()) {
1138 other
.mBegin
= mBegin
;
1139 mBegin
= inlineStorage();
1140 } else if (usingInlineStorage() && !other
.usingInlineStorage()) {
1141 mBegin
= other
.mBegin
;
1142 other
.mBegin
= other
.inlineStorage();
1143 } else if (!usingInlineStorage() && !other
.usingInlineStorage()) {
1144 Swap(mBegin
, other
.mBegin
);
1146 // This case is a no-op, since we'd set both to use their inline storage.
1149 Swap(mLength
, other
.mLength
);
1150 Swap(mCapacity
, other
.mCapacity
);
1152 Swap(mReserved
, other
.mReserved
);
1157 * STL-like container providing a short-lived, dynamic buffer. Vector calls the
1158 * constructors/destructors of all elements stored in its internal buffer, so
1159 * non-PODs may be safely used. Additionally, Vector will store the first N
1160 * elements in-place before resorting to dynamic allocation.
1163 * - default and copy constructible, assignable, destructible
1164 * - operations do not throw
1166 * - any value, however, N is clamped to min/max values
1168 * - see "Allocation policies" in AllocPolicy.h (defaults to
1169 * mozilla::MallocAllocPolicy)
1171 * Vector is not reentrant: T member functions called during Vector member
1172 * functions must not call back into the same object!
1174 template<typename T
,
1175 size_t MinInlineCapacity
= 0,
1176 class AllocPolicy
= MallocAllocPolicy
>
1178 : public VectorBase
<T
,
1181 Vector
<T
, MinInlineCapacity
, AllocPolicy
> >
1183 typedef VectorBase
<T
, MinInlineCapacity
, AllocPolicy
, Vector
> Base
;
1186 Vector(AllocPolicy alloc
= AllocPolicy()) : Base(alloc
) {}
1187 Vector(Vector
&& vec
) : Base(Move(vec
)) {}
1188 Vector
& operator=(Vector
&& vec
) {
1189 return Base::operator=(Move(vec
));
1193 } // namespace mozilla
1196 #pragma warning(pop)
1199 #endif /* mozilla_Vector_h */