// 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
// .
/** @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
#ifdef __glibcxx_inplace_vector // C++ >= 26
#include
#include
#include
#include // borrowed_iterator_t, __detail::__container_compatible_range
#include // subrange
#include
#include
#include
#include
#include // rotate
namespace std _GLIBCXX_VISIBILITY(default)
{
_GLIBCXX_BEGIN_NAMESPACE_VERSION
// [indirect], class template indirect
template
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;
using reverse_iterator = std::reverse_iterator;
using const_reverse_iterator = std::reverse_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 (std::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 (std::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 < _M_size && __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(_M_elems); }
[[nodiscard]]
constexpr const _Tp*
data() const noexcept
{ return static_cast(_M_elems); }
// [containers.sequences.inplace.vector.modifiers], modifiers
template
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 __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
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 __tail(data() + _M_size, data() + _Nm);
auto [__in, __out] = ranges::uninitialized_copy(__rg, __tail);
_M_size = __out - data();
return std::move(__in);
}
}
template
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
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
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
static constexpr bool __fits<_UInt, false> = false;
static consteval auto __select_size_type()
{
if constexpr (__fits)
return (unsigned char)0;
#if __SHRT_WIDTH__ < __SIZE_WIDTH__
else if constexpr (__fits)
return (unsigned short)0;
#endif
#if __INT_WIDTH__ < __SIZE_WIDTH__ && __INT_WIDTH__ > __SHRT_WIDTH__
else if constexpr (__fits)
return 0u;
#endif
#if __LONG_WIDTH__ < __SIZE_WIDTH__ && __LONG_WIDTH__ > __INT_WIDTH__
else if constexpr (__fits)
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
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
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
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;
using reverse_iterator = std::reverse_iterator;
using const_reverse_iterator = std::reverse_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
[[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
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
[[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
[[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
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
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
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