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
, const U
* srcbeg
, const U
* srcend
) {
88 for (const U
* p
= srcbeg
; p
< srcend
; ++p
, ++dst
)
89 new(dst
) T(OldMove(*p
));
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(OldMove(*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(const 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(MoveRef
<ThisVector
>); /* Move constructor. */
318 ThisVector
& operator=(MoveRef
<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;
457 * Potentially fallible append operations.
459 * The function templates that take an unspecified type U require a const T&
460 * or a MoveRef<T>. The MoveRef<T> variants move their operands into the
461 * vector, instead of copying them. If they fail, the operand is left
464 template<typename U
> bool append(const 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(const 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!
529 T
* insert(T
* p
, const T
& val
);
532 * Removes the element |t|, which must fall in the bounds [begin, end),
533 * shifting existing elements from |t + 1| onward one position lower.
538 * Measure the size of the vector's heap-allocated storage.
540 size_t sizeOfExcludingThis(MallocSizeOf mallocSizeOf
) const;
543 * Like sizeOfExcludingThis, but also measures the size of the vector
544 * object (which must be heap-allocated) itself.
546 size_t sizeOfIncludingThis(MallocSizeOf mallocSizeOf
) const;
548 void swap(ThisVector
& other
);
551 VectorBase(const VectorBase
&) MOZ_DELETE
;
552 void operator=(const VectorBase
&) MOZ_DELETE
;
555 /* This does the re-entrancy check plus several other sanity checks. */
556 #define MOZ_REENTRANCY_GUARD_ET_AL \
557 ReentrancyGuard g(*this); \
558 MOZ_ASSERT_IF(usingInlineStorage(), mCapacity == sInlineCapacity); \
559 MOZ_ASSERT(reserved() <= mCapacity); \
560 MOZ_ASSERT(mLength <= reserved()); \
561 MOZ_ASSERT(mLength <= mCapacity)
563 /* Vector Implementation */
565 template<typename T
, size_t N
, class AP
, class TV
>
567 VectorBase
<T
, N
, AP
, TV
>::VectorBase(AP ap
)
570 mCapacity(sInlineCapacity
)
572 , mReserved(sInlineCapacity
),
576 mBegin
= static_cast<T
*>(storage
.addr());
579 /* Move constructor. */
580 template<typename T
, size_t N
, class AllocPolicy
, class TV
>
582 VectorBase
<T
, N
, AllocPolicy
, TV
>::VectorBase(MoveRef
<TV
> rhs
)
588 mLength
= rhs
->mLength
;
589 mCapacity
= rhs
->mCapacity
;
591 mReserved
= rhs
->mReserved
;
594 if (rhs
->usingInlineStorage()) {
595 /* We can't move the buffer over in this case, so copy elements. */
596 mBegin
= static_cast<T
*>(storage
.addr());
597 Impl::moveConstruct(mBegin
, rhs
->beginNoCheck(), rhs
->endNoCheck());
599 * Leave rhs's mLength, mBegin, mCapacity, and mReserved as they are.
600 * The elements in its in-line storage still need to be destroyed.
604 * Take src's buffer, and turn src into an empty vector using
607 mBegin
= rhs
->mBegin
;
608 rhs
->mBegin
= static_cast<T
*>(rhs
->storage
.addr());
609 rhs
->mCapacity
= sInlineCapacity
;
612 rhs
->mReserved
= sInlineCapacity
;
617 /* Move assignment. */
618 template<typename T
, size_t N
, class AP
, class TV
>
621 VectorBase
<T
, N
, AP
, TV
>::operator=(MoveRef
<TV
> rhs
)
623 TV
* tv
= static_cast<TV
*>(this);
629 template<typename T
, size_t N
, class AP
, class TV
>
631 VectorBase
<T
, N
, AP
, TV
>::~VectorBase()
633 MOZ_REENTRANCY_GUARD_ET_AL
;
634 Impl::destroy(beginNoCheck(), endNoCheck());
635 if (!usingInlineStorage())
636 this->free_(beginNoCheck());
640 * This function will create a new heap buffer with capacity newCap,
641 * move all elements in the inline buffer to this new buffer,
644 template<typename T
, size_t N
, class AP
, class TV
>
646 VectorBase
<T
, N
, AP
, TV
>::convertToHeapStorage(size_t newCap
)
648 MOZ_ASSERT(usingInlineStorage());
650 /* Allocate buffer. */
651 MOZ_ASSERT(!detail::CapacityHasExcessSpace
<T
>(newCap
));
652 T
* newBuf
= reinterpret_cast<T
*>(this->malloc_(newCap
* sizeof(T
)));
656 /* Copy inline elements into heap buffer. */
657 Impl::moveConstruct(newBuf
, beginNoCheck(), endNoCheck());
658 Impl::destroy(beginNoCheck(), endNoCheck());
660 /* Switch in heap buffer. */
662 /* mLength is unchanged. */
667 template<typename T
, size_t N
, class AP
, class TV
>
668 MOZ_NEVER_INLINE
bool
669 VectorBase
<T
, N
, AP
, TV
>::growStorageBy(size_t incr
)
671 MOZ_ASSERT(mLength
+ incr
> mCapacity
);
672 MOZ_ASSERT_IF(!usingInlineStorage(),
673 !detail::CapacityHasExcessSpace
<T
>(mCapacity
));
676 * When choosing a new capacity, its size should is as close to 2**N bytes
677 * as possible. 2**N-sized requests are best because they are unlikely to
678 * be rounded up by the allocator. Asking for a 2**N number of elements
679 * isn't as good, because if sizeof(T) is not a power-of-two that would
680 * result in a non-2**N request size.
686 if (usingInlineStorage()) {
687 /* This case occurs in ~70--80% of the calls to this function. */
689 tl::RoundUpPow2
<(sInlineCapacity
+ 1) * sizeof(T
)>::value
;
690 newCap
= newSize
/ sizeof(T
);
695 /* This case occurs in ~0--10% of the calls to this function. */
700 /* This case occurs in ~15--20% of the calls to this function. */
703 * Will mLength * 4 *sizeof(T) overflow? This condition limits a vector
704 * to 1GB of memory on a 32-bit system, which is a reasonable limit. It
707 * static_cast<char*>(end()) - static_cast<char*>(begin())
709 * doesn't overflow ptrdiff_t (see bug 510319).
711 if (mLength
& tl::MulOverflowMask
<4 * sizeof(T
)>::value
) {
712 this->reportAllocOverflow();
717 * If we reach here, the existing capacity will have a size that is already
718 * as close to 2^N as sizeof(T) will allow. Just double the capacity, and
719 * then there might be space for one more element.
721 newCap
= mLength
* 2;
722 if (detail::CapacityHasExcessSpace
<T
>(newCap
))
725 /* This case occurs in ~2% of the calls to this function. */
726 size_t newMinCap
= mLength
+ incr
;
728 /* Did mLength + incr overflow? Will newCap * sizeof(T) overflow? */
729 if (newMinCap
< mLength
||
730 newMinCap
& tl::MulOverflowMask
<2 * sizeof(T
)>::value
)
732 this->reportAllocOverflow();
736 size_t newMinSize
= newMinCap
* sizeof(T
);
737 size_t newSize
= RoundUpPow2(newMinSize
);
738 newCap
= newSize
/ sizeof(T
);
741 if (usingInlineStorage()) {
743 return convertToHeapStorage(newCap
);
747 return Impl::growTo(*this, newCap
);
750 template<typename T
, size_t N
, class AP
, class TV
>
752 VectorBase
<T
, N
, AP
, TV
>::initCapacity(size_t request
)
755 MOZ_ASSERT(usingInlineStorage());
758 T
* newbuf
= reinterpret_cast<T
*>(this->malloc_(request
* sizeof(T
)));
769 template<typename T
, size_t N
, class AP
, class TV
>
771 VectorBase
<T
, N
, AP
, TV
>::reserve(size_t request
)
773 MOZ_REENTRANCY_GUARD_ET_AL
;
774 if (request
> mCapacity
&& !growStorageBy(request
- mLength
))
778 if (request
> mReserved
)
780 MOZ_ASSERT(mLength
<= mReserved
);
781 MOZ_ASSERT(mReserved
<= mCapacity
);
786 template<typename T
, size_t N
, class AP
, class TV
>
788 VectorBase
<T
, N
, AP
, TV
>::shrinkBy(size_t incr
)
790 MOZ_REENTRANCY_GUARD_ET_AL
;
791 MOZ_ASSERT(incr
<= mLength
);
792 Impl::destroy(endNoCheck() - incr
, endNoCheck());
796 template<typename T
, size_t N
, class AP
, class TV
>
797 MOZ_ALWAYS_INLINE
bool
798 VectorBase
<T
, N
, AP
, TV
>::growBy(size_t incr
)
800 MOZ_REENTRANCY_GUARD_ET_AL
;
801 if (incr
> mCapacity
- mLength
&& !growStorageBy(incr
))
804 MOZ_ASSERT(mLength
+ incr
<= mCapacity
);
805 T
* newend
= endNoCheck() + incr
;
806 Impl::initialize(endNoCheck(), newend
);
809 if (mLength
> mReserved
)
815 template<typename T
, size_t N
, class AP
, class TV
>
816 MOZ_ALWAYS_INLINE
bool
817 VectorBase
<T
, N
, AP
, TV
>::growByUninitialized(size_t incr
)
819 MOZ_REENTRANCY_GUARD_ET_AL
;
820 if (incr
> mCapacity
- mLength
&& !growStorageBy(incr
))
823 MOZ_ASSERT(mLength
+ incr
<= mCapacity
);
826 if (mLength
> mReserved
)
832 template<typename T
, size_t N
, class AP
, class TV
>
834 VectorBase
<T
, N
, AP
, TV
>::resize(size_t newLength
)
836 size_t curLength
= mLength
;
837 if (newLength
> curLength
)
838 return growBy(newLength
- curLength
);
839 shrinkBy(curLength
- newLength
);
843 template<typename T
, size_t N
, class AP
, class TV
>
844 MOZ_ALWAYS_INLINE
bool
845 VectorBase
<T
, N
, AP
, TV
>::resizeUninitialized(size_t newLength
)
847 size_t curLength
= mLength
;
848 if (newLength
> curLength
)
849 return growByUninitialized(newLength
- curLength
);
850 shrinkBy(curLength
- newLength
);
854 template<typename T
, size_t N
, class AP
, class TV
>
856 VectorBase
<T
, N
, AP
, TV
>::clear()
858 MOZ_REENTRANCY_GUARD_ET_AL
;
859 Impl::destroy(beginNoCheck(), endNoCheck());
863 template<typename T
, size_t N
, class AP
, class TV
>
865 VectorBase
<T
, N
, AP
, TV
>::clearAndFree()
869 if (usingInlineStorage())
872 this->free_(beginNoCheck());
873 mBegin
= static_cast<T
*>(storage
.addr());
874 mCapacity
= sInlineCapacity
;
876 mReserved
= sInlineCapacity
;
880 template<typename T
, size_t N
, class AP
, class TV
>
882 VectorBase
<T
, N
, AP
, TV
>::canAppendWithoutRealloc(size_t needed
) const
884 return mLength
+ needed
<= mCapacity
;
887 template<typename T
, size_t N
, class AP
, class TV
>
888 template<typename U
, size_t O
, class BP
, class UV
>
889 MOZ_ALWAYS_INLINE
void
890 VectorBase
<T
, N
, AP
, TV
>::internalAppendAll(const VectorBase
<U
, O
, BP
, UV
>& other
)
892 internalAppend(other
.begin(), other
.length());
895 template<typename T
, size_t N
, class AP
, class TV
>
897 MOZ_ALWAYS_INLINE
void
898 VectorBase
<T
, N
, AP
, TV
>::internalAppend(const U
& u
)
900 MOZ_ASSERT(mLength
+ 1 <= mReserved
);
901 MOZ_ASSERT(mReserved
<= mCapacity
);
902 new(endNoCheck()) T(u
);
906 template<typename T
, size_t N
, class AP
, class TV
>
907 MOZ_ALWAYS_INLINE
bool
908 VectorBase
<T
, N
, AP
, TV
>::appendN(const T
& t
, size_t needed
)
910 MOZ_REENTRANCY_GUARD_ET_AL
;
911 if (mLength
+ needed
> mCapacity
&& !growStorageBy(needed
))
915 if (mLength
+ needed
> mReserved
)
916 mReserved
= mLength
+ needed
;
918 internalAppendN(t
, needed
);
922 template<typename T
, size_t N
, class AP
, class TV
>
923 MOZ_ALWAYS_INLINE
void
924 VectorBase
<T
, N
, AP
, TV
>::internalAppendN(const T
& t
, size_t needed
)
926 MOZ_ASSERT(mLength
+ needed
<= mReserved
);
927 MOZ_ASSERT(mReserved
<= mCapacity
);
928 Impl::copyConstructN(endNoCheck(), needed
, t
);
932 template<typename T
, size_t N
, class AP
, class TV
>
934 VectorBase
<T
, N
, AP
, TV
>::insert(T
* p
, const T
& val
)
936 MOZ_ASSERT(begin() <= p
);
937 MOZ_ASSERT(p
<= end());
938 size_t pos
= p
- begin();
939 MOZ_ASSERT(pos
<= mLength
);
940 size_t oldLength
= mLength
;
941 if (pos
== oldLength
) {
946 if (!append(oldBack
)) /* Dup the last element. */
948 for (size_t i
= oldLength
; i
> pos
; --i
)
949 (*this)[i
] = (*this)[i
- 1];
952 return begin() + pos
;
955 template<typename T
, size_t N
, class AP
, class TV
>
957 VectorBase
<T
, N
, AP
, TV
>::erase(T
* it
)
959 MOZ_ASSERT(begin() <= it
);
960 MOZ_ASSERT(it
< end());
961 while (it
+ 1 < end()) {
968 template<typename T
, size_t N
, class AP
, class TV
>
970 MOZ_ALWAYS_INLINE
bool
971 VectorBase
<T
, N
, AP
, TV
>::append(const U
* insBegin
, const U
* insEnd
)
973 MOZ_REENTRANCY_GUARD_ET_AL
;
974 size_t needed
= PointerRangeSize(insBegin
, insEnd
);
975 if (mLength
+ needed
> mCapacity
&& !growStorageBy(needed
))
979 if (mLength
+ needed
> mReserved
)
980 mReserved
= mLength
+ needed
;
982 internalAppend(insBegin
, needed
);
986 template<typename T
, size_t N
, class AP
, class TV
>
988 MOZ_ALWAYS_INLINE
void
989 VectorBase
<T
, N
, AP
, TV
>::internalAppend(const U
* insBegin
, size_t insLength
)
991 MOZ_ASSERT(mLength
+ insLength
<= mReserved
);
992 MOZ_ASSERT(mReserved
<= mCapacity
);
993 Impl::copyConstruct(endNoCheck(), insBegin
, insBegin
+ insLength
);
994 mLength
+= insLength
;
997 template<typename T
, size_t N
, class AP
, class TV
>
999 MOZ_ALWAYS_INLINE
bool
1000 VectorBase
<T
, N
, AP
, TV
>::append(const U
& u
)
1002 MOZ_REENTRANCY_GUARD_ET_AL
;
1003 if (mLength
== mCapacity
&& !growStorageBy(1))
1007 if (mLength
+ 1 > mReserved
)
1008 mReserved
= mLength
+ 1;
1014 template<typename T
, size_t N
, class AP
, class TV
>
1015 template<typename U
, size_t O
, class BP
, class UV
>
1016 MOZ_ALWAYS_INLINE
bool
1017 VectorBase
<T
, N
, AP
, TV
>::appendAll(const VectorBase
<U
, O
, BP
, UV
>& other
)
1019 return append(other
.begin(), other
.length());
1022 template<typename T
, size_t N
, class AP
, class TV
>
1024 MOZ_ALWAYS_INLINE
bool
1025 VectorBase
<T
, N
, AP
, TV
>::append(const U
*insBegin
, size_t insLength
)
1027 return append(insBegin
, insBegin
+ insLength
);
1030 template<typename T
, size_t N
, class AP
, class TV
>
1031 MOZ_ALWAYS_INLINE
void
1032 VectorBase
<T
, N
, AP
, TV
>::popBack()
1034 MOZ_REENTRANCY_GUARD_ET_AL
;
1035 MOZ_ASSERT(!empty());
1040 template<typename T
, size_t N
, class AP
, class TV
>
1042 VectorBase
<T
, N
, AP
, TV
>::popCopy()
1049 template<typename T
, size_t N
, class AP
, class TV
>
1051 VectorBase
<T
, N
, AP
, TV
>::extractRawBuffer()
1054 if (usingInlineStorage()) {
1055 ret
= reinterpret_cast<T
*>(this->malloc_(mLength
* sizeof(T
)));
1058 Impl::copyConstruct(ret
, beginNoCheck(), endNoCheck());
1059 Impl::destroy(beginNoCheck(), endNoCheck());
1060 /* mBegin, mCapacity are unchanged. */
1064 mBegin
= static_cast<T
*>(storage
.addr());
1066 mCapacity
= sInlineCapacity
;
1068 mReserved
= sInlineCapacity
;
1074 template<typename T
, size_t N
, class AP
, class TV
>
1076 VectorBase
<T
, N
, AP
, TV
>::replaceRawBuffer(T
* p
, size_t aLength
)
1078 MOZ_REENTRANCY_GUARD_ET_AL
;
1080 /* Destroy what we have. */
1081 Impl::destroy(beginNoCheck(), endNoCheck());
1082 if (!usingInlineStorage())
1083 this->free_(beginNoCheck());
1085 /* Take in the new buffer. */
1086 if (aLength
<= sInlineCapacity
) {
1088 * We convert to inline storage if possible, even though p might
1089 * otherwise be acceptable. Maybe this behaviour should be
1090 * specifiable with an argument to this function.
1092 mBegin
= static_cast<T
*>(storage
.addr());
1094 mCapacity
= sInlineCapacity
;
1095 Impl::moveConstruct(mBegin
, p
, p
+ aLength
);
1096 Impl::destroy(p
, p
+ aLength
);
1101 mCapacity
= aLength
;
1104 mReserved
= aLength
;
1108 template<typename T
, size_t N
, class AP
, class TV
>
1110 VectorBase
<T
, N
, AP
, TV
>::sizeOfExcludingThis(MallocSizeOf mallocSizeOf
) const
1112 return usingInlineStorage() ? 0 : mallocSizeOf(beginNoCheck());
1115 template<typename T
, size_t N
, class AP
, class TV
>
1117 VectorBase
<T
, N
, AP
, TV
>::sizeOfIncludingThis(MallocSizeOf mallocSizeOf
) const
1119 return mallocSizeOf(this) + sizeOfExcludingThis(mallocSizeOf
);
1122 template<typename T
, size_t N
, class AP
, class TV
>
1124 VectorBase
<T
, N
, AP
, TV
>::swap(TV
& other
)
1126 static_assert(N
== 0,
1127 "still need to implement this for N != 0");
1129 // This only works when inline storage is always empty.
1130 if (!usingInlineStorage() && other
.usingInlineStorage()) {
1131 other
.mBegin
= mBegin
;
1132 mBegin
= inlineStorage();
1133 } else if (usingInlineStorage() && !other
.usingInlineStorage()) {
1134 mBegin
= other
.mBegin
;
1135 other
.mBegin
= other
.inlineStorage();
1136 } else if (!usingInlineStorage() && !other
.usingInlineStorage()) {
1137 Swap(mBegin
, other
.mBegin
);
1139 // This case is a no-op, since we'd set both to use their inline storage.
1142 Swap(mLength
, other
.mLength
);
1143 Swap(mCapacity
, other
.mCapacity
);
1145 Swap(mReserved
, other
.mReserved
);
1150 * STL-like container providing a short-lived, dynamic buffer. Vector calls the
1151 * constructors/destructors of all elements stored in its internal buffer, so
1152 * non-PODs may be safely used. Additionally, Vector will store the first N
1153 * elements in-place before resorting to dynamic allocation.
1156 * - default and copy constructible, assignable, destructible
1157 * - operations do not throw
1159 * - any value, however, N is clamped to min/max values
1161 * - see "Allocation policies" in AllocPolicy.h (defaults to
1162 * mozilla::MallocAllocPolicy)
1164 * Vector is not reentrant: T member functions called during Vector member
1165 * functions must not call back into the same object!
1167 template<typename T
,
1168 size_t MinInlineCapacity
= 0,
1169 class AllocPolicy
= MallocAllocPolicy
>
1171 : public VectorBase
<T
,
1174 Vector
<T
, MinInlineCapacity
, AllocPolicy
> >
1176 typedef VectorBase
<T
, MinInlineCapacity
, AllocPolicy
, Vector
> Base
;
1179 Vector(AllocPolicy alloc
= AllocPolicy()) : Base(alloc
) {}
1180 Vector(mozilla::MoveRef
<Vector
> vec
) : Base(vec
) {}
1181 Vector
& operator=(mozilla::MoveRef
<Vector
> vec
) {
1182 return Base::operator=(vec
);
1186 } // namespace mozilla
1189 #pragma warning(pop)
1192 #endif /* mozilla_Vector_h */