On Thu, 17 Jul 2025, Tomasz Kamiński wrote: > From: Jonathan Wakely <jwak...@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 <ppa...@redhat.com> > Reviewed-by: Jonathan Wakely <jwak...@redhat.com> > Co-authored-by: Tomasz Kamiński <tkami...@redhat.com> > Signed-off-by: Tomasz Kamiński <tkami...@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 > >