libstdc++: inplace_vector Source File

libstdc++

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