52 static_assert(N > 0,
"SmallVector requires at least 1 inline element. Use std::vector for N=0.");
53 static_assert(N < 65536,
"SmallVector inline capacity is too large. Use std::vector instead.");
57 using size_type = size_t;
58 using difference_type = std::ptrdiff_t;
60 using const_reference =
const T&;
62 using const_pointer =
const T*;
64 using const_iterator =
const T*;
77 constructOrRelease([&]() {
resize(count); });
87 constructOrRelease([&]() {
resize(count, value); });
96 constructOrRelease([&]() {
97 ensureCapacity(init.size());
98 for (
const auto& v : init) {
106 constructOrRelease([&]() {
107 ensureCapacity(other.rawSize());
108 for (
const auto& v : other) {
116 if (other.isInline()) {
119 const size_type n = other.size_;
120 for (size_type i = 0; i < n; ++i) {
121 new (inlineData() + i) T(std::move(other.inlineData()[i]));
122 other.inlineData()[i].~T();
125 storage_.heap_.ptr = other.storage_.heap_.ptr;
126 storage_.heap_.capacity = other.storage_.heap_.capacity;
139 if (
this != &other) {
142 ensureCapacity(other.rawSize());
143 for (
const auto& v : other) {
152 if (
this != &other) {
155 if (other.isInline()) {
159 const size_type n = other.size_;
160 for (size_type i = 0; i < n; ++i) {
161 new (inlineData() + i) T(std::move(other.inlineData()[i]));
162 other.inlineData()[i].~T();
165 storage_.heap_.ptr = other.storage_.heap_.ptr;
166 storage_.heap_.capacity = other.storage_.heap_.capacity;
181 reference operator[](size_type pos) {
185 const_reference operator[](size_type pos)
const {
198 return data()[rawSize() - 1];
202 return data()[rawSize() - 1];
207 return isInline() ? inlineData() : storage_.heap_.ptr;
210 const_pointer
data() const noexcept {
211 return isInline() ? inlineData() : storage_.heap_.ptr;
221 const_iterator
begin() const noexcept {
230 return data() + rawSize();
233 const_iterator
end() const noexcept {
234 return data() + rawSize();
237 const_iterator
cend() const noexcept {
238 return data() + rawSize();
245 return rawSize() == 0;
248 size_type
size() const noexcept {
257 return isInline() ? N : storage_.heap_.capacity;
266 ensureCapacity(newCap);
295 template <
typename... Args>
299 size_type sz = rawSize();
303 return growAndEmplaceBack(N * 2, std::forward<Args>(args)...);
306 size_type sz = rawSize();
307 if (sz == storage_.heap_.capacity) {
308 return growAndEmplaceBack(storage_.heap_.capacity * 2, std::forward<Args>(args)...);
310 ptr = storage_.heap_.ptr;
312 size_type idx = rawSize();
313 new (ptr + idx) T(std::forward<Args>(args)...);
316 assert(rawSize() > 0 &&
"Size overflow into heap bit");
323 size_type sz = rawSize();
335 size_type sz = rawSize();
337 ensureCapacity(count);
338 constructRange(
data(), sz, count, [](T* p) {
new (p) T(); });
340 }
else if (count < sz) {
342 for (size_type i = count; i < sz; ++i) {
356 void resize(size_type count,
const T& value) {
357 size_type sz = rawSize();
359 if (count >
capacity() && isElement(&value)) {
366 ensureCapacity(count);
367 constructRange(
data(), sz, count, [&value](T* p) {
new (p) T(value); });
369 }
else if (count < sz) {
371 for (size_type i = count; i < sz; ++i) {
386 iterator
erase(const_iterator pos) {
388 size_type sz = rawSize();
389 size_type index = pos - ptr;
391 for (size_type i = index; i + 1 < sz; ++i) {
392 ptr[i] = std::move(ptr[i + 1]);
396 return data() + index;
404 static constexpr size_type kHeapBit = size_type(1) << (
sizeof(size_type) * 8 - 1);
405 static constexpr size_type kSizeMask = ~kHeapBit;
407 bool isInline() const noexcept {
408 return (size_ & kHeapBit) == 0;
411 size_type rawSize() const noexcept {
412 return size_ & kSizeMask;
416 void setSize(size_type s)
noexcept {
417 assert((s & kHeapBit) == 0 &&
"Size overflow into heap bit");
418 size_ = (size_ & kHeapBit) | s;
421 T* inlineData() noexcept {
422 return reinterpret_cast<T*
>(&storage_.inline_);
424 const T* inlineData() const noexcept {
425 return reinterpret_cast<const T*
>(&storage_.inline_);
430 bool isElement(
const T* p)
const noexcept {
432 return !std::less<const T*>()(p,
begin) && std::less<const T*>()(p,
begin + rawSize());
437 template <
typename Fill>
438 void constructOrRelease(Fill fill) {
439#if defined(__cpp_exceptions)
453 template <
typename Construct>
454 static void constructRange(T* ptr, size_type
begin, size_type
end, Construct construct) {
456#if defined(__cpp_exceptions)
459 for (; i <
end; ++i) {
462#if defined(__cpp_exceptions)
464 for (size_type j =
begin; j < i; ++j) {
472 void destroyAll() noexcept {
474 size_type sz = rawSize();
475 for (size_type i = 0; i < sz; ++i) {
479 deallocate(storage_.heap_.ptr);
489 static constexpr bool kOverAligned =
alignof(T) >
alignof(std::max_align_t);
491 static T* allocate(size_type count) {
493 return static_cast<T*
>(detail::alignedMallocOrThrow(count *
sizeof(T),
alignof(T)));
495 return static_cast<T*
>(::operator
new(count *
sizeof(T)));
498 static void deallocate(T* ptr)
noexcept {
500 detail::alignedFree(ptr);
511 DISPENSO_DISABLE_WARNING_PUSH
512 DISPENSO_DISABLE_WARNING_FREE_NONHEAP_OBJECT
513 ::operator
delete(ptr);
514 DISPENSO_DISABLE_WARNING_POP
520 void growToHeap(size_type newCap) {
521 T* newData = allocate(newCap);
522#if defined(__cpp_exceptions)
532 adoptHeap(newData, newCap);
540 void transferTo(T* newData) {
542 size_type sz = rawSize();
544#if defined(__cpp_exceptions)
547 for (; i < sz; ++i) {
548 new (newData + i) T(std::move_if_noexcept(oldData[i]));
550#if defined(__cpp_exceptions)
552 for (size_type j = 0; j < i; ++j) {
562 void adoptHeap(T* newData, size_type newCap)
noexcept {
564 size_type sz = rawSize();
566 for (size_type i = 0; i < sz; ++i) {
571 deallocate(storage_.heap_.ptr);
574 storage_.heap_.ptr = newData;
575 storage_.heap_.capacity = newCap;
576 size_ = kHeapBit | sz;
583 template <
typename... Args>
584 reference growAndEmplaceBack(size_type newCap, Args&&... args) {
585 T* newData = allocate(newCap);
586 size_type sz = rawSize();
587#if defined(__cpp_exceptions)
589 new (newData + sz) T(std::forward<Args>(args)...);
602 new (newData + sz) T(std::forward<Args>(args)...);
605 adoptHeap(newData, newCap);
607 assert(rawSize() > 0 &&
"Size overflow into heap bit");
611 void ensureCapacity(size_type newCap) {
612 if (newCap <= N && isInline()) {
617 }
else if (newCap > storage_.heap_.capacity) {
630 alignas(T)
unsigned char inline_[
sizeof(T) * N];
632 Storage() noexcept {}