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