| // 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/stdexcept_throw.h> |
| #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/stl_construct.h> |
| #include <bits/stl_uninitialized.h> |
| #include <bits/stl_algo.h> // rotate |
| |
| namespace std _GLIBCXX_VISIBILITY(default) |
| { |
| _GLIBCXX_BEGIN_NAMESPACE_VERSION |
| _GLIBCXX_BEGIN_NAMESPACE_CONTAINER |
| |
| // [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 (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<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); |
| } |
| |
| // [inplace.vector.special], specialized algorithms |
| 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{}; |
| } |
| }; |
| |
| // 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(); |
| return *this; |
| } |
| |
| 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 |
| { } |
| }; |
| |
| _GLIBCXX_END_NAMESPACE_CONTAINER |
| |
| template<typename _Tp, size_t _Nm, typename _Predicate> |
| constexpr size_t |
| erase_if(_GLIBCXX_STD_C::inplace_vector<_Tp, _Nm>& __cont, |
| _Predicate __pred) |
| { |
| if constexpr (_Nm != 0) |
| { |
| const auto __osz = __cont.size(); |
| const auto __end = __cont.end(); |
| auto __removed = std::__remove_if(__cont.begin(), __end, |
| std::move(__pred)); |
| if (__removed != __end) |
| { |
| __cont.erase(__removed, __end); |
| return __osz - __cont.size(); |
| } |
| } |
| |
| return 0; |
| } |
| |
| template<typename _Tp, size_t _Nm, typename _Up = _Tp> |
| constexpr size_t |
| erase(_GLIBCXX_STD_C::inplace_vector<_Tp, _Nm>& __cont, const _Up& __value) |
| { return std::erase_if(__cont, __gnu_cxx::__ops::__equal_to(__value)); } |
| |
| _GLIBCXX_END_NAMESPACE_VERSION |
| } // namespace |
| |
| #ifdef _GLIBCXX_DEBUG |
| # include <debug/inplace_vector> |
| #endif |
| |
| #endif // __glibcxx_inplace_vector |
| #endif // _GLIBCXX_INPLACE_VECTOR |