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