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