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