libstdc++
inplace_vector
Go to the documentation of this file.
1// Sequence container with fixed capacity -*- C++ -*-
2
3// Copyright The GNU Toolchain Authors.
4//
5// This file is part of the GNU ISO C++ Library. This library is free
6// software; you can redistribute it and/or modify it under the
7// terms of the GNU General Public License as published by the
8// Free Software Foundation; either version 3, or (at your option)
9// any later version.
10
11// This library is distributed in the hope that it will be useful,
12// but WITHOUT ANY WARRANTY; without even the implied warranty of
13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14// GNU General Public License for more details.
15
16// Under Section 7 of GPL version 3, you are granted additional
17// permissions described in the GCC Runtime Library Exception, version
18// 3.1, as published by the Free Software Foundation.
19
20// You should have received a copy of the GNU General Public License and
21// a copy of the GCC Runtime Library Exception along with this program;
22// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
23// <http://www.gnu.org/licenses/>.
24
25/** @file include/inplace_vector
26 * This is a Standard C++ Library header.
27 * @ingroup sequences
28 */
29
30#ifndef _GLIBCXX_INPLACE_VECTOR
31#define _GLIBCXX_INPLACE_VECTOR 1
32
33#pragma GCC system_header
34
35#define __glibcxx_want_inplace_vector
36#include <bits/version.h>
37
38#ifdef __glibcxx_inplace_vector // C++ >= 26
39#include <compare>
40#include <initializer_list>
41#include <bits/range_access.h>
42#include <bits/ranges_base.h> // borrowed_iterator_t, __detail::__container_compatible_range
43#include <bits/ranges_util.h> // subrange
44#include <bits/ranges_uninitialized.h>
45#include <bits/refwrap.h>
46#include <bits/stl_construct.h>
47#include <bits/stl_uninitialized.h>
48#include <bits/stl_algo.h> // rotate
49
50namespace std _GLIBCXX_VISIBILITY(default)
51{
52_GLIBCXX_BEGIN_NAMESPACE_VERSION
53
54 // [indirect], class template indirect
55 template<typename _Tp, size_t _Nm>
56 class inplace_vector
57 {
58 public:
59
60 // types:
61 using value_type = _Tp;
62 using pointer = _Tp*;
63 using const_pointer = const _Tp*;
64 using reference = value_type&;
65 using const_reference = const value_type&;
66 using size_type = size_t;
67 using difference_type = ptrdiff_t;
68 using iterator
69 = __gnu_cxx::__normal_iterator<_Tp*, inplace_vector>;
70 using const_iterator
71 = __gnu_cxx::__normal_iterator<const _Tp*, inplace_vector>;
72 using reverse_iterator = std::reverse_iterator<iterator>;
73 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
74
75 // [containers.sequences.inplace.vector.cons], construct/copy/destroy
76 constexpr
77 inplace_vector() noexcept
78 { _M_init(); }
79
80 constexpr explicit
81 inplace_vector(size_type __n)
82 {
83 _M_init();
84 _S_reserve(__n);
85 std::uninitialized_value_construct_n(data(), __n);
86 _M_size = __n;
87 }
88
89 constexpr
90 inplace_vector(size_type __n, const _Tp& __value)
91 {
92 _M_init();
93 _S_reserve(__n);
94 std::uninitialized_fill_n(data(), __n, __value);
95 _M_size = __n;
96 }
97
98 template<__any_input_iterator _InputIterator>
99 constexpr
100 inplace_vector(_InputIterator __first, _InputIterator __last)
101 : inplace_vector()
102 {
103 if (const auto __n = _S_distance(__first, __last))
104 {
105 _S_reserve(__n);
106 std::uninitialized_copy(__first, __last, data());
107 _M_size = __n;
108 }
109 else
110 {
111 while (__first != __last)
112 emplace_back(*__first++);
113 }
114 }
115
116 template <__detail::__container_compatible_range<_Tp> _Rg>
117 constexpr
118 inplace_vector(from_range_t, _Rg&& __rg)
119 : inplace_vector()
120 { append_range(__rg); }
121
122 constexpr
123 inplace_vector(initializer_list<_Tp> __il)
124 {
125 _M_init();
126 _S_reserve(__il.size());
127 std::uninitialized_copy(__il.begin(), __il.end(), data());
128 _M_size = __il.size();
129 }
130
131 inplace_vector(const inplace_vector&)
132 requires is_trivially_copy_constructible_v<_Tp>
133 = default;
134
135 constexpr
136 inplace_vector(const inplace_vector& __other)
137 noexcept(is_nothrow_copy_constructible_v<_Tp>)
138 {
139 _M_init();
140 std::uninitialized_copy(__other.begin(), __other.end(), data());
141 _M_size = __other.size();
142 }
143
144 inplace_vector(inplace_vector&&)
145 requires is_trivially_move_constructible_v<_Tp>
146 = default;
147
148 constexpr
149 inplace_vector(inplace_vector&& __other)
150 noexcept(is_nothrow_move_constructible_v<_Tp>)
151 {
152 _M_init();
153 std::uninitialized_move(__other.begin(), __other.end(), data());
154 _M_size = __other.size();
155 }
156
157 ~inplace_vector()
158 requires is_trivially_destructible_v<_Tp>
159 = default;
160
161 constexpr
162 ~inplace_vector()
163 { clear(); }
164
165 inplace_vector&
166 operator=(const inplace_vector&)
167 requires is_trivially_copy_assignable_v<_Tp>
168 && is_trivially_copy_constructible_v<_Tp>
169 && is_trivially_destructible_v<_Tp>
170 = default;
171
172 constexpr inplace_vector&
173 operator=(const inplace_vector& __other)
174 noexcept(is_nothrow_copy_assignable_v<_Tp>
175 && is_nothrow_copy_constructible_v<_Tp>)
176 {
177 if (std::addressof(__other) != this) [[likely]]
178 assign(__other.begin(), __other.end());
179 return *this;
180 }
181
182 inplace_vector&
183 operator=(inplace_vector&&)
184 requires is_trivially_move_assignable_v<_Tp>
185 && is_trivially_move_constructible_v<_Tp>
186 && is_trivially_destructible_v<_Tp>
187 = default;
188
189 constexpr inplace_vector&
190 operator=(inplace_vector&& __other)
191 noexcept(is_nothrow_move_assignable_v<_Tp>
192 && is_nothrow_move_constructible_v<_Tp>)
193 {
194 if (std::addressof(__other) != this) [[likely]]
195 assign(std::make_move_iterator(__other.begin()),
196 std::make_move_iterator(__other.end()));
197 return *this;
198 }
199
200 constexpr inplace_vector&
201 operator=(initializer_list<_Tp> __il)
202 {
203 assign(__il.begin(), __il.end());
204 return *this;
205 }
206
207 template<__any_input_iterator _InputIterator>
208 constexpr void
209 assign(_InputIterator __first, _InputIterator __last)
210 {
211 if (const auto __n = _S_distance(__first, __last))
212 {
213 _S_reserve(__n);
214 if (_M_size <= __n)
215 {
216 for (size_t __i = 0; __i < _M_size; ++__i, (void)++__first)
217 _M_elems[__i] = *__first;
218 std::uninitialized_copy(__first, __last, end());
219 }
220 else
221 std::destroy(std::copy(__first, __last, begin()), end());
222 _M_size = __n;
223 }
224 else
225 {
226 size_t __i = 0;
227 for (;__first != __last && __i < _M_size; ++__first)
228 _M_elems[__i++] = *__first;
229 if (__first == __last)
230 {
231 std::_Destroy_n(data() + __i, _M_size - __i);
232 _M_size = __i;
233 }
234 else
235 {
236 while (__first != __last)
237 emplace_back(*__first++);
238 }
239 }
240 }
241
242 template<__detail::__container_compatible_range<_Tp> _Rg>
243 constexpr void
244 assign_range(_Rg&& __rg)
245 {
246 if constexpr (ranges::forward_range<_Rg> || ranges::sized_range<_Rg>)
247 {
248 const auto __sz = ranges::distance(__rg);
249 if (__sz > _Nm)
250 __throw_bad_alloc();
251 if (__sz <= size())
252 {
253 ranges::copy_n(ranges::begin(__rg), __sz, data());
254 std::destroy(data() + __sz, data() + _M_size);
255 }
256 else
257 {
258 auto [__in, __out] = ranges::copy_n(
259 ranges::begin(__rg), _M_size,
260 data());
261 ranges::uninitialized_copy(
262 std::move(__in), ranges::end(__rg),
263 __out, unreachable_sentinel);
264 }
265 _M_size = __sz;
266 }
267 else
268 {
269 auto __in = ranges::begin(__rg);
270 auto __end = ranges::end(__rg);
271 size_type __n = 0;
272 for (; __n < _M_size && __in != __end; ++__in)
273 _M_elems[__n++] = *__in;
274
275 if (__in == __end)
276 {
277 std::destroy(data() + __n, data() + _M_size);
278 _M_size = __n;
279 return;
280 }
281 else if (__n < _Nm)
282 {
283 auto __res = ranges::uninitialized_copy(
284 std::move(__in), __end,
285 data() + __n, data() + _Nm);
286 _M_size = __res.out - data();
287 if (__res.in == ranges::end(__rg))
288 return;
289 }
290 __throw_bad_alloc();
291 }
292 }
293
294 constexpr void
295 assign(size_type __n, const _Tp& __u)
296 {
297 _S_reserve(__n);
298 if (_M_size <= __n)
299 std::uninitialized_fill_n(std::fill_n(data(), _M_size, __u),
300 __n - _M_size, __u);
301 else
302 std::destroy_n(std::fill_n(data(), __n, __u), _M_size - __n);
303 _M_size = __n;
304 }
305
306 constexpr void
307 assign(initializer_list<_Tp> __il)
308 { assign(__il.begin(), __il.end()); }
309
310 // iterators
311 [[nodiscard]]
312 constexpr iterator
313 begin() noexcept { return iterator(data()); }
314
315 [[nodiscard]]
316 constexpr const_iterator
317 begin() const noexcept { return const_iterator(data()); }
318
319 [[nodiscard]]
320 constexpr iterator
321 end() noexcept
322 { return iterator(data() + _M_size); }
323
324 [[nodiscard]]
325 constexpr const_iterator
326 end() const noexcept
327 { return const_iterator(data() + _M_size); }
328
329 [[nodiscard]]
330 constexpr reverse_iterator
331 rbegin() noexcept
332 { return reverse_iterator(end()); }
333
334 [[nodiscard]]
335 constexpr const_reverse_iterator
336 rbegin() const noexcept
337 { return const_reverse_iterator(end()); }
338
339 [[nodiscard]]
340 constexpr reverse_iterator
341 rend() noexcept { return reverse_iterator(begin()); }
342
343 [[nodiscard]]
344 constexpr const_reverse_iterator
345 rend() const noexcept { return const_reverse_iterator(begin()); }
346
347 [[nodiscard]]
348 constexpr const_iterator
349 cbegin() const noexcept { return begin(); }
350
351 [[nodiscard]]
352 constexpr const_iterator
353 cend() const noexcept { return end(); }
354
355 [[nodiscard]]
356 constexpr const_reverse_iterator
357 crbegin() const noexcept { return rbegin(); }
358
359 [[nodiscard]]
360 constexpr const_reverse_iterator
361 crend() const noexcept { return rend(); }
362
363 // [containers.sequences.inplace.vector.members] size/capacity
364 [[nodiscard]]
365 constexpr bool
366 empty() const noexcept { return _M_size == 0; }
367
368 [[nodiscard]]
369 constexpr size_type
370 size() const noexcept
371 {
372 if (_M_size > _Nm)
373 __builtin_unreachable();
374 return _M_size;
375 }
376
377 [[nodiscard]]
378 static constexpr size_type
379 max_size() noexcept { return _Nm; }
380
381 [[nodiscard]]
382 static constexpr size_type
383 capacity() noexcept { return _Nm; }
384
385 constexpr void
386 resize(size_type __n)
387 {
388 _S_reserve(__n);
389 if (__n > _M_size)
390 std::uninitialized_value_construct_n(data() + _M_size, __n - _M_size);
391 else if (__n < _M_size)
392 std::destroy_n(data() + __n, _M_size - __n);
393 _M_size = __n;
394 }
395
396 constexpr void
397 resize(size_type __n, const _Tp& __c)
398 {
399 _S_reserve(__n);
400 if (__n > _M_size)
401 std::uninitialized_fill_n(data() + _M_size, __n - _M_size, __c);
402 else if (__n < _M_size)
403 std::destroy_n(data() + __n, _M_size - __n);
404 _M_size = __n;
405 }
406
407 static constexpr void
408 reserve(size_type __n)
409 { _S_reserve(__n); }
410
411 static constexpr void
412 shrink_to_fit() { }
413
414 // element access
415 [[nodiscard]]
416 constexpr reference
417 operator[](size_type __n)
418 {
419 __glibcxx_requires_subscript(__n);
420 return _M_elems[__n];
421 }
422
423 [[nodiscard]]
424 constexpr const_reference
425 operator[](size_type __n) const
426 {
427 __glibcxx_requires_subscript(__n);
428 return _M_elems[__n];
429 }
430
431 [[nodiscard]]
432 constexpr const_reference
433 at(size_type __n) const
434 {
435 if (__n >= _M_size)
436 std::__throw_out_of_range_fmt(__N("inplace_vector::at: __n "
437 "(which is %zu) "
438 ">= size() (which is %zu)"),
439 __n, _M_size);
440 return _M_elems[__n];
441 }
442
443 [[nodiscard]]
444 constexpr reference
445 at(size_type __n)
446 {
447 if (__n >= _M_size)
448 std::__throw_out_of_range_fmt(__N("inplace_vector::at: __n "
449 "(which is %zu) "
450 ">= size() (which is %zu)"),
451 __n, _M_size);
452 return _M_elems[__n];
453 }
454
455 [[nodiscard]]
456 constexpr reference
457 front()
458 {
459 __glibcxx_requires_nonempty();
460 return _M_elems[0];
461 }
462
463 [[nodiscard]]
464 constexpr const_reference
465 front() const
466 {
467 __glibcxx_requires_nonempty();
468 return _M_elems[0];
469 }
470
471 [[nodiscard]]
472 constexpr reference
473 back()
474 {
475 __glibcxx_requires_nonempty();
476 return _M_elems[_M_size - 1];
477 }
478
479 [[nodiscard]]
480 constexpr const_reference
481 back() const
482 {
483 __glibcxx_requires_nonempty();
484 return _M_elems[_M_size - 1];
485 }
486
487 // [containers.sequences.inplace.vector.data], data access
488
489 [[nodiscard]]
490 constexpr _Tp*
491 data() noexcept
492 { return static_cast<pointer>(_M_elems); }
493
494 [[nodiscard]]
495 constexpr const _Tp*
496 data() const noexcept
497 { return static_cast<const_pointer>(_M_elems); }
498
499 // [containers.sequences.inplace.vector.modifiers], modifiers
500 template<typename... _Args>
501 constexpr _Tp&
502 emplace_back(_Args&&... __args)
503 {
504 if (_M_size >= _Nm)
505 __throw_bad_alloc();
506 return unchecked_emplace_back(std::forward<_Args>(__args)...);
507 }
508
509 constexpr _Tp&
510 push_back(const _Tp& __x)
511 { return emplace_back(__x); }
512
513 constexpr _Tp&
514 push_back(_Tp&& __x)
515 { return emplace_back(std::move(__x)); }
516
517 template<__detail::__container_compatible_range<_Tp> _Rg>
518 constexpr void
519 append_range(_Rg&& __rg)
520 {
521 if constexpr (ranges::forward_range<_Rg> || ranges::sized_range<_Rg>)
522 {
523 const auto __sz = ranges::distance(__rg);
524 if (__sz > (_Nm - size()))
525 __throw_bad_alloc();
526 // Bounded on output range due PR121143
527 ranges::uninitialized_copy(
528 ranges::begin(__rg), unreachable_sentinel,
529 data() + _M_size, data() + _M_size + __sz);
530 _M_size += size_type(__sz);
531 }
532 else
533 {
534 ranges::subrange<pointer> __tail(data() + _M_size, data() + _Nm);
535 auto [__in, __out] = ranges::uninitialized_copy(__rg, __tail);
536 _M_size = __out - data();
537 if (__in != ranges::end(__rg))
538 __throw_bad_alloc();
539 }
540 }
541
542 constexpr void
543 pop_back()
544 {
545 __glibcxx_requires_nonempty();
546 --_M_size;
547 _M_elems[_M_size].~_Tp();
548 }
549
550 template<typename... _Args>
551 constexpr _Tp*
552 try_emplace_back(_Args&&... __args)
553 {
554 if (_M_size >= _Nm) [[unlikely]]
555 return nullptr;
556 auto& __r = unchecked_emplace_back(std::forward<_Args>(__args)...);
557 return __builtin_addressof(__r);
558 }
559
560 constexpr _Tp*
561 try_push_back(const _Tp& __x)
562 {
563 if (_M_size >= _Nm) [[unlikely]]
564 return nullptr;
565 return __builtin_addressof(unchecked_emplace_back(__x));
566 }
567
568 constexpr _Tp*
569 try_push_back(_Tp&& __x)
570 {
571 if (_M_size >= _Nm) [[unlikely]]
572 return nullptr;
573 return __builtin_addressof(unchecked_emplace_back(std::move(__x)));
574 }
575
576 template<__detail::__container_compatible_range<_Tp> _Rg>
577 constexpr ranges::borrowed_iterator_t<_Rg>
578 try_append_range(_Rg&& __rg)
579 {
580 if constexpr (ranges::sized_range<_Rg>)
581 {
582 auto __n = ranges::distance(__rg);
583 if (__n == 0) [[unlikely]]
584 return ranges::begin(__rg);
585
586 const auto __end = data() + _M_size;
587 const size_t __avail = _Nm - size();
588 if (__n <= __avail)
589 _M_size += size_type(__n);
590 else
591 {
592 __n = __avail;
593 _M_size = _Nm;
594 }
595 return ranges::uninitialized_copy_n(
596 ranges::begin(__rg), __n,
597 __end, unreachable_sentinel).in;
598 }
599 else
600 {
601 ranges::subrange<pointer> __tail(data() + _M_size, data() + _Nm);
602 auto [__in, __out] = ranges::uninitialized_copy(__rg, __tail);
603 _M_size = __out - data();
604 return std::move(__in);
605 }
606 }
607
608 template<typename... _Args>
609 constexpr _Tp&
610 unchecked_emplace_back(_Args&&... __args)
611 {
612 __glibcxx_assert(_M_size < _Nm);
613 auto __p = std::construct_at(data() + _M_size,
614 std::forward<_Args>(__args)...);
615 ++_M_size;
616 return *__p;
617 }
618
619 constexpr _Tp&
620 unchecked_push_back(const _Tp& __x)
621 { return unchecked_emplace_back(__x); }
622
623 constexpr _Tp&
624 unchecked_push_back(_Tp&& __x)
625 { return unchecked_emplace_back(std::move(__x)); }
626
627 template<typename... _Args>
628 constexpr iterator
629 emplace(const_iterator __position, _Args&&... __args)
630 {
631 size_t __b = __position - cbegin(); // elements before position
632 __glibcxx_assert(__b <= _M_size);
633 if (_M_size >= _Nm)
634 __throw_bad_alloc();
635 iterator __pos = begin() + __b;
636 std::construct_at(data() + _M_size, std::forward<_Args>(__args)...);
637 if (_M_size++)
638 std::rotate(__pos, end() - 1, end());
639 return __pos;
640 }
641
642 constexpr iterator
643 insert(const_iterator __position, const _Tp& __x)
644 { return emplace(__position, __x); }
645
646 constexpr iterator
647 insert(const_iterator __position, _Tp&& __x)
648 { return emplace(__position, std::move(__x)); }
649
650 constexpr iterator
651 insert(const_iterator __position, size_type __n, const _Tp& __x)
652 {
653 size_t __b = __position - cbegin(); // elements before position
654 __glibcxx_assert(__b <= _M_size);
655 if ((_Nm - _M_size) < __n)
656 __throw_bad_alloc();
657 iterator __pos = begin() + __b;
658 std::uninitialized_fill_n(data() + _M_size, __n, __x);
659 if (std::__exchange(_M_size, _M_size + __n))
660 std::rotate(__pos, end() - __n, end());
661 return __pos;
662 }
663
664 template<__any_input_iterator _InputIterator>
665 constexpr iterator
666 insert(const_iterator __position, _InputIterator __first,
667 _InputIterator __last)
668 {
669 size_t __b = __position - cbegin(); // elements before position
670 __glibcxx_assert(__b <= _M_size);
671 iterator __pos = begin() + __b;
672 const size_t __s = _M_size;
673 if (const auto __n = _S_distance(__first, __last))
674 {
675 if ((_Nm - _M_size) < __n)
676 __throw_bad_alloc();
677 std::uninitialized_copy(__first, __last, data() + _M_size);
678 _M_size += __n;
679 }
680 else
681 {
682 while (__first != __last)
683 emplace_back(*__first++);
684 }
685 if (__s)
686 std::rotate(__pos, begin() + __s, end());
687 return __pos;
688 }
689
690 template<__detail::__container_compatible_range<_Tp> _Rg>
691 constexpr iterator
692 insert_range(const_iterator __position, _Rg&& __rg)
693 {
694 iterator __pos = begin() + (__position - cbegin());
695 const auto __end = end();
696 if constexpr (ranges::forward_range<_Rg> || ranges::sized_range<_Rg>)
697 {
698 const auto __len = ranges::distance(__rg);
699 if (__len > (_Nm - size()))
700 __throw_bad_alloc();
701 if (!__len) [[unlikely]]
702 return __pos;
703
704 const size_type __n = size_type(__len);
705 const size_type __num_after = __end - __pos;
706 if (__num_after >= __n)
707 {
708 ranges::uninitialized_move(__end - __n, __end,
709 __end, unreachable_sentinel);
710 _M_size += __n;
711 ranges::move_backward(__pos, __end - __n, __end);
712 ranges::copy(__rg, __pos);
713 }
714 else if constexpr (ranges::forward_range<_Rg>)
715 {
716 auto __mid = ranges::next(ranges::begin(__rg), __num_after);
717 ranges::uninitialized_copy(__mid, ranges::end(__rg),
718 __end, unreachable_sentinel);
719 _M_size += __n - __num_after;
720 ranges::uninitialized_move(__pos, __end,
721 __pos + __n, unreachable_sentinel);
722 _M_size += __num_after;
723 ranges::copy(ranges::begin(__rg), __mid, __pos);
724 }
725 else
726 {
727 ranges::uninitialized_copy(
728 ranges::begin(__rg), ranges::end(__rg),
729 __end, unreachable_sentinel);
730 _M_size += __n;
731 std::rotate(__pos, __end, end());
732 }
733 }
734 else
735 {
736 append_range(__rg);
737 std::rotate(__pos, __end, end());
738 }
739 return __pos;
740 }
741
742 constexpr iterator
743 insert(const_iterator __position, initializer_list<_Tp> __il)
744 { return insert(__position, __il.begin(), __il.end()); }
745
746 constexpr iterator
747 erase(const_iterator __position)
748 {
749 size_t __n = __position - cbegin();
750 __glibcxx_assert(__n < _M_size);
751 iterator __pos = begin() + __n;
752 std::move(__pos + 1, end(), __pos);
753 pop_back();
754 return __pos;
755 }
756
757 constexpr iterator
758 erase(const_iterator __first, const_iterator __last)
759 {
760 size_t __n = __first - cbegin();
761 size_t __x = __last - __first;
762 __glibcxx_assert(__n <= _M_size);
763 __glibcxx_assert(__x <= _M_size);
764 iterator __pos = begin() + __n;
765 iterator __end = std::move(__pos + __x, end(), __pos);
766 std::destroy_n(__end, __x);
767 _M_size -= __x;
768 return __pos;
769 }
770
771 constexpr void
772 swap(inplace_vector& __x)
773 noexcept(is_nothrow_swappable_v<_Tp> && is_nothrow_move_constructible_v<_Tp>)
774 {
775 inplace_vector* __vs[2]{ this, std::addressof(__x) };
776 const auto __smaller = __vs[__x.size() < size()];
777 const auto __bigger = __vs[__x.size() >= size()];
778 size_type __n = __smaller->size();
779 size_type __n2 = __bigger->size();
780
781 if constexpr (is_nothrow_move_constructible_v<_Tp>)
782 {
783 for (size_type __i = __n; __i < __n2; ++__i)
784 {
785 std::construct_at(__smaller->data() + __i,
786 std::move(*(__bigger->data() + __i)));
787 std::destroy_at(__bigger->data() + __i);
788 }
789 }
790 else
791 {
792 std::uninitialized_copy(__bigger->data() + __n,
793 __bigger->data() + __n2,
794 __smaller->data() + __n);
795 std::destroy(__bigger->data() + __n, __bigger->data() + __n2);
796 }
797 __smaller->_M_size = __n2;
798 __bigger->_M_size = __n;
799
800 using std::swap;
801 for (size_type __i = 0; __i < __n; __i++)
802 swap(_M_elems[__i], __x._M_elems[__i]);
803 }
804
805 constexpr void
806 clear() noexcept
807 {
808 std::destroy_n(data(), size_t(_M_size));
809 _M_size = 0;
810 }
811
812 constexpr friend bool
813 operator==(const inplace_vector& __x, const inplace_vector& __y)
814 { return std::equal(__x.begin(), __x.end(), __y.begin(), __y.end()); }
815
816 constexpr friend auto
817 operator<=>(const inplace_vector& __x, const inplace_vector& __y)
818 requires requires (const _Tp __t) {
819 { __t < __t } -> __detail::__boolean_testable;
820 }
821 {
822 return std::lexicographical_compare_three_way(__x.begin(), __x.end(),
823 __y.begin(), __y.end(),
824 __detail::__synth3way);
825 }
826
827 constexpr friend void
828 swap(inplace_vector& __x, inplace_vector& __y)
829 noexcept(is_nothrow_swappable_v<_Tp> && is_nothrow_move_constructible_v<_Tp>)
830 { __x.swap(__y); }
831
832 private:
833 union {
834 _Tp _M_elems[_Nm];
835 };
836
837 // Check whether integer type _UInt is wide enough to store _Nm,
838 // so that we use a smaller type for _M_size when that saves space.
839 template<typename _UInt, bool = (alignof(_Tp) <= sizeof(_UInt))>
840 static constexpr bool __fits
841 = _Nm <= __gnu_cxx::__int_traits<_UInt>::__max;
842
843 // Don't bother using a smaller type if alignment of the array elements
844 // means that it doesn't actually save space.
845 template<typename _UInt>
846 static constexpr bool __fits<_UInt, false> = false;
847
848 static consteval auto __select_size_type()
849 {
850 if constexpr (__fits<unsigned char>)
851 return (unsigned char)0;
852#if __SHRT_WIDTH__ < __SIZE_WIDTH__
853 else if constexpr (__fits<unsigned short>)
854 return (unsigned short)0;
855#endif
856#if __INT_WIDTH__ < __SIZE_WIDTH__ && __INT_WIDTH__ > __SHRT_WIDTH__
857 else if constexpr (__fits<unsigned int>)
858 return 0u;
859#endif
860#if __LONG_WIDTH__ < __SIZE_WIDTH__ && __LONG_WIDTH__ > __INT_WIDTH__
861 else if constexpr (__fits<unsigned long>)
862 return 0ul;
863#endif
864 else // Just use size_t.
865 return 0uz;
866 }
867 decltype(__select_size_type()) _M_size = 0;
868
869 constexpr void
870 _M_init()
871 {
872 if !consteval
873 {
874#if __glibcxx_start_lifetime_as
875 std::start_lifetime_as_array<_Tp>(data(), _Nm);
876#endif
877 }
878 else
879 {
880 // TODO: use new(_M_elems) _Tp[_Nm]() once PR121068 is fixed
881 if constexpr (is_trivial_v<_Tp>)
882 for (size_t __i = 0; __i < _Nm; ++__i)
883 _M_elems[__i] = _Tp();
884 else
885 __builtin_unreachable(); // only trivial types are supported at compile time
886 }
887 }
888
889 static constexpr void
890 _S_reserve(size_t __n)
891 {
892 if (__n > _Nm)
893 __throw_bad_alloc();
894 }
895
896 template<typename _InputIterator>
897 constexpr static auto
898 _S_distance(_InputIterator __first, _InputIterator __last)
899 {
900 if constexpr (sized_sentinel_for<_InputIterator, _InputIterator>
901 || forward_iterator<_InputIterator>)
902 return (size_type)ranges::distance(__first, __last);
903 else if constexpr (derived_from<__iter_category_t<_InputIterator>,
904 forward_iterator_tag>)
905 return (size_type)std::distance(__first, __last);
906 else
907 return false_type{};
908 }
909 };
910
911 // [inplace.vector.special], specialized algorithms
912 template<typename _Tp, size_t _Nm>
913 constexpr void
914 swap(inplace_vector<_Tp, _Nm>& __x, inplace_vector<_Tp, _Nm>& __y)
915 noexcept(noexcept(__x.swap(__y)))
916 { __x.swap(__y); }
917
918 // specialization for zero capacity, that is required to be trivally copyable
919 // and empty regardless of _Tp.
920 template<typename _Tp>
921 class inplace_vector<_Tp, 0>
922 {
923 public:
924 // types:
925 using value_type = _Tp;
926 using pointer = _Tp*;
927 using const_pointer = const _Tp*;
928 using reference = value_type&;
929 using const_reference = const value_type&;
930 using size_type = size_t;
931 using difference_type = ptrdiff_t;
932 using iterator
933 = __gnu_cxx::__normal_iterator<_Tp*, inplace_vector>;
934 using const_iterator
935 = __gnu_cxx::__normal_iterator<const _Tp*, inplace_vector>;
936 using reverse_iterator = std::reverse_iterator<iterator>;
937 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
938
939 // [containers.sequences.inplace.vector.cons], construct/copy/destroy
940 inplace_vector() = default;
941
942 constexpr explicit
943 inplace_vector(size_type __n)
944 {
945 if (__n != 0)
946 __throw_bad_alloc();
947 }
948
949 constexpr
950 inplace_vector(size_type __n, const _Tp& __value)
951 {
952 if (__n != 0)
953 __throw_bad_alloc();
954 }
955
956 template<__any_input_iterator _InputIterator>
957 constexpr
958 inplace_vector(_InputIterator __first, _InputIterator __last)
959 {
960 if (__first != __last)
961 __throw_bad_alloc();
962 }
963
964 template <__detail::__container_compatible_range<_Tp> _Rg>
965 constexpr
966 inplace_vector(from_range_t, _Rg&& __rg)
967 {
968 if (ranges::begin(__rg) != ranges::end(__rg))
969 __throw_bad_alloc();
970 }
971
972 constexpr
973 inplace_vector(initializer_list<_Tp> __il)
974 {
975 if (__il.size() != 0)
976 __throw_bad_alloc();
977 }
978
979 inplace_vector(const inplace_vector&) = default;
980 inplace_vector(inplace_vector&&) = default;
981
982 constexpr
983 ~inplace_vector() = default;
984
985 inplace_vector&
986 operator=(const inplace_vector&) = default;
987
988 inplace_vector&
989 operator=(inplace_vector&&) = default;
990
991 constexpr inplace_vector&
992 operator=(initializer_list<_Tp> __il)
993 {
994 if (__il.size() != 0)
995 __throw_bad_alloc();
996 }
997
998 template<__any_input_iterator _InputIterator>
999 constexpr void
1000 assign(_InputIterator __first, _InputIterator __last)
1001 {
1002 if (__first != __last)
1003 __throw_bad_alloc();
1004 }
1005
1006 template<__detail::__container_compatible_range<_Tp> _Rg>
1007 constexpr void
1008 assign_range(_Rg&& __rg)
1009 {
1010 if (ranges::begin(__rg) != ranges::end(__rg))
1011 __throw_bad_alloc();
1012 }
1013
1014 constexpr void
1015 assign(size_type __n, const _Tp& __u)
1016 {
1017 if (__n != 0)
1018 __throw_bad_alloc();
1019 }
1020
1021 constexpr void
1022 assign(initializer_list<_Tp> __il)
1023 {
1024 if (__il.size() != 0)
1025 __throw_bad_alloc();
1026 }
1027
1028 // iterators
1029 [[nodiscard]]
1030 constexpr iterator
1031 begin() noexcept { return iterator(nullptr); }
1032
1033 [[nodiscard]]
1034 constexpr const_iterator
1035 begin() const noexcept { return const_iterator(nullptr); }
1036
1037 [[nodiscard]]
1038 constexpr iterator
1039 end() noexcept { return iterator(nullptr); }
1040
1041 [[nodiscard]]
1042 constexpr const_iterator
1043 end() const noexcept { return const_iterator(nullptr); }
1044
1045 [[nodiscard]]
1046 constexpr reverse_iterator
1047 rbegin() noexcept
1048 { return reverse_iterator(end()); }
1049
1050 [[nodiscard]]
1051 constexpr const_reverse_iterator
1052 rbegin() const noexcept
1053 { return const_reverse_iterator(end()); }
1054
1055 [[nodiscard]]
1056 constexpr reverse_iterator
1057 rend() noexcept { return reverse_iterator(begin()); }
1058
1059 [[nodiscard]]
1060 constexpr const_reverse_iterator
1061 rend() const noexcept { return const_reverse_iterator(begin()); }
1062
1063 [[nodiscard]]
1064 constexpr const_iterator
1065 cbegin() const noexcept { return begin(); }
1066
1067 [[nodiscard]]
1068 constexpr const_iterator
1069 cend() const noexcept { return end(); }
1070
1071 [[nodiscard]]
1072 constexpr const_reverse_iterator
1073 crbegin() const noexcept { return rbegin(); }
1074
1075 [[nodiscard]]
1076 constexpr const_reverse_iterator
1077 crend() const noexcept { return rend(); }
1078
1079 // [containers.sequences.inplace.vector.members] size/capacity
1080 [[nodiscard]]
1081 constexpr bool
1082 empty() const noexcept { return true; }
1083
1084 [[nodiscard]]
1085 constexpr size_type
1086 size() const noexcept { return 0; }
1087
1088 [[nodiscard]]
1089 static constexpr size_type
1090 max_size() noexcept { return 0; }
1091
1092 [[nodiscard]]
1093 static constexpr size_type
1094 capacity() noexcept { return 0; }
1095
1096 constexpr void
1097 resize(size_type __n)
1098 {
1099 if (__n != 0)
1100 __throw_bad_alloc();
1101 }
1102
1103 constexpr void
1104 resize(size_type __n, const _Tp&)
1105 {
1106 if (__n != 0)
1107 __throw_bad_alloc();
1108 }
1109
1110 static constexpr void
1111 reserve(size_type __n)
1112 {
1113 if (__n != 0)
1114 __throw_bad_alloc();
1115 }
1116
1117 static constexpr void
1118 shrink_to_fit() { }
1119
1120 // element access
1121 [[nodiscard,noreturn]]
1122 constexpr reference
1123 operator[](size_type)
1124 { __builtin_trap(); }
1125
1126 [[nodiscard,noreturn]]
1127 constexpr const_reference
1128 operator[](size_type) const
1129 { __builtin_trap(); }
1130
1131 [[nodiscard,noreturn]]
1132 constexpr const_reference
1133 at(size_type __n) const
1134 {
1135 std::__throw_out_of_range_fmt(__N("inplace_vector::at: __n "
1136 "(which is %zu) "
1137 ">= size() (which is 0)"),
1138 __n);
1139 }
1140
1141 [[nodiscard,noreturn]]
1142 constexpr reference
1143 at(size_type __n)
1144 {
1145 std::__throw_out_of_range_fmt(__N("inplace_vector::at: __n "
1146 "(which is %zu) "
1147 ">= size() (which is 0)"),
1148 __n);
1149 }
1150
1151 [[nodiscard,noreturn]]
1152 constexpr reference
1153 front()
1154 { __builtin_trap(); }
1155
1156 [[nodiscard,noreturn]]
1157 constexpr const_reference
1158 front() const
1159 { __builtin_trap(); }
1160
1161 [[nodiscard,noreturn]]
1162 constexpr reference
1163 back()
1164 { __builtin_trap(); }
1165
1166 [[nodiscard,noreturn]]
1167 constexpr const_reference
1168 back() const
1169 { __builtin_trap(); }
1170
1171 // [containers.sequences.inplace.vector.data], data access
1172
1173 [[nodiscard]]
1174 constexpr _Tp*
1175 data() noexcept
1176 { return nullptr; }
1177
1178 [[nodiscard]]
1179 constexpr const _Tp*
1180 data() const noexcept
1181 { return nullptr; }
1182
1183 // [containers.sequences.inplace.vector.modifiers], modifiers
1184 template<typename... _Args>
1185 [[noreturn]]
1186 constexpr _Tp&
1187 emplace_back(_Args&&...)
1188 { __throw_bad_alloc(); }
1189
1190 [[noreturn]]
1191 constexpr _Tp&
1192 push_back(const _Tp&)
1193 { __throw_bad_alloc(); }
1194
1195 [[noreturn]]
1196 constexpr _Tp&
1197 push_back(_Tp&&)
1198 { __throw_bad_alloc(); }
1199
1200 template<__detail::__container_compatible_range<_Tp> _Rg>
1201 constexpr void
1202 append_range(_Rg&& __rg)
1203 {
1204 if (ranges::begin(__rg) != ranges::end(__rg))
1205 __throw_bad_alloc();
1206 }
1207
1208 [[noreturn]]
1209 constexpr void
1210 pop_back()
1211 { __builtin_trap(); }
1212
1213 template<typename... _Args>
1214 constexpr _Tp*
1215 try_emplace_back(_Args&&...)
1216 { return nullptr; }
1217
1218 constexpr _Tp*
1219 try_push_back(const _Tp&)
1220 { return nullptr; }
1221
1222 constexpr _Tp*
1223 try_push_back(_Tp&&)
1224 { return nullptr; }
1225
1226 template<__detail::__container_compatible_range<_Tp> _Rg>
1227 constexpr ranges::borrowed_iterator_t<_Rg>
1228 try_append_range(_Rg&& __rg)
1229 { return ranges::begin(__rg); }
1230
1231 template<typename... _Args>
1232 [[noreturn]]
1233 constexpr _Tp&
1234 unchecked_emplace_back(_Args&&...)
1235 { __builtin_trap(); }
1236
1237 [[noreturn]]
1238 constexpr _Tp&
1239 unchecked_push_back(const _Tp&)
1240 { __builtin_trap(); }
1241
1242 [[noreturn]]
1243 constexpr _Tp&
1244 unchecked_push_back(_Tp&&)
1245 { __builtin_trap(); }
1246
1247 template<typename... _Args>
1248 [[noreturn]]
1249 constexpr iterator
1250 emplace(const_iterator, _Args&&...)
1251 { __throw_bad_alloc(); }
1252
1253 [[noreturn]]
1254 constexpr iterator
1255 insert(const_iterator, const _Tp&)
1256 { __throw_bad_alloc(); }
1257
1258 [[noreturn]]
1259 constexpr iterator
1260 insert(const_iterator, _Tp&&)
1261 { __throw_bad_alloc(); }
1262
1263 constexpr iterator
1264 insert(const_iterator, size_type __n, const _Tp&)
1265 {
1266 if (__n != 0)
1267 __throw_bad_alloc();
1268 return begin();
1269 }
1270
1271 template<typename _InputIterator>
1272 constexpr iterator
1273 insert(const_iterator, _InputIterator __first, _InputIterator __last)
1274 {
1275 if (__first != __last)
1276 __throw_bad_alloc();
1277 return begin();
1278 }
1279
1280 template<__detail::__container_compatible_range<_Tp> _Rg>
1281 constexpr iterator
1282 insert_range(const_iterator, _Rg&& __rg)
1283 {
1284 if (ranges::begin(__rg) != ranges::end(__rg))
1285 __throw_bad_alloc();
1286 return begin();
1287 }
1288
1289 constexpr iterator
1290 insert(const_iterator, initializer_list<_Tp> __il)
1291 {
1292 if (__il.size() != 0)
1293 __throw_bad_alloc();
1294 return begin();
1295 }
1296
1297 [[noreturn]]
1298 constexpr iterator
1299 erase(const_iterator)
1300 { __builtin_trap(); }
1301
1302 constexpr iterator
1303 erase(const_iterator __first, const_iterator __last)
1304 {
1305 __glibcxx_assert(__first == __last);
1306 return begin();
1307 }
1308
1309 constexpr void
1310 swap(inplace_vector& __x)
1311 noexcept
1312 { }
1313
1314 constexpr void
1315 clear() noexcept
1316 { }
1317
1318 constexpr friend bool
1319 operator==(const inplace_vector&, const inplace_vector&)
1320 { return true; }
1321
1322 constexpr friend auto
1323 operator<=>(const inplace_vector&, const inplace_vector&)
1324 requires requires (const _Tp __t) {
1325 { __t < __t } -> __detail::__boolean_testable;
1326 }
1327 { return std::strong_ordering::equal; }
1328
1329 // n.b. there is not explicit wording requiring that swap for inplace_vector,
1330 // with zero size, works even if element type is not swappable. However given
1331 // that move operations are required to be present and trivial, it makes sense
1332 // to support them.
1333 constexpr friend void
1334 swap(inplace_vector&, inplace_vector&) noexcept
1335 { }
1336 };
1337
1338 template<typename _Tp, size_t _Nm, typename _Predicate>
1339 constexpr size_t
1340 erase_if(inplace_vector<_Tp, _Nm>& __cont, _Predicate __pred)
1341 {
1342 using namespace __gnu_cxx;
1343 const auto __osz = __cont.size();
1344 const auto __end = __cont.end();
1345 auto __removed = std::__remove_if(__cont.begin(), __end,
1346 __ops::__pred_iter(std::ref(__pred)));
1347 if (__removed != __end)
1348 {
1349 __cont.erase(__niter_wrap(__cont.begin(), __removed),
1350 __cont.end());
1351 return __osz - __cont.size();
1352 }
1353 return 0;
1354 }
1355
1356
1357 template<typename _Tp, size_t _Nm, typename _Up = _Tp>
1358 constexpr size_t
1359 erase(inplace_vector<_Tp, _Nm>& __cont, const _Up& __value)
1360 {
1361 using namespace __gnu_cxx;
1362 const auto __osz = __cont.size();
1363 const auto __end = __cont.end();
1364 auto __removed = std::__remove_if(__cont.begin(), __end,
1365 __ops::__iter_equals_val(__value));
1366 if (__removed != __end)
1367 {
1368 __cont.erase(__niter_wrap(__cont.begin(), __removed),
1369 __cont.end());
1370 return __osz - __cont.size();
1371 }
1372 return 0;
1373 }
1374
1375_GLIBCXX_END_NAMESPACE_VERSION
1376} // namespace
1377
1378#endif // __glibcxx_inplace_vector
1379#endif // _GLIBCXX_INPLACE_VECTOR