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