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