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