77 constexpr T *base_data() {
return data_; }
78 constexpr const T *base_data()
const {
return data_; }
79 constexpr void set_size(
size_t n) { size_ = n; }
81 constexpr explicit ipvbase()
noexcept {}
83 noexcept(std::is_nothrow_copy_constructible_v<T>)
85 if constexpr (std::is_trivially_copy_constructible_v<T>) {
86 std::memmove((
void*)
this, (
const void*)std::addressof(rhs),
sizeof(
ipvbase));
88 std::uninitialized_copy_n(rhs.data_, rhs.size_, data_);
93 noexcept(std::is_nothrow_move_constructible_v<T>
94#if defined(__cpp_lib_trivially_relocatable)
95 || std::is_trivially_relocatable_v<T>
99 if constexpr (std::is_trivially_move_constructible_v<T>) {
100 std::memmove((
void*)
this, (
const void*)std::addressof(rhs),
sizeof(
ipvbase));
101#if defined(__cpp_lib_trivially_relocatable)
102 }
else if constexpr (std::is_trivially_relocatable_v<T>) {
103 std::uninitialized_relocate_n(rhs.data_, rhs.size_, data_);
108 std::uninitialized_move_n(rhs.data_, rhs.size_, data_);
112 void operator=(
const ipvbase& rhs)
113 noexcept(std::is_nothrow_copy_constructible_v<T> && std::is_nothrow_copy_assignable_v<T>)
115 if constexpr (std::is_trivially_copy_constructible_v<T> && std::is_trivially_copy_assignable_v<T> && std::is_trivially_destructible_v<T>) {
116 std::memmove((
void*)
this, (
const void*)std::addressof(rhs),
sizeof(
ipvbase));
117 }
else if (
this == std::addressof(rhs)) {
119 }
else if (rhs.size_ <= size_) {
120 std::copy(rhs.data_, rhs.data_ + rhs.size_, data_);
121 std::destroy(data_ + rhs.size_, data_ + size_);
124 std::copy(rhs.data_, rhs.data_ + size_, data_);
125 std::uninitialized_copy(rhs.data_ + size_, rhs.data_ + rhs.size_, data_ + size_);
130 noexcept(std::is_nothrow_move_constructible_v<T> && std::is_nothrow_move_assignable_v<T>)
132 if constexpr (std::is_trivially_move_constructible_v<T> && std::is_trivially_move_assignable_v<T> && std::is_trivially_destructible_v<T>) {
133 std::memmove((
void*)
this, (
const void*)std::addressof(rhs),
sizeof(
ipvbase));
134 }
else if (
this == std::addressof(rhs)) {
136 }
else if (rhs.size_ <= size_) {
137 std::move(rhs.data_, rhs.data_ + rhs.size_, data_);
138 std::destroy(data_ + rhs.size_, data_ + size_);
141 std::move(rhs.data_, rhs.data_ + size_, data_);
142#if defined(__cpp_lib_trivially_relocatable)
143 if constexpr (std::is_trivially_relocatable_v<T>) {
144 std::uninitialized_relocate(rhs.data_ + size_, rhs.data_ + rhs.size_, data_ + size_);
145 std::swap(rhs.size_, size_);
149 std::uninitialized_move(rhs.data_ + size_, rhs.data_ + rhs.size_, data_ + size_);
154#if __cpp_concepts >= 202002L
155 ipvbase(
const ipvbase&)
requires std::is_trivially_copy_constructible_v<T> =
default;
156 ipvbase(
ipvbase&&)
requires std::is_trivially_move_constructible_v<T> =
default;
157 ipvbase& operator=(
const ipvbase&)
requires std::is_trivially_copy_constructible_v<T> && std::is_trivially_copy_assignable_v<T> && std::is_trivially_destructible_v<T> =
default;
158 ipvbase& operator=(
ipvbase&&)
requires std::is_trivially_move_constructible_v<T> && std::is_trivially_move_assignable_v<T> && std::is_trivially_destructible_v<T> =
default;
159 ~ipvbase()
requires std::is_trivially_destructible_v<T> =
default;
162#if PLUGIFY_CPP_VERSION >= 202002L
166 std::destroy(data_, data_ + size_);
205 using detail::ipvbase_t<T,
N>::size_;
206 using detail::ipvbase_t<T,
N>::set_size;
208 using value_type = T;
210 using const_pointer =
const T*;
211 using reference = T&;
212 using const_reference =
const T&;
216 using const_iterator =
const T*;
217 using reverse_iterator = std::reverse_iterator<iterator>;
218 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
228 requires std::is_copy_constructible_v<T>
230 assign(
il.begin(),
il.end());
237 requires std::default_initializable<T>
242 std::uninitialized_value_construct_n(data(), n);
245 constexpr explicit inplace_vector(
size_t n,
const value_type& value)
246 requires std::copy_constructible<T>
251 template<std::input_iterator InputIterator>
252 requires std::constructible_from<T, typename std::iterator_traits<InputIterator>::value_type>
255 if constexpr (std::random_access_iterator<InputIterator>) {
260 std::uninitialized_copy_n(
first, n, data());
264 emplace_back(*
first);
269 constexpr void assign(std::initializer_list<value_type>
il)
270 requires std::is_copy_constructible_v<T>
272 assign(
il.begin(),
il.end());
275 constexpr void assign(
size_t n,
const value_type& value)
276 requires std::is_copy_constructible_v<T>
280 }
else if (size_ >= n) {
281 std::fill_n(data(), n, value);
282 std::destroy(data() + n, data() + size_);
284 std::fill_n(data(), size_, value);
285 std::uninitialized_fill_n(data() + size_, n - size_, value);
290 template<std::input_iterator InputIterator>
291 requires std::is_constructible_v<T, typename std::iterator_traits<InputIterator>::value_type>
296 }
else if (size_ >= n) {
298 std::destroy(data() + n, data() + size_);
301 std::uninitialized_copy(
first + size_,
last, data() + size_);
306 #if __cpp_lib_ranges >= 201911L && __cpp_lib_ranges_to_container >= 202202L
307 template<std::ranges::input_range R>
308 requires std::convertible_to<std::ranges::range_reference_t<R>, value_type>
310 if constexpr (std::ranges::sized_range<R>) {
311 size_t n = std::ranges::size(
rg);
315 std::ranges::uninitialized_copy_n(std::ranges::begin(
rg), n, data(), std::unreachable_sentinel);
318 for (
auto&&
e :
rg) {
319 emplace_back(
decltype(
e)(
e));
324 template<std::ranges::input_range R>
325 requires std::convertible_to<std::ranges::range_reference_t<R>, value_type>
327 auto first = std::ranges::begin(
rg);
328 auto last = std::ranges::end(
rg);
329 size_t n = std::ranges::size(
rg);
332 }
else if (size_ >= n) {
334 std::destroy(data() + n, data() + size_);
337 std::ranges::copy(
first,
mid, data());
338 std::ranges::uninitialized_copy(
mid,
last, data() + size_);
346 constexpr iterator begin()
noexcept {
return data(); }
347 constexpr iterator end()
noexcept {
return data() + size_; }
348 constexpr const_iterator begin()
const noexcept {
return data(); }
349 constexpr const_iterator end()
const noexcept {
return data() + size_; }
350 constexpr reverse_iterator rbegin()
noexcept {
return reverse_iterator(end()); }
351 constexpr reverse_iterator rend()
noexcept {
return reverse_iterator(begin()); }
352 constexpr const_reverse_iterator rbegin()
const noexcept {
return const_reverse_iterator(end()); }
353 constexpr const_reverse_iterator rend()
const noexcept {
return const_reverse_iterator(begin()); }
354 constexpr const_iterator cbegin()
const noexcept {
return data(); }
355 constexpr const_iterator cend()
const noexcept {
return data() + size_; }
356 constexpr const_reverse_iterator crbegin()
const noexcept {
return const_reverse_iterator(end()); }
357 constexpr const_reverse_iterator crend()
const noexcept {
return const_reverse_iterator(begin()); }
360 requires std::is_default_constructible_v<T>
364 }
else if (n < size_) {
365 std::destroy(data() + n, data() + size_);
368 std::uninitialized_value_construct(data() + size_, data() + n);
373 constexpr void resize(
size_type n,
const value_type& value)
374 requires std::is_copy_constructible_v<T>
378 }
else if (n < size_) {
379 std::destroy(data() + n, data() + size_);
382 std::uninitialized_fill(data() + size_, data() + n, value);
387 static constexpr void reserve(
size_type n) {
392 static constexpr void shrink_to_fit()
noexcept {}
400 constexpr reference front() {
404 constexpr reference back() {
406 return data()[size_ - 1];
409 constexpr const_reference operator[](
size_type pos)
const {
413 constexpr const_reference front()
const {
417 constexpr const_reference back()
const {
419 return data()[size_ - 1];
424 throw_out_of_range();
428 constexpr const_reference at(
size_type i)
const {
430 throw_out_of_range();
437 constexpr T* data()
noexcept {
return this->base_data(); }
438 constexpr const T* data()
const noexcept {
return this->base_data(); }
439 constexpr size_type size()
const noexcept {
return size_; }
440 static constexpr size_type max_size()
noexcept {
return N; }
441 static constexpr size_type capacity()
noexcept {
return N; }
442 [[
nodiscard]]
constexpr bool empty()
const noexcept {
return size_ == 0; };
446 template<
class...
Args>
447 requires std::is_constructible_v<T,
Args...>
448 value_type& unchecked_emplace_back(
Args&&...
args) {
450 value_type*
p = data() + size_;
451 p = std::construct_at(
p, std::forward<Args>(
args)...);
455 value_type& unchecked_push_back(
const value_type& value)
456 requires std::is_copy_constructible_v<T>
458 return unchecked_emplace_back(value);
460 value_type& unchecked_push_back(value_type&& value)
461 requires std::is_move_constructible_v<T>
463 return unchecked_emplace_back(
static_cast<value_type&&
>(value));
466 template<
class...
Args>
467 requires std::is_constructible_v<T,
Args...>
468 constexpr value_type* try_emplace_back(
Args&&...
args) {
472 return std::addressof(unchecked_emplace_back(
static_cast<Args&&
>(
args)...));
474 constexpr value_type* try_push_back(
const value_type& value)
475 requires std::is_copy_constructible_v<T>
477 return try_emplace_back(value);
479 constexpr value_type* try_push_back(value_type&& value)
480 requires std::is_move_constructible_v<T>
482 return try_emplace_back(
static_cast<value_type&&
>(value));
485 template<
class...
Args>
486 requires std::is_constructible_v<T,
Args...>
487 value_type& emplace_back(
Args&&...
args) {
491 return unchecked_emplace_back(
static_cast<Args&&
>(
args)...);
493 value_type& push_back(
const value_type& value)
494 requires std::is_copy_constructible_v<T>
496 return emplace_back(value);
498 value_type& push_back(value_type&& value)
499 requires std::is_move_constructible_v<T>
501 return emplace_back(
static_cast<value_type&&
>(value));
504 #if __cpp_lib_ranges >= 201911L && __cpp_lib_ranges_to_container >= 202202L
505 template<std::ranges::input_range R>
506 requires std::convertible_to<std::ranges::range_reference_t<R>, value_type>
508 for (
auto&&
e :
rg) {
515 std::destroy_at(data() + size_ - 1);
519 template<
class...
Args>
520 requires std::is_constructible_v<T,
Args...>
521 iterator emplace(const_iterator
pos,
Args&&...
args) {
522 auto it = iterator(
pos);
523 emplace_back(
static_cast<Args&&
>(
args)...);
524 std::rotate(
it, end() - 1, end());
527 iterator insert(const_iterator
pos,
const value_type& value)
528 requires std::is_copy_constructible_v<T>
530 return emplace(
pos, value);
532 iterator insert(const_iterator
pos, value_type&& value)
533 requires std::is_move_constructible_v<T>
535 return emplace(
pos,
static_cast<value_type&&
>(value));
538 iterator insert(const_iterator
pos,
size_type n,
const value_type& value)
539 requires std::is_copy_constructible_v<T>
544 auto it = iterator(
pos);
546 #if defined(__cpp_lib_trivially_relocatable)
548 if constexpr (std::is_trivially_relocatable_v<value_type>) {
551 std::uninitialized_fill_n(
it, n, value);
554 std::uninitialized_relocate(
it + n,
oldend + n,
it);
561 std::uninitialized_fill_n(
oldend, n, value);
567 template<std::input_iterator InputIterator>
568 requires (std::is_constructible_v<T, typename std::iterator_traits<InputIterator>::value_type> && !std::is_const_v<T>)
570 auto it = iterator(
pos);
572 if constexpr (std::random_access_iterator<InputIterator>) {
577 #if defined(__cpp_lib_trivially_relocatable)
579 if constexpr (std::is_trivially_relocatable_v<value_type>) {
582 std::uninitialized_copy_n(
first, n,
it);
585 std::uninitialized_relocate(
it + n,
oldend + n,
it);
597 emplace_back(*
first);
604 #if __cpp_lib_ranges >= 201911L && __cpp_lib_ranges_to_container >= 202202L
605 template<std::ranges::input_range R>
606 requires std::convertible_to<std::ranges::range_reference_t<R>, value_type>
608 auto it = iterator(
pos);
610 if constexpr (std::ranges::sized_range<R>) {
615 #if defined(__cpp_lib_trivially_relocatable)
617 if constexpr (std::is_trivially_relocatable_v<value_type>) {
620 std::ranges::uninitialized_copy_n(std::ranges::begin(
rg), n,
it, std::unreachable_sentinel);
623 std::uninitialized_relocate(
it + n,
oldend + n,
it);
630 std::ranges::uninitialized_copy_n(std::ranges::begin(
rg), n,
oldend, std::unreachable_sentinel);
634 auto [
rgend,
newend] = std::ranges::uninitialized_copy(
rg, std::ranges::subrange(
oldend, data() +
N));
635 if (
rgend != std::ranges::end(
rg)) {
639 set_size(
newend - data());
647 iterator insert(const_iterator
pos, std::initializer_list<value_type>
il)
648 requires (std::is_copy_constructible_v<T> && !std::is_const_v<T>)
650 return insert(
pos,
il.begin(),
il.end());
653 iterator erase(const_iterator
pos)
654 requires (!std::is_const_v<T>)
656 auto it = iterator(
pos);
658 #if defined(__cpp_lib_trivially_relocatable)
659 if constexpr (std::is_trivially_relocatable_v<value_type>) {
661 std::uninitialized_relocate(
it + 1,
oldend,
it);
667 std::destroy_at(
oldend - 1);
672 iterator erase(const_iterator
first, const_iterator
last)
673 requires (!std::is_const_v<T>)
680 #if defined(__cpp_lib_trivially_relocatable)
681 if constexpr (std::is_trivially_relocatable_v<value_type>) {
694 constexpr void clear()
noexcept {
695 std::destroy(data(), data() + size_);
700 noexcept(
N == 0 || (std::is_nothrow_swappable_v<T> && std::is_nothrow_move_constructible_v<T>))
701 requires (!std::is_const_v<T>)
704 if (a.size_ < b.size_) {
707 std::swap_ranges(a.data(), a.data() + b.size_, b.data());
708 #if defined(__cpp_lib_trivially_relocatable)
711 std::uninitialized_relocate(a.data() + b.size_, a.data() + n, b.data() + b.size_);
714 std::uninitialized_move(a.data() + b.size_, a.data() + a.size_, b.data() + b.size_);
715 std::destroy(a.data() + b.size_, a.data() + a.size_);
716 if constexpr (
N != 0) {
717 std::swap(a.size_, b.size_);
728 if (
lhs.size() != rhs.size())
return false;
729 return std::equal(
lhs.cbegin(),
lhs.cend(), rhs.cbegin());
732 #if __cpp_impl_three_way_comparison >= 201907L
734 return std::lexicographical_compare_three_way(
lhs.begin(),
lhs.end(), rhs.begin(), rhs.end());
738 const T*
adata = a.data();
739 const T*
bdata = b.data();
740 size_t n = (a.size_ < b.size_) ? a.size_ : b.size_;
741 for (
size_t i = 0;
i < n; ++
i) {
748 return (a.size_ < b.size_);
757 [[
noreturn]]
static void throw_bad_alloc() {
758 PLUGIFY_THROW(
"memory size would exceed capacity()", std::bad_alloc);
761 [[
noreturn]]
static void throw_out_of_range() {
762 PLUGIFY_THROW(
"input index is out of bounds", std::out_of_range);