include/functional \
include/future \
include/generator \
+ include/inplace_vector \
include/iomanip \
include/ios \
include/iosfwd \
${std_srcdir}/forward_list \
${std_srcdir}/fstream \
${std_srcdir}/future \
+ ${std_srcdir}/inplace_vector \
${std_srcdir}/iomanip \
${std_srcdir}/ios \
${std_srcdir}/iosfwd \
@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 \
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,
};
};
+ftms = {
+ name = inplace_vector;
+ values = {
+ v = 202406;
+ cxxmin = 26;
+ };
+};
+
ftms = {
name = indirect;
values = {
#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
#endif
#if __cplusplus > 202302L
+#include <inplace_vector>
#include <text_encoding>
#include <stdbit.h>
#include <stdckdint.h>
--- /dev/null
+// 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>)
+ {
+ if (addressof(__other) != this) [[likely]]
+ assign(__other.begin(), __other.end());
+ 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>)
+ {
+ if (addressof(__other) != this) [[likely]]
+ 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();
+ // Bounded on output range due PR121143
+ ranges::uninitialized_copy(
+ ranges::begin(__rg), unreachable_sentinel,
+ data() + _M_size, data() + _M_size + __sz);
+ _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
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
--- /dev/null
+// { 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());;
+}
--- /dev/null
+// { 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());;
+}
--- /dev/null
+// { 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" }
--- /dev/null
+// { 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();
+}
--- /dev/null
+// { 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() );
+}
+
--- /dev/null
+// { 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();
+}
+
--- /dev/null
+// { 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();
+}
--- /dev/null
+// { 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;
+ }();
+}
--- /dev/null
+// { 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());
+}
--- /dev/null
+// { 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());;
+}
--- /dev/null
+// { 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());
+}
--- /dev/null
+// { 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());;
+}
--- /dev/null
+// { 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();
+}
--- /dev/null
+// { 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());;
+}
--- /dev/null
+// { 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
return !(*this == in);
}
+ T*
+ base() const
+ {
+ return ptr;
+ }
+
T&
operator*() const
{