88class Vector :
private detail::VectorStorage<T, InlineCapacity> {
89 using Storage = detail::VectorStorage<T, InlineCapacity>;
92 using Storage::capacity_;
94 template<
typename U,
size_t M>
120 ensure_capacity(count);
121 default_construct_range(data_, count);
131 ensure_capacity(count);
132 fill_construct_range(data_, count, value);
138 if (init.size() > 0) {
139 ensure_capacity(init.size());
140 copy_construct_range(data_, init.begin(), init.size());
145 template<
typename InputIt,
146 typename =
typename std::enable_if<!std::is_integral<InputIt>::value>::type>
148 size_t count =
static_cast<size_t>(std::distance(first, last));
150 ensure_capacity(count);
151 copy_construct_from_iter(data_, first, count);
157 if (other.size_ > 0) {
158 ensure_capacity(other.size_);
159 copy_construct_range(data_, other.data_, other.size_);
164 template<
size_t OtherInline>
166 if (other.size_ > 0) {
167 ensure_capacity(other.size_);
168 copy_construct_range(data_, other.data_, other.size_);
174 noexcept(InlineCapacity == 0 || std::is_nothrow_move_constructible<T>::value) {
175 move_from(std::move(other));
178 template<
size_t OtherInline>
180 noexcept(std::is_nothrow_move_constructible<T>::value) {
181 if (other.size_ > 0) {
182 ensure_capacity(other.size_);
183 move_construct_range(data_, other.data_, other.size_);
190 destroy_range(data_, size_);
198 assign_from_copy(other.data_, other.size_);
202 template<
size_t OtherInline>
204 assign_from_copy(other.data_, other.size_);
209 noexcept(InlineCapacity == 0 || std::is_nothrow_move_constructible<T>::value) {
210 if (
this != &other) {
211 destroy_range(data_, size_);
214 move_from(std::move(other));
219 template<
size_t OtherInline>
221 noexcept(std::is_nothrow_move_constructible<T>::value) {
222 destroy_range(data_, size_);
224 if (other.size_ > 0) {
225 ensure_capacity(other.size_);
226 move_construct_range(data_, other.data_, other.size_);
238 void assign(
size_t count,
const T& value) {
239 destroy_range(data_, size_);
241 ensure_capacity(count);
242 fill_construct_range(data_, count, value);
246 template<
typename InputIt,
247 typename =
typename std::enable_if<!std::is_integral<InputIt>::value>::type>
248 void assign(InputIt first, InputIt last) {
249 size_t count =
static_cast<size_t>(std::distance(first, last));
250 destroy_range(data_, size_);
252 ensure_capacity(count);
253 copy_construct_from_iter(data_, first, count);
257 void assign(std::initializer_list<T> init) {
258 destroy_range(data_, size_);
260 ensure_capacity(init.size());
261 copy_construct_range(data_, init.begin(), init.size());
271 const T&
operator[](
size_t index)
const {
return data_[index]; }
276 T&
at(
size_t index) { assert(index < size_);
return data_[index]; }
277 const T&
at(
size_t index)
const { assert(index < size_);
return data_[index]; }
279 T&
front() { assert(size_ > 0);
return data_[0]; }
280 const T&
front()
const { assert(size_ > 0);
return data_[0]; }
282 T&
back() { assert(size_ > 0);
return data_[size_ - 1]; }
283 const T&
back()
const { assert(size_ > 0);
return data_[size_ - 1]; }
286 const T*
data()
const {
return data_; }
300 bool empty()
const {
return size_ == 0; }
301 size_t size()
const {
return size_; }
314 if (min_capacity > capacity_)
315 grow_to(min_capacity);
323 if (size_ == capacity_)
332 if constexpr (InlineCapacity > 0) {
333 if (size_ <= InlineCapacity && !this->is_inline()) {
335 size_t old_size = size_;
336 data_ = this->inline_buffer();
337 capacity_ = InlineCapacity;
338 move_construct_range(data_, old_data, old_size);
339 destroy_range(old_data, old_size);
340 deallocate(old_data);
345 if (!this->is_inline()) {
346 if constexpr (std::is_trivially_copyable_v<T>) {
347 void* p = reallocate(data_, size_ *
sizeof(T));
348 data_ =
static_cast<T*
>(p);
351 T* new_data =
static_cast<T*
>(allocate(size_ *
sizeof(T)));
352 move_construct_range(new_data, data_, size_);
353 destroy_range(data_, size_);
364 destroy_range(data_, size_);
370 construct_at(data_ + size_, value);
377 construct_at(data_ + size_, std::move(tmp));
383 construct_at(data_ + size_, std::move(value));
387 T tmp(std::move(value));
389 construct_at(data_ + size_, std::move(tmp));
396 template<
typename... Args>
399 construct_at(data_ + size_, std::forward<Args>(args)...);
400 return data_[size_++];
402 return emplace_back_slow(std::forward<Args>(args)...);
409 assert(size_ < capacity_);
410 construct_at(data_ + size_, value);
418 template<
typename... Args>
420 assert(size_ < capacity_);
421 construct_at(data_ + size_, std::forward<Args>(args)...);
422 return data_[size_++];
428 destroy_at(data_ + size_);
437 T result(std::move(data_[size_]));
438 destroy_at(data_ + size_);
443 size_t index =
static_cast<size_t>(pos - data_);
444 assert(index <= size_);
446 return insert_slow_path(index, value);
448 insert_no_grow(index, std::move(tmp));
449 return data_ + index;
453 size_t index =
static_cast<size_t>(pos - data_);
454 assert(index <= size_);
456 return insert_slow_path(index, std::move(value));
457 T tmp(std::move(value));
458 insert_no_grow(index, std::move(tmp));
459 return data_ + index;
462 template<
typename... Args>
464 size_t index =
static_cast<size_t>(pos - data_);
465 assert(index <= size_);
467 return insert_slow_path(index, std::forward<Args>(args)...);
468 if constexpr (std::is_trivially_copyable_v<T>) {
469 std::memmove(data_ + index + 1, data_ + index, (size_ - index) *
sizeof(T));
470 construct_at(data_ + index, std::forward<Args>(args)...);
471 }
else if (index == size_) {
472 construct_at(data_ + index, std::forward<Args>(args)...);
474 construct_at(data_ + size_, std::move(data_[size_ - 1]));
475 for (
size_t i = size_ - 1; i > index; --i)
476 data_[i] = std::move(data_[i - 1]);
477 destroy_at(data_ + index);
478 construct_at(data_ + index, std::forward<Args>(args)...);
481 return data_ + index;
485 size_t index =
static_cast<size_t>(pos - data_);
486 assert(index < size_);
487 if constexpr (std::is_trivially_copyable_v<T>) {
488 std::memmove(data_ + index, data_ + index + 1, (size_ - index - 1) *
sizeof(T));
490 for (
size_t i = index; i < size_ - 1; ++i)
491 data_[i] = std::move(data_[i + 1]);
492 destroy_at(data_ + size_ - 1);
495 return data_ + index;
501 size_t start =
static_cast<size_t>(first - data_);
502 size_t count =
static_cast<size_t>(last - first);
503 assert(start + count <= size_);
504 size_t remaining = size_ - start - count;
505 if constexpr (std::is_trivially_copyable_v<T>) {
506 std::memmove(data_ + start, data_ + start + count, remaining *
sizeof(T));
508 for (
size_t i = 0; i < remaining; ++i)
509 data_[start + i] = std::move(data_[start + count + i]);
510 destroy_range(data_ + size_ - count, count);
513 return data_ + start;
518 destroy_range(data_ + count, size_ - count);
520 }
else if (count > size_) {
521 ensure_capacity(count);
522 default_construct_range(data_ + size_, count - size_);
527 void resize(
size_t count,
const T& value) {
529 destroy_range(data_ + count, size_ - count);
531 }
else if (count > size_) {
532 ensure_capacity(count);
533 fill_construct_range(data_ + size_, count - size_, value);
539 if constexpr (InlineCapacity == 0) {
540 std::swap(data_, other.data_);
541 std::swap(size_, other.size_);
542 std::swap(capacity_, other.capacity_);
544 bool a_inline = this->is_inline();
545 bool b_inline = other.is_inline();
547 if (!a_inline && !b_inline) {
548 std::swap(data_, other.data_);
549 std::swap(size_, other.size_);
550 std::swap(capacity_, other.capacity_);
551 }
else if (a_inline && b_inline) {
552 swap_both_inline(other);
553 }
else if (a_inline) {
554 swap_inline_with_heap(other);
556 other.swap_inline_with_heap(*
this);
566 template<
size_t OtherInline>
568 if (other.size_ == 0)
570 ensure_capacity(size_ + other.size_);
571 copy_construct_range(data_ + size_, other.data_, other.size_);
572 size_ += other.size_;
578 template<
size_t OtherInline>
580 if (other.size_ == 0)
582 ensure_capacity(size_ + other.size_);
583 move_construct_range(data_ + size_, other.data_, other.size_);
584 size_ += other.size_;
591 if (a.size_ != b.size_)
593 if constexpr (std::is_trivially_copyable_v<T>) {
594 return std::memcmp(a.data_, b.data_, a.size_ *
sizeof(T)) == 0;
596 for (
size_t i = 0; i < a.size_; ++i) {
597 if (!(a.data_[i] == b.data_[i]))
609 static void* allocate(
size_t bytes) {
611 if constexpr (
alignof(T) >
alignof(std::max_align_t))
612 p = ul_aligned_malloc(bytes,
alignof(T));
614 p = ul_malloc(bytes);
615 assert(p &&
"Vector: allocation failed");
619 static void deallocate(
void* ptr) {
620 if constexpr (
alignof(T) >
alignof(std::max_align_t))
621 ul_aligned_free(ptr);
626 static void* reallocate(
void* ptr,
size_t bytes) {
628 if constexpr (
alignof(T) >
alignof(std::max_align_t))
629 p = ul_aligned_realloc(ptr, bytes,
alignof(T));
631 p = ul_realloc(ptr, bytes);
632 assert(p &&
"Vector: reallocation failed");
638 template<
typename... Args>
639 static void construct_at(T* ptr, Args&&... args) {
640 ::new (
static_cast<void*
>(ptr)) T(std::forward<Args>(args)...);
643 static void destroy_at(T* ptr) {
644 if constexpr (!std::is_trivially_destructible_v<T>)
648 static void destroy_range(T* ptr,
size_t count) {
649 if constexpr (!std::is_trivially_destructible_v<T>) {
650 for (
size_t i = 0; i < count; ++i)
655 static void copy_construct_range(T* dst,
const T* src,
size_t count) {
656 if constexpr (std::is_trivially_copyable_v<T>) {
657 std::memcpy(dst, src, count *
sizeof(T));
659 for (
size_t i = 0; i < count; ++i)
660 ::new (
static_cast<void*
>(dst + i)) T(src[i]);
664 static void move_construct_range(T* dst, T* src,
size_t count) {
665 if constexpr (std::is_trivially_copyable_v<T>) {
666 std::memcpy(dst, src, count *
sizeof(T));
668 for (
size_t i = 0; i < count; ++i)
669 ::new (
static_cast<void*
>(dst + i)) T(std::move(src[i]));
673 static void fill_construct_range(T* dst,
size_t count,
const T& value) {
674 for (
size_t i = 0; i < count; ++i)
675 ::new (
static_cast<void*
>(dst + i)) T(value);
678 static void default_construct_range(T* dst,
size_t count) {
679 if constexpr (std::is_trivially_default_constructible_v<T>) {
680 std::memset(dst, 0, count *
sizeof(T));
682 for (
size_t i = 0; i < count; ++i)
683 ::new (
static_cast<void*
>(dst + i)) T();
687 template<
typename InputIt>
688 static void copy_construct_from_iter(T* dst, InputIt first,
size_t count) {
689 for (
size_t i = 0; i < count; ++i, ++first)
690 ::new (
static_cast<void*
>(dst + i)) T(*first);
694 static void relocate_range(T* dst, T* src,
size_t count) {
697 if constexpr (std::is_trivially_copyable_v<T>) {
698 std::memcpy(dst, src, count *
sizeof(T));
700 for (
size_t i = 0; i < count; ++i) {
701 ::new (
static_cast<void*
>(dst + i)) T(std::move(src[i]));
709 size_t next_capacity()
const {
710 size_t new_cap = capacity_ + capacity_ / 2 + 1;
711 assert(new_cap > capacity_ &&
"Vector: capacity overflow");
715 void grow() { grow_to(next_capacity()); }
717 void grow_to(
size_t new_cap) {
718 assert(new_cap > capacity_);
719 assert(new_cap <= SIZE_MAX /
sizeof(T) &&
"Vector: allocation size overflow");
721 if constexpr (std::is_trivially_copyable_v<T>) {
722 if (!this->is_inline()) {
723 data_ =
static_cast<T*
>(reallocate(data_, new_cap *
sizeof(T)));
725 T* new_data =
static_cast<T*
>(allocate(new_cap *
sizeof(T)));
726 std::memcpy(new_data, data_, size_ *
sizeof(T));
730 T* new_data =
static_cast<T*
>(allocate(new_cap *
sizeof(T)));
731 for (
size_t i = 0; i < size_; ++i) {
732 ::new (
static_cast<void*
>(new_data + i)) T(std::move(data_[i]));
735 if (!this->is_inline())
742 void ensure_capacity(
size_t min_cap) {
743 if (min_cap > capacity_)
750 if (!this->is_inline() && data_)
754 void reset_to_inline() {
755 if constexpr (InlineCapacity > 0) {
756 data_ = this->inline_buffer();
757 capacity_ = InlineCapacity;
765 void move_from(
Vector&& other) {
766 if constexpr (InlineCapacity == 0) {
769 capacity_ = other.capacity_;
770 other.data_ =
nullptr;
774 if (other.is_inline()) {
775 if constexpr (std::is_trivially_copyable_v<T>) {
776 std::memcpy(data_, other.data_, other.size_ *
sizeof(T));
778 move_construct_range(data_, other.data_, other.size_);
779 destroy_range(other.data_, other.size_);
787 capacity_ = other.capacity_;
788 other.data_ = other.inline_buffer();
790 other.capacity_ = InlineCapacity;
795 void assign_from_copy(
const T* src,
size_t count) {
796 destroy_range(data_, size_);
798 ensure_capacity(count);
799 copy_construct_range(data_, src, count);
805 void insert_no_grow(
size_t index, T&& val) {
806 if constexpr (std::is_trivially_copyable_v<T>) {
807 std::memmove(data_ + index + 1, data_ + index, (size_ - index) *
sizeof(T));
808 std::memcpy(data_ + index, &val,
sizeof(T));
809 }
else if (index == size_) {
810 construct_at(data_ + index, std::move(val));
812 construct_at(data_ + size_, std::move(data_[size_ - 1]));
813 for (
size_t i = size_ - 1; i > index; --i)
814 data_[i] = std::move(data_[i - 1]);
815 data_[index] = std::move(val);
822 template<
typename... Args>
823 iterator insert_slow_path(
size_t index, Args&&... args) {
824 size_t new_cap = next_capacity();
825 T* new_data =
static_cast<T*
>(allocate(new_cap *
sizeof(T)));
827 construct_at(new_data + index, std::forward<Args>(args)...);
829 relocate_range(new_data, data_, index);
830 relocate_range(new_data + index + 1, data_ + index, size_ - index);
831 if (!this->is_inline())
836 return data_ + index;
839 template<
typename... Args>
840 T& emplace_back_slow(Args&&... args) {
841 size_t new_cap = next_capacity();
842 T* new_data =
static_cast<T*
>(allocate(new_cap *
sizeof(T)));
843 construct_at(new_data + size_, std::forward<Args>(args)...);
844 relocate_range(new_data, data_, size_);
845 if (!this->is_inline())
849 return data_[size_++];
854 void swap_both_inline(
Vector& other) {
855 size_t a_size = size_;
856 size_t b_size = other.size_;
858 if constexpr (std::is_trivially_copyable_v<T>) {
859 alignas(T)
unsigned char tmp[
sizeof(T) * InlineCapacity];
860 std::memcpy(tmp, data_, a_size *
sizeof(T));
861 std::memcpy(data_, other.data_, b_size *
sizeof(T));
862 std::memcpy(other.data_, tmp, a_size *
sizeof(T));
864 size_t min_size = a_size < b_size ? a_size : b_size;
865 for (
size_t i = 0; i < min_size; ++i) {
867 swap(data_[i], other.data_[i]);
869 if (a_size > b_size) {
870 move_construct_range(other.data_ + min_size, data_ + min_size, a_size - b_size);
871 destroy_range(data_ + min_size, a_size - b_size);
872 }
else if (b_size > a_size) {
873 move_construct_range(data_ + min_size, other.data_ + min_size, b_size - a_size);
874 destroy_range(other.data_ + min_size, b_size - a_size);
879 other.size_ = a_size;
883 void swap_inline_with_heap(
Vector& other) {
884 T* heap_data = other.data_;
885 size_t heap_size = other.size_;
886 size_t heap_cap = other.capacity_;
889 other.data_ = other.inline_buffer();
890 other.capacity_ = InlineCapacity;
893 if constexpr (std::is_trivially_copyable_v<T>) {
894 std::memcpy(other.data_, data_, size_ *
sizeof(T));
896 move_construct_range(other.data_, data_, size_);
897 destroy_range(data_, size_);
904 capacity_ = heap_cap;