[PATCH v2] libstdc++: Add std::inplace_vector for C++26 (P0843R14) [PR119137]
Patrick Palka
ppalka@redhat.com
Thu Jul 17 19:23:42 GMT 2025
On Thu, 17 Jul 2025, Tomasz Kamiński wrote:
> From: Jonathan Wakely <jwakely@redhat.com>
>
> Implement std::inplace_vector as specified in P0843R14, without follow
> up papers, in particular P3074R7 (trivial unions). In consequence
> inplace_vector<T, N> can be used inside constant evaluations only
> if T is trivial or N is equal to zero.
>
> We provide a separate specialization for inplace_vector<T, 0> to meet
> the requirements of N5008 [inplace.vector.overview] p5. In particular
> objects of such types needs to be empty.
>
> To allow constexpr variable of inplace_vector v, where v.size() < v.capacity(),
> we need to guaranteed that all elements of the storage array are initialized,
> even ones in range [v.data() + v.size(), v.data() + v.capacity()). This is
> perfomed by _M_init function, that is alled by each constructored. By storing
> the array in anonymous union, we can perform this initialization in constant
> evaluation, avoiding the impact on runtime path.
>
> The size() function conveys the information that _M_size <= _Nm to compiler,
> by calling __builtin_unreachable(). In particular this allows us to eliminate
> FP warnings by using _Nm - size() instead of _Nm - _M_size, when computing
> available elements.
>
> However, we still have one -Waggressive-loop-optimizations (to best of our
> knowledge false-positive warning produced in cons/from_range.cc and
> cons/throws.cc. Currently it is pruned using dg-prune-output and tracked by
> PR121143.
>
> The included test cover almost all code paths at runtime, however some
> compile time evaluation test are not yet implemented:
> * operations on range, they depenend on making testsuite_iterators constexpr
> * negative test for invoking operations with preconditions at compile time,
> especially for zero size specialization.
>
> PR libstdc++/119137
>
> libstdc++-v3/ChangeLog:
>
> * doc/doxygen/user.cfg.in (INPUT): Add new header.
> * include/Makefile.am: Add new header.
> * include/Makefile.in: Regenerate.
> * include/bits/stl_iterator_base_types.h (__any_input_iterator):
> Define.
> * include/bits/version.def (inplace_vector): Define.
> * include/bits/version.h: Regenerate.
> * include/precompiled/stdc++.h: Include new header.
> * src/c++23/std.cc.in: Export contents if new header.
> * include/std/inplace_vector: New file.
> * testsuite/23_containers/inplace_vector/access/capacity.cc: New file.
> * testsuite/23_containers/inplace_vector/access/elem.cc: New file.
> * testsuite/23_containers/inplace_vector/access/elem_neg.cc: New file.
> * testsuite/23_containers/inplace_vector/cons/1.cc: New file.
> * testsuite/23_containers/inplace_vector/cons/from_range.cc: New file.
> * testsuite/23_containers/inplace_vector/cons/throws.cc: New file.
> * testsuite/23_containers/inplace_vector/copy.cc: New file.
> * testsuite/23_containers/inplace_vector/erasure.cc: New file.
> * testsuite/23_containers/inplace_vector/modifiers/assign.cc: New file.
> * testsuite/23_containers/inplace_vector/modifiers/erase.cc: New file.
> * testsuite/23_containers/inplace_vector/modifiers/multi_insert.cc:
> New file.
> * testsuite/23_containers/inplace_vector/modifiers/single_insert.cc:
> New file.
> * testsuite/23_containers/inplace_vector/move.cc: New file.
> * testsuite/23_containers/inplace_vector/relops.cc: New file.
> * testsuite/23_containers/inplace_vector/version.cc: New file.
> * testsuite/util/testsuite_iterators.h (input_iterator_wrapper::base):
> Define.
>
> Reviewed-by: Patrick Palka <ppalka@redhat.com>
> Reviewed-by: Jonathan Wakely <jwakely@redhat.com>
> Co-authored-by: Tomasz Kamiński <tkaminsk@redhat.com>
> Signed-off-by: Tomasz Kamiński <tkaminsk@redhat.com>
> ---
> v2 hopefully addressed all the comments from Patrick review,
> except making _S_distance a free functions.
> The detail::__input_iterator is moved to stl_iterator_base_types.h,
> and renamed any_input_iterator.
>
> libstdc++-v3/doc/doxygen/user.cfg.in | 1 +
> libstdc++-v3/include/Makefile.am | 1 +
> libstdc++-v3/include/Makefile.in | 1 +
> .../include/bits/stl_iterator_base_types.h | 5 +
> libstdc++-v3/include/bits/version.def | 8 +
> libstdc++-v3/include/bits/version.h | 10 +
> libstdc++-v3/include/precompiled/stdc++.h | 1 +
> libstdc++-v3/include/std/inplace_vector | 1376 +++++++++++++++++
> libstdc++-v3/src/c++23/std.cc.in | 10 +-
> .../inplace_vector/access/capacity.cc | 51 +
> .../inplace_vector/access/elem.cc | 103 ++
> .../inplace_vector/access/elem_neg.cc | 29 +
> .../23_containers/inplace_vector/cons/1.cc | 385 +++++
> .../inplace_vector/cons/from_range.cc | 186 +++
> .../inplace_vector/cons/throws.cc | 131 ++
> .../23_containers/inplace_vector/copy.cc | 247 +++
> .../23_containers/inplace_vector/erasure.cc | 49 +
> .../inplace_vector/modifiers/assign.cc | 386 +++++
> .../inplace_vector/modifiers/erase.cc | 117 ++
> .../inplace_vector/modifiers/multi_insert.cc | 611 ++++++++
> .../inplace_vector/modifiers/single_insert.cc | 215 +++
> .../23_containers/inplace_vector/move.cc | 358 +++++
> .../23_containers/inplace_vector/relops.cc | 60 +
> .../23_containers/inplace_vector/version.cc | 20 +
> .../testsuite/util/testsuite_iterators.h | 6 +
> 25 files changed, 4366 insertions(+), 1 deletion(-)
> create mode 100644 libstdc++-v3/include/std/inplace_vector
> create mode 100644 libstdc++-v3/testsuite/23_containers/inplace_vector/access/capacity.cc
> create mode 100644 libstdc++-v3/testsuite/23_containers/inplace_vector/access/elem.cc
> create mode 100644 libstdc++-v3/testsuite/23_containers/inplace_vector/access/elem_neg.cc
> create mode 100644 libstdc++-v3/testsuite/23_containers/inplace_vector/cons/1.cc
> create mode 100644 libstdc++-v3/testsuite/23_containers/inplace_vector/cons/from_range.cc
> create mode 100644 libstdc++-v3/testsuite/23_containers/inplace_vector/cons/throws.cc
> create mode 100644 libstdc++-v3/testsuite/23_containers/inplace_vector/copy.cc
> create mode 100644 libstdc++-v3/testsuite/23_containers/inplace_vector/erasure.cc
> create mode 100644 libstdc++-v3/testsuite/23_containers/inplace_vector/modifiers/assign.cc
> create mode 100644 libstdc++-v3/testsuite/23_containers/inplace_vector/modifiers/erase.cc
> create mode 100644 libstdc++-v3/testsuite/23_containers/inplace_vector/modifiers/multi_insert.cc
> create mode 100644 libstdc++-v3/testsuite/23_containers/inplace_vector/modifiers/single_insert.cc
> create mode 100644 libstdc++-v3/testsuite/23_containers/inplace_vector/move.cc
> create mode 100644 libstdc++-v3/testsuite/23_containers/inplace_vector/relops.cc
> create mode 100644 libstdc++-v3/testsuite/23_containers/inplace_vector/version.cc
>
> diff --git a/libstdc++-v3/doc/doxygen/user.cfg.in b/libstdc++-v3/doc/doxygen/user.cfg.in
> index 536e035b023..8969bb8b948 100644
> --- a/libstdc++-v3/doc/doxygen/user.cfg.in
> +++ b/libstdc++-v3/doc/doxygen/user.cfg.in
> @@ -869,6 +869,7 @@ INPUT = @srcdir@/doc/doxygen/doxygroups.cc \
> include/functional \
> include/future \
> include/generator \
> + include/inplace_vector \
> include/iomanip \
> include/ios \
> include/iosfwd \
> diff --git a/libstdc++-v3/include/Makefile.am b/libstdc++-v3/include/Makefile.am
> index cc402f0648f..6f248fe48cb 100644
> --- a/libstdc++-v3/include/Makefile.am
> +++ b/libstdc++-v3/include/Makefile.am
> @@ -77,6 +77,7 @@ std_headers = \
> ${std_srcdir}/forward_list \
> ${std_srcdir}/fstream \
> ${std_srcdir}/future \
> + ${std_srcdir}/inplace_vector \
> ${std_srcdir}/iomanip \
> ${std_srcdir}/ios \
> ${std_srcdir}/iosfwd \
> diff --git a/libstdc++-v3/include/Makefile.in b/libstdc++-v3/include/Makefile.in
> index 0ef8564f238..014466fc40b 100644
> --- a/libstdc++-v3/include/Makefile.in
> +++ b/libstdc++-v3/include/Makefile.in
> @@ -433,6 +433,7 @@ std_freestanding = \
> @GLIBCXX_HOSTED_TRUE@ ${std_srcdir}/forward_list \
> @GLIBCXX_HOSTED_TRUE@ ${std_srcdir}/fstream \
> @GLIBCXX_HOSTED_TRUE@ ${std_srcdir}/future \
> +@GLIBCXX_HOSTED_TRUE@ ${std_srcdir}/inplace_vector \
> @GLIBCXX_HOSTED_TRUE@ ${std_srcdir}/iomanip \
> @GLIBCXX_HOSTED_TRUE@ ${std_srcdir}/ios \
> @GLIBCXX_HOSTED_TRUE@ ${std_srcdir}/iosfwd \
> diff --git a/libstdc++-v3/include/bits/stl_iterator_base_types.h b/libstdc++-v3/include/bits/stl_iterator_base_types.h
> index a67d7bd1931..71da909613e 100644
> --- a/libstdc++-v3/include/bits/stl_iterator_base_types.h
> +++ b/libstdc++-v3/include/bits/stl_iterator_base_types.h
> @@ -257,6 +257,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> template<typename _InIter>
> concept __has_input_iter_cat
> = is_convertible_v<__iter_category_t<_InIter>, input_iterator_tag>;
> +
> + // Is a Cpp17InputIterator or satisfies std::input_iterator.
> + template<typename _InIterator>
> + concept __any_input_iterator
> + = input_iterator<_InIterator> || __has_input_iter_cat<_InIterator>;
> #endif
>
> template<typename _It,
> diff --git a/libstdc++-v3/include/bits/version.def b/libstdc++-v3/include/bits/version.def
> index 2f70a529927..dbe2cb8f175 100644
> --- a/libstdc++-v3/include/bits/version.def
> +++ b/libstdc++-v3/include/bits/version.def
> @@ -1988,6 +1988,14 @@ ftms = {
> };
> };
>
> +ftms = {
> + name = inplace_vector;
> + values = {
> + v = 202406;
> + cxxmin = 26;
> + };
> +};
> +
> ftms = {
> name = indirect;
> values = {
> diff --git a/libstdc++-v3/include/bits/version.h b/libstdc++-v3/include/bits/version.h
> index 8e0ae682251..7bb6016df68 100644
> --- a/libstdc++-v3/include/bits/version.h
> +++ b/libstdc++-v3/include/bits/version.h
> @@ -2229,6 +2229,16 @@
> #endif /* !defined(__cpp_lib_modules) && defined(__glibcxx_want_modules) */
> #undef __glibcxx_want_modules
>
> +#if !defined(__cpp_lib_inplace_vector)
> +# if (__cplusplus > 202302L)
> +# define __glibcxx_inplace_vector 202406L
> +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_inplace_vector)
> +# define __cpp_lib_inplace_vector 202406L
> +# endif
> +# endif
> +#endif /* !defined(__cpp_lib_inplace_vector) && defined(__glibcxx_want_inplace_vector) */
> +#undef __glibcxx_want_inplace_vector
> +
> #if !defined(__cpp_lib_indirect)
> # if (__cplusplus > 202302L) && _GLIBCXX_HOSTED
> # define __glibcxx_indirect 202502L
> diff --git a/libstdc++-v3/include/precompiled/stdc++.h b/libstdc++-v3/include/precompiled/stdc++.h
> index e7d89c92704..733a5e5fb0b 100644
> --- a/libstdc++-v3/include/precompiled/stdc++.h
> +++ b/libstdc++-v3/include/precompiled/stdc++.h
> @@ -237,6 +237,7 @@
> #endif
>
> #if __cplusplus > 202302L
> +#include <inplace_vector>
> #include <text_encoding>
> #include <stdbit.h>
> #include <stdckdint.h>
> diff --git a/libstdc++-v3/include/std/inplace_vector b/libstdc++-v3/include/std/inplace_vector
> new file mode 100644
> index 00000000000..3fb38f383fb
> --- /dev/null
> +++ b/libstdc++-v3/include/std/inplace_vector
> @@ -0,0 +1,1376 @@
> +// Sequence container with fixed capacity -*- C++ -*-
> +
> +// Copyright The GNU Toolchain Authors.
> +//
> +// This file is part of the GNU ISO C++ Library. This library is free
> +// software; you can redistribute it and/or modify it under the
> +// terms of the GNU General Public License as published by the
> +// Free Software Foundation; either version 3, or (at your option)
> +// any later version.
> +
> +// This library is distributed in the hope that it will be useful,
> +// but WITHOUT ANY WARRANTY; without even the implied warranty of
> +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> +// GNU General Public License for more details.
> +
> +// Under Section 7 of GPL version 3, you are granted additional
> +// permissions described in the GCC Runtime Library Exception, version
> +// 3.1, as published by the Free Software Foundation.
> +
> +// You should have received a copy of the GNU General Public License and
> +// a copy of the GCC Runtime Library Exception along with this program;
> +// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
> +// <http://www.gnu.org/licenses/>.
> +
> +/** @file include/inplace_vector
> + * This is a Standard C++ Library header.
> + * @ingroup sequences
> + */
> +
> +#ifndef _GLIBCXX_INPLACE_VECTOR
> +#define _GLIBCXX_INPLACE_VECTOR 1
> +
> +#pragma GCC system_header
> +
> +#define __glibcxx_want_inplace_vector
> +#include <bits/version.h>
> +
> +#ifdef __glibcxx_inplace_vector // C++ >= 26
> +#include <compare>
> +#include <initializer_list>
> +#include <bits/range_access.h>
> +#include <bits/ranges_base.h> // borrowed_iterator_t, __detail::__container_compatible_range
> +#include <bits/ranges_util.h> // subrange
> +#include <bits/ranges_uninitialized.h>
> +#include <bits/refwrap.h>
> +#include <bits/stl_construct.h>
> +#include <bits/stl_uninitialized.h>
> +#include <bits/stl_algo.h> // rotate
> +
> +namespace std _GLIBCXX_VISIBILITY(default)
> +{
> +_GLIBCXX_BEGIN_NAMESPACE_VERSION
> +
> + // [indirect], class template indirect
> + template<typename _Tp, size_t _Nm>
> + class inplace_vector
> + {
> + public:
> +
> + // types:
> + using value_type = _Tp;
> + using pointer = _Tp*;
> + using const_pointer = const _Tp*;
> + using reference = value_type&;
> + using const_reference = const value_type&;
> + using size_type = size_t;
> + using difference_type = ptrdiff_t;
> + using iterator
> + = __gnu_cxx::__normal_iterator<_Tp*, inplace_vector>;
> + using const_iterator
> + = __gnu_cxx::__normal_iterator<const _Tp*, inplace_vector>;
> + using reverse_iterator = std::reverse_iterator<iterator>;
> + using const_reverse_iterator = std::reverse_iterator<const_iterator>;
> +
> + // [containers.sequences.inplace.vector.cons], construct/copy/destroy
> + constexpr
> + inplace_vector() noexcept
> + { _M_init(); }
> +
> + constexpr explicit
> + inplace_vector(size_type __n)
> + {
> + _M_init();
> + _S_reserve(__n);
> + std::uninitialized_value_construct_n(data(), __n);
> + _M_size = __n;
> + }
> +
> + constexpr
> + inplace_vector(size_type __n, const _Tp& __value)
> + {
> + _M_init();
> + _S_reserve(__n);
> + std::uninitialized_fill_n(data(), __n, __value);
> + _M_size = __n;
> + }
> +
> + template<__any_input_iterator _InputIterator>
> + constexpr
> + inplace_vector(_InputIterator __first, _InputIterator __last)
> + : inplace_vector()
> + {
> + if (const auto __n = _S_distance(__first, __last))
> + {
> + _S_reserve(__n);
> + std::uninitialized_copy(__first, __last, data());
> + _M_size = __n;
> + }
> + else
> + {
> + while (__first != __last)
> + emplace_back(*__first++);
> + }
> + }
> +
> + template <__detail::__container_compatible_range<_Tp> _Rg>
> + constexpr
> + inplace_vector(from_range_t, _Rg&& __rg)
> + : inplace_vector()
> + { append_range(__rg); }
> +
> + constexpr
> + inplace_vector(initializer_list<_Tp> __il)
> + {
> + _M_init();
> + _S_reserve(__il.size());
> + std::uninitialized_copy(__il.begin(), __il.end(), data());
> + _M_size = __il.size();
> + }
> +
> + inplace_vector(const inplace_vector&)
> + requires is_trivially_copy_constructible_v<_Tp>
> + = default;
> +
> + constexpr
> + inplace_vector(const inplace_vector& __other)
> + noexcept(is_nothrow_copy_constructible_v<_Tp>)
> + {
> + _M_init();
> + std::uninitialized_copy(__other.begin(), __other.end(), data());
> + _M_size = __other.size();
> + }
> +
> + inplace_vector(inplace_vector&&)
> + requires is_trivially_move_constructible_v<_Tp>
> + = default;
> +
> + constexpr
> + inplace_vector(inplace_vector&& __other)
> + noexcept(is_nothrow_move_constructible_v<_Tp>)
> + {
> + _M_init();
> + std::uninitialized_move(__other.begin(), __other.end(), data());
> + _M_size = __other.size();
> + }
> +
> + ~inplace_vector()
> + requires is_trivially_destructible_v<_Tp>
> + = default;
> +
> + constexpr
> + ~inplace_vector()
> + { clear(); }
> +
> + inplace_vector&
> + operator=(const inplace_vector&)
> + requires is_trivially_copy_assignable_v<_Tp>
> + && is_trivially_copy_constructible_v<_Tp>
> + && is_trivially_destructible_v<_Tp>
> + = default;
> +
> + constexpr inplace_vector&
> + operator=(const inplace_vector& __other)
> + noexcept(is_nothrow_copy_assignable_v<_Tp>
> + && is_nothrow_copy_constructible_v<_Tp>)
> + {
> + assign(__other.begin(), __other.end());
Do we need to worry about self-assignment here? IIUC it's a
precondition violation to call assign with an iterator into the
container being assigned to. LGTM other than that.
> + return *this;
> + }
> +
> + inplace_vector&
> + operator=(inplace_vector&&)
> + requires is_trivially_move_assignable_v<_Tp>
> + && is_trivially_move_constructible_v<_Tp>
> + && is_trivially_destructible_v<_Tp>
> + = default;
> +
> + constexpr inplace_vector&
> + operator=(inplace_vector&& __other)
> + noexcept(is_nothrow_move_assignable_v<_Tp>
> + && is_nothrow_move_constructible_v<_Tp>)
> + {
> + assign(std::make_move_iterator(__other.begin()),
> + std::make_move_iterator(__other.end()));
> + return *this;
> + }
> +
> + constexpr inplace_vector&
> + operator=(initializer_list<_Tp> __il)
> + {
> + assign(__il.begin(), __il.end());
> + return *this;
> + }
> +
> + template<__any_input_iterator _InputIterator>
> + constexpr void
> + assign(_InputIterator __first, _InputIterator __last)
> + {
> + if (const auto __n = _S_distance(__first, __last))
> + {
> + _S_reserve(__n);
> + if (_M_size <= __n)
> + {
> + for (size_t __i = 0; __i < _M_size; ++__i, (void)++__first)
> + _M_elems[__i] = *__first;
> + std::uninitialized_copy(__first, __last, end());
> + }
> + else
> + std::destroy(std::copy(__first, __last, begin()), end());
> + _M_size = __n;
> + }
> + else
> + {
> + size_t __i = 0;
> + for (;__first != __last && __i < _M_size; ++__first)
> + _M_elems[__i++] = *__first;
> + if (__first == __last)
> + {
> + std::_Destroy_n(data() + __i, _M_size - __i);
> + _M_size = __i;
> + }
> + else
> + {
> + while (__first != __last)
> + emplace_back(*__first++);
> + }
> + }
> + }
> +
> + template<__detail::__container_compatible_range<_Tp> _Rg>
> + constexpr void
> + assign_range(_Rg&& __rg)
> + {
> + if constexpr (ranges::forward_range<_Rg> || ranges::sized_range<_Rg>)
> + {
> + const auto __sz = ranges::distance(__rg);
> + if (__sz > _Nm)
> + __throw_bad_alloc();
> + if (__sz <= size())
> + {
> + ranges::copy_n(ranges::begin(__rg), __sz, data());
> + std::destroy(data() + __sz, data() + _M_size);
> + }
> + else
> + {
> + auto [__in, __out] = ranges::copy_n(
> + ranges::begin(__rg), _M_size,
> + data());
> + ranges::uninitialized_copy(
> + std::move(__in), ranges::end(__rg),
> + __out, unreachable_sentinel);
> + }
> + _M_size = __sz;
> + }
> + else
> + {
> + auto __in = ranges::begin(__rg);
> + auto __end = ranges::end(__rg);
> + size_type __n = 0;
> + for (; __n < _Nm && __in != __end; ++__in)
> + _M_elems[__n++] = *__in;
> +
> + if (__in == __end)
> + {
> + std::destroy(data() + __n, data() + _M_size);
> + _M_size = __n;
> + return;
> + }
> + else if (__n < _Nm)
> + {
> + auto __res = ranges::uninitialized_copy(
> + std::move(__in), __end,
> + data() + __n, data() + _Nm);
> + _M_size = __res.out - data();
> + if (__res.in == ranges::end(__rg))
> + return;
> + }
> + __throw_bad_alloc();
> + }
> + }
> +
> + constexpr void
> + assign(size_type __n, const _Tp& __u)
> + {
> + _S_reserve(__n);
> + if (_M_size <= __n)
> + std::uninitialized_fill_n(std::fill_n(data(), _M_size, __u),
> + __n - _M_size, __u);
> + else
> + std::destroy_n(std::fill_n(data(), __n, __u), _M_size - __n);
> + _M_size = __n;
> + }
> +
> + constexpr void
> + assign(initializer_list<_Tp> __il)
> + { assign(__il.begin(), __il.end()); }
> +
> + // iterators
> + [[nodiscard]]
> + constexpr iterator
> + begin() noexcept { return iterator(data()); }
> +
> + [[nodiscard]]
> + constexpr const_iterator
> + begin() const noexcept { return const_iterator(data()); }
> +
> + [[nodiscard]]
> + constexpr iterator
> + end() noexcept
> + { return iterator(data() + _M_size); }
> +
> + [[nodiscard]]
> + constexpr const_iterator
> + end() const noexcept
> + { return const_iterator(data() + _M_size); }
> +
> + [[nodiscard]]
> + constexpr reverse_iterator
> + rbegin() noexcept
> + { return reverse_iterator(end()); }
> +
> + [[nodiscard]]
> + constexpr const_reverse_iterator
> + rbegin() const noexcept
> + { return const_reverse_iterator(end()); }
> +
> + [[nodiscard]]
> + constexpr reverse_iterator
> + rend() noexcept { return reverse_iterator(begin()); }
> +
> + [[nodiscard]]
> + constexpr const_reverse_iterator
> + rend() const noexcept { return const_reverse_iterator(begin()); }
> +
> + [[nodiscard]]
> + constexpr const_iterator
> + cbegin() const noexcept { return begin(); }
> +
> + [[nodiscard]]
> + constexpr const_iterator
> + cend() const noexcept { return end(); }
> +
> + [[nodiscard]]
> + constexpr const_reverse_iterator
> + crbegin() const noexcept { return rbegin(); }
> +
> + [[nodiscard]]
> + constexpr const_reverse_iterator
> + crend() const noexcept { return rend(); }
> +
> + // [containers.sequences.inplace.vector.members] size/capacity
> + [[nodiscard]]
> + constexpr bool
> + empty() const noexcept { return _M_size == 0; }
> +
> + [[nodiscard]]
> + constexpr size_type
> + size() const noexcept
> + {
> + if (_M_size > _Nm)
> + __builtin_unreachable();
> + return _M_size;
> + }
> +
> + [[nodiscard]]
> + static constexpr size_type
> + max_size() noexcept { return _Nm; }
> +
> + [[nodiscard]]
> + static constexpr size_type
> + capacity() noexcept { return _Nm; }
> +
> + constexpr void
> + resize(size_type __n)
> + {
> + _S_reserve(__n);
> + if (__n > _M_size)
> + std::uninitialized_value_construct_n(data() + _M_size, __n - _M_size);
> + else if (__n < _M_size)
> + std::destroy_n(data() + __n, _M_size - __n);
> + _M_size = __n;
> + }
> +
> + constexpr void
> + resize(size_type __n, const _Tp& __c)
> + {
> + _S_reserve(__n);
> + if (__n > _M_size)
> + std::uninitialized_fill_n(data() + _M_size, __n - _M_size, __c);
> + else if (__n < _M_size)
> + std::destroy_n(data() + __n, _M_size - __n);
> + _M_size = __n;
> + }
> +
> + static constexpr void
> + reserve(size_type __n)
> + { _S_reserve(__n); }
> +
> + static constexpr void
> + shrink_to_fit() { }
> +
> + // element access
> + [[nodiscard]]
> + constexpr reference
> + operator[](size_type __n)
> + {
> + __glibcxx_requires_subscript(__n);
> + return _M_elems[__n];
> + }
> +
> + [[nodiscard]]
> + constexpr const_reference
> + operator[](size_type __n) const
> + {
> + __glibcxx_requires_subscript(__n);
> + return _M_elems[__n];
> + }
> +
> + [[nodiscard]]
> + constexpr const_reference
> + at(size_type __n) const
> + {
> + if (__n >= _M_size)
> + std::__throw_out_of_range_fmt(__N("inplace_vector::at: __n "
> + "(which is %zu) "
> + ">= size() (which is %zu)"),
> + __n, _M_size);
> + return _M_elems[__n];
> + }
> +
> + [[nodiscard]]
> + constexpr reference
> + at(size_type __n)
> + {
> + if (__n >= _M_size)
> + std::__throw_out_of_range_fmt(__N("inplace_vector::at: __n "
> + "(which is %zu) "
> + ">= size() (which is %zu)"),
> + __n, _M_size);
> + return _M_elems[__n];
> + }
> +
> + [[nodiscard]]
> + constexpr reference
> + front()
> + {
> + __glibcxx_requires_nonempty();
> + return _M_elems[0];
> + }
> +
> + [[nodiscard]]
> + constexpr const_reference
> + front() const
> + {
> + __glibcxx_requires_nonempty();
> + return _M_elems[0];
> + }
> +
> + [[nodiscard]]
> + constexpr reference
> + back()
> + {
> + __glibcxx_requires_nonempty();
> + return _M_elems[_M_size - 1];
> + }
> +
> + [[nodiscard]]
> + constexpr const_reference
> + back() const
> + {
> + __glibcxx_requires_nonempty();
> + return _M_elems[_M_size - 1];
> + }
> +
> + // [containers.sequences.inplace.vector.data], data access
> +
> + [[nodiscard]]
> + constexpr _Tp*
> + data() noexcept
> + { return static_cast<pointer>(_M_elems); }
> +
> + [[nodiscard]]
> + constexpr const _Tp*
> + data() const noexcept
> + { return static_cast<const_pointer>(_M_elems); }
> +
> + // [containers.sequences.inplace.vector.modifiers], modifiers
> + template<typename... _Args>
> + constexpr _Tp&
> + emplace_back(_Args&&... __args)
> + {
> + if (_M_size >= _Nm)
> + __throw_bad_alloc();
> + return unchecked_emplace_back(std::forward<_Args>(__args)...);
> + }
> +
> + constexpr _Tp&
> + push_back(const _Tp& __x)
> + { return emplace_back(__x); }
> +
> + constexpr _Tp&
> + push_back(_Tp&& __x)
> + { return emplace_back(std::move(__x)); }
> +
> + template<__detail::__container_compatible_range<_Tp> _Rg>
> + constexpr void
> + append_range(_Rg&& __rg)
> + {
> + if constexpr (ranges::forward_range<_Rg> || ranges::sized_range<_Rg>)
> + {
> + const auto __sz = ranges::distance(__rg);
> + if (__sz > (_Nm - size()))
> + __throw_bad_alloc();
> + ranges::uninitialized_copy_n(
> + ranges::begin(__rg), __sz,
> + data() + _M_size, unreachable_sentinel);
> + _M_size += size_type(__sz);
> + }
> + else
> + {
> + ranges::subrange<pointer> __tail(data() + _M_size, data() + _Nm);
> + auto [__in, __out] = ranges::uninitialized_copy(__rg, __tail);
> + _M_size = __out - data();
> + if (__in != ranges::end(__rg))
> + __throw_bad_alloc();
> + }
> + }
> +
> + constexpr void
> + pop_back()
> + {
> + __glibcxx_requires_nonempty();
> + --_M_size;
> + _M_elems[_M_size].~_Tp();
> + }
> +
> + template<typename... _Args>
> + constexpr _Tp*
> + try_emplace_back(_Args&&... __args)
> + {
> + if (_M_size >= _Nm) [[unlikely]]
> + return nullptr;
> + auto& __r = unchecked_emplace_back(std::forward<_Args>(__args)...);
> + return __builtin_addressof(__r);
> + }
> +
> + constexpr _Tp*
> + try_push_back(const _Tp& __x)
> + {
> + if (_M_size >= _Nm) [[unlikely]]
> + return nullptr;
> + return __builtin_addressof(unchecked_emplace_back(__x));
> + }
> +
> + constexpr _Tp*
> + try_push_back(_Tp&& __x)
> + {
> + if (_M_size >= _Nm) [[unlikely]]
> + return nullptr;
> + return __builtin_addressof(unchecked_emplace_back(std::move(__x)));
> + }
> +
> + template<__detail::__container_compatible_range<_Tp> _Rg>
> + constexpr ranges::borrowed_iterator_t<_Rg>
> + try_append_range(_Rg&& __rg)
> + {
> + if constexpr (ranges::sized_range<_Rg>)
> + {
> + auto __n = ranges::distance(__rg);
> + if (__n == 0) [[unlikely]]
> + return ranges::begin(__rg);
> +
> + const auto __end = data() + _M_size;
> + const size_t __avail = _Nm - size();
> + if (__n <= __avail)
> + _M_size += size_type(__n);
> + else
> + {
> + __n = __avail;
> + _M_size = _Nm;
> + }
> + return ranges::uninitialized_copy_n(
> + ranges::begin(__rg), __n,
> + __end, unreachable_sentinel).in;
> + }
> + else
> + {
> + ranges::subrange<pointer> __tail(data() + _M_size, data() + _Nm);
> + auto [__in, __out] = ranges::uninitialized_copy(__rg, __tail);
> + _M_size = __out - data();
> + return std::move(__in);
> + }
> + }
> +
> + template<typename... _Args>
> + constexpr _Tp&
> + unchecked_emplace_back(_Args&&... __args)
> + {
> + __glibcxx_assert(_M_size < _Nm);
> + auto __p = std::construct_at(data() + _M_size,
> + std::forward<_Args>(__args)...);
> + ++_M_size;
> + return *__p;
> + }
> +
> + constexpr _Tp&
> + unchecked_push_back(const _Tp& __x)
> + { return unchecked_emplace_back(__x); }
> +
> + constexpr _Tp&
> + unchecked_push_back(_Tp&& __x)
> + { return unchecked_emplace_back(std::move(__x)); }
> +
> + template<typename... _Args>
> + constexpr iterator
> + emplace(const_iterator __position, _Args&&... __args)
> + {
> + size_t __b = __position - cbegin(); // elements before position
> + __glibcxx_assert(__b <= _M_size);
> + if (_M_size >= _Nm)
> + __throw_bad_alloc();
> + iterator __pos = begin() + __b;
> + std::construct_at(data() + _M_size, std::forward<_Args>(__args)...);
> + if (_M_size++)
> + std::rotate(__pos, end() - 1, end());
> + return __pos;
> + }
> +
> + constexpr iterator
> + insert(const_iterator __position, const _Tp& __x)
> + { return emplace(__position, __x); }
> +
> + constexpr iterator
> + insert(const_iterator __position, _Tp&& __x)
> + { return emplace(__position, std::move(__x)); }
> +
> + constexpr iterator
> + insert(const_iterator __position, size_type __n, const _Tp& __x)
> + {
> + size_t __b = __position - cbegin(); // elements before position
> + __glibcxx_assert(__b <= _M_size);
> + if ((_Nm - _M_size) < __n)
> + __throw_bad_alloc();
> + iterator __pos = begin() + __b;
> + std::uninitialized_fill_n(data() + _M_size, __n, __x);
> + if (std::__exchange(_M_size, _M_size + __n))
> + std::rotate(__pos, end() - __n, end());
> + return __pos;
> + }
> +
> + template<__any_input_iterator _InputIterator>
> + constexpr iterator
> + insert(const_iterator __position, _InputIterator __first,
> + _InputIterator __last)
> + {
> + size_t __b = __position - cbegin(); // elements before position
> + __glibcxx_assert(__b <= _M_size);
> + iterator __pos = begin() + __b;
> + const size_t __s = _M_size;
> + if (const auto __n = _S_distance(__first, __last))
> + {
> + if ((_Nm - _M_size) < __n)
> + __throw_bad_alloc();
> + std::uninitialized_copy(__first, __last, data() + _M_size);
> + _M_size += __n;
> + }
> + else
> + {
> + while (__first != __last)
> + emplace_back(*__first++);
> + }
> + if (__s)
> + std::rotate(__pos, begin() + __s, end());
> + return __pos;
> + }
> +
> + template<__detail::__container_compatible_range<_Tp> _Rg>
> + constexpr iterator
> + insert_range(const_iterator __position, _Rg&& __rg)
> + {
> + iterator __pos = begin() + (__position - cbegin());
> + const auto __end = end();
> + if constexpr (ranges::forward_range<_Rg> || ranges::sized_range<_Rg>)
> + {
> + const auto __len = ranges::distance(__rg);
> + if (__len > (_Nm - size()))
> + __throw_bad_alloc();
> + if (!__len) [[unlikely]]
> + return __pos;
> +
> + const size_type __n = size_type(__len);
> + const size_type __num_after = __end - __pos;
> + if (__num_after >= __n)
> + {
> + ranges::uninitialized_move(__end - __n, __end,
> + __end, unreachable_sentinel);
> + _M_size += __n;
> + ranges::move_backward(__pos, __end - __n, __end);
> + ranges::copy(__rg, __pos);
> + }
> + else if constexpr (ranges::forward_range<_Rg>)
> + {
> + auto __mid = ranges::next(ranges::begin(__rg), __num_after);
> + ranges::uninitialized_copy(__mid, ranges::end(__rg),
> + __end, unreachable_sentinel);
> + _M_size += __n - __num_after;
> + ranges::uninitialized_move(__pos, __end,
> + __pos + __n, unreachable_sentinel);
> + _M_size += __num_after;
> + ranges::copy(ranges::begin(__rg), __mid, __pos);
> + }
> + else
> + {
> + ranges::uninitialized_copy(
> + ranges::begin(__rg), ranges::end(__rg),
> + __end, unreachable_sentinel);
> + _M_size += __n;
> + std::rotate(__pos, __end, end());
> + }
> + }
> + else
> + {
> + append_range(__rg);
> + std::rotate(__pos, __end, end());
> + }
> + return __pos;
> + }
> +
> + constexpr iterator
> + insert(const_iterator __position, initializer_list<_Tp> __il)
> + { return insert(__position, __il.begin(), __il.end()); }
> +
> + constexpr iterator
> + erase(const_iterator __position)
> + {
> + size_t __n = __position - cbegin();
> + __glibcxx_assert(__n < _M_size);
> + iterator __pos = begin() + __n;
> + std::move(__pos + 1, end(), __pos);
> + pop_back();
> + return __pos;
> + }
> +
> + constexpr iterator
> + erase(const_iterator __first, const_iterator __last)
> + {
> + size_t __n = __first - cbegin();
> + size_t __x = __last - __first;
> + __glibcxx_assert(__n <= _M_size);
> + __glibcxx_assert(__x <= _M_size);
> + iterator __pos = begin() + __n;
> + iterator __end = std::move(__pos + __x, end(), __pos);
> + std::destroy_n(__end, __x);
> + _M_size -= __x;
> + return __pos;
> + }
> +
> + constexpr void
> + swap(inplace_vector& __x)
> + noexcept(is_nothrow_swappable_v<_Tp> && is_nothrow_move_constructible_v<_Tp>)
> + {
> + inplace_vector* __vs[2]{ this, std::addressof(__x) };
> + const auto __smaller = __vs[__x.size() < size()];
> + const auto __bigger = __vs[__x.size() >= size()];
> + size_type __n = __smaller->size();
> + size_type __n2 = __bigger->size();
> +
> + if constexpr (is_nothrow_move_constructible_v<_Tp>)
> + {
> + for (size_type __i = __n; __i < __n2; ++__i)
> + {
> + std::construct_at(__smaller->data() + __i,
> + std::move(*(__bigger->data() + __i)));
> + std::destroy_at(__bigger->data() + __i);
> + }
> + }
> + else
> + {
> + std::uninitialized_copy(__bigger->data() + __n,
> + __bigger->data() + __n2,
> + __smaller->data() + __n);
> + std::destroy(__bigger->data() + __n, __bigger->data() + __n2);
> + }
> + __smaller->_M_size = __n2;
> + __bigger->_M_size = __n;
> +
> + using std::swap;
> + for (size_type __i = 0; __i < __n; __i++)
> + swap(_M_elems[__i], __x._M_elems[__i]);
> + }
> +
> + constexpr void
> + clear() noexcept
> + {
> + std::destroy_n(data(), size_t(_M_size));
> + _M_size = 0;
> + }
> +
> + constexpr friend bool
> + operator==(const inplace_vector& __x, const inplace_vector& __y)
> + { return std::equal(__x.begin(), __x.end(), __y.begin(), __y.end()); }
> +
> + constexpr friend auto
> + operator<=>(const inplace_vector& __x, const inplace_vector& __y)
> + requires requires (const _Tp __t) {
> + { __t < __t } -> __detail::__boolean_testable;
> + }
> + {
> + return std::lexicographical_compare_three_way(__x.begin(), __x.end(),
> + __y.begin(), __y.end(),
> + __detail::__synth3way);
> + }
> +
> + constexpr friend void
> + swap(inplace_vector& __x, inplace_vector& __y)
> + noexcept(is_nothrow_swappable_v<_Tp> && is_nothrow_move_constructible_v<_Tp>)
> + { __x.swap(__y); }
> +
> + private:
> + union {
> + _Tp _M_elems[_Nm];
> + };
> +
> + // Check whether integer type _UInt is wide enough to store _Nm,
> + // so that we use a smaller type for _M_size when that saves space.
> + template<typename _UInt, bool = (alignof(_Tp) <= sizeof(_UInt))>
> + static constexpr bool __fits
> + = _Nm <= __gnu_cxx::__int_traits<_UInt>::__max;
> +
> + // Don't bother using a smaller type if alignment of the array elements
> + // means that it doesn't actually save space.
> + template<typename _UInt>
> + static constexpr bool __fits<_UInt, false> = false;
> +
> + static consteval auto __select_size_type()
> + {
> + if constexpr (__fits<unsigned char>)
> + return (unsigned char)0;
> +#if __SHRT_WIDTH__ < __SIZE_WIDTH__
> + else if constexpr (__fits<unsigned short>)
> + return (unsigned short)0;
> +#endif
> +#if __INT_WIDTH__ < __SIZE_WIDTH__ && __INT_WIDTH__ > __SHRT_WIDTH__
> + else if constexpr (__fits<unsigned int>)
> + return 0u;
> +#endif
> +#if __LONG_WIDTH__ < __SIZE_WIDTH__ && __LONG_WIDTH__ > __INT_WIDTH__
> + else if constexpr (__fits<unsigned long>)
> + return 0ul;
> +#endif
> + else // Just use size_t.
> + return 0uz;
> + }
> + decltype(__select_size_type()) _M_size = 0;
> +
> + constexpr void
> + _M_init()
> + {
> + if !consteval
> + {
> +#if __glibcxx_start_lifetime_as
> + std::start_lifetime_as_array<_Tp>(data(), _Nm);
> +#endif
> + }
> + else
> + {
> + // TODO: use new(_M_elems) _Tp[_Nm]() once PR121068 is fixed
> + if constexpr (is_trivial_v<_Tp>)
> + for (size_t __i = 0; __i < _Nm; ++__i)
> + _M_elems[__i] = _Tp();
> + else
> + __builtin_unreachable(); // only trivial types are supported at compile time
> + }
> + }
> +
> + static constexpr void
> + _S_reserve(size_t __n)
> + {
> + if (__n > _Nm)
> + __throw_bad_alloc();
> + }
> +
> + template<typename _InputIterator>
> + constexpr static auto
> + _S_distance(_InputIterator __first, _InputIterator __last)
> + {
> + if constexpr (sized_sentinel_for<_InputIterator, _InputIterator>
> + || forward_iterator<_InputIterator>)
> + return (size_type)ranges::distance(__first, __last);
> + else if constexpr (derived_from<__iter_category_t<_InputIterator>,
> + forward_iterator_tag>)
> + return (size_type)std::distance(__first, __last);
> + else
> + return false_type{};
> + }
> + };
> +
> + // [inplace.vector.special], specialized algorithms
> + template<typename _Tp, size_t _Nm>
> + constexpr void
> + swap(inplace_vector<_Tp, _Nm>& __x, inplace_vector<_Tp, _Nm>& __y)
> + noexcept(noexcept(__x.swap(__y)))
> + { __x.swap(__y); }
> +
> + // specialization for zero capacity, that is required to be trivally copyable
> + // and empty regardless of _Tp.
> + template<typename _Tp>
> + class inplace_vector<_Tp, 0>
> + {
> + public:
> + // types:
> + using value_type = _Tp;
> + using pointer = _Tp*;
> + using const_pointer = const _Tp*;
> + using reference = value_type&;
> + using const_reference = const value_type&;
> + using size_type = size_t;
> + using difference_type = ptrdiff_t;
> + using iterator
> + = __gnu_cxx::__normal_iterator<_Tp*, inplace_vector>;
> + using const_iterator
> + = __gnu_cxx::__normal_iterator<const _Tp*, inplace_vector>;
> + using reverse_iterator = std::reverse_iterator<iterator>;
> + using const_reverse_iterator = std::reverse_iterator<const_iterator>;
> +
> + // [containers.sequences.inplace.vector.cons], construct/copy/destroy
> + inplace_vector() = default;
> +
> + constexpr explicit
> + inplace_vector(size_type __n)
> + {
> + if (__n != 0)
> + __throw_bad_alloc();
> + }
> +
> + constexpr
> + inplace_vector(size_type __n, const _Tp& __value)
> + {
> + if (__n != 0)
> + __throw_bad_alloc();
> + }
> +
> + template<__any_input_iterator _InputIterator>
> + constexpr
> + inplace_vector(_InputIterator __first, _InputIterator __last)
> + {
> + if (__first != __last)
> + __throw_bad_alloc();
> + }
> +
> + template <__detail::__container_compatible_range<_Tp> _Rg>
> + constexpr
> + inplace_vector(from_range_t, _Rg&& __rg)
> + {
> + if (ranges::begin(__rg) != ranges::end(__rg))
> + __throw_bad_alloc();
> + }
> +
> + constexpr
> + inplace_vector(initializer_list<_Tp> __il)
> + {
> + if (__il.size() != 0)
> + __throw_bad_alloc();
> + }
> +
> + inplace_vector(const inplace_vector&) = default;
> + inplace_vector(inplace_vector&&) = default;
> +
> + constexpr
> + ~inplace_vector() = default;
> +
> + inplace_vector&
> + operator=(const inplace_vector&) = default;
> +
> + inplace_vector&
> + operator=(inplace_vector&&) = default;
> +
> + constexpr inplace_vector&
> + operator=(initializer_list<_Tp> __il)
> + {
> + if (__il.size() != 0)
> + __throw_bad_alloc();
> + }
> +
> + template<__any_input_iterator _InputIterator>
> + constexpr void
> + assign(_InputIterator __first, _InputIterator __last)
> + {
> + if (__first != __last)
> + __throw_bad_alloc();
> + }
> +
> + template<__detail::__container_compatible_range<_Tp> _Rg>
> + constexpr void
> + assign_range(_Rg&& __rg)
> + {
> + if (ranges::begin(__rg) != ranges::end(__rg))
> + __throw_bad_alloc();
> + }
> +
> + constexpr void
> + assign(size_type __n, const _Tp& __u)
> + {
> + if (__n != 0)
> + __throw_bad_alloc();
> + }
> +
> + constexpr void
> + assign(initializer_list<_Tp> __il)
> + {
> + if (__il.size() != 0)
> + __throw_bad_alloc();
> + }
> +
> + // iterators
> + [[nodiscard]]
> + constexpr iterator
> + begin() noexcept { return iterator(nullptr); }
> +
> + [[nodiscard]]
> + constexpr const_iterator
> + begin() const noexcept { return const_iterator(nullptr); }
> +
> + [[nodiscard]]
> + constexpr iterator
> + end() noexcept { return iterator(nullptr); }
> +
> + [[nodiscard]]
> + constexpr const_iterator
> + end() const noexcept { return const_iterator(nullptr); }
> +
> + [[nodiscard]]
> + constexpr reverse_iterator
> + rbegin() noexcept
> + { return reverse_iterator(end()); }
> +
> + [[nodiscard]]
> + constexpr const_reverse_iterator
> + rbegin() const noexcept
> + { return const_reverse_iterator(end()); }
> +
> + [[nodiscard]]
> + constexpr reverse_iterator
> + rend() noexcept { return reverse_iterator(begin()); }
> +
> + [[nodiscard]]
> + constexpr const_reverse_iterator
> + rend() const noexcept { return const_reverse_iterator(begin()); }
> +
> + [[nodiscard]]
> + constexpr const_iterator
> + cbegin() const noexcept { return begin(); }
> +
> + [[nodiscard]]
> + constexpr const_iterator
> + cend() const noexcept { return end(); }
> +
> + [[nodiscard]]
> + constexpr const_reverse_iterator
> + crbegin() const noexcept { return rbegin(); }
> +
> + [[nodiscard]]
> + constexpr const_reverse_iterator
> + crend() const noexcept { return rend(); }
> +
> + // [containers.sequences.inplace.vector.members] size/capacity
> + [[nodiscard]]
> + constexpr bool
> + empty() const noexcept { return true; }
> +
> + [[nodiscard]]
> + constexpr size_type
> + size() const noexcept { return 0; }
> +
> + [[nodiscard]]
> + static constexpr size_type
> + max_size() noexcept { return 0; }
> +
> + [[nodiscard]]
> + static constexpr size_type
> + capacity() noexcept { return 0; }
> +
> + constexpr void
> + resize(size_type __n)
> + {
> + if (__n != 0)
> + __throw_bad_alloc();
> + }
> +
> + constexpr void
> + resize(size_type __n, const _Tp&)
> + {
> + if (__n != 0)
> + __throw_bad_alloc();
> + }
> +
> + static constexpr void
> + reserve(size_type __n)
> + {
> + if (__n != 0)
> + __throw_bad_alloc();
> + }
> +
> + static constexpr void
> + shrink_to_fit() { }
> +
> + // element access
> + [[nodiscard,noreturn]]
> + constexpr reference
> + operator[](size_type)
> + { __builtin_trap(); }
> +
> + [[nodiscard,noreturn]]
> + constexpr const_reference
> + operator[](size_type) const
> + { __builtin_trap(); }
> +
> + [[nodiscard,noreturn]]
> + constexpr const_reference
> + at(size_type __n) const
> + {
> + std::__throw_out_of_range_fmt(__N("inplace_vector::at: __n "
> + "(which is %zu) "
> + ">= size() (which is 0)"),
> + __n);
> + }
> +
> + [[nodiscard,noreturn]]
> + constexpr reference
> + at(size_type __n)
> + {
> + std::__throw_out_of_range_fmt(__N("inplace_vector::at: __n "
> + "(which is %zu) "
> + ">= size() (which is 0)"),
> + __n);
> + }
> +
> + [[nodiscard,noreturn]]
> + constexpr reference
> + front()
> + { __builtin_trap(); }
> +
> + [[nodiscard,noreturn]]
> + constexpr const_reference
> + front() const
> + { __builtin_trap(); }
> +
> + [[nodiscard,noreturn]]
> + constexpr reference
> + back()
> + { __builtin_trap(); }
> +
> + [[nodiscard,noreturn]]
> + constexpr const_reference
> + back() const
> + { __builtin_trap(); }
> +
> + // [containers.sequences.inplace.vector.data], data access
> +
> + [[nodiscard]]
> + constexpr _Tp*
> + data() noexcept
> + { return nullptr; }
> +
> + [[nodiscard]]
> + constexpr const _Tp*
> + data() const noexcept
> + { return nullptr; }
> +
> + // [containers.sequences.inplace.vector.modifiers], modifiers
> + template<typename... _Args>
> + [[noreturn]]
> + constexpr _Tp&
> + emplace_back(_Args&&...)
> + { __throw_bad_alloc(); }
> +
> + [[noreturn]]
> + constexpr _Tp&
> + push_back(const _Tp&)
> + { __throw_bad_alloc(); }
> +
> + [[noreturn]]
> + constexpr _Tp&
> + push_back(_Tp&&)
> + { __throw_bad_alloc(); }
> +
> + template<__detail::__container_compatible_range<_Tp> _Rg>
> + constexpr void
> + append_range(_Rg&& __rg)
> + {
> + if (ranges::begin(__rg) != ranges::end(__rg))
> + __throw_bad_alloc();
> + }
> +
> + [[noreturn]]
> + constexpr void
> + pop_back()
> + { __builtin_trap(); }
> +
> + template<typename... _Args>
> + constexpr _Tp*
> + try_emplace_back(_Args&&...)
> + { return nullptr; }
> +
> + constexpr _Tp*
> + try_push_back(const _Tp&)
> + { return nullptr; }
> +
> + constexpr _Tp*
> + try_push_back(_Tp&&)
> + { return nullptr; }
> +
> + template<__detail::__container_compatible_range<_Tp> _Rg>
> + constexpr ranges::borrowed_iterator_t<_Rg>
> + try_append_range(_Rg&& __rg)
> + { return ranges::begin(__rg); }
> +
> + template<typename... _Args>
> + [[noreturn]]
> + constexpr _Tp&
> + unchecked_emplace_back(_Args&&...)
> + { __builtin_trap(); }
> +
> + [[noreturn]]
> + constexpr _Tp&
> + unchecked_push_back(const _Tp&)
> + { __builtin_trap(); }
> +
> + [[noreturn]]
> + constexpr _Tp&
> + unchecked_push_back(_Tp&&)
> + { __builtin_trap(); }
> +
> + template<typename... _Args>
> + [[noreturn]]
> + constexpr iterator
> + emplace(const_iterator, _Args&&...)
> + { __throw_bad_alloc(); }
> +
> + [[noreturn]]
> + constexpr iterator
> + insert(const_iterator, const _Tp&)
> + { __throw_bad_alloc(); }
> +
> + [[noreturn]]
> + constexpr iterator
> + insert(const_iterator, _Tp&&)
> + { __throw_bad_alloc(); }
> +
> + constexpr iterator
> + insert(const_iterator, size_type __n, const _Tp&)
> + {
> + if (__n != 0)
> + __throw_bad_alloc();
> + return begin();
> + }
> +
> + template<typename _InputIterator>
> + constexpr iterator
> + insert(const_iterator, _InputIterator __first, _InputIterator __last)
> + {
> + if (__first != __last)
> + __throw_bad_alloc();
> + return begin();
> + }
> +
> + template<__detail::__container_compatible_range<_Tp> _Rg>
> + constexpr iterator
> + insert_range(const_iterator, _Rg&& __rg)
> + {
> + if (ranges::begin(__rg) != ranges::end(__rg))
> + __throw_bad_alloc();
> + return begin();
> + }
> +
> + constexpr iterator
> + insert(const_iterator, initializer_list<_Tp> __il)
> + {
> + if (__il.size() != 0)
> + __throw_bad_alloc();
> + return begin();
> + }
> +
> + [[noreturn]]
> + constexpr iterator
> + erase(const_iterator)
> + { __builtin_trap(); }
> +
> + constexpr iterator
> + erase(const_iterator __first, const_iterator __last)
> + {
> + __glibcxx_assert(__first == __last);
> + return begin();
> + }
> +
> + constexpr void
> + swap(inplace_vector& __x)
> + noexcept
> + { }
> +
> + constexpr void
> + clear() noexcept
> + { }
> +
> + constexpr friend bool
> + operator==(const inplace_vector&, const inplace_vector&)
> + { return true; }
> +
> + constexpr friend auto
> + operator<=>(const inplace_vector&, const inplace_vector&)
> + requires requires (const _Tp __t) {
> + { __t < __t } -> __detail::__boolean_testable;
> + }
> + { return std::strong_ordering::equal; }
> +
> + // n.b. there is not explicit wording requiring that swap for inplace_vector,
> + // with zero size, works even if element type is not swappable. However given
> + // that move operations are required to be present and trivial, it makes sense
> + // to support them.
> + constexpr friend void
> + swap(inplace_vector&, inplace_vector&) noexcept
> + { }
> + };
> +
> + template<typename _Tp, size_t _Nm, typename _Predicate>
> + constexpr size_t
> + erase_if(inplace_vector<_Tp, _Nm>& __cont, _Predicate __pred)
> + {
> + using namespace __gnu_cxx;
> + const auto __osz = __cont.size();
> + const auto __end = __cont.end();
> + auto __removed = std::__remove_if(__cont.begin(), __end,
> + __ops::__pred_iter(std::ref(__pred)));
> + if (__removed != __end)
> + {
> + __cont.erase(__niter_wrap(__cont.begin(), __removed),
> + __cont.end());
> + return __osz - __cont.size();
> + }
> + return 0;
> + }
> +
> +
> + template<typename _Tp, size_t _Nm, typename _Up>
> + constexpr size_t
> + erase(inplace_vector<_Tp, _Nm>& __cont, const _Up& __value)
> + {
> + using namespace __gnu_cxx;
> + const auto __osz = __cont.size();
> + const auto __end = __cont.end();
> + auto __removed = std::__remove_if(__cont.begin(), __end,
> + __ops::__iter_equals_val(__value));
> + if (__removed != __end)
> + {
> + __cont.erase(__niter_wrap(__cont.begin(), __removed),
> + __cont.end());
> + return __osz - __cont.size();
> + }
> + return 0;
> + }
> +
> +_GLIBCXX_END_NAMESPACE_VERSION
> +} // namespace
> +
> +#endif // __glibcxx_inplace_vector
> +#endif // _GLIBCXX_INPLACE_VECTOR
> diff --git a/libstdc++-v3/src/c++23/std.cc.in b/libstdc++-v3/src/c++23/std.cc.in
> index dd05a839a92..1bd4bd58f21 100644
> --- a/libstdc++-v3/src/c++23/std.cc.in
> +++ b/libstdc++-v3/src/c++23/std.cc.in
> @@ -1513,7 +1513,15 @@ export namespace std
> using std::initializer_list;
> }
>
> -// <inplace_vector> FIXME
> +// <inplace_vector>
> +#if __cpp_lib_inplace_vector
> +export namespace std
> +{
> + using std::inplace_vector;
> + using std::erase;
> + using std::erase_if;
> +}
> +#endif
>
> // <iomanip>
> export namespace std
> diff --git a/libstdc++-v3/testsuite/23_containers/inplace_vector/access/capacity.cc b/libstdc++-v3/testsuite/23_containers/inplace_vector/access/capacity.cc
> new file mode 100644
> index 00000000000..2797e205971
> --- /dev/null
> +++ b/libstdc++-v3/testsuite/23_containers/inplace_vector/access/capacity.cc
> @@ -0,0 +1,51 @@
> +// { dg-do run { target c++26 } }
> +
> +#include <inplace_vector>
> +
> +#include <span>
> +#include <testsuite_hooks.h>
> +
> +template<size_t N, typename T>
> +constexpr void
> +test_reserve()
> +{
> + std::inplace_vector<T, N> v;
> +
> + static_assert(v.max_size() == N);
> + static_assert(v.capacity() == N);
> +
> + // static methods
> + v.shrink_to_fit();
> + v.reserve(0);
> + v.reserve(N);
> +
> +#ifdef __cpp_exceptions
> +#ifdef __cpp_lib_constexpr_exceptions
> +#error remove the consteval check
> +#endif
> + if consteval {
> + return;
> + }
> +
> + try
> + {
> + v.reserve(N + 2);
> + VERIFY(false);
> + }
> + catch (std::bad_alloc const&)
> + {
> + }
> +#endif
> +}
> +
> +int main()
> +{
> + auto test_all = [] {
> + test_reserve<0, int>();
> + test_reserve<4, int>();
> + return true;
> + };
> +
> + test_all();
> + static_assert(test_all());;
> +}
> diff --git a/libstdc++-v3/testsuite/23_containers/inplace_vector/access/elem.cc b/libstdc++-v3/testsuite/23_containers/inplace_vector/access/elem.cc
> new file mode 100644
> index 00000000000..a598514bd9b
> --- /dev/null
> +++ b/libstdc++-v3/testsuite/23_containers/inplace_vector/access/elem.cc
> @@ -0,0 +1,103 @@
> +// { dg-do run { target c++26 } }
> +
> +#include <inplace_vector>
> +
> +#include <span>
> +#include <stdexcept>
> +#include <testsuite_hooks.h>
> +#include <utility>
> +
> +template<size_t N, typename T>
> +constexpr void
> +test_out_of_capacity()
> +{
> + std::inplace_vector<T, N> v;
> +
> +#ifdef __cpp_exceptions
> +#ifdef __cpp_lib_constexpr_exceptions
> +#error remove the consteval check
> +#endif
> + if consteval {
> + return;
> + }
> +
> + try
> + {
> + (void)v.at(N + 2);
> + VERIFY(false);
> + }
> + catch (std::out_of_range const&)
> + {
> + }
> +
> + try
> + {
> + (void)as_const(v).at(N + 2);
> + VERIFY(false);
> + }
> + catch (std::out_of_range const&)
> + {
> + }
> +#endif
> +}
> +
> +template<typename T>
> +constexpr void
> +test_access()
> +{
> + std::inplace_vector<T, 10> v{1, 2, 3, 4, 5};
> +
> + auto& e3a = v[2];
> + auto& e3b = std::as_const(v).at(2);
> + VERIFY( &e3a == &e3b );
> + VERIFY( &e3a == &v.begin()[2] );
> + VERIFY( &e3a == std::as_const(v).data() + 2 );
> + VERIFY( e3a == T(3) );
> +
> + auto& e4a = as_const(v)[4];
> + auto& e4b = v.at(4);
> + VERIFY( &e4a == &e4b );
> + VERIFY( &e4a == &v.cbegin()[4] );
> + VERIFY( &e4a == v.data() + 4 );
> + VERIFY( e4a == T(5) );
> +
> +#ifdef __cpp_exceptions
> +#ifdef __cpp_lib_constexpr_exceptions
> +#error remove the consteval check
> +#endif
> + if consteval {
> + return;
> + }
> +
> + try
> + {
> + (void)v.at(7);
> + VERIFY(false);
> + }
> + catch (std::out_of_range const&)
> + {
> + }
> +
> + try
> + {
> + (void)as_const(v).at(7);
> + VERIFY(false);
> + }
> + catch (std::out_of_range const&)
> + {
> + }
> +#endif
> +}
> +
> +int main()
> +{
> + auto test_all = [] {
> + test_out_of_capacity<0, int>();
> + test_out_of_capacity<4, int>();
> + test_access<int>();
> + return true;
> + };
> +
> + test_all();
> + static_assert(test_all());;
> +}
> diff --git a/libstdc++-v3/testsuite/23_containers/inplace_vector/access/elem_neg.cc b/libstdc++-v3/testsuite/23_containers/inplace_vector/access/elem_neg.cc
> new file mode 100644
> index 00000000000..e3ba5eb6866
> --- /dev/null
> +++ b/libstdc++-v3/testsuite/23_containers/inplace_vector/access/elem_neg.cc
> @@ -0,0 +1,29 @@
> +// { dg-do compile { target c++26 } }
> +
> +#include <inplace_vector>
> +
> +template<size_t N, typename T>
> +constexpr bool
> +test_out_of_capacity()
> +{
> + std::inplace_vector<T, N> v;
> + (void)v[N+2]; // { dg-error "in 'constexpr' expansion of" }
> + return true;
> +}
> +
> +template<typename T>
> +constexpr bool
> +test_out_of_size()
> +{
> + std::inplace_vector<T, 10> v{1, 2, 3, 4, 5};
> + (void)v[7]; // { dg-error "in 'constexpr' expansion of" }
> + return true;
> +}
> +
> +static_assert(test_out_of_capacity<0, int>()); // { dg-error "in 'constexpr' expansion of" }
> +static_assert(test_out_of_capacity<4, int>()); // { dg-error "in 'constexpr' expansion of" }
> +static_assert(test_out_of_size<int>()); // { dg-error "in 'constexpr' expansion of" }
> +
> +// { dg-prune-output "non-constant condition for static assertion" }
> +// { dg-prune-output "is not a constant expression" }
> +// { dg-prune-output "call to non-'constexpr' function" }
> diff --git a/libstdc++-v3/testsuite/23_containers/inplace_vector/cons/1.cc b/libstdc++-v3/testsuite/23_containers/inplace_vector/cons/1.cc
> new file mode 100644
> index 00000000000..e9c2cdc8665
> --- /dev/null
> +++ b/libstdc++-v3/testsuite/23_containers/inplace_vector/cons/1.cc
> @@ -0,0 +1,385 @@
> +// { dg-do run { target c++26 } }
> +
> +#include <inplace_vector>
> +#include <testsuite_hooks.h>
> +
> +struct X
> +{
> + constexpr X() { } // not trivially default constructible
> +};
> +
> +struct N
> +{
> + constexpr N() noexcept { } // not trivially default constructible
> +};
> +
> +struct D
> +{
> + ~D() {} // not trivially destructible
> +};
> +
> +struct U
> +{
> + U() noexcept(false) = default; // lies about noexcept
> +};
> +
> +// n5008 inplace.vector.overview says for inplace_vector<T, 0>
> +// provides trivial copy/move/default cosntructpr regardless of T
> +struct Z
> +{
> + constexpr Z(int) {}
> + Z() = delete;
> +};
> +
> +static_assert(std::is_default_constructible_v<std::inplace_vector<int, 2>>);
> +static_assert(std::is_default_constructible_v<std::inplace_vector<X, 2>>);
> +static_assert(std::is_default_constructible_v<std::inplace_vector<N, 2>>);
> +static_assert(std::is_default_constructible_v<std::inplace_vector<D, 2>>);
> +static_assert(std::is_default_constructible_v<std::inplace_vector<U, 2>>);
> +// The operators are not constrained, as for any other container
> +static_assert(std::is_default_constructible_v<std::inplace_vector<Z, 2>>);
> +
> +static_assert(std::is_nothrow_default_constructible_v<std::inplace_vector<int, 2>>);
> +static_assert(std::is_nothrow_default_constructible_v<std::inplace_vector<X, 2>>);
> +static_assert(std::is_nothrow_default_constructible_v<std::inplace_vector<N, 2>>);
> +static_assert(std::is_nothrow_default_constructible_v<std::inplace_vector<D, 2>>);
> +static_assert(std::is_nothrow_default_constructible_v<std::inplace_vector<U, 2>>);
> +
> +// Needs to set size to zero, not trivial
> +static_assert(!std::is_trivially_default_constructible_v<std::inplace_vector<int, 2>>);
> +static_assert(!std::is_trivially_default_constructible_v<std::inplace_vector<X, 2>>);
> +static_assert(!std::is_trivially_default_constructible_v<std::inplace_vector<N, 2>>);
> +static_assert(!std::is_trivially_default_constructible_v<std::inplace_vector<D, 2>>);
> +static_assert(!std::is_trivially_default_constructible_v<std::inplace_vector<U, 2>>);
> +
> +static_assert(std::is_trivially_destructible_v<std::inplace_vector<int, 2>>);
> +static_assert(std::is_trivially_destructible_v<std::inplace_vector<X, 2>>);
> +static_assert(std::is_trivially_destructible_v<std::inplace_vector<N, 2>>);
> +static_assert(!std::is_trivially_destructible_v<std::inplace_vector<D, 2>>);
> +static_assert(std::is_trivially_destructible_v<std::inplace_vector<U, 2>>);
> +
> +static_assert(std::is_nothrow_default_constructible_v<std::inplace_vector<int, 0>>);
> +static_assert(std::is_nothrow_default_constructible_v<std::inplace_vector<X, 0>>);
> +static_assert(std::is_nothrow_default_constructible_v<std::inplace_vector<N, 0>>);
> +static_assert(std::is_nothrow_default_constructible_v<std::inplace_vector<D, 0>>);
> +static_assert(std::is_nothrow_default_constructible_v<std::inplace_vector<U, 0>>);
> +
> +// Size is always zero, so trivial
> +static_assert(std::is_trivially_default_constructible_v<std::inplace_vector<int, 0>>);
> +static_assert(std::is_trivially_default_constructible_v<std::inplace_vector<X, 0>>);
> +static_assert(std::is_trivially_default_constructible_v<std::inplace_vector<N, 0>>);
> +static_assert(std::is_trivially_default_constructible_v<std::inplace_vector<D, 0>>);
> +static_assert(std::is_trivially_default_constructible_v<std::inplace_vector<U, 0>>);
> +static_assert(std::is_trivially_default_constructible_v<std::inplace_vector<Z, 0>>);
> +
> +static_assert(std::is_trivially_destructible_v<std::inplace_vector<int, 0>>);
> +static_assert(std::is_trivially_destructible_v<std::inplace_vector<X, 0>>);
> +static_assert(std::is_trivially_destructible_v<std::inplace_vector<N, 0>>);
> +static_assert(std::is_trivially_destructible_v<std::inplace_vector<D, 0>>);
> +static_assert(std::is_trivially_destructible_v<std::inplace_vector<U, 0>>);
> +
> +static_assert(std::is_empty_v<std::inplace_vector<int, 0>>);
> +static_assert(std::is_empty_v<std::inplace_vector<X, 0>>);
> +static_assert(std::is_empty_v<std::inplace_vector<N, 0>>);
> +static_assert(std::is_empty_v<std::inplace_vector<D, 0>>);
> +static_assert(std::is_empty_v<std::inplace_vector<U, 0>>);
> +static_assert(std::is_empty_v<std::inplace_vector<Z, 0>>);
> +
> +constexpr void
> +test_default()
> +{
> + std::inplace_vector<int, 5> c;
> + VERIFY( c.size() == 0 );
> + VERIFY( c.capacity() == 5 );
> + VERIFY( c.empty() );
> + VERIFY( c.begin() == c.end() );
> +
> + std::inplace_vector<int, 0> c0;
> + VERIFY( c0.size() == 0 );
> + VERIFY( c0.capacity() == 0 );
> + VERIFY( c0.empty() );
> + VERIFY( c0.begin() == c0.end() );
> +
> + std::inplace_vector<Z, 0> z0;
> + VERIFY( z0.size() == 0 );
> + VERIFY( z0.capacity() == 0 );
> + VERIFY( z0.empty() );
> + VERIFY( z0.begin() == z0.end() );
> +
> +#ifdef __cpp_lib_constexpr_inplace_vector
> +#error remove the consteval check
> +#endif
> + if consteval {
> + return;
> + }
> +
> + std::inplace_vector<X, 5> cx;
> + VERIFY( cx.size() == 0 );
> + VERIFY( cx.capacity() == 5 );
> + VERIFY( cx.empty() );
> + VERIFY( cx.begin() == cx.end() );
> +
> + std::inplace_vector<X, 0> cx0;
> + VERIFY( cx0.size() == 0 );
> + VERIFY( cx0.capacity() == 0 );
> + VERIFY( cx0.empty() );
> + VERIFY( cx0.begin() == cx0.end() );
> +}
> +
> +constexpr void
> +test_n()
> +{
> + std::inplace_vector<int, 5> c(2);
> + VERIFY( c.size() == 2 );
> + VERIFY( c.capacity() == 5 );
> + VERIFY( not c.empty() );
> + VERIFY( c.begin() + 2 == c.end() );
> + VERIFY( c[0] == 0 );
> + VERIFY( c[1] == 0 );
> +
> + std::inplace_vector<int, 2> c2(2);
> + VERIFY( c2.size() == 2 );
> + VERIFY( c2.capacity() == 2 );
> + VERIFY( not c2.empty() );
> + VERIFY( c2.begin() + 2 == c2.end() );
> + VERIFY( c2[0] == 0 );
> + VERIFY( c2[1] == 0 );
> +
> + std::inplace_vector<int, 0> c0(0);
> + VERIFY( c0.size() == 0 );
> + VERIFY( c0.capacity() == 0 );
> + VERIFY( c0.empty() );
> + VERIFY( c0.begin() == c0.end() );
> +
> + std::inplace_vector<int, 2> c20(0);
> + VERIFY( c20.size() == 0 );
> + VERIFY( c20.capacity() == 2 );
> + VERIFY( c20.empty() );
> + VERIFY( c20.begin() == c20.end() );
> +
> + std::inplace_vector<Z, 0> z0(0);
> + VERIFY( z0.size() == 0 );
> + VERIFY( z0.capacity() == 0 );
> + VERIFY( z0.empty() );
> + VERIFY( z0.begin() == z0.end() );
> +
> +#ifdef __cpp_exceptions
> +#ifdef __cpp_lib_constexpr_exceptions
> +#error remove the consteval check
> +#endif
> + if not consteval {
> + try
> + {
> + std::inplace_vector<int, 2> ct(3);
> + VERIFY(false);
> + }
> + catch (std::bad_alloc const&)
> + {
> + }
> +
> + try
> + {
> + std::inplace_vector<int, 0> ct(1);
> + VERIFY(false);
> + }
> + catch (std::bad_alloc const&)
> + {
> + }
> +
> + }
> +#endif
> +
> +#ifdef __cpp_lib_constexpr_inplace_vector
> +#error remove the consteval check
> +#endif
> + if consteval {
> + return;
> + }
> +
> + std::inplace_vector<X, 5> cx(3);
> + VERIFY( cx.size() == 3 );
> + VERIFY( cx.capacity() == 5 );
> + VERIFY( not cx.empty() );
> + VERIFY( cx.begin() + 3 == cx.end() );
> + (void) cx[2];
> +}
> +
> +constexpr void
> +test_n_val()
> +{
> + std::inplace_vector<int, 5> c(2, 99);
> + VERIFY( c.size() == 2 );
> + VERIFY( c.capacity() == 5 );
> + VERIFY( not c.empty() );
> + VERIFY( c.begin() + 2 == c.end() );
> + VERIFY( c[0] == 99 );
> + VERIFY( c[1] == 99 );
> +
> + std::inplace_vector<int, 1> c1(1, 44);
> + VERIFY( c1.size() == 1 );
> + VERIFY( c1.capacity() == 1 );
> + VERIFY( not c1.empty() );
> + VERIFY( c1.begin() + 1 == c1.end() );
> + VERIFY( c1[0] == 44 );
> +
> + std::inplace_vector<int, 0> c0(0, 33);
> + VERIFY( c0.size() == 0 );
> + VERIFY( c0.capacity() == 0 );
> + VERIFY( c0.empty() );
> + VERIFY( c0.begin() == c0.end() );
> +
> + std::inplace_vector<int, 2> c20(0, 22);
> + VERIFY( c20.size() == 0 );
> + VERIFY( c20.capacity() == 2 );
> + VERIFY( c20.empty() );
> + VERIFY( c20.begin() == c20.end() );
> +
> + std::inplace_vector<Z, 0> z0(0, 33);
> + VERIFY( z0.size() == 0 );
> + VERIFY( z0.capacity() == 0 );
> + VERIFY( z0.empty() );
> + VERIFY( z0.begin() == z0.end() );
> +
> +#ifdef __cpp_exceptions
> +#ifdef __cpp_lib_constexpr_exceptions
> +#error remove the consteval check
> +#endif
> + if not consteval {
> + try
> + {
> + std::inplace_vector<int, 2> ct(3, 11);
> + VERIFY(false);
> + }
> + catch (std::bad_alloc const&)
> + {
> + }
> +
> + try
> + {
> + std::inplace_vector<int, 0> ct(2, 11);
> + VERIFY(false);
> + }
> + catch (std::bad_alloc const&)
> + {
> + }
> + }
> +#endif
> +
> +#ifdef __cpp_lib_constexpr_inplace_vector
> +#error remove the consteval check
> +#endif
> + if consteval {
> + return;
> + }
> +
> + std::inplace_vector<X, 5> cx(4);
> + VERIFY( cx.size() == 4 );
> + VERIFY( cx.capacity() == 5 );
> + VERIFY( not cx.empty() );
> + VERIFY( cx.begin() + 4 == cx.end() );
> + (void) cx[3];
> +}
> +
> +constexpr void
> +test_initializer_list()
> +{
> + std::inplace_vector<int, 5> c{22, 33};
> + VERIFY( c.size() == 2 );
> + VERIFY( c.capacity() == 5 );
> + VERIFY( not c.empty() );
> + VERIFY( c.begin() + 2 == c.end() );
> + VERIFY( c[0] == 22 );
> + VERIFY( c[1] == 33 );
> +
> + std::inplace_vector<int, 1> c1{44};
> + VERIFY( c1.size() == 1 );
> + VERIFY( c1.capacity() == 1 );
> + VERIFY( not c1.empty() );
> + VERIFY( c1.begin() + 1 == c1.end() );
> + VERIFY( c1[0] == 44 );
> +
> + std::inplace_vector<int, 0> c0({});
> + VERIFY( c0.size() == 0 );
> + VERIFY( c0.capacity() == 0 );
> + VERIFY( c0.empty() );
> + VERIFY( c0.begin() == c0.end() );
> +
> + std::inplace_vector<int, 2> c20({});
> + VERIFY( c20.size() == 0 );
> + VERIFY( c20.capacity() == 2 );
> + VERIFY( c20.empty() );
> + VERIFY( c20.begin() == c20.end() );
> +
> + std::inplace_vector<Z, 0> z0({});
> + VERIFY( z0.size() == 0 );
> + VERIFY( z0.capacity() == 0 );
> + VERIFY( z0.empty() );
> + VERIFY( z0.begin() == z0.end() );
> +
> +#ifdef __cpp_exceptions
> +#ifdef __cpp_lib_constexpr_exceptions
> +#error remove the consteval check
> +#endif
> + if not consteval {
> + try
> + {
> + std::inplace_vector<int, 2> ct{11, 22, 33};
> + VERIFY(false);
> + }
> + catch (std::bad_alloc const&)
> + {
> + }
> +
> + try
> + {
> + std::inplace_vector<int, 0> ct{11, 22};
> + VERIFY(false);
> + }
> + catch (std::bad_alloc const&)
> + {
> + }
> + }
> +#endif
> +
> +#ifdef __cpp_lib_constexpr_inplace_vector
> +#error remove the consteval check
> +#endif
> + if consteval {
> + return;
> + }
> +
> + std::inplace_vector<X, 5> cx{X(), X(), X(), X()};
> + VERIFY( cx.size() == 4 );
> + VERIFY( cx.capacity() == 5 );
> + VERIFY( not cx.empty() );
> + VERIFY( cx.begin() + 4 == cx.end() );
> + (void) cx[3];
> +}
> +
> +constexpr std::inplace_vector<int, 0> e0;
> +constexpr std::inplace_vector<X, 0> e1;
> +constexpr std::inplace_vector<Z, 0> e2;
> +
> +constexpr std::inplace_vector<int, 5> g1;
> +constexpr std::inplace_vector<int, 5> g2(2, 100);
> +constexpr std::inplace_vector<int, 5> g3 = g2;
> +constexpr std::inplace_vector<int, 5> g4{1, 2, 3};
> +constexpr std::inplace_vector<int, 5> g5 = [] {
> + std::inplace_vector<int, 5> res;
> + res = g3;
> + return res;
> +}();
> +
> +int main()
> +{
> + auto tests = [] {
> + test_default();
> + test_n();
> + test_n_val();
> + test_initializer_list();
> + return true;
> + };
> +
> + tests();
> + constexpr bool _ = tests();
> +}
> diff --git a/libstdc++-v3/testsuite/23_containers/inplace_vector/cons/from_range.cc b/libstdc++-v3/testsuite/23_containers/inplace_vector/cons/from_range.cc
> new file mode 100644
> index 00000000000..73b8d3b6307
> --- /dev/null
> +++ b/libstdc++-v3/testsuite/23_containers/inplace_vector/cons/from_range.cc
> @@ -0,0 +1,186 @@
> +// { dg-do run { target c++26 } }
> +
> +#include <inplace_vector>
> +
> +#include <span>
> +#include <testsuite_hooks.h>
> +#include <testsuite_iterators.h>
> +#include <testsuite_allocator.h>
> +
> +template<typename T, typename V, size_t N>
> +constexpr bool
> +eq(const std::inplace_vector<V, N>& l, std::span<const T> r) {
> + if (l.size() != r.size())
> + return false;
> + for (auto i = 0u; i < l.size(); ++i)
> + if (l[i] != r[i])
> + return false;
> + return true;
> +};
> +
> +template<typename T, template<class TT> class ItType>
> +constexpr void
> +do_test_it()
> +{
> + // The vector's value_type.
> + using V = int;
> +
> + T a[]{1,2,3,4,5,6,7,8,9};
> + using It = ItType<T>;
> +
> + auto bounds = typename It::ContainerType(a, a+9);
> + std::inplace_vector<V, 0> e0(It(a, &bounds), It(a, &bounds));
> + VERIFY( e0.empty() );
> +
> + bounds = typename It::ContainerType(a, a+9);
> + std::inplace_vector<V, 10> v0(It(a, &bounds), It(a, &bounds));
> + VERIFY( v0.empty() );
> +
> + bounds = typename It::ContainerType(a, a+9);
> + std::inplace_vector<V, 10> v4(It(a, &bounds), It(a+4, &bounds));
> + VERIFY( eq<T>(v4, {a, 4}) );
> +
> +#ifdef __cpp_exceptions
> +#ifdef __cpp_lib_constexpr_exceptions
> +#error remove the consteval check
> +#endif
> + if consteval {
> + return;
> + }
> +
> + bounds = typename It::ContainerType(a, a+9);
> + try
> + {
> + std::inplace_vector<int, 5> v9(It(a, &bounds), It(a+9, &bounds));
> + VERIFY(false);
> + }
> + catch (std::bad_alloc const&)
> + {
> + }
> +
> + bounds = typename It::ContainerType(a, a+9);
> + try
> + {
> + std::inplace_vector<int, 0> v2(It(a, &bounds), It(a+2, &bounds));
> + VERIFY(false);
> + }
> + catch (std::bad_alloc const&)
> + {
> + }
> +#endif
> +}
> +
> +bool
> +test_iterators()
> +{
> + using namespace __gnu_test;
> +
> + do_test_it<int, input_iterator_wrapper>();
> + do_test_it<int, forward_iterator_wrapper>();
> + do_test_it<int, random_access_iterator_wrapper>();
> +
> + do_test_it<short, forward_iterator_wrapper>();
> + return true;
> +}
> +
> +template<typename Range>
> +constexpr void
> +do_test_r()
> +{
> + // The vector's value_type.
> + using V = int;
> +
> + // The range's value_type.
> + using T = std::ranges::range_value_t<Range>;
> + T a[]{1,2,3,4,5,6,7,8,9};
> +
> + std::inplace_vector<V, 0> e0(std::from_range, Range(a, a+0));
> + VERIFY( e0.empty() );
> +
> + std::inplace_vector<V, 10> v0(std::from_range, Range(a, a+0));
> + VERIFY( v0.empty() );
> +
> + std::inplace_vector<V, 10> v4(std::from_range, Range(a, a+4));
> + VERIFY( eq<T>(v4, {a, 4}) );
> +
> +#ifdef __cpp_exceptions
> +#ifdef __cpp_lib_constexpr_exceptions
> +#error remove the consteval check
> +#endif
> + if consteval {
> + return;
> + }
> +
> + try
> + {
> + std::inplace_vector<V, 5> v9(std::from_range, Range(a, a+9));
> + VERIFY(false);
> + }
> + catch (std::bad_alloc const&)
> + {
> + }
> +
> + try
> + {
> + std::inplace_vector<V, 0> v3(std::from_range, Range(a, a+3));
> + VERIFY(false);
> + }
> + catch (std::bad_alloc const&)
> + {
> + }
> +#endif
> +}
> +
> +bool
> +test_ranges()
> +{
> + using namespace __gnu_test;
> +
> + do_test_r<test_forward_range<int>>();
> + do_test_r<test_sized_range_sized_sent<int, forward_iterator_wrapper>>();
> +
> + do_test_r<test_input_range<int>>();
> + do_test_r<test_input_sized_range<int>>();
> + do_test_r<test_sized_range_sized_sent<int, input_iterator_wrapper>>();
> +
> + do_test_r<test_range<int, input_iterator_wrapper_nocopy>>();
> + do_test_r<test_sized_range<int, input_iterator_wrapper_nocopy>>();
> + do_test_r<test_sized_range_sized_sent<int, input_iterator_wrapper_nocopy>>();
> +
> + do_test_r<test_forward_range<short>>();
> + do_test_r<test_input_range<short>>();
> +
> + // Not lvalue-convertible to int
> + struct C {
> + C(int v) : val(v) { }
> + operator int() && { return val; }
> + bool operator==(int b) const { return b == val; }
> + int val;
> + };
> + using rvalue_input_range = test_range<C, input_iterator_wrapper_rval>;
> + do_test_r<rvalue_input_range>();
> +
> + return true;
> +}
> +
> +constexpr bool
> +test_constexpr()
> +{
> + // XXX: this doesn't test the non-forward_range code paths are constexpr.
> + std::initializer_list<int> il{1, 2, 3, 4};
> + std::inplace_vector<int, 6> v(il.begin(), il.end());
> + eq<int>(v, il);
> +
> + do_test_r<std::span<short>>();
> + return true;
> +}
> +
> +int main()
> +{
> + test_iterators();
> + test_ranges();
> + static_assert( test_constexpr() );
> +}
> +
> +// Bug PR121143
> +// { dg-prune-output "warning: iteration 5 invokes undefined behavior" }
> diff --git a/libstdc++-v3/testsuite/23_containers/inplace_vector/cons/throws.cc b/libstdc++-v3/testsuite/23_containers/inplace_vector/cons/throws.cc
> new file mode 100644
> index 00000000000..fd4e51f17c4
> --- /dev/null
> +++ b/libstdc++-v3/testsuite/23_containers/inplace_vector/cons/throws.cc
> @@ -0,0 +1,131 @@
> +// { dg-do run { target c++26 } }
> +
> +#include <inplace_vector>
> +
> +#include <span>
> +#include <testsuite_hooks.h>
> +#include <testsuite_iterators.h>
> +#include <testsuite_allocator.h>
> +
> +struct CopyFailed {};
> +
> +struct Thrower
> +{
> + static inline size_t throw_after = 0;
> + static inline size_t incontainer = 0;
> +
> + Thrower() {}
> + Thrower(int x) {}
> + Thrower(const Thrower&)
> + {
> + if (incontainer >= throw_after)
> + throw CopyFailed();
> + ++incontainer;
> + }
> +
> + ~Thrower()
> + { --incontainer; }
> +};
> +
> +template<template<class TT> class ItType>
> +void
> +do_test_it()
> +{
> + // The vector's value_type.
> + using V = Thrower;
> +
> + V a[]{1,2,3,4,5,6,7,8,9};
> + using It = ItType<V>;
> +
> + auto bounds = typename It::ContainerType(a, a+9);
> + Thrower::throw_after = 100;
> + Thrower::incontainer = 0;
> + try
> + {
> + std::inplace_vector<V, 5> v9(It(a, &bounds), It(a+9, &bounds));
> + VERIFY(false);
> + }
> + catch (std::bad_alloc const&)
> + {
> + }
> + VERIFY( Thrower::incontainer == 0 );
> +
> + bounds = typename It::ContainerType(a, a+9);
> + Thrower::throw_after = 2;
> + Thrower::incontainer = 0;
> + try
> + {
> + std::inplace_vector<V, 5> v2(It(a, &bounds), It(a+3, &bounds));
> + VERIFY(false);
> + }
> + catch (CopyFailed const&)
> + {
> + }
> + VERIFY( Thrower::incontainer == 0 );
> +}
> +
> +bool
> +test_iterators()
> +{
> + using namespace __gnu_test;
> + do_test_it<input_iterator_wrapper>();
> + do_test_it<forward_iterator_wrapper>();
> + do_test_it<random_access_iterator_wrapper>();
> + return true;
> +}
> +
> +template<typename Range>
> +void
> +do_test_r()
> +{
> + // The vector's value_type.
> + using V = Thrower;
> +
> + V a[]{1,2,3,4,5,6,7,8,9};
> +
> + Thrower::throw_after = 100;
> + Thrower::incontainer = 0;
> + try
> + {
> + std::inplace_vector<V, 5> v9(std::from_range, Range(a, a+9));
> + VERIFY(false);
> + }
> + catch (std::bad_alloc const&)
> + {
> + }
> + VERIFY( Thrower::incontainer == 0 );
> +
> + Thrower::throw_after = 2;
> + Thrower::incontainer = 0;
> + try
> + {
> + std::inplace_vector<V, 5> v9(std::from_range, Range(a, a+3));
> + VERIFY(false);
> + }
> + catch (CopyFailed const&)
> + {
> + }
> + VERIFY( Thrower::incontainer == 0 );
> +}
> +
> +bool
> +test_ranges()
> +{
> + using namespace __gnu_test;
> + do_test_r<test_forward_range<Thrower>>();
> + do_test_r<test_sized_range_sized_sent<Thrower, forward_iterator_wrapper>>();
> +
> + do_test_r<test_input_range<Thrower>>();
> + do_test_r<test_input_sized_range<Thrower>>();
> + do_test_r<test_sized_range_sized_sent<Thrower, input_iterator_wrapper>>();
> + return true;
> +}
> +
> +int main()
> +{
> + test_iterators();
> + test_ranges();
> +}
> +
> +// Bug PR121143
> +// { dg-prune-output "warning: iteration 5 invokes undefined behavior" }
> diff --git a/libstdc++-v3/testsuite/23_containers/inplace_vector/copy.cc b/libstdc++-v3/testsuite/23_containers/inplace_vector/copy.cc
> new file mode 100644
> index 00000000000..d149e63970c
> --- /dev/null
> +++ b/libstdc++-v3/testsuite/23_containers/inplace_vector/copy.cc
> @@ -0,0 +1,247 @@
> +// { dg-do run { target c++26 } }
> +
> +#include <inplace_vector>
> +#include <ranges>
> +#include <testsuite_hooks.h>
> +
> +struct X
> +{
> + X() = default;
> + constexpr X(int p) : v(p) {}
> + constexpr X(const X& o) : v(o.v) { } // not trivial
> + constexpr X& operator=(const X& o) // not trivial
> + { v = o.v; return *this; }
> +
> + int v;
> +
> + friend auto operator<=>(const X&, const X&) = default;
> +};
> +
> +template<bool CNoex, bool ANoex>
> +struct N
> +{
> + N() = default;
> + constexpr N(const N&) noexcept(CNoex) { } // not trivial
> + constexpr N& operator=(const N& o) noexcept(ANoex) // not trivial
> + { return *this; }
> +};
> +
> +struct D
> +{
> + D() = default;
> + D(const D&) = default;
> + D& operator=(const D&) = default;
> + ~D() {} // not trivially destructible
> +};
> +
> +struct U
> +{
> + U() = default;
> + U(const U&) noexcept(false) = default; // lies about noexcept, is trivial but throwing
> + U& operator=(const U&) noexcept(false) = default; // lies about noexcept, is trivial but throwing
> +};
> +
> +// n5008 inplace.vector.overview p5 says for inplace_vector<T, 0>
> +// provides trivial copy/move/default cosntructpr regardless of T
> +struct Z
> +{
> + Z(Z&&) = delete;
> + Z& operator=(Z&&) = delete;
> +};
> +
> +template<size_t N, typename T>
> + constexpr std::inplace_vector<T, N> const&
> + materialize(std::inplace_vector<T, N> const& r)
> + { return r; }
> +
> +static_assert(std::is_copy_constructible_v<std::inplace_vector<int, 2>>);
> +static_assert(std::is_copy_constructible_v<std::inplace_vector<X, 2>>);
> +static_assert(std::is_copy_constructible_v<std::inplace_vector<N<false, false>, 2>>);
> +static_assert(std::is_copy_constructible_v<std::inplace_vector<D, 2>>);
> +static_assert(std::is_copy_constructible_v<std::inplace_vector<U, 2>>);
> +// The operators are not constrained, as for any other container
> +static_assert(std::is_copy_constructible_v<std::inplace_vector<Z, 2>>);
> +
> +// conditional noexcept here is libstdc++ extension,
> +static_assert(std::is_nothrow_copy_constructible_v<std::inplace_vector<int, 2>>);
> +static_assert(!std::is_nothrow_copy_constructible_v<std::inplace_vector<X, 2>>);
> +static_assert(std::is_nothrow_copy_constructible_v<std::inplace_vector<N<true, true>, 2>>);
> +static_assert(std::is_nothrow_copy_constructible_v<std::inplace_vector<N<true, false>, 2>>);
> +static_assert(!std::is_nothrow_copy_constructible_v<std::inplace_vector<N<false, true>, 2>>);
> +static_assert(!std::is_nothrow_copy_constructible_v<std::inplace_vector<N<false, false>, 2>>);
> +static_assert(std::is_nothrow_copy_constructible_v<std::inplace_vector<D, 2>>);
> +static_assert(!std::is_nothrow_copy_constructible_v<std::inplace_vector<U, 2>>);
> +
> +static_assert(std::is_trivially_copy_constructible_v<std::inplace_vector<int, 2>>);
> +static_assert(!std::is_trivially_copy_constructible_v<std::inplace_vector<X, 2>>);
> +static_assert(!std::is_trivially_copy_constructible_v<std::inplace_vector<N<true, true>, 2>>);
> +// is_trivially_copy_constructible_v checks destructor
> +static_assert(!std::is_trivially_copy_constructible_v<std::inplace_vector<D, 2>>);
> +static_assert(std::is_trivially_copy_constructible_v<std::inplace_vector<U, 2>>);
> +
> +static_assert(std::is_copy_assignable_v<std::inplace_vector<int, 2>>);
> +static_assert(std::is_copy_assignable_v<std::inplace_vector<X, 2>>);
> +static_assert(std::is_copy_assignable_v<std::inplace_vector<N<false, false>, 2>>);
> +static_assert(std::is_copy_assignable_v<std::inplace_vector<D, 2>>);
> +static_assert(std::is_copy_assignable_v<std::inplace_vector<U, 2>>);
> +// The operators are not constrained, as for any other container
> +static_assert(std::is_copy_assignable_v<std::inplace_vector<Z, 2>>);
> +
> +static_assert(std::is_nothrow_copy_assignable_v<std::inplace_vector<int, 2>>);
> +static_assert(!std::is_nothrow_copy_assignable_v<std::inplace_vector<X, 2>>);
> +static_assert(std::is_nothrow_copy_assignable_v<std::inplace_vector<N<true, true>, 2>>);
> +static_assert(!std::is_nothrow_copy_assignable_v<std::inplace_vector<N<true, false>, 2>>);
> +static_assert(!std::is_nothrow_copy_assignable_v<std::inplace_vector<N<false, true>, 2>>);
> +static_assert(!std::is_nothrow_copy_assignable_v<std::inplace_vector<N<false, false>, 2>>);
> +static_assert(std::is_nothrow_copy_assignable_v<std::inplace_vector<D, 2>>);
> +static_assert(!std::is_nothrow_copy_assignable_v<std::inplace_vector<U, 2>>);
> +
> +// conditional noexcept here is libstdc++ extension,
> +static_assert(std::is_trivially_copy_assignable_v<std::inplace_vector<int, 2>>);
> +static_assert(!std::is_trivially_copy_assignable_v<std::inplace_vector<X, 2>>);
> +static_assert(!std::is_trivially_copy_assignable_v<std::inplace_vector<N<true, true>, 2>>);
> +// destructor is not trivial
> +static_assert(!std::is_trivially_copy_assignable_v<std::inplace_vector<D, 2>>);
> +static_assert(std::is_trivially_copy_assignable_v<std::inplace_vector<U, 2>>);
> +
> +static_assert(std::is_nothrow_copy_constructible_v<std::inplace_vector<int, 0>>);
> +static_assert(std::is_nothrow_copy_constructible_v<std::inplace_vector<X, 0>>);
> +static_assert(std::is_nothrow_copy_constructible_v<std::inplace_vector<N<false, false>, 0>>);
> +static_assert(std::is_nothrow_copy_constructible_v<std::inplace_vector<D, 0>>);
> +static_assert(std::is_nothrow_copy_constructible_v<std::inplace_vector<U, 0>>);
> +static_assert(std::is_nothrow_copy_constructible_v<std::inplace_vector<Z, 0>>);
> +
> +static_assert(std::is_trivially_copy_constructible_v<std::inplace_vector<int, 0>>);
> +static_assert(std::is_trivially_copy_constructible_v<std::inplace_vector<X, 0>>);
> +static_assert(std::is_trivially_copy_constructible_v<std::inplace_vector<D, 0>>);
> +static_assert(std::is_trivially_copy_constructible_v<std::inplace_vector<U, 0>>);
> +static_assert(std::is_trivially_copy_constructible_v<std::inplace_vector<Z, 0>>);
> +
> +static_assert(std::is_nothrow_copy_assignable_v<std::inplace_vector<int, 0>>);
> +static_assert(std::is_nothrow_copy_assignable_v<std::inplace_vector<X, 0>>);
> +static_assert(std::is_nothrow_copy_assignable_v<std::inplace_vector<N<false, false>, 0>>);
> +static_assert(std::is_nothrow_copy_assignable_v<std::inplace_vector<D, 0>>);
> +static_assert(std::is_nothrow_copy_assignable_v<std::inplace_vector<U, 0>>);
> +static_assert(std::is_nothrow_copy_assignable_v<std::inplace_vector<Z, 0>>);
> +
> +static_assert(std::is_trivially_copy_assignable_v<std::inplace_vector<int, 0>>);
> +static_assert(std::is_trivially_copy_assignable_v<std::inplace_vector<X, 0>>);
> +static_assert(std::is_trivially_copy_assignable_v<std::inplace_vector<N<false, false>, 0>>);
> +static_assert(std::is_trivially_copy_assignable_v<std::inplace_vector<D, 0>>);
> +static_assert(std::is_trivially_copy_assignable_v<std::inplace_vector<U, 0>>);
> +static_assert(std::is_trivially_copy_assignable_v<std::inplace_vector<Z, 0>>);
> +
> +
> +template<typename T, size_t N>
> +constexpr bool
> +eq(const std::inplace_vector<T, N>& s, std::span<const T> o)
> +{ return std::ranges::equal(s, o); }
> +
> +constexpr void
> +test_ctor()
> +{
> + auto e0 = materialize<0, int>({});
> + VERIFY( e0.empty() );
> + auto e1 = materialize<0, X>({});
> + VERIFY( e1.empty() );
> + auto e2 = materialize<0, Z>({});
> + VERIFY( e2.empty() );
> +
> + auto c0 = materialize<5, int>({});
> + VERIFY( c0.empty() );
> +
> + auto c3 = materialize<5, int>({1, 2, 3});
> + VERIFY( eq(c3, {1, 2, 3}) );
> +
> + auto c5 = materialize<5, int>({1, 2, 3, 4, 5});
> + VERIFY( eq(c5, {1, 2, 3, 4, 5}) );
> +
> +#ifdef __cpp_lib_constexpr_inplace_vector
> +#error remove the consteval check
> +#endif
> + if consteval {
> + return;
> + }
> +
> + auto x0 = materialize<3, X>({});
> + VERIFY( x0.empty() );
> +
> + auto x2 = materialize<3, X>({1, 2});
> + VERIFY( eq(x2, {1, 2}) );
> +
> + auto x3 = materialize<3, X>({1, 2, 3});
> + VERIFY( eq(x3, {1, 2, 3}) );
> +}
> +
> +constexpr void
> +test_assign()
> +{
> + std::inplace_vector<int, 0> e0;
> + e0 = materialize<0, int>({});
> + VERIFY( e0.empty() );
> + std::inplace_vector<X, 0> e1;
> + e1 = materialize<0, X>({});
> + VERIFY( e1.empty() );
> + std::inplace_vector<Z, 0> e2;
> + e2 = materialize<0, Z>({});
> + VERIFY( e2.empty() );
> +
> + std::inplace_vector<int, 5> c;
> + c = materialize<5, int>({});
> + VERIFY( c.empty() );
> +
> + c = materialize<5, int>({1, 2, 3});
> + VERIFY( eq(c, {1, 2, 3}) );
> +
> + c = materialize<5, int>({1, 2, 3, 4, 5});
> + VERIFY( eq(c, {1, 2, 3, 4, 5}) );
> +
> + c = materialize<5, int>({4, 5});
> + VERIFY( eq(c, {4, 5}) );
> +
> + c = materialize<5, int>({});
> + VERIFY( c.empty() );
> +
> +#ifdef __cpp_lib_constexpr_inplace_vector
> +#error remove the consteval check
> +#endif
> + if consteval {
> + return;
> + }
> +
> + std::inplace_vector<X, 5> x;
> + x = materialize<5, X>({});
> + VERIFY( x.empty() );
> +
> + x = materialize<5, X>({1, 2, 3});
> + VERIFY( eq(x, {1, 2, 3}) );
> +
> + x = materialize<5, X>({1, 2, 3, 4, 5});
> + VERIFY( eq(x, {1, 2, 3, 4, 5}) );
> +
> + x = materialize<5, X>({4, 5});
> + VERIFY( eq(x, {4, 5}) );
> +
> + x = materialize<5, X>({});
> + VERIFY( x.empty() );
> +}
> +
> +constexpr auto e0 = materialize<0, int>({});
> +constexpr auto e1 = materialize<0, X>({});
> +constexpr auto e2 = materialize<0, Z>({});
> +
> +constexpr auto t1 = materialize<3, int>({});
> +constexpr auto t2 = materialize<3, int>({1, 2});
> +constexpr auto t3 = materialize<3, int>({11, 22, 33});
> +
> +int main()
> +{
> + auto tests = [] {
> + test_ctor();
> + test_assign();
> + return true;
> + };
> +
> + tests();
> + constexpr bool _ = tests();
> +}
> diff --git a/libstdc++-v3/testsuite/23_containers/inplace_vector/erasure.cc b/libstdc++-v3/testsuite/23_containers/inplace_vector/erasure.cc
> new file mode 100644
> index 00000000000..c7fda097896
> --- /dev/null
> +++ b/libstdc++-v3/testsuite/23_containers/inplace_vector/erasure.cc
> @@ -0,0 +1,49 @@
> +// { dg-do run { target c++26 } }
> +
> +#include <inplace_vector>
> +#include <testsuite_hooks.h>
> +
> +constexpr void
> +test_erase()
> +{
> + std::inplace_vector<int, 15> c{1, 2, 3, 4, 5, 6, 5, 4, 3, 2, 1, 4, 4, 9};
> + std::erase(c, 4);
> + VERIFY( c.size() == 10 );
> + std::erase(c, 1);
> + VERIFY( c.size() == 8 );
> + std::erase(c, 9);
> + VERIFY( c.size() == 7 );
> + VERIFY( (c == std::inplace_vector<int, 15>{2, 3, 5, 6, 5, 3, 2}) );
> +
> + std::inplace_vector<int, 0> e;
> + std::erase(e, 10);
> + VERIFY( e.empty() );
> +}
> +
> +constexpr void
> +test_erase_if()
> +{
> + std::inplace_vector<int, 15> c{1, 2, 3, 4, 5, 6, 5, 4, 3, 2, 1, 4, 4, 9};
> + std::erase_if(c, [](int i) { return i > 5; });
> + VERIFY( c.size() == 12 );
> + std::erase_if(c, [](int i) { return i == 4; });
> + VERIFY( c.size() == 8 );
> + std::erase_if(c, [](int i) { return i & 1; });
> + VERIFY( (c == std::inplace_vector<int, 15>{2, 2}) );
> +
> + std::inplace_vector<int, 0> e;
> + std::erase_if(e, [](int i) { return i > 5; });
> + VERIFY( e.empty() );
> +}
> +
> +int main()
> +{
> + test_erase();
> + test_erase_if();
> +
> + constexpr bool _ = [] {
> + test_erase();
> + test_erase_if();
> + return true;
> + }();
> +}
> diff --git a/libstdc++-v3/testsuite/23_containers/inplace_vector/modifiers/assign.cc b/libstdc++-v3/testsuite/23_containers/inplace_vector/modifiers/assign.cc
> new file mode 100644
> index 00000000000..91132be550e
> --- /dev/null
> +++ b/libstdc++-v3/testsuite/23_containers/inplace_vector/modifiers/assign.cc
> @@ -0,0 +1,386 @@
> +// { dg-do run { target c++26 } }
> +
> +#include <inplace_vector>
> +
> +#include <span>
> +#include <testsuite_hooks.h>
> +#include <testsuite_iterators.h>
> +
> +struct X
> +{
> + X() = default;
> + constexpr X(int p) : v(p) {}
> + constexpr X(const X& o) : v(o.v) { } // not trivial
> + constexpr X& operator=(const X& o) // not trivial
> + { v = o.v; return *this; }
> +
> + int v;
> +
> + friend auto operator<=>(const X&, const X&) = default;
> +};
> +
> +template<typename T, typename V, size_t N>
> +constexpr bool
> +eq(const std::inplace_vector<V, N>& l, std::span<const T> r) {
> + if (l.size() != r.size())
> + return false;
> + for (auto i = 0u; i < l.size(); ++i)
> + if (l[i] != r[i])
> + return false;
> + return true;
> +};
> +
> +template<size_t N, typename T, template<class TT> class ItType>
> +constexpr void
> +test_assign_empty_it()
> +{
> + using namespace __gnu_test;
> +
> + T a[]{1,2,3,4,5,6,7,8,9,10};
> + using It = ItType<T>;
> + using Range = test_range<T, ItType>;
> + using SizedRange = test_sized_range<T, ItType>;
> +
> + const std::inplace_vector<T, N> src(std::from_range, std::span(a, N));
> + std::inplace_vector<T, N> v;
> +
> + v = src;
> + v.assign_range(Range(a, a));
> + VERIFY( v.empty() );
> + v.assign_range(Range(a, a));
> + VERIFY( v.empty() );
> +
> + v = src;
> + v.assign_range(SizedRange(a, a));
> + VERIFY( v.empty() );
> +
> + v = src;
> + auto bounds = typename It::ContainerType(a, a+9);
> + v.assign(It(a, &bounds), It(a, &bounds));
> + VERIFY( v.empty() );
> +
> +#ifdef __cpp_exceptions
> +#ifdef __cpp_lib_constexpr_exceptions
> +#error remove the consteval check
> +#endif
> + if consteval {
> + return;
> + }
> +
> + static_assert(N < 9);
> +
> + v = src;
> + try
> + {
> + v.assign_range(Range(a, a+9));
> + VERIFY(false);
> + }
> + catch (std::bad_alloc const&)
> + {
> + }
> + if constexpr (std::ranges::sized_range<Range> || std::ranges::forward_range<Range>)
> + VERIFY( eq<T>(v, {a, N}) );
> +
> + v = src;
> + try
> + {
> + v.assign_range(SizedRange(a, a+9));
> + VERIFY(false);
> + }
> + catch (std::bad_alloc const&)
> + {
> + }
> + VERIFY( eq<T>(v, {a, N}) );
> +
> + v = src;
> + bounds = typename It::ContainerType(a, a+9);
> + try
> + {
> + v.assign(It(a, &bounds), It(a+9, &bounds));
> + VERIFY(false);
> + }
> + catch (std::bad_alloc const&)
> + {
> + }
> + if constexpr(std::forward_iterator<It>)
> + VERIFY( eq<T>(v, {a, N}) );
> +#endif
> +}
> +
> +template<size_t N, typename T>
> +constexpr void
> +test_assign_empty_other()
> +{
> + T a[]{1,2,3,4,5,6,7,8,9,10};
> + const std::inplace_vector<T, N> src(std::from_range, std::span(a, N));
> + std::inplace_vector<T, N> v;
> +
> + v = src;
> + v.assign(0, T(4));
> + VERIFY( v.empty() );
> +
> + v = src;
> + v.assign({});
> + VERIFY( v.empty() );
> +
> + v = src;
> + v = {};
> + VERIFY( v.empty() );
> +
> + v = src;
> + v.resize(0, T(3));
> + VERIFY( v.empty() );
> +
> + v = src;
> + v.resize(0);
> + VERIFY( v.empty() );
> +
> +#ifdef __cpp_exceptions
> +#ifdef __cpp_lib_constexpr_exceptions
> +#error remove the consteval check
> +#endif
> + if consteval {
> + return;
> + }
> +
> + static_assert(N < 9);
> +
> + v = src;
> + try
> + {
> + v.assign(9, T(4));
> + VERIFY(false);
> + }
> + catch (std::bad_alloc const&)
> + {
> + }
> + VERIFY( eq<T>(v, {a, N}) );
> +
> + std::initializer_list<T> il =
> + {T(0), T(1), T(2), T(3), T(4), T(5), T(6), T(7), T(8), T(9), T(10)};
> + try
> + {
> + v.assign(il);
> + VERIFY(false);
> + }
> + catch (std::bad_alloc const&)
> + {
> + }
> + VERIFY( eq<T>(v, {a, N}) );
> +
> + try
> + {
> + v = il;
> + VERIFY(false);
> + }
> + catch (std::bad_alloc const&)
> + {
> + }
> + VERIFY( eq<T>(v, {a, N}) );
> +
> + try
> + {
> + v.resize(9, T(3));
> + VERIFY(false);
> + }
> + catch (std::bad_alloc const&)
> + {
> + }
> + VERIFY( eq<T>(v, {a, N}) );
> +
> + try
> + {
> + v.resize(9);
> + VERIFY(false);
> + }
> + catch (std::bad_alloc const&)
> + {
> + }
> + VERIFY( eq<T>(v, {a, N}) );
> +#endif
> +}
> +
> +template<size_t N, typename T>
> +constexpr void
> +test_assign_empty()
> +{
> + // TODO make test iterators consteval
> + if !consteval
> + {
> + using namespace __gnu_test;
> + test_assign_empty_it<N, T, input_iterator_wrapper>();
> + test_assign_empty_it<N, T, forward_iterator_wrapper>();
> + test_assign_empty_it<N, T, random_access_iterator_wrapper>();
> + }
> +
> + test_assign_empty_other<N, T>;
> +}
> +
> +template<typename Range>
> +constexpr void
> +test_assign_range()
> +{
> + using T = std::ranges::range_value_t<Range>;
> + T a[]{1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
> +
> + std::inplace_vector<T, 10> v;
> + v.assign_range(Range(a,a+5));
> + VERIFY( eq<T>(v, {a, 5}) );
> +
> + v.assign_range(Range(a,a+7));
> + VERIFY( eq<T>(v, {a, 7}) );
> +
> + v.assign_range(Range(a,a+3));
> + VERIFY( eq<T>(v, {a, 3}) );
> +
> + v.assign_range(Range(a,a+10));
> + VERIFY( eq<T>(v, {a, 10}) );
> +}
> +
> +template<typename T, template<class TT> class ItType>
> +constexpr void
> +test_assign_iterators()
> +{
> + T a[]{1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
> + using It = ItType<T>;
> +
> + std::inplace_vector<T, 10> v;
> +
> + auto bounds = typename It::ContainerType(a, a+15);
> + v.assign(It(a, &bounds), It(a+5, &bounds));
> + VERIFY( eq<T>(v, {a, 5}) );
> +
> + bounds = typename It::ContainerType(a, a+15);
> + v.assign(It(a, &bounds), It(a+7, &bounds));
> + VERIFY( eq<T>(v, {a, 7}) );
> +
> + bounds = typename It::ContainerType(a, a+15);
> + v.assign(It(a, &bounds), It(a+3, &bounds));
> + VERIFY( eq<T>(v, {a, 3}) );
> +
> + bounds = typename It::ContainerType(a, a+15);
> + v.assign(It(a, &bounds), It(a+10, &bounds));
> + VERIFY( eq<T>(v, {a, 10}) );
> +}
> +
> +template<typename T>
> +constexpr void
> +test_assign_initializer_list()
> +{
> + T a[]{1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
> +
> + std::inplace_vector<T, 10> v;
> +
> + v.assign({T(1), T(2), T(3), T(4), T(5)});
> + VERIFY( eq<T>(v, {a, 5}) );
> +
> + v = {T(1), T(2), T(3), T(4), T(5), T(6), T(7)};
> + VERIFY( eq<T>(v, {a, 7}) );
> +
> + v.assign({T(1), T(2), T(3)});
> + VERIFY( eq<T>(v, {a, 3}) );
> +
> + v = {T(1), T(2), T(3), T(4), T(5), T(6), T(7), T(8), T(9), T(10)};
> + VERIFY( eq<T>(v, {a, 10}) );
> +}
> +
> +template<typename T>
> +constexpr void
> +test_assign_repeated()
> +{
> + auto rep = [](const std::inplace_vector<T, 10>& v, size_t c, const T& t)
> + {
> + if (v.size() != c)
> + return false;
> + for (const T& o : v)
> + if (o != t)
> + return false;
> + return true;
> + };
> +
> + std::inplace_vector<T, 10> v;
> +
> + v.assign(5, T(1));
> + VERIFY( rep(v, 5, T(1)) );
> +
> + v.assign(7, T(2));
> + VERIFY( rep(v, 7, T(2)) );
> +
> + v.assign(3, T(4));
> + VERIFY( rep(v, 3, T(4)) );
> +
> + v.assign(10, T(8));
> + VERIFY( rep(v, 10, T(8)) );
> +}
> +
> +template<typename T>
> +constexpr void
> +test_resize()
> +{
> + T a[]{1,1,1,1,2,2,2,0,0,0};
> +
> + std::inplace_vector<T, 10> v;
> +
> + v.resize(4, T(1));
> + VERIFY( eq<T>(v, {a, 4}) );
> +
> + v.resize(7, T(2));
> + VERIFY( eq<T>(v, {a, 7}) );
> +
> + v.resize(10);
> + VERIFY( eq<T>(v, {a, 10}) );
> +
> + v.resize(6, T(1));
> + VERIFY( eq<T>(v, {a, 6}) );
> +}
> +
> +template<typename T>
> +constexpr void
> +test_assigns()
> +{
> + using namespace __gnu_test;
> + // TODO make test iterators consteval
> + if !consteval {
> + test_assign_range<test_forward_range<int>>();
> + test_assign_range<test_sized_range_sized_sent<int, forward_iterator_wrapper>>();
> +
> + test_assign_range<test_input_range<int>>();
> + test_assign_range<test_input_sized_range<int>>();
> + test_assign_range<test_sized_range_sized_sent<int, input_iterator_wrapper>>();
> +
> + test_assign_range<test_range<int, input_iterator_wrapper_nocopy>>();
> + test_assign_range<test_sized_range<int, input_iterator_wrapper_nocopy>>();
> + test_assign_range<test_sized_range_sized_sent<int, input_iterator_wrapper_nocopy>>();
> +
> + test_assign_iterators<T, input_iterator_wrapper>();
> + test_assign_iterators<T, forward_iterator_wrapper>();
> + test_assign_iterators<T, random_access_iterator_wrapper>();
> + }
> +
> + test_assign_initializer_list<T>();
> + test_assign_repeated<T>();
> + test_resize<T>();
> +}
> +
> +int main()
> +{
> + auto test_all = [] {
> + test_assign_empty<0, int>();
> + test_assign_empty<0, X>();
> + test_assign_empty<2, int>();
> +
> + test_assigns<int>();
> +#ifdef __cpp_lib_constexpr_inplace_vector
> +#error uncomemnt test_inserts<X>()
> +#endif
> + if !consteval {
> + test_assign_empty<2, X>();
> + test_assigns<X>();
> + }
> + return true;
> + };
> +
> +
> + test_all();
> + static_assert(test_all());
> +}
> diff --git a/libstdc++-v3/testsuite/23_containers/inplace_vector/modifiers/erase.cc b/libstdc++-v3/testsuite/23_containers/inplace_vector/modifiers/erase.cc
> new file mode 100644
> index 00000000000..8b82ab4189c
> --- /dev/null
> +++ b/libstdc++-v3/testsuite/23_containers/inplace_vector/modifiers/erase.cc
> @@ -0,0 +1,117 @@
> +// { dg-do run { target c++26 } }
> +
> +#include <inplace_vector>
> +
> +#include <span>
> +#include <testsuite_hooks.h>
> +
> +struct X
> +{
> + X() = default;
> + constexpr X(int p) : v(p) {}
> + constexpr X(const X& o) : v(o.v) { } // not trivial
> + constexpr X& operator=(const X& o) // not trivial
> + { v = o.v; return *this; }
> +
> + int v;
> +
> + friend auto operator<=>(const X&, const X&) = default;
> +};
> +
> +template<typename T, typename V, size_t N>
> +constexpr bool
> +eq(const std::inplace_vector<V, N>& l, std::span<const T> r) {
> + if (l.size() != r.size())
> + return false;
> + for (auto i = 0u; i < l.size(); ++i)
> + if (l[i] != r[i])
> + return false;
> + return true;
> +};
> +
> +template<typename T, typename V, size_t N>
> +constexpr bool
> +eq(const std::inplace_vector<V, N>& l, std::initializer_list<T> r)
> +{ return eq<T>(l, std::span<const T>(r)); }
> +
> +template<size_t N, typename T>
> +constexpr void
> +test_erase_all_or_none()
> +{
> + using namespace __gnu_test;
> +
> + T a[]{1,2,3,4,5,6,7,8,9};
> + const T c(10);
> +
> + std::inplace_vector<T, N> src(std::from_range, std::span(a, a+N));
> + std::inplace_vector<T, N> v;
> +
> + v = src;
> + auto it = v.erase(v.begin(), v.begin());
> + VERIFY( it == v.begin() );
> + VERIFY( eq<T>(v, {a, N}) );
> +
> + it = v.erase(v.end(), v.end());
> + VERIFY( it == v.end() );
> + VERIFY( eq<T>(v, {a, N}) );
> +
> + it = v.erase(v.begin(), v.end());
> + VERIFY( it == v.begin() );
> + VERIFY( v.empty() );
> +
> + v = src;
> + v.clear();
> + VERIFY( v.empty() );
> +}
> +
> +template<typename T>
> +constexpr void
> +test_erase()
> +{
> + std::inplace_vector<T, 10> v{T(1), T(2), T(3), T(4), T(5), T(6), T(7)};
> +
> + auto it = v.erase(v.begin());
> + VERIFY( eq<T>(v, {T(2), T(3), T(4), T(5), T(6), T(7)}) );
> + VERIFY( it == v.begin() );
> +
> + it = v.erase(v.end()-1);
> + VERIFY( eq<T>(v, {T(2), T(3), T(4), T(5), T(6)}) );
> + VERIFY( it == v.end() );
> +
> + it = v.erase(v.begin()+2, v.begin()+4);
> + VERIFY( eq<T>(v, {T(2), T(3), T(6)}) );
> + VERIFY( it == v.begin()+2 );
> +
> + it = v.erase(v.end()-1, v.end());
> + VERIFY( eq<T>(v, {T(2), T(3)}) );
> + VERIFY( it == v.end() );
> +
> + it = v.erase(v.begin(), v.begin()+1);
> + VERIFY( eq<T>(v, {T(3)}) );
> + VERIFY( it == v.begin() );
> +
> + v.pop_back();
> + VERIFY( v.empty() );
> +}
> +
> +int main()
> +{
> + auto test_all = [] {
> + test_erase_all_or_none<0, int>();
> + test_erase_all_or_none<0, X>();
> +
> + test_erase_all_or_none<4, int>();
> +
> + test_erase<int>();
> +#ifdef __cpp_lib_constexpr_inplace_vector
> +#error uncomemnt test_inserts<X>()
> +#endif
> + if ! consteval {
> + test_erase_all_or_none<4, X>();
> + }
> + return true;
> + };
> +
> + test_all();
> + static_assert(test_all());;
> +}
> diff --git a/libstdc++-v3/testsuite/23_containers/inplace_vector/modifiers/multi_insert.cc b/libstdc++-v3/testsuite/23_containers/inplace_vector/modifiers/multi_insert.cc
> new file mode 100644
> index 00000000000..072f0b3e095
> --- /dev/null
> +++ b/libstdc++-v3/testsuite/23_containers/inplace_vector/modifiers/multi_insert.cc
> @@ -0,0 +1,611 @@
> +// { dg-do run { target c++26 } }
> +
> +#include <inplace_vector>
> +
> +#include <span>
> +#include <testsuite_hooks.h>
> +#include <testsuite_iterators.h>
> +
> +struct X
> +{
> + X() = default;
> + constexpr X(int p) : v(p) {}
> + constexpr X(const X& o) : v(o.v) { } // not trivial
> + constexpr X& operator=(const X& o) // not trivial
> + { v = o.v; return *this; }
> +
> + int v;
> +
> + friend auto operator<=>(const X&, const X&) = default;
> +};
> +
> +template<typename T, typename V, size_t N>
> +constexpr bool
> +eq(const std::inplace_vector<V, N>& l, std::span<const T> r) {
> + if (l.size() != r.size())
> + return false;
> + for (auto i = 0u; i < l.size(); ++i)
> + if (l[i] != r[i])
> + return false;
> + return true;
> +};
> +
> +template<typename T, typename V, size_t N>
> +constexpr bool
> +prefix(const std::inplace_vector<V, N>& l, std::span<const T> r) {
> + if (l.size() < r.size())
> + return false;
> + for (auto i = 0u; i < r.size(); ++i)
> + if (l[i] != r[i])
> + return false;
> + return true;
> +};
> +
> +template<size_t N, typename T, template<class TT> class ItType>
> +constexpr void
> +test_add_to_full_it()
> +{
> + using namespace __gnu_test;
> +
> + T a[]{1,2,3,4,5,6,7,8,9};
> + using It = ItType<T>;
> + using Range = test_range<T, ItType>;
> + using SizedRange = test_sized_range<T, ItType>;
> +
> + std::inplace_vector<T, N> v(std::from_range, std::span(a, a+N));
> +
> + Range r1(a, a);
> + auto rit1 = v.try_append_range(r1);
> + VERIFY( eq<T>(v, {a, N}) );
> + VERIFY( rit1.base() == a );
> +
> + SizedRange r2(a, a);
> + auto rit2 = v.try_append_range(r2);
> + VERIFY( eq<T>(v, {a, N}) );
> + VERIFY( rit2.base() == a );
> +
> + v.append_range(Range(a, a));
> + VERIFY( eq<T>(v, {a, N}) );
> + v.append_range(SizedRange(a, a));
> + VERIFY( eq<T>(v, {a, N}) );
> +
> + auto it = v.insert_range(v.end(), Range(a, a));
> + VERIFY( eq<T>(v, {a, N}) );
> + VERIFY( it == v.end() );
> + it = v.insert_range(v.end(), SizedRange(a, a));
> + VERIFY( eq<T>(v, {a, N}) );
> + VERIFY( it == v.end() );
> +
> + auto bounds = typename It::ContainerType(a, a+9);
> + it = v.insert(v.end(), It(a, &bounds), It(a, &bounds));
> + VERIFY( eq<T>(v, {a, N}) );
> + VERIFY( it == v.end() );
> +
> + it = v.insert_range(v.begin(), SizedRange(a, a));
> + VERIFY( eq<T>(v, {a, N}) );
> + VERIFY( it == v.begin() );
> + it = v.insert_range(v.begin(), Range(a, a));
> + VERIFY( eq<T>(v, {a, N}) );
> + VERIFY( it == v.begin() );
> +
> + bounds = typename It::ContainerType(a, a+9);
> + it = v.insert(v.begin(), It(a, &bounds), It(a, &bounds));
> + VERIFY( eq<T>(v, {a, N}) );
> + VERIFY( it == v.begin() );
> +
> + // Inserting non-empty range
> + Range r3(a+3, a+5);
> + auto rit3 = v.try_append_range(r3);
> + VERIFY( eq<T>(v, {a, N}) );
> + VERIFY( rit3.base() == a+3 );
> +
> + SizedRange r4(a+2, a+5);
> + auto rit4 = v.try_append_range(r4);
> + VERIFY( eq<T>(v, {a, N}) );
> + VERIFY( rit4.base() == a+2 );
> +
> +#ifdef __cpp_exceptions
> +#ifdef __cpp_lib_constexpr_exceptions
> +#error remove the consteval check
> +#endif
> + if consteval {
> + return;
> + }
> +
> + try
> + {
> + v.append_range(Range(a, a + 5));
> + VERIFY(false);
> + }
> + catch (std::bad_alloc const&)
> + {
> + }
> + VERIFY( eq<T>(v, {a, N}) );
> +
> + try
> + {
> + v.append_range(SizedRange(a, a + 5));
> + VERIFY(false);
> + }
> + catch (std::bad_alloc const&)
> + {
> + }
> + VERIFY( eq<T>(v, {a, N}) );
> +
> + try
> + {
> + v.insert_range(v.begin(), SizedRange(a, a+5));
> + VERIFY(false);
> + }
> + catch (std::bad_alloc const&)
> + {
> + }
> + VERIFY( eq<T>(v, {a, N}) );
> +
> + try
> + {
> + v.insert_range(v.begin(), Range(a, a+5));
> + VERIFY(false);
> + }
> + catch (std::bad_alloc const&)
> + {
> + }
> + auto gn = std::ranges::sized_range<Range> || std::ranges::forward_range<Range> ? N : 0;
> + VERIFY( prefix<T>(v, {a, gn}) );
> +
> + v = std::inplace_vector<T, N>(std::from_range, std::span(a, a+N));
> + try
> + {
> + v.insert_range(v.begin(), Range(a, a+5));
> + VERIFY(false);
> + }
> + catch (std::bad_alloc const&)
> + {
> + }
> + gn = std::forward_iterator<It> ? N : 0;
> + VERIFY( prefix<T>(v, {a, gn}) );
> +#endif
> +}
> +
> +template<size_t N, typename T>
> +constexpr void
> +test_add_to_full_other()
> +{
> + using namespace __gnu_test;
> +
> + T a[]{1,2,3,4,5,6,7,8,9};
> + std::inplace_vector<T, N> v(std::from_range, std::span(a, a+N));
> +
> + auto it = v.insert(v.end(), {});
> + VERIFY( eq<T>(v, {a, N}) );
> + VERIFY( it == v.end() );
> + it = v.insert(v.end(), 0u, T(2));
> + VERIFY( eq<T>(v, {a, N}) );
> + VERIFY( it == v.end() );
> +
> + it = v.insert(v.begin(), {});
> + VERIFY( eq<T>(v, {a, N}) );
> + VERIFY( it == v.begin() );
> + it = v.insert(v.begin(), 0u, T(2));
> + VERIFY( eq<T>(v, {a, N}) );
> + VERIFY( it == v.begin() );
> +
> +#ifdef __cpp_exceptions
> +#ifdef __cpp_lib_constexpr_exceptions
> +#error remove the consteval check
> +#endif
> + if consteval {
> + return;
> + }
> +
> + v = std::inplace_vector<T, N>(std::from_range, std::span(a, a+N));
> + try
> + {
> + v.insert(v.begin(), {T(1), T(2), T(3)});
> + VERIFY(false);
> + }
> + catch (std::bad_alloc const&)
> + {
> + }
> + VERIFY( eq<T>(v, {a, N}) );
> +
> + try
> + {
> + v.insert(v.begin(), 4u, T(3));
> + VERIFY(false);
> + }
> + catch (std::bad_alloc const&)
> + {
> + }
> + VERIFY( eq<T>(v, {a, N}) );
> +#endif
> +}
> +
> +
> +template<size_t N, typename T>
> +constexpr void
> +test_add_to_full()
> +{
> + using namespace __gnu_test;
> + // TODO make test iterators consteval
> + if !consteval {
> + test_add_to_full_it<N, T, input_iterator_wrapper>();
> + test_add_to_full_it<N, T, forward_iterator_wrapper>();
> + test_add_to_full_it<N, T, random_access_iterator_wrapper>();
> + }
> + test_add_to_full_other<N, T>();
> +}
> +
> +template<typename Range>
> +constexpr void
> +test_append_range()
> +{
> + using T = std::ranges::range_value_t<Range>;
> + T a[]{1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
> +
> + std::inplace_vector<T, 20> v;
> + v.append_range(Range(a,a+10));
> + VERIFY( eq<T>(v, {a, 10}) );
> +
> + v.append_range(Range(a+10, a+15));
> + VERIFY( eq<T>(v, {a, 15}) );
> +
> +#ifdef __cpp_exceptions
> +#ifdef __cpp_lib_constexpr_exceptions
> +#error remove the consteval check
> +#endif
> + if consteval {
> + return;
> + }
> +
> + try
> + {
> + v.append_range(Range(a, a+10));
> + VERIFY(false);
> + }
> + catch (std::bad_alloc const&)
> + {
> + }
> + VERIFY( prefix<T>(v, {a, 15}) );
> +#endif
> +}
> +
> +template<typename Range>
> +constexpr void
> +test_try_append_range()
> +{
> + using T = std::ranges::range_value_t<Range>;
> + T a[]{1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25};
> +
> + std::inplace_vector<T, 20> v;
> + Range r1 = Range(a, a+10);
> + auto it1 = v.try_append_range(r1);
> + VERIFY( eq<T>(v, {a, 10}) );
> + VERIFY( it1.base() == a+10 );
> +
> + Range r2 = Range(a+10, a+15);
> + auto it2 = v.try_append_range(r2);
> + VERIFY( eq<T>(v, {a, 15}) );
> + VERIFY( it2.base() == a+15 );
> +
> + Range r3 = Range(a+15, a+25);
> + auto it3 = v.try_append_range(r3);
> + VERIFY( eq<T>(v, {a, 20}) );
> + VERIFY( it3.base() == a+20 );
> +}
> +
> +template<typename Range>
> +constexpr void
> +test_insert_range()
> +{
> + using T = std::ranges::range_value_t<Range>;
> + T a[]{1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
> +
> + std::inplace_vector<T, 20> v;
> + auto it = v.insert_range(v.begin(), Range(a+10,a+15));
> + VERIFY( eq<T>(v, {a+10, 5}) );
> + VERIFY( it == v.begin() );
> +
> + it = v.insert_range(v.begin(), Range(a, a+5));
> + VERIFY( prefix<T>(v, {a, 5}) );
> + VERIFY( it == v.begin() );
> +
> + it = v.insert_range(v.begin() + 5, Range(a+5, a+10));
> + VERIFY( eq<T>(v, {a, 15}) );
> + VERIFY( it == v.begin() + 5 );
> +
> +#ifdef __cpp_exceptions
> +#ifdef __cpp_lib_constexpr_exceptions
> +#error remove the consteval check
> +#endif
> + if consteval {
> + return;
> + }
> +
> + const bool seg = std::ranges::sized_range<Range> || std::ranges::forward_range<Range>;
> + auto vc = v;
> + try
> + {
> + vc.insert_range(vc.begin(), Range(a, a+10));
> + VERIFY(false);
> + }
> + catch (std::bad_alloc const&)
> + {
> + }
> + VERIFY( prefix<T>(vc, {a, seg ? 15 : 0}) );
> +
> + vc = v;
> + try
> + {
> + vc.insert_range(vc.begin()+5, Range(a, a+10));
> + VERIFY(false);
> + }
> + catch (std::bad_alloc const&)
> + {
> + }
> + VERIFY( prefix<T>(vc, {a, seg ? 15 : 5}) );
> +
> + vc = v;
> + try
> + {
> + vc.insert_range(vc.end(), Range(a, a+10));
> + VERIFY(false);
> + }
> + catch (std::bad_alloc const&)
> + {
> + }
> + VERIFY( prefix<T>(vc, {a, 15}) );
> +#endif
> +}
> +
> +template<typename Range>
> +constexpr void
> +do_test_ranges()
> +{
> + test_append_range<Range>();
> + test_try_append_range<Range>();
> + test_insert_range<Range>();
> +}
> +
> +template<typename T, template<class TT> class ItType>
> +constexpr void
> +test_insert_iterators()
> +{
> + T a[]{1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
> + using It = ItType<T>;
> +
> + std::inplace_vector<T, 20> v;
> +
> + auto bounds = typename It::ContainerType(a, a+15);
> + auto it = v.insert(v.begin(), It(a+10, &bounds), It(a+15, &bounds));
> + VERIFY( eq<T>(v, {a+10, 5}) );
> + VERIFY( it == v.begin() );
> +
> + bounds = typename It::ContainerType(a, a+15);
> + it = v.insert(v.begin(), It(a, &bounds), It(a+5, &bounds));
> + VERIFY( prefix<T>(v, {a, 5}) );
> + VERIFY( it == v.begin() );
> +
> + bounds = typename It::ContainerType(a, a+15);
> + it = v.insert(v.begin() + 5, It(a+5, &bounds), It(a+10, &bounds));
> + VERIFY( eq<T>(v, {a, 15}) );
> + VERIFY( it == v.begin() + 5 );
> +
> +#ifdef __cpp_exceptions
> +#ifdef __cpp_lib_constexpr_exceptions
> +#error remove the consteval check
> +#endif
> + if consteval {
> + return;
> + }
> +
> + const bool seg = std::forward_iterator<It>;
> + auto vc = v;
> + bounds = typename It::ContainerType(a, a+15);
> + try
> + {
> + vc.insert(vc.begin(), It(a, &bounds), It(a+10, &bounds));
> + VERIFY(false);
> + }
> + catch (std::bad_alloc const&)
> + {
> + }
> + VERIFY( prefix<T>(vc, {a, seg ? 15 : 0}) );
> +
> + vc = v;
> + bounds = typename It::ContainerType(a, a+15);
> + try
> + {
> + vc.insert(vc.begin()+5, It(a, &bounds), It(a+10, &bounds));
> + VERIFY(false);
> + }
> + catch (std::bad_alloc const&)
> + {
> + }
> + VERIFY( prefix<T>(vc, {a, seg ? 15 : 5}) );
> +
> + vc = v;
> + bounds = typename It::ContainerType(a, a+15);
> + try
> + {
> + vc.insert(vc.end(), It(a, &bounds), It(a+10, &bounds));
> + VERIFY(false);
> + }
> + catch (std::bad_alloc const&)
> + {
> + }
> + VERIFY( prefix<T>(vc, {a, 15}) );
> +#endif
> +}
> +
> +template<typename T>
> +constexpr void
> +test_insert_initializer_list()
> +{
> + T a[]{1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
> +
> + std::inplace_vector<T, 20> v;
> +
> + auto it = v.insert(v.begin(), {T(11), T(12), T(13), T(14), T(15)});
> + VERIFY( eq<T>(v, {a+10, 5}) );
> + VERIFY( it == v.begin() );
> +
> + it = v.insert(v.begin(), {T(1), T(2), T(3), T(4), T(5)});
> + VERIFY( prefix<T>(v, {a, 5}) );
> + VERIFY( it == v.begin() );
> +
> + it = v.insert(v.begin() + 5, {T(6), T(7), T(8), T(9), T(10)});
> + VERIFY( eq<T>(v, {a, 15}) );
> + VERIFY( it == v.begin() + 5 );
> +
> +#ifdef __cpp_exceptions
> +#ifdef __cpp_lib_constexpr_exceptions
> +#error remove the consteval check
> +#endif
> + if consteval {
> + return;
> + }
> +
> + std::initializer_list<T> il
> + = {T(0), T(1), T(2), T(3), T(4), T(5), T(6), T(7), T(8), T(9)};
> +
> + try
> + {
> + v.insert(v.begin(), il);
> + VERIFY(false);
> + }
> + catch (std::bad_alloc const&)
> + {
> + }
> + VERIFY( eq<T>(v, {a, 15}) );
> +
> + try
> + {
> + v.insert(v.begin()+5, il);
> + VERIFY(false);
> + }
> + catch (std::bad_alloc const&)
> + {
> + }
> + VERIFY( eq<T>(v, {a, 15}) );
> +
> + try
> + {
> + v.insert(v.end(), il);
> + VERIFY(false);
> + }
> + catch (std::bad_alloc const&)
> + {
> + }
> + VERIFY( eq<T>(v, {a, 15}) );
> +#endif
> +}
> +
> +template<typename T>
> +constexpr void
> +test_insert_repeated()
> +{
> + T a[]{5,5,5,5,5,6,6,6,6,6,7,7,7,7,7};
> +
> + std::inplace_vector<T, 20> v;
> +
> + auto it = v.insert(v.begin(), 5, T(7));
> + VERIFY( eq<T>(v, {a+10, 5}) );
> + VERIFY( it == v.begin() );
> +
> + it = v.insert(v.begin(), 5, T(5));
> + VERIFY( prefix<T>(v, {a, 5}) );
> + VERIFY( it == v.begin() );
> +
> + it = v.insert(v.begin() + 5, 5, T(6));
> + VERIFY( eq<T>(v, {a, 15}) );
> + VERIFY( it == v.begin() + 5 );
> +
> +#ifdef __cpp_exceptions
> +#ifdef __cpp_lib_constexpr_exceptions
> +#error remove the consteval check
> +#endif
> + if consteval {
> + return;
> + }
> +
> + try
> + {
> + v.insert(v.begin(), 10u, T(6));
> + VERIFY(false);
> + }
> + catch (std::bad_alloc const&)
> + {
> + }
> + VERIFY( eq<T>(v, {a, 15}) );
> +
> + try
> + {
> + v.insert(v.begin()+5, 10u, T(6));
> + VERIFY(false);
> + }
> + catch (std::bad_alloc const&)
> + {
> + }
> + VERIFY( eq<T>(v, {a, 15}) );
> +
> + try
> + {
> + v.insert(v.end(), 10u, T(6));
> + VERIFY(false);
> + }
> + catch (std::bad_alloc const&)
> + {
> + }
> + VERIFY( eq<T>(v, {a, 15}) );
> +#endif
> +}
> +
> +template<typename T>
> +constexpr void
> +test_inserts()
> +{
> + using namespace __gnu_test;
> + // TODO make test iterators consteval
> + if !consteval {
> + do_test_ranges<test_forward_range<int>>();
> + do_test_ranges<test_sized_range_sized_sent<int, forward_iterator_wrapper>>();
> +
> + do_test_ranges<test_input_range<int>>();
> + do_test_ranges<test_input_sized_range<int>>();
> + do_test_ranges<test_sized_range_sized_sent<int, input_iterator_wrapper>>();
> +
> + do_test_ranges<test_range<int, input_iterator_wrapper_nocopy>>();
> + do_test_ranges<test_sized_range<int, input_iterator_wrapper_nocopy>>();
> + do_test_ranges<test_sized_range_sized_sent<int, input_iterator_wrapper_nocopy>>();
> +
> + test_insert_iterators<T, input_iterator_wrapper>();
> + test_insert_iterators<T, forward_iterator_wrapper>();
> + test_insert_iterators<T, random_access_iterator_wrapper>();
> + }
> +
> + test_insert_initializer_list<T>();
> + test_insert_repeated<T>();
> +}
> +
> +int main()
> +{
> + auto test_all = []{
> + test_add_to_full<0, int>();
> + test_add_to_full<0, X>();
> + test_add_to_full<4, int>();
> +
> + test_inserts<int>();
> +#ifdef __cpp_lib_constexpr_inplace_vector
> +#error uncomemnt test_inserts<X>()
> +#endif
> + if !consteval {
> + test_add_to_full<4, X>();
> + test_inserts<X>();
> + }
> + return true;
> + };
> +
> + test_all();
> + static_assert(test_all());
> +}
> diff --git a/libstdc++-v3/testsuite/23_containers/inplace_vector/modifiers/single_insert.cc b/libstdc++-v3/testsuite/23_containers/inplace_vector/modifiers/single_insert.cc
> new file mode 100644
> index 00000000000..d5e893cc7f3
> --- /dev/null
> +++ b/libstdc++-v3/testsuite/23_containers/inplace_vector/modifiers/single_insert.cc
> @@ -0,0 +1,215 @@
> +// { dg-do run { target c++26 } }
> +
> +#include <inplace_vector>
> +
> +#include <span>
> +#include <testsuite_hooks.h>
> +
> +struct X
> +{
> + X() = default;
> + constexpr X(int p) : v(p) {}
> + constexpr X(const X& o) : v(o.v) { } // not trivial
> + constexpr X& operator=(const X& o) // not trivial
> + { v = o.v; return *this; }
> +
> + int v;
> +
> + friend auto operator<=>(const X&, const X&) = default;
> +};
> +
> +template<typename T, typename V, size_t N>
> +constexpr bool
> +eq(const std::inplace_vector<V, N>& l, std::span<const T> r) {
> + if (l.size() != r.size())
> + return false;
> + for (auto i = 0u; i < l.size(); ++i)
> + if (l[i] != r[i])
> + return false;
> + return true;
> +};
> +
> +template<size_t N, typename T>
> +constexpr void
> +test_add_to_full()
> +{
> + using namespace __gnu_test;
> +
> + T a[]{1,2,3,4,5,6,7,8,9};
> + const T c(10);
> +
> + std::inplace_vector<T, N> v(std::from_range, std::span(a, a+N));
> +
> + VERIFY( v.try_emplace_back(1) == nullptr );
> + VERIFY( eq<T>(v, {a, N}) );
> + VERIFY( v.try_push_back(T(1)) == nullptr );
> + VERIFY( eq<T>(v, {a, N}) );
> + VERIFY( v.try_push_back(c) == nullptr );
> + VERIFY( eq<T>(v, {a, N}) );
> +
> +#ifdef __cpp_exceptions
> +#ifdef __cpp_lib_constexpr_exceptions
> +#error remove the consteval check
> +#endif
> + if consteval {
> + return;
> + }
> +
> + try
> + {
> + v.emplace_back(1);
> + VERIFY(false);
> + }
> + catch (std::bad_alloc const&)
> + {
> + }
> + VERIFY( eq<T>(v, {a, N}) );
> +
> + try
> + {
> + v.push_back(T(1));
> + VERIFY(false);
> + }
> + catch (std::bad_alloc const&)
> + {
> + }
> + VERIFY( eq<T>(v, {a, N}) );
> +
> + try
> + {
> + v.push_back(c);
> + VERIFY(false);
> + }
> + catch (std::bad_alloc const&)
> + {
> + }
> + VERIFY( eq<T>(v, {a, N}) );
> +
> + try
> + {
> + v.insert(v.end(), T(1));
> + VERIFY(false);
> + }
> + catch (std::bad_alloc const&)
> + {
> + }
> + VERIFY( eq<T>(v, {a, N}) );
> +
> + try
> + {
> + v.insert(v.begin(), c);
> + VERIFY(false);
> + }
> + catch (std::bad_alloc const&)
> + {
> + }
> + VERIFY( eq<T>(v, {a, N}) );
> +
> + try
> + {
> + v.emplace(v.end(), c);
> + VERIFY(false);
> + }
> + catch (std::bad_alloc const&)
> + {
> + }
> + VERIFY( eq<T>(v, {a, N}) );
> +
> + try
> + {
> + v.emplace(v.begin(), T(2));
> + VERIFY(false);
> + }
> + catch (std::bad_alloc const&)
> + {
> + }
> + VERIFY( eq<T>(v, {a, N}) );
> +#endif
> +}
> +
> +template<typename T>
> +constexpr void
> +test_inserts()
> +{
> + T a[]{3,14,13,1,2,3,4,5,3,7,8,3,10,11,3};
> + const T c(3);
> +
> + std::inplace_vector<T, 20> v;
> +
> + v.emplace_back(1);
> + VERIFY( eq<T>(v, {a+3, 1}) );
> + v.push_back(T(2));
> + VERIFY( eq<T>(v, {a+3, 2}) );
> + v.push_back(c);
> + VERIFY( eq<T>(v, {a+3, 3}) );
> +
> + v.unchecked_emplace_back(4);
> + VERIFY( eq<T>(v, {a+3, 4}) );
> + v.unchecked_push_back(T(5));
> + VERIFY( eq<T>(v, {a+3, 5}) );
> + v.unchecked_push_back(c);
> + VERIFY( eq<T>(v, {a+3, 6}) );
> +
> + T* ptr = v.try_emplace_back(7);
> + VERIFY( eq<T>(v, {a+3, 7}) );
> + VERIFY( ptr = &v.back() );
> + ptr = v.try_push_back(T(8));
> + VERIFY( eq<T>(v, {a+3, 8}) );
> + VERIFY( ptr = &v.back() );
> + ptr = v.try_push_back(c);
> + VERIFY( eq<T>(v, {a+3, 9}) );
> + VERIFY( ptr = &v.back() );
> +
> + auto it = v.emplace(v.end(), 10);
> + VERIFY( eq<T>(v, {a+3, 10}) );
> + VERIFY( it == v.end()-1 );
> + it = v.insert(v.end(), T(11));
> + VERIFY( eq<T>(v, {a+3, 11}) );
> + VERIFY( it == v.end()-1 );
> + it = v.insert(v.end(), c);
> + VERIFY( eq<T>(v, {a+3, 12}) );
> + VERIFY( it == v.end()-1 );
> +
> + it = v.emplace(v.begin(), 13);
> + VERIFY( eq<T>(v, {a+2, 13}) );
> + VERIFY( it == v.begin() );
> + it = v.insert(v.begin(), T(14));
> + VERIFY( eq<T>(v, {a+1, 14}) );
> + VERIFY( it == v.begin() );
> + it = v.insert(v.begin(), c);
> + VERIFY( eq<T>(v, {a+0, 15}) );
> + VERIFY( it == v.begin() );
> +
> + it = v.emplace(v.begin()+2, 22);
> + VERIFY( *it == 22 );
> + VERIFY( it == v.begin()+2 );
> + it = v.insert(v.begin()+6, T(24));
> + VERIFY( *it == 24 );
> + VERIFY( it == v.begin()+6 );
> + it = v.insert(v.begin()+13, c);
> + VERIFY( *it == 3 );
> + VERIFY( it == v.begin()+13 );
> +}
> +
> +int main()
> +{
> + auto test_all = [] {
> + test_add_to_full<0, int>();
> + test_add_to_full<0, X>();
> +
> + test_add_to_full<4, int>();
> +
> + test_inserts<int>();
> +#ifdef __cpp_lib_constexpr_inplace_vector
> +#error uncomemnt test_inserts<X>()
> +#endif
> + if ! consteval {
> + test_add_to_full<4, X>();
> + test_inserts<X>();
> + }
> + return true;
> + };
> +
> + test_all();
> + static_assert(test_all());;
> +}
> diff --git a/libstdc++-v3/testsuite/23_containers/inplace_vector/move.cc b/libstdc++-v3/testsuite/23_containers/inplace_vector/move.cc
> new file mode 100644
> index 00000000000..5abcc8764bd
> --- /dev/null
> +++ b/libstdc++-v3/testsuite/23_containers/inplace_vector/move.cc
> @@ -0,0 +1,358 @@
> +// { dg-do run { target c++26 } }
> +
> +#include <inplace_vector>
> +#include <ranges>
> +#include <testsuite_hooks.h>
> +
> +struct X
> +{
> + X() = default;
> + constexpr X(int p) : v(p) {}
> + constexpr X(const X& o) : v(o.v) { } // not trivial
> + constexpr X(X&& o) : v(o.v) { } // not trivial
> +
> + constexpr X& operator=(const X& o) // not trivial
> + { v = o.v; return *this; }
> + constexpr X& operator=(X&& o) // not trivial
> + { v = o.v; return *this; }
> +
> + int v;
> +
> + friend auto operator<=>(const X&, const X&) = default;
> +};
> +
> +template<bool CNoex, bool ANoex>
> +struct N
> +{
> + N() = default;
> + constexpr N(N&&) noexcept(CNoex) { } // not trivial
> + constexpr N& operator=(N&& o) noexcept(ANoex) // not trivial
> + { return *this; }
> +};
> +
> +struct D
> +{
> + D() = default;
> + D(D&&) = default;
> + D& operator=(D&&) = default;
> + ~D() {} // not trivially destructible
> +};
> +
> +struct U
> +{
> + U() = default;
> + U(U&&) noexcept(false) = default; // lies about noexcept, is trivial but throwing
> + U& operator=(U&&) noexcept(false) = default; // lies about noexcept, is trivial but throwing
> +};
> +
> +template<bool SNoex, bool CNoex, bool ANoex>
> +struct S {
> + S() = default;
> + constexpr S(S&&) noexcept(CNoex) { } // not trivial
> + constexpr S& operator=(S&& o) noexcept(ANoex) // not trivial
> + { return *this; }
> +
> + friend constexpr
> + void swap(S&, S&) noexcept(SNoex) {}
> +};
> +
> +// n5008 inplace.vector.overview says for inplace_vector<T, 0>
> +// provides trivial copy/move/default cosntructpr regardless of T
> +struct Z
> +{
> + Z(const Z&) = delete;
> + Z& operator=(const Z&) = delete;
> +};
> +
> +template<size_t N, typename T>
> + constexpr std::inplace_vector<T, N>
> + materialize(std::initializer_list<int> il)
> + {
> + std::inplace_vector<T, N> res;
> + for (int x : il)
> + res.emplace_back(x);
> + return res;
> + }
> +
> +static_assert(std::is_move_constructible_v<std::inplace_vector<int, 2>>);
> +static_assert(std::is_move_constructible_v<std::inplace_vector<X, 2>>);
> +static_assert(std::is_move_constructible_v<std::inplace_vector<N<false, false>, 2>>);
> +static_assert(std::is_move_constructible_v<std::inplace_vector<D, 2>>);
> +static_assert(std::is_move_constructible_v<std::inplace_vector<U, 2>>);
> +// The operators are not constrained, as for any other container
> +static_assert(std::is_move_constructible_v<std::inplace_vector<Z, 2>>);
> +
> +static_assert(std::is_nothrow_move_constructible_v<std::inplace_vector<int, 2>>);
> +static_assert(!std::is_nothrow_move_constructible_v<std::inplace_vector<X, 2>>);
> +static_assert(std::is_nothrow_move_constructible_v<std::inplace_vector<N<true, true>, 2>>);
> +static_assert(std::is_nothrow_move_constructible_v<std::inplace_vector<N<true, false>, 2>>);
> +static_assert(!std::is_nothrow_move_constructible_v<std::inplace_vector<N<false, true>, 2>>);
> +static_assert(!std::is_nothrow_move_constructible_v<std::inplace_vector<N<false, false>, 2>>);
> +static_assert(std::is_nothrow_move_constructible_v<std::inplace_vector<D, 2>>);
> +static_assert(!std::is_nothrow_move_constructible_v<std::inplace_vector<U, 2>>);
> +
> +static_assert(std::is_trivially_move_constructible_v<std::inplace_vector<int, 2>>);
> +static_assert(!std::is_trivially_move_constructible_v<std::inplace_vector<X, 2>>);
> +static_assert(!std::is_trivially_move_constructible_v<std::inplace_vector<N<true, true>, 2>>);
> +// is_trivially_move_constructible_v checks destructor
> +static_assert(!std::is_trivially_move_constructible_v<std::inplace_vector<D, 2>>);
> +static_assert(std::is_trivially_move_constructible_v<std::inplace_vector<U, 2>>);
> +
> +static_assert(std::is_move_assignable_v<std::inplace_vector<int, 2>>);
> +static_assert(std::is_move_assignable_v<std::inplace_vector<X, 2>>);
> +static_assert(std::is_move_assignable_v<std::inplace_vector<N<false, false>, 2>>);
> +static_assert(std::is_move_assignable_v<std::inplace_vector<D, 2>>);
> +static_assert(std::is_move_assignable_v<std::inplace_vector<U, 2>>);
> +// The operators are not constrained, as for any other container
> +static_assert(std::is_move_assignable_v<std::inplace_vector<Z, 2>>);
> +
> +static_assert(std::is_nothrow_move_assignable_v<std::inplace_vector<int, 2>>);
> +static_assert(!std::is_nothrow_move_assignable_v<std::inplace_vector<X, 2>>);
> +static_assert(std::is_nothrow_move_assignable_v<std::inplace_vector<N<true, true>, 2>>);
> +static_assert(!std::is_nothrow_move_assignable_v<std::inplace_vector<N<true, false>, 2>>);
> +static_assert(!std::is_nothrow_move_assignable_v<std::inplace_vector<N<false, true>, 2>>);
> +static_assert(!std::is_nothrow_move_assignable_v<std::inplace_vector<N<false, false>, 2>>);
> +static_assert(std::is_nothrow_move_assignable_v<std::inplace_vector<D, 2>>);
> +static_assert(!std::is_nothrow_move_assignable_v<std::inplace_vector<U, 2>>);
> +
> +static_assert(std::is_trivially_move_assignable_v<std::inplace_vector<int, 2>>);
> +static_assert(!std::is_trivially_move_assignable_v<std::inplace_vector<X, 2>>);
> +static_assert(!std::is_trivially_move_assignable_v<std::inplace_vector<N<true, true>, 2>>);
> +// destructor is not trivial
> +static_assert(!std::is_trivially_move_assignable_v<std::inplace_vector<D, 2>>);
> +static_assert(std::is_trivially_move_assignable_v<std::inplace_vector<U, 2>>);
> +
> +static_assert(std::is_nothrow_swappable_v<std::inplace_vector<int, 2>>);
> +static_assert(!std::is_nothrow_swappable_v<std::inplace_vector<X, 2>>);
> +static_assert(std::is_nothrow_swappable_v<std::inplace_vector<N<true, true>, 2>>);
> +static_assert(!std::is_nothrow_swappable_v<std::inplace_vector<N<true, false>, 2>>);
> +static_assert(!std::is_nothrow_swappable_v<std::inplace_vector<N<false, true>, 2>>);
> +static_assert(!std::is_nothrow_swappable_v<std::inplace_vector<N<false, false>, 2>>);
> +static_assert(std::is_nothrow_swappable_v<std::inplace_vector<S<true, true, true>, 2>>);
> +static_assert(std::is_nothrow_swappable_v<std::inplace_vector<S<true, true, false>, 2>>);
> +static_assert(!std::is_nothrow_swappable_v<std::inplace_vector<S<true, false, true>, 2>>);
> +static_assert(!std::is_nothrow_swappable_v<std::inplace_vector<S<true, false, false>, 2>>);
> +static_assert(!std::is_nothrow_swappable_v<std::inplace_vector<S<false, true, false>, 2>>);
> +static_assert(!std::is_nothrow_swappable_v<std::inplace_vector<S<false, false, false>, 2>>);
> +static_assert(std::is_nothrow_swappable_v<std::inplace_vector<D, 2>>);
> +static_assert(!std::is_nothrow_swappable_v<std::inplace_vector<U, 2>>);
> +
> +static_assert(std::is_nothrow_move_constructible_v<std::inplace_vector<int, 0>>);
> +static_assert(std::is_nothrow_move_constructible_v<std::inplace_vector<X, 0>>);
> +static_assert(std::is_nothrow_move_constructible_v<std::inplace_vector<N<false, false>, 0>>);
> +static_assert(std::is_nothrow_move_constructible_v<std::inplace_vector<D, 0>>);
> +static_assert(std::is_nothrow_move_constructible_v<std::inplace_vector<U, 0>>);
> +static_assert(std::is_nothrow_move_constructible_v<std::inplace_vector<Z, 0>>);
> +
> +static_assert(std::is_trivially_move_constructible_v<std::inplace_vector<int, 0>>);
> +static_assert(std::is_trivially_move_constructible_v<std::inplace_vector<X, 0>>);
> +static_assert(std::is_trivially_move_constructible_v<std::inplace_vector<D, 0>>);
> +static_assert(std::is_trivially_move_constructible_v<std::inplace_vector<U, 0>>);
> +static_assert(std::is_trivially_move_constructible_v<std::inplace_vector<Z, 0>>);
> +
> +static_assert(std::is_nothrow_move_assignable_v<std::inplace_vector<int, 0>>);
> +static_assert(std::is_nothrow_move_assignable_v<std::inplace_vector<X, 0>>);
> +static_assert(std::is_nothrow_move_assignable_v<std::inplace_vector<N<false, false>, 0>>);
> +static_assert(std::is_nothrow_move_assignable_v<std::inplace_vector<D, 0>>);
> +static_assert(std::is_nothrow_move_assignable_v<std::inplace_vector<U, 0>>);
> +static_assert(std::is_nothrow_move_assignable_v<std::inplace_vector<Z, 0>>);
> +
> +static_assert(std::is_trivially_move_assignable_v<std::inplace_vector<int, 0>>);
> +static_assert(std::is_trivially_move_assignable_v<std::inplace_vector<X, 0>>);
> +static_assert(std::is_trivially_move_assignable_v<std::inplace_vector<N<false, false>, 0>>);
> +static_assert(std::is_trivially_move_assignable_v<std::inplace_vector<D, 0>>);
> +static_assert(std::is_trivially_move_assignable_v<std::inplace_vector<U, 0>>);
> +static_assert(std::is_trivially_move_assignable_v<std::inplace_vector<Z, 0>>);
> +
> +static_assert(std::is_nothrow_swappable_v<std::inplace_vector<int, 0>>);
> +static_assert(std::is_nothrow_swappable_v<std::inplace_vector<X, 0>>);
> +static_assert(std::is_nothrow_swappable_v<std::inplace_vector<N<false, false>, 0>>);
> +static_assert(std::is_nothrow_swappable_v<std::inplace_vector<D, 0>>);
> +static_assert(std::is_nothrow_swappable_v<std::inplace_vector<U, 0>>);
> +static_assert(std::is_nothrow_swappable_v<std::inplace_vector<Z, 0>>);
> +
> +template<typename T, size_t N>
> +constexpr bool
> +eq(const std::inplace_vector<T, N>& s, std::span<const T> o)
> +{ return std::ranges::equal(s, o); }
> +
> +constexpr void
> +test_ctor()
> +{
> + auto e0 = materialize<0, int>({});
> + VERIFY( e0.empty() );
> + auto e1 = materialize<0, X>({});
> + VERIFY( e1.empty() );
> + auto e2 = materialize<0, Z>({});
> + VERIFY( e2.empty() );
> +
> + auto c0 = materialize<5, int>({});
> + VERIFY( c0.empty() );
> +
> + auto c3 = materialize<5, int>({1, 2, 3});
> + VERIFY( eq(c3, {1, 2, 3}) );
> +
> + auto c5 = materialize<5, int>({1, 2, 3, 4, 5});
> + VERIFY( eq(c5, {1, 2, 3, 4, 5}) );
> +
> +#ifdef __cpp_lib_constexpr_inplace_vector
> +#error remove the consteval check
> +#endif
> + if consteval {
> + return;
> + }
> +
> + auto x0 = materialize<3, X>({});
> + VERIFY( x0.empty() );
> +
> + auto x2 = materialize<3, X>({1, 2});
> + VERIFY( eq(x2, {1, 2}) );
> +
> + auto x3 = materialize<3, X>({1, 2, 3});
> + VERIFY( eq(x3, {1, 2, 3}) );
> +}
> +
> +constexpr void
> +test_assign()
> +{
> + std::inplace_vector<int, 0> e0;
> + e0 = materialize<0, int>({});
> + VERIFY( e0.empty() );
> + std::inplace_vector<X, 0> e1;
> + e1 = materialize<0, X>({});
> + VERIFY( e1.empty() );
> + std::inplace_vector<Z, 0> e2;
> + e2 = materialize<0, Z>({});
> + VERIFY( e2.empty() );
> +
> + std::inplace_vector<int, 5> c;
> + c = materialize<5, int>({});
> + VERIFY( c.empty() );
> +
> + c = materialize<5, int>({1, 2, 3});
> + VERIFY( eq(c, {1, 2, 3}) );
> +
> + c = materialize<5, int>({1, 2, 3, 4, 5});
> + VERIFY( eq(c, {1, 2, 3, 4, 5}) );
> +
> + c = materialize<5, int>({4, 5});
> + VERIFY( eq(c, {4, 5}) );
> +
> + c = materialize<5, int>({});
> + VERIFY( c.empty() );
> +
> +#ifdef __cpp_lib_constexpr_inplace_vector
> +#error remove the consteval check
> +#endif
> + if consteval {
> + return;
> + }
> +
> + std::inplace_vector<X, 5> x;
> + x = materialize<5, X>({});
> + VERIFY( x.empty() );
> +
> + x = materialize<5, X>({1, 2, 3});
> + VERIFY( eq(x, {1, 2, 3}) );
> +
> + x = materialize<5, X>({1, 2, 3, 4, 5});
> + VERIFY( eq(x, {1, 2, 3, 4, 5}) );
> +
> + x = materialize<5, X>({4, 5});
> + VERIFY( eq(x, {4, 5}) );
> +
> + x = materialize<5, X>({});
> + VERIFY( x.empty() );
> +}
> +
> +constexpr void
> +test_swap()
> +{
> + std::inplace_vector<int, 0> e0a, e0b;
> + swap(e0a, e0b);
> + VERIFY( e0a.empty() );
> + VERIFY( e0b.empty() );
> + e0a.swap(e0b);
> + VERIFY( e0a.empty() );
> + VERIFY( e0b.empty() );
> +
> + std::inplace_vector<X, 0> e1a, e1b;
> + swap(e1a, e1b);
> + VERIFY( e1a.empty() );
> + VERIFY( e1b.empty() );
> + e1a.swap(e1b);
> + VERIFY( e1a.empty() );
> + VERIFY( e1b.empty() );
> +
> + std::inplace_vector<Z, 0> e2a, e2b;
> + swap(e2a, e2b);
> + VERIFY( e2a.empty() );
> + VERIFY( e2b.empty() );
> + e2a.swap(e2b);
> + VERIFY( e2a.empty() );
> + VERIFY( e2b.empty() );
> +
> + std::inplace_vector<int, 5> c0;
> + std::inplace_vector<int, 5> c3{1, 2, 3};
> + std::inplace_vector<int, 5> c5{1, 2, 3, 4, 5};
> +
> + swap(c0, c3);
> + VERIFY( c3.empty() );
> + VERIFY( eq(c0, {1, 2, 3}) );
> + c0.swap(c3);
> + VERIFY( c0.empty() );
> + VERIFY( eq(c3, {1, 2, 3}) );
> +
> + swap(c3, c5);
> + VERIFY( eq(c5, {1, 2, 3}) );
> + VERIFY( eq(c3, {1, 2, 3, 4, 5}) );
> + c5.swap(c3);
> + VERIFY( eq(c3, {1, 2, 3}) );
> + VERIFY( eq(c5, {1, 2, 3, 4, 5}) );
> +
> +#ifdef __cpp_lib_constexpr_inplace_vector
> +#error remove the consteval check
> +#endif
> + if consteval {
> + return;
> + }
> +
> + std::inplace_vector<X, 5> x0;
> + std::inplace_vector<X, 5> x3 = {1, 2, 3};
> + std::inplace_vector<X, 5> x5 = {1, 2, 3, 4, 5};
> +
> + swap(x0, x3);
> + VERIFY( x3.empty() );
> + VERIFY( eq(x0, {1, 2, 3}) );
> + x0.swap(x3);
> + VERIFY( x0.empty() );
> + VERIFY( eq(x3, {1, 2, 3}) );
> +
> + swap(x3, x5);
> + VERIFY( eq(x5, {1, 2, 3}) );
> + VERIFY( eq(x3, {1, 2, 3, 4, 5}) );
> + x5.swap(x3);
> + VERIFY( eq(x3, {1, 2, 3}) );
> + VERIFY( eq(x5, {1, 2, 3, 4, 5}) );
> +}
> +
> +constexpr auto e0 = materialize<0, int>({});
> +constexpr auto e1 = materialize<0, X>({});
> +constexpr auto e2 = materialize<0, Z>({});
> +
> +constexpr auto t1 = materialize<3, int>({});
> +constexpr auto t2 = materialize<3, int>({1, 2});
> +constexpr auto t3 = materialize<3, int>({11, 22, 33});
> +
> +int main()
> +{
> + auto tests = [] {
> + test_ctor();
> + test_assign();
> + test_swap();
> + return true;
> + };
> +
> + tests();
> + constexpr bool _ = tests();
> +}
> diff --git a/libstdc++-v3/testsuite/23_containers/inplace_vector/relops.cc b/libstdc++-v3/testsuite/23_containers/inplace_vector/relops.cc
> new file mode 100644
> index 00000000000..f9c5ce96ae1
> --- /dev/null
> +++ b/libstdc++-v3/testsuite/23_containers/inplace_vector/relops.cc
> @@ -0,0 +1,60 @@
> +// { dg-do run { target c++26 } }
> +
> +#include <inplace_vector>
> +
> +#include <span>
> +#include <testsuite_hooks.h>
> +
> +template<size_t N, typename T>
> +constexpr void
> +test_equal(size_t c)
> +{
> + T a[]{1, 2, 3, 4, 5, 6, 7, 8, 9};
> + std::inplace_vector<T, N> v(a, a+c);
> + VERIFY( v == v );
> + VERIFY( !(v != v) );
> + VERIFY( !(v < v) );
> + VERIFY( !(v > v) );
> + VERIFY( v <= v );
> + VERIFY( v >= v );
> + VERIFY( (v <=> v) == 0 );
> +}
> +
> +template<typename T>
> +constexpr void
> +test_not_equal()
> +{
> + std::inplace_vector<T, 10> v3l{T{1}, T{2}, T{3}};
> + std::inplace_vector<T, 10> v3g{T{1}, T{3}, T{3}};
> + VERIFY( !(v3l == v3g) );
> + VERIFY( v3l != v3g );
> + VERIFY( v3l < v3g );
> + VERIFY( !(v3l > v3g) );
> + VERIFY( v3l <= v3g );
> + VERIFY( !(v3l >= v3g) );
> + VERIFY( (v3l <=> v3g) < 0 );
> +
> + std::inplace_vector<T, 10> v2{T{1}, T{2}};
> + VERIFY( !(v2 == v3l) );
> + VERIFY( v2 != v3l );
> + VERIFY( v2 < v3l );
> + VERIFY( !(v2 > v3l) );
> + VERIFY( v2 <= v3l );
> + VERIFY( !(v2 >= v3l) );
> + VERIFY( (v2 <=> v3l) < 0 );
> +}
> +
> +int main()
> +{
> + auto test_all = [] {
> + test_equal<0, int>(0);
> + test_equal<4, int>(0);
> + test_equal<4, int>(2);
> + test_equal<4, int>(4);
> + test_not_equal<int>();
> + return true;
> + };
> +
> + test_all();
> + static_assert(test_all());;
> +}
> diff --git a/libstdc++-v3/testsuite/23_containers/inplace_vector/version.cc b/libstdc++-v3/testsuite/23_containers/inplace_vector/version.cc
> new file mode 100644
> index 00000000000..a5bbdb8464b
> --- /dev/null
> +++ b/libstdc++-v3/testsuite/23_containers/inplace_vector/version.cc
> @@ -0,0 +1,20 @@
> +// { dg-do preprocess { target c++26 } }
> +// { dg-add-options no_pch }
> +
> +#include <inplace_vector>
> +
> +#ifndef __cpp_lib_inplace_vector
> +# error "Feature-test macro for inplace_vector missing in <inplace_vector>"
> +#elif __cpp_lib_inplace_vector != 202406L
> +# error "Feature-test macro for inplace_vector has wrong value in <inplace_vector>"
> +#endif
> +
> +#undef __cpp_lib_inplace_vector
> +
> +#include <version>
> +
> +#ifndef __cpp_lib_inplace_vector
> +# error "Feature-test macro for inplace_vector missing in <version>"
> +#elif __cpp_lib_inplace_vector != 202406L
> +# error "Feature-test macro for inplace_vector has wrong value in <version>"
> +#endif
> diff --git a/libstdc++-v3/testsuite/util/testsuite_iterators.h b/libstdc++-v3/testsuite/util/testsuite_iterators.h
> index 74a87395cd7..e9f8f56eb27 100644
> --- a/libstdc++-v3/testsuite/util/testsuite_iterators.h
> +++ b/libstdc++-v3/testsuite/util/testsuite_iterators.h
> @@ -270,6 +270,12 @@ namespace __gnu_test
> return !(*this == in);
> }
>
> + T*
> + base() const
> + {
> + return ptr;
> + }
> +
> T&
> operator*() const
> {
> --
> 2.49.0
>
>
More information about the Libstdc++
mailing list