libstdc++: [_GLIBCXX_DEBUG] Implement std::__debug::inplace_vector

Add _GLIBCXX_DEBUG std::inplace_vector implementation.

libstdc++-v3/ChangeLog:

	* include/Makefile.am (debug_headers): Add inplace_vector.
	* include/Makefile.in: Regenerate.
	* include/debug/functions.h (__check_valid_range): Add C++20 constexpr.
	* include/debug/helper_functions.h (__valid_range): Likewise.
	* include/debug/inplace_vector: New.
	* include/debug/safe_base.h (~_Safe_sequence_base()): Add C++11 noexcept.
	(_Safe_sequence_base::operator=(const _Safe_sequence_base&)): New.
	(_Safe_sequence_base::operator=(_Safe_sequence_base&&)): New.
	(_Safe_sequence_base::_M_invalidate_all): Add C++20 constexpr.
	* include/debug/safe_container.h
	(_Safe_container<>::operator=(const _Safe_container<>&)): Implement using
	_Safe_sequence_base same operator.
	* include/debug/safe_iterator.h (__valid_range): Add C++20 constexpr.
	* include/debug/safe_sequence.h
	(_Not_equal_to(const _Type&)): Add C++20 constexpr.
	(_Equal_to(const _Type&)): Add C++20 constexpr.
	(_After_nth_from(const difference_type&, const _Iterator&)): Add C++20 constexpr.
	(_Safe_sequence<>::_M_invalidate_if): Add C++20 constexpr.
	(_Safe_node_sequence::operator=(const _Safe_node_sequence&)): New.
	(_Safe_node_sequence::operator=(_Safe_node_sequence&&)): New.
	(_Safe_node_sequence<>::_M_invalidate_all()): Add C++20 constexpr.
	* include/debug/safe_sequence.tcc
	(_Safe_sequence<>::_M_invalidate_if): Add C++20 constexpr.
	* include/std/inplace_vector [_GLIBCXX_DEBUG](std::inplace_vector<>): Move
	implementation into __cxx1998 namespace.
	(erase, erase_if): Limit to non-debug inplace_vector<>, cleanup code.
	[_GLIBCXX_DEBUG]: Add include <debug/inplace_vector>.
	* testsuite/23_containers/inplace_vector/cons/1.cc: Adapt, skip several
	is_trivially_xxx checks when in _GLIBCXX_DEBUG mode.
	* testsuite/23_containers/inplace_vector/copy.cc: Likewise.
	* testsuite/23_containers/inplace_vector/move.cc: Likewise.
	* testsuite/23_containers/inplace_vector/debug/assign1_neg.cc: New test case.
	* testsuite/23_containers/inplace_vector/debug/assign2_neg.cc: New test case.
	* testsuite/23_containers/inplace_vector/debug/assign3_neg.cc: New test case.
	* testsuite/23_containers/inplace_vector/debug/assign4_backtrace_neg.cc: New test case.
	* testsuite/23_containers/inplace_vector/debug/assign4_neg.cc: New test case.
	* testsuite/23_containers/inplace_vector/debug/construct1_neg.cc: New test case.
	* testsuite/23_containers/inplace_vector/debug/construct2_neg.cc: New test case.
	* testsuite/23_containers/inplace_vector/debug/construct3_neg.cc: New test case.
	* testsuite/23_containers/inplace_vector/debug/construct4_neg.cc: New test case.
	* testsuite/23_containers/inplace_vector/debug/debug_functions.cc: New test case.
	* testsuite/23_containers/inplace_vector/debug/erase.cc: New test case.
	* testsuite/23_containers/inplace_vector/debug/insert1_neg.cc: New test case.
	* testsuite/23_containers/inplace_vector/debug/insert2_neg.cc: New test case.
	* testsuite/23_containers/inplace_vector/debug/insert3_neg.cc: New test case.
	* testsuite/23_containers/inplace_vector/debug/insert4_neg.cc: New test case.
	* testsuite/23_containers/inplace_vector/debug/insert5_neg.cc: New test case.
	* testsuite/23_containers/inplace_vector/debug/insert7_neg.cc: New test case.
	* testsuite/23_containers/inplace_vector/debug/invalidation/1.cc: New test case.
	* testsuite/23_containers/inplace_vector/debug/invalidation/2.cc: New test case.
	* testsuite/23_containers/inplace_vector/debug/invalidation/3.cc: New test case.
	* testsuite/23_containers/inplace_vector/debug/invalidation/4.cc: New test case.
	* testsuite/23_containers/inplace_vector/debug/invalidation/append_range.cc:
	New test case.
	* testsuite/23_containers/inplace_vector/debug/invalidation/erase.cc:
	New test case.
	* testsuite/23_containers/inplace_vector/debug/invalidation/pop_back.cc:
	New test case.
	* testsuite/23_containers/inplace_vector/debug/invalidation/push_back.cc:
	New test case.
	* testsuite/23_containers/inplace_vector/debug/invalidation/swap.cc:
	New test case.
	* testsuite/23_containers/inplace_vector/debug/invalidation/try_append_range.cc:
	New test case.
	* testsuite/23_containers/inplace_vector/debug/invalidation/try_emplace_back.cc:
	New test case.
	* testsuite/23_containers/inplace_vector/debug/invalidation/try_push_back.cc:
	New test case.
	* testsuite/23_containers/inplace_vector/debug/invalidation/unchecked_emplace_back.cc:
	New test case.
	* testsuite/util/debug/checks.h: Avoid using _GLIBCXX_DEBUG containers in test
	implementations.
This commit is contained in:
François Dumont 2025-09-22 18:58:52 +02:00 committed by François Dumont
parent 6cae8aac08
commit 8a2e6590cc
No known key found for this signature in database
45 changed files with 1660 additions and 42 deletions

View File

@ -971,6 +971,7 @@ debug_headers = \
${debug_srcdir}/forward_list \
${debug_srcdir}/functions.h \
${debug_srcdir}/helper_functions.h \
${debug_srcdir}/inplace_vector \
${debug_srcdir}/list \
${debug_srcdir}/map \
${debug_srcdir}/macros.h \

View File

@ -1308,6 +1308,7 @@ debug_freestanding = \
@GLIBCXX_HOSTED_TRUE@ ${debug_srcdir}/forward_list \
@GLIBCXX_HOSTED_TRUE@ ${debug_srcdir}/functions.h \
@GLIBCXX_HOSTED_TRUE@ ${debug_srcdir}/helper_functions.h \
@GLIBCXX_HOSTED_TRUE@ ${debug_srcdir}/inplace_vector \
@GLIBCXX_HOSTED_TRUE@ ${debug_srcdir}/list \
@GLIBCXX_HOSTED_TRUE@ ${debug_srcdir}/map \
@GLIBCXX_HOSTED_TRUE@ ${debug_srcdir}/macros.h \

View File

@ -53,15 +53,19 @@ namespace __gnu_debug
* assertion statement because, e.g., we are in a constructor.
*/
template<typename _InputIterator>
inline _InputIterator
_GLIBCXX20_CONSTEXPR inline _InputIterator
__check_valid_range(const _InputIterator& __first,
const _InputIterator& __last,
const char* __file,
unsigned int __line,
const char* __function)
{
__glibcxx_check_valid_range_at(__first, __last,
__file, __line, __function);
if (!std::__is_constant_evaluated())
{
__glibcxx_check_valid_range_at(__first, __last,
__file, __line, __function);
}
return __first;
}

View File

@ -249,7 +249,7 @@ namespace __gnu_debug
}
template<typename _Iterator, typename _Sequence, typename _Category>
bool
_GLIBCXX20_CONSTEXPR bool
__valid_range(const _Safe_iterator<_Iterator, _Sequence, _Category>&,
const _Safe_iterator<_Iterator, _Sequence, _Category>&,
typename _Distance_traits<_Iterator>::__type&);
@ -272,7 +272,7 @@ namespace __gnu_debug
}
template<typename _Iterator, typename _Sequence, typename _Category>
bool
_GLIBCXX20_CONSTEXPR bool
__valid_range(const _Safe_iterator<_Iterator, _Sequence, _Category>&,
const _Safe_iterator<_Iterator, _Sequence, _Category>&);

View File

@ -0,0 +1,691 @@
// Debugging inplace_vector implementation -*- 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 debug/inplace_vector
* This file is a GNU debug extension to the Standard C++ Library.
*/
#ifndef _GLIBCXX_DEBUG_INPLACE_VECTOR
#define _GLIBCXX_DEBUG_INPLACE_VECTOR 1
#ifdef _GLIBCXX_SYSHDR
#pragma GCC system_header
#endif
#include <debug/debug.h>
namespace std _GLIBCXX_VISIBILITY(default) { namespace __debug {
template<typename _Tp, size_t _Nm> class inplace_vector;
} } // namespace std::__debug
#include <inplace_vector>
#ifdef __glibcxx_inplace_vector // C++ >= 26
#include <debug/safe_sequence.h>
#include <debug/safe_iterator.h>
namespace std _GLIBCXX_VISIBILITY(default)
{
namespace __debug
{
/// Class std::inplace_vector with safety/checking/debug instrumentation.
template<typename _Tp, size_t _Nm>
class inplace_vector
: public __gnu_debug::_Safe_sequence<inplace_vector<_Tp, _Nm>>
, public _GLIBCXX_STD_C::inplace_vector<_Tp, _Nm>
{
using _Base = _GLIBCXX_STD_C::inplace_vector<_Tp, _Nm>;
using _Base_iterator = typename _Base::iterator;
using _Base_const_iterator = typename _Base::const_iterator;
using _Equal = __gnu_debug::_Equal_to<_Base_const_iterator>;
template<typename _ItT, typename _SeqT, typename _CatT>
friend class ::__gnu_debug::_Safe_iterator;
public:
// types:
using value_type = _Base::value_type;
using pointer = _Base::pointer;
using const_pointer = _Base::const_pointer;
using reference = _Base::reference;
using const_reference = _Base::const_reference;
using size_type = _Base::size_type;
using difference_type = _Base::difference_type;
using iterator
= __gnu_debug::_Safe_iterator<_Base_iterator, inplace_vector>;
using const_iterator
= __gnu_debug::_Safe_iterator<_Base_const_iterator, inplace_vector>;
using reverse_iterator = std::reverse_iterator<iterator>;
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
constexpr
inplace_vector() noexcept = default;
constexpr explicit
inplace_vector(size_type __n)
: _Base(__n) { }
constexpr
inplace_vector(size_type __n, const _Tp& __value)
: _Base(__n, __value) { }
template<__any_input_iterator _InputIterator>
constexpr
inplace_vector(_InputIterator __first, _InputIterator __last)
: _Base(__gnu_debug::__base(
__glibcxx_check_valid_constructor_range(__first, __last)),
__gnu_debug::__base(__last)) { }
template<__detail::__container_compatible_range<_Tp> _Rg>
constexpr
inplace_vector(from_range_t, _Rg&& __rg)
: _Base(from_range_t{}, std::forward<_Rg>(__rg)) { }
constexpr
inplace_vector(initializer_list<_Tp> __il)
: _Base(__il) { }
inplace_vector(const inplace_vector&) = default;
inplace_vector(inplace_vector&&) = default;
~inplace_vector() = default;
inplace_vector&
operator=(const inplace_vector&) = default;
inplace_vector&
operator=(inplace_vector&&) = default;
constexpr inplace_vector&
operator=(initializer_list<_Tp> __il)
{
_Base::operator=(__il);
this->_M_invalidate_all();
return *this;
}
template<__any_input_iterator _InputIterator>
constexpr void
assign(_InputIterator __first, _InputIterator __last)
{
typename __gnu_debug::_Distance_traits<_InputIterator>::__type __dist;
__glibcxx_check_valid_range2(__first, __last, __dist);
const auto __size = size();
const auto __end = _Base::end();
if (__dist.second >= __gnu_debug::__dp_sign)
_Base::assign(__gnu_debug::__unsafe(__first),
__gnu_debug::__unsafe(__last));
else
_Base::assign(__first, __last);
if (size() < __size)
_M_invalidate_after_nth(size());
else if (size() > __size)
this->_M_invalidate_if(_Equal(__end));
}
template<__detail::__container_compatible_range<_Tp> _Rg>
constexpr void
assign_range(_Rg&& __rg)
{
_Base::assign_range(std::forward<_Rg>(__rg));
this->_M_invalidate_all();
}
constexpr void
assign(size_type __n, const _Tp& __u)
{
_Base::assign(__n, __u);
this->_M_invalidate_all();
}
constexpr void
assign(initializer_list<_Tp> __il)
{
_Base::assign(__il);
this->_M_invalidate_all();
}
// iterators
[[nodiscard]]
constexpr iterator
begin() noexcept
{ return { _Base::begin(), this }; }
[[nodiscard]]
constexpr const_iterator
begin() const noexcept
{ return { _Base::begin(), this }; }
[[nodiscard]]
constexpr iterator
end() noexcept
{ return { _Base::end(), this }; }
[[nodiscard]]
constexpr const_iterator
end() const noexcept
{ return { _Base::end(), this }; }
[[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 { _Base::cbegin(), this }; }
[[nodiscard]]
constexpr const_iterator
cend() const noexcept
{ return { _Base::cend(), this }; }
[[nodiscard]]
constexpr const_reverse_iterator
crbegin() const noexcept { return rbegin(); }
[[nodiscard]]
constexpr const_reverse_iterator
crend() const noexcept { return rend(); }
using _Base::empty;
using _Base::size;
using _Base::max_size;
using _Base::capacity;
constexpr void
resize(size_type __n)
{
_Base::resize(__n);
_M_invalidate_after_nth(__n);
}
constexpr void
resize(size_type __n, const _Tp& __c)
{
_Base::resize(__n, __c);
_M_invalidate_after_nth(__n);
}
using _Base::reserve;
using _Base::shrink_to_fit;
// element access
[[nodiscard]]
constexpr reference
operator[](size_type __n)
{
__glibcxx_check_subscript(__n);
return _Base::operator[](__n);
}
[[nodiscard]]
constexpr const_reference
operator[](size_type __n) const
{
__glibcxx_check_subscript(__n);
return _Base::operator[](__n);
}
using _Base::at;
[[nodiscard]]
constexpr reference
front()
{
__glibcxx_check_nonempty();
return data()[0];
}
[[nodiscard]]
constexpr const_reference
front() const
{
__glibcxx_check_nonempty();
return data()[0];
}
[[nodiscard]]
constexpr reference
back()
{
__glibcxx_check_nonempty();
return data()[size() - 1];
}
[[nodiscard]]
constexpr const_reference
back() const
{
__glibcxx_check_nonempty();
return data()[size() - 1];
}
using _Base::data;
template<typename... _Args>
constexpr _Tp&
emplace_back(_Args&&... __args)
{
const auto __end = _Base::cend();
_Tp& __res = _Base::emplace_back(std::forward<_Args>(__args)...);
this->_M_invalidate_if(_Equal(__end));
return __res;
}
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)
{
const auto __size = size();
const auto __end = _Base::cend();
_Base::append_range(__rg);
if (size() != __size)
this->_M_invalidate_if(_Equal(__end));
}
constexpr void
pop_back()
{
__glibcxx_check_nonempty();
_M_invalidate_after_nth(_Base::size() - 1);
_Base::pop_back();
}
template<typename... _Args>
constexpr _Tp*
try_emplace_back(_Args&&... __args)
{
auto __end = _Base::cend();
_Tp* __res = _Base::try_emplace_back(std::forward<_Args>(__args)...);
if (__res)
this->_M_invalidate_if(_Equal(__end));
return __res;
}
constexpr _Tp*
try_push_back(const _Tp& __x)
{
const auto __end = _Base::cend();
_Tp* __res = _Base::try_push_back(__x);
if (__res)
this->_M_invalidate_if(_Equal(__end));
return __res;
}
constexpr _Tp*
try_push_back(_Tp&& __x)
{
const auto __end = _Base::cend();
_Tp* __res = _Base::try_push_back(std::move(__x));
if (__res)
this->_M_invalidate_if(_Equal(__end));
return __res;
}
template<__detail::__container_compatible_range<_Tp> _Rg>
constexpr ranges::borrowed_iterator_t<_Rg>
try_append_range(_Rg&& __rg)
{
const auto __size = size();
const auto __end = _Base::cend();
auto __res = _Base::try_append_range(__rg);
if (size() != __size)
this->_M_invalidate_if(_Equal(__end));
return __res;
}
template<typename... _Args>
constexpr _Tp&
unchecked_emplace_back(_Args&&... __args)
{
const auto __end = _Base::cend();
_Tp& __res =
_Base::unchecked_emplace_back(std::forward<_Args>(__args)...);
this->_M_invalidate_if(_Equal(__end));
return __res;
}
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)
{
if (std::is_constant_evaluated())
return iterator(_Base::emplace(__position.base(),
std::forward<_Args>(__args)...),
this);
__glibcxx_check_insert(__position);
const difference_type __offset = __position.base() - _Base::cbegin();
_Base_iterator __res = _Base::emplace(__position.base(),
std::forward<_Args>(__args)...);
_M_invalidate_after_nth(__offset);
return { __res, this };
}
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)
{
if (std::is_constant_evaluated())
return iterator(_Base::insert(__position.base(), __n, __x), this);
__glibcxx_check_insert(__position);
const difference_type __offset = __position.base() - _Base::cbegin();
_Base_iterator __res = _Base::insert(__position.base(), __n, __x);
_M_invalidate_after_nth(__offset);
return { __res, this };
}
template<__any_input_iterator _InputIterator>
constexpr iterator
insert(const_iterator __position, _InputIterator __first,
_InputIterator __last)
{
if (std::is_constant_evaluated())
return iterator(_Base::insert(__position.base(),
__gnu_debug::__unsafe(__first),
__gnu_debug::__unsafe(__last)), this);
typename __gnu_debug::_Distance_traits<_InputIterator>::__type __dist;
__glibcxx_check_insert_range(__position, __first, __last, __dist);
const difference_type __offset = __position.base() - _Base::cbegin();
_Base_iterator __res;
if (__dist.second >= __gnu_debug::__dp_sign)
__res = _Base::insert(__position.base(),
__gnu_debug::__unsafe(__first),
__gnu_debug::__unsafe(__last));
else
__res = _Base::insert(__position.base(), __first, __last);
_M_invalidate_after_nth(__offset);
return { __res, this };
}
template<__detail::__container_compatible_range<_Tp> _Rg>
constexpr iterator
insert_range(const_iterator __position, _Rg&& __rg)
{
const auto __size = size();
const difference_type __offset = __position.base() - _Base::cbegin();
auto __res = _Base::insert_range(__position.base(), __rg);
if (size() > __size)
this->_M_invalidate_after_nth(__offset);
return iterator(__res, this);
}
constexpr iterator
insert(const_iterator __position, initializer_list<_Tp> __il)
{
if (std::is_constant_evaluated())
return iterator(_Base::insert(__position.base(), __il), this);
__glibcxx_check_insert(__position);
const auto __size = size();
difference_type __offset = __position.base() - _Base::begin();
_Base_iterator __res = _Base::insert(__position.base(), __il);
if (size() > __size)
this->_M_invalidate_after_nth(__offset);
return iterator(__res, this);
}
constexpr iterator
erase(const_iterator __position)
{
if (std::is_constant_evaluated())
return iterator(_Base::erase(__position.base()), this);
__glibcxx_check_erase(__position);
difference_type __offset = __position.base() - _Base::cbegin();
_Base_iterator __res = _Base::erase(__position.base());
this->_M_invalidate_after_nth(__offset);
return iterator(__res, this);
}
constexpr iterator
erase(const_iterator __first, const_iterator __last)
{
if (std::is_constant_evaluated())
return iterator(_Base::erase(__first.base(), __last.base()),
this);
__glibcxx_check_erase_range(__first, __last);
if (__first.base() != __last.base())
{
difference_type __offset = __first.base() - _Base::cbegin();
_Base_iterator __res = _Base::erase(__first.base(),
__last.base());
this->_M_invalidate_after_nth(__offset);
return { __res, this };
}
else
return { _Base::begin() + (__first.base() - _Base::cbegin()), this };
}
constexpr void
swap(inplace_vector& __x)
noexcept(is_nothrow_swappable_v<_Tp> && is_nothrow_move_constructible_v<_Tp>)
{
this->_M_invalidate_all();
__x._M_invalidate_all();
_Base::swap(__x);
}
constexpr void
clear() noexcept
{
_Base::clear();
this->_M_invalidate_all();
}
constexpr friend bool
operator==(const inplace_vector& __x, const inplace_vector& __y)
{ return __x._M_base() == __y._M_base(); }
constexpr friend auto
operator<=>(const inplace_vector& __x, const inplace_vector& __y)
requires requires (const _Tp __t) {
{ __t < __t } -> __detail::__boolean_testable;
}
{ return __x._M_base() <=> __y._M_base(); }
constexpr friend void
swap(inplace_vector& __x, inplace_vector& __y)
noexcept( noexcept(__x.swap(__y)) )
{ __x.swap(__y); }
private:
constexpr _Base&
_M_base() noexcept { return *this; }
constexpr const _Base&
_M_base() const noexcept { return *this; }
constexpr void
_M_invalidate_after_nth(difference_type __n) noexcept
{
using _After_nth
= __gnu_debug::_After_nth_from<_Base_const_iterator>;
this->_M_invalidate_if(_After_nth(__n, _Base::cbegin()));
}
};
// 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 _GLIBCXX_STD_C::inplace_vector<_Tp, 0>
{
using _Base = _GLIBCXX_STD_C::inplace_vector<_Tp, 0>;
public:
// types:
using value_type = _Base::value_type;
using pointer = _Base::pointer;
using const_pointer = _Base::const_pointer;
using reference = _Base::reference;
using const_reference = _Base::const_reference;
using size_type = _Base::size_type;
using difference_type = _Base::difference_type;
using iterator = _Base::iterator;
using const_iterator = _Base::const_iterator;
using reverse_iterator = _Base::reverse_iterator;
using const_reverse_iterator = _Base::const_reverse_iterator;
inplace_vector() = default;
constexpr explicit
inplace_vector(size_type __n) : _Base(__n) { }
constexpr
inplace_vector(size_type __n, const _Tp& __value)
: _Base(__n, __value) { }
template<__any_input_iterator _InputIterator>
constexpr
inplace_vector(_InputIterator __first, _InputIterator __last)
: _Base(__gnu_debug::__base(
__glibcxx_check_valid_constructor_range(__first, __last)),
__gnu_debug::__base(__last)) { }
template <__detail::__container_compatible_range<_Tp> _Rg>
constexpr
inplace_vector(from_range_t, _Rg&& __rg)
: _Base(from_range_t{}, std::forward<_Rg>(__rg)) { }
constexpr
inplace_vector(initializer_list<_Tp> __il)
: _Base(__il) { }
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)
{
_Base::operator=(__il);
return *this;
}
constexpr void
swap(inplace_vector& __x)
noexcept
{ }
};
} // namespace __debug
_GLIBCXX_BEGIN_NAMESPACE_VERSION
template<typename _Tp, size_t _Nm, typename _Predicate>
constexpr size_t
erase_if(__debug::inplace_vector<_Tp, _Nm>& __cont, _Predicate __pred)
{
if constexpr (_Nm != 0)
{
_GLIBCXX_STD_C::inplace_vector<_Tp, _Nm>& __ucont = __cont;
const auto __osz = __cont.size();
const auto __end = __ucont.end();
auto __removed = std::__remove_if(__ucont.begin(), __end,
std::move(__pred));
if (__removed != __end)
{
__cont.erase(__niter_wrap(__cont.cbegin(), __removed),
__cont.cend());
return __osz - __cont.size();
}
}
return 0;
}
template<typename _Tp, size_t _Nm, typename _Up = _Tp>
constexpr size_t
erase(__debug::inplace_vector<_Tp, _Nm>& __cont, const _Up& __value)
{ return std::erase_if(__cont, __gnu_cxx::__ops::__equal_to(__value)); }
_GLIBCXX_END_NAMESPACE_VERSION
} // namespace std
#endif // __glibcxx_inplace_vector
#endif // _GLIBCXX_DEBUG_INPLACE_VECTOR

View File

@ -254,12 +254,30 @@ namespace __gnu_debug
/** Notify all iterators that reference this sequence that the
sequence is being destroyed. */
_GLIBCXX20_CONSTEXPR
~_Safe_sequence_base()
~_Safe_sequence_base() _GLIBCXX_NOEXCEPT
{
if (!std::__is_constant_evaluated())
this->_M_detach_all();
}
// Copy assignment invalidate all iterators.
_GLIBCXX20_CONSTEXPR _Safe_sequence_base&
operator=(const _Safe_sequence_base&) _GLIBCXX_NOEXCEPT
{
_M_invalidate_all();
return *this;
}
#if __cplusplus >= 201103L
_GLIBCXX20_CONSTEXPR _Safe_sequence_base&
operator=(_Safe_sequence_base&& __x) noexcept
{
_M_invalidate_all();
__x._M_invalidate_all();
return *this;
}
#endif
/** Detach all iterators, leaving them singular. */
void
_M_detach_all() const;
@ -292,7 +310,7 @@ namespace __gnu_debug
_M_get_mutex() const _GLIBCXX_USE_NOEXCEPT;
/** Invalidates all iterators. */
void
_GLIBCXX20_CONSTEXPR void
_M_invalidate_all() const
{ if (++_M_version == 0) _M_version = 1; }

View File

@ -86,17 +86,22 @@ namespace __gnu_debug
{ }
#endif
// Copy assignment invalidate all iterators.
_GLIBCXX20_CONSTEXPR
#if __cplusplus < 201103L
_Safe_container&
operator=(const _Safe_container&) _GLIBCXX_NOEXCEPT
operator=(const _Safe_container& __x)
{
if (!std::__is_constant_evaluated())
this->_M_invalidate_all();
_Base::operator=(__x);
return *this;
}
#if __cplusplus >= 201103L
void
_M_swap(const _Safe_container& __x) const throw()
{ _Base::_M_swap(__x); }
#else
_GLIBCXX20_CONSTEXPR
_Safe_container&
operator=(const _Safe_container&) noexcept = default;
_GLIBCXX20_CONSTEXPR
_Safe_container&
operator=(_Safe_container&& __x) noexcept
@ -146,10 +151,6 @@ namespace __gnu_debug
_M_swap_base(__x);
}
#else
void
_M_swap(const _Safe_container& __x) const throw()
{ _Base::_M_swap(__x); }
#endif
};

View File

@ -1114,21 +1114,31 @@ namespace __gnu_debug
/** Safe iterators know how to check if they form a valid range. */
template<typename _Iterator, typename _Sequence, typename _Category>
_GLIBCXX20_CONSTEXPR
inline bool
__valid_range(const _Safe_iterator<_Iterator, _Sequence,
_Category>& __first,
const _Safe_iterator<_Iterator, _Sequence,
_Category>& __last,
typename _Distance_traits<_Iterator>::__type& __dist)
{ return __first._M_valid_range(__last, __dist); }
{
if (std::__is_constant_evaluated())
return true;
return __first._M_valid_range(__last, __dist);
}
template<typename _Iterator, typename _Sequence, typename _Category>
_GLIBCXX20_CONSTEXPR
inline bool
__valid_range(const _Safe_iterator<_Iterator, _Sequence,
_Category>& __first,
const _Safe_iterator<_Iterator, _Sequence,
_Category>& __last)
{
if (std::__is_constant_evaluated())
return true;
typename _Distance_traits<_Iterator>::__type __dist;
return __first._M_valid_range(__last, __dist);
}

View File

@ -46,6 +46,7 @@ namespace __gnu_debug
_Type __value;
public:
_GLIBCXX20_CONSTEXPR
explicit _Not_equal_to(const _Type& __v) : __value(__v) { }
bool
@ -61,6 +62,7 @@ namespace __gnu_debug
_Type __value;
public:
_GLIBCXX20_CONSTEXPR
explicit _Equal_to(const _Type& __v) : __value(__v) { }
bool
@ -80,6 +82,7 @@ namespace __gnu_debug
difference_type _M_n;
public:
_GLIBCXX20_CONSTEXPR
_After_nth_from(const difference_type& __n, const _Iterator& __base)
: _M_base(__base), _M_n(__n) { }
@ -113,7 +116,7 @@ namespace __gnu_debug
true. @c __pred will be invoked with the normal iterators nested
in the safe ones. */
template<typename _Predicate>
void
_GLIBCXX20_CONSTEXPR void
_M_invalidate_if(_Predicate __pred) const;
/** Transfers all iterators @c x that reference @c from sequence,
@ -132,10 +135,31 @@ namespace __gnu_debug
class _Safe_node_sequence
: public _Safe_sequence<_Sequence>
{
public:
_GLIBCXX20_CONSTEXPR _Safe_node_sequence&
operator=(const _Safe_node_sequence&) _GLIBCXX_NOEXCEPT
{
_M_invalidate_all();
return *this;
}
#if __cplusplus >= 201103L
_GLIBCXX20_CONSTEXPR _Safe_node_sequence&
operator=(_Safe_node_sequence&& __x) noexcept
{
_M_invalidate_all();
__x._M_invalidate_all();
return *this;
}
#endif
protected:
void
_GLIBCXX20_CONSTEXPR void
_M_invalidate_all() const
{
if (std::__is_constant_evaluated())
return;
typedef typename _Sequence::const_iterator _Const_iterator;
typedef typename _Const_iterator::iterator_type _Base_const_iterator;
typedef __gnu_debug::_Not_equal_to<_Base_const_iterator> _Not_equal;

View File

@ -33,10 +33,13 @@ namespace __gnu_debug
{
template<typename _Sequence>
template<typename _Predicate>
void
_GLIBCXX20_CONSTEXPR void
_Safe_sequence<_Sequence>::
_M_invalidate_if(_Predicate __pred) const
{
if (std::__is_constant_evaluated())
return;
typedef typename _Sequence::iterator iterator;
typedef typename _Sequence::const_iterator const_iterator;

View File

@ -35,7 +35,7 @@
#define __glibcxx_want_inplace_vector
#include <bits/version.h>
#ifdef __glibcxx_inplace_vector // C++ >= 26
#ifdef __glibcxx_inplace_vector // C++ >= 26
#include <compare>
#include <initializer_list>
#include <bits/range_access.h>
@ -49,6 +49,7 @@
namespace std _GLIBCXX_VISIBILITY(default)
{
_GLIBCXX_BEGIN_NAMESPACE_VERSION
_GLIBCXX_BEGIN_NAMESPACE_CONTAINER
// [indirect], class template indirect
template<typename _Tp, size_t _Nm>
@ -1329,32 +1330,40 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
{ }
};
_GLIBCXX_END_NAMESPACE_CONTAINER
template<typename _Tp, size_t _Nm, typename _Predicate>
constexpr size_t
erase_if(inplace_vector<_Tp, _Nm>& __cont, _Predicate __pred)
erase_if(_GLIBCXX_STD_C::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,
std::move(__pred));
if (__removed != __end)
if constexpr (_Nm != 0)
{
__cont.erase(__niter_wrap(__cont.begin(), __removed),
__cont.end());
return __osz - __cont.size();
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(inplace_vector<_Tp, _Nm>& __cont, const _Up& __value)
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

View File

@ -24,7 +24,7 @@ struct U
};
// n5008 inplace.vector.overview says for inplace_vector<T, 0>
// provides trivial copy/move/default cosntructpr regardless of T
// provides trivial copy/move/default constructor regardless of T
struct Z
{
constexpr Z(int) {}
@ -52,11 +52,13 @@ static_assert(!std::is_trivially_default_constructible_v<std::inplace_vector<N,
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>>);
#if !_GLIBCXX_DEBUG
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>>);
#endif
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>>);

View File

@ -72,12 +72,14 @@ static_assert(!std::is_nothrow_copy_constructible_v<std::inplace_vector<N<false,
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>>);
#if !_GLIBCXX_DEBUG
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>>);
#endif
static_assert(std::is_copy_assignable_v<std::inplace_vector<int, 2>>);
static_assert(std::is_copy_assignable_v<std::inplace_vector<X, 2>>);
@ -96,6 +98,7 @@ static_assert(!std::is_nothrow_copy_assignable_v<std::inplace_vector<N<false, fa
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>>);
#if !_GLIBCXX_DEBUG
// 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>>);
@ -103,6 +106,7 @@ static_assert(!std::is_trivially_copy_assignable_v<std::inplace_vector<N<true, t
// 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>>);
#endif
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>>);

View File

@ -0,0 +1,16 @@
// { dg-do run { target c++26 xfail *-*-* } }
// { dg-require-debug-mode "" }
#include <inplace_vector>
#include <debug/checks.h>
void test01()
{
__gnu_test::check_assign1<std::inplace_vector<int, 10> >();
}
int main()
{
test01();
return 0;
}

View File

@ -0,0 +1,16 @@
// { dg-do run { target c++26 xfail *-*-* } }
// { dg-require-debug-mode "" }
#include <inplace_vector>
#include <debug/checks.h>
void test01()
{
__gnu_test::check_assign2<std::inplace_vector<int, 10>>();
}
int main()
{
test01();
return 0;
}

View File

@ -0,0 +1,16 @@
// { dg-do run { target c++26 xfail *-*-* } }
// { dg-require-debug-mode "" }
#include <inplace_vector>
#include <debug/checks.h>
void test01()
{
__gnu_test::check_assign3<std::inplace_vector<int, 10>>();
}
int main()
{
test01();
return 0;
}

View File

@ -0,0 +1,17 @@
// { dg-do run { target c++26 xfail *-*-* } }
// { dg-options "-D_GLIBCXX_DEBUG_BACKTRACE -lstdc++exp" }
// { dg-require-cpp-feature-test __cpp_lib_stacktrace }
#include <debug/inplace_vector>
#include <debug/checks.h>
void test01()
{
__gnu_test::check_assign1<__gnu_debug::inplace_vector<int, 10>>();
}
int main()
{
test01();
return 0;
}

View File

@ -0,0 +1,15 @@
// { dg-do run { target c++26 xfail *-*-* } }
#include <debug/inplace_vector>
#include <debug/checks.h>
void test01()
{
__gnu_test::check_assign1<__gnu_debug::inplace_vector<int, 10>>();
}
int main()
{
test01();
return 0;
}

View File

@ -0,0 +1,16 @@
// { dg-do run { target c++26 xfail *-*-* } }
// { dg-require-debug-mode "" }
#include <inplace_vector>
#include <debug/checks.h>
void test01()
{
__gnu_test::check_construct1<std::inplace_vector<int, 10> >();
}
int main()
{
test01();
return 0;
}

View File

@ -0,0 +1,16 @@
// { dg-do run { target c++26 xfail *-*-* } }
// { dg-require-debug-mode "" }
#include <inplace_vector>
#include <debug/checks.h>
void test01()
{
__gnu_test::check_construct2<std::inplace_vector<int, 10> >();
}
int main()
{
test01();
return 0;
}

View File

@ -0,0 +1,16 @@
// { dg-do run { target c++26 xfail *-*-* } }
// { dg-require-debug-mode "" }
#include <inplace_vector>
#include <debug/checks.h>
void test01()
{
__gnu_test::check_construct3<std::inplace_vector<int, 10> >();
}
int main()
{
test01();
return 0;
}

View File

@ -0,0 +1,15 @@
// { dg-do run { target c++26 xfail *-*-* } }
#include <debug/inplace_vector>
#include <debug/checks.h>
void test01()
{
__gnu_test::check_construct1<__gnu_debug::inplace_vector<int, 10> >();
}
int main()
{
test01();
return 0;
}

View File

@ -0,0 +1,34 @@
// { dg-do run { target c++26 } }
// { dg-require-debug-mode "" }
#include <inplace_vector>
#include <testsuite_hooks.h>
void test02()
{
using namespace __gnu_debug;
std::inplace_vector<int, 10> v1(3, 1);
VERIFY( !__check_singular(v1.begin()) );
auto it = v1.begin();
VERIFY( !__check_singular(it) );
VERIFY( !__check_singular(v1.end()) );
it = v1.end();
VERIFY( !__check_singular(it) );
v1.clear();
VERIFY( it._M_singular() );
VERIFY( __check_singular(it) );
it = v1.end();
VERIFY( !it._M_singular() );
VERIFY( !__check_singular(it) );
}
int main()
{
test02();
return 0;
}

View File

@ -0,0 +1,35 @@
// { dg-do run { target c++26 } }
// { dg-require-debug-mode "" }
#include <inplace_vector>
#include <testsuite_hooks.h>
void test01()
{
std::inplace_vector<int, 10> v;
for (int i = 0; i != 10; ++i)
v.push_back(i);
auto before = v.begin() + 4;
auto last = v.end() - 1;
VERIFY( std::erase(v, 6) == 1 );
VERIFY(before._M_dereferenceable());
VERIFY(last._M_singular());
}
void test02()
{
std::inplace_vector<int, 0> v;
VERIFY( std::erase(v, 6) == 0 );
}
int main()
{
test01();
test02();
return 0;
}

View File

@ -0,0 +1,16 @@
// { dg-do run { target c++26 xfail *-*-* } }
// { dg-require-debug-mode "" }
#include <inplace_vector>
#include <debug/checks.h>
void test01()
{
__gnu_test::check_insert1<std::inplace_vector<int, 10>>();
}
int main()
{
test01();
return 0;
}

View File

@ -0,0 +1,16 @@
// { dg-do run { target c++26 xfail *-*-* } }
// { dg-require-debug-mode "" }
#include <inplace_vector>
#include <debug/checks.h>
void test01()
{
__gnu_test::check_insert2<std::inplace_vector<int, 10>>();
}
int main()
{
test01();
return 0;
}

View File

@ -0,0 +1,16 @@
// { dg-do run { target c++26 xfail *-*-* } }
// { dg-require-debug-mode "" }
#include <inplace_vector>
#include <debug/checks.h>
void test01()
{
__gnu_test::check_insert3<std::inplace_vector<int, 10>>();
}
int main()
{
test01();
return 0;
}

View File

@ -0,0 +1,15 @@
// { dg-do run { target c++26 xfail *-*-* } }
#include <debug/inplace_vector>
#include <debug/checks.h>
void test01()
{
__gnu_test::check_insert1<__gnu_debug::inplace_vector<int, 10>>();
}
int main()
{
test01();
return 0;
}

View File

@ -0,0 +1,16 @@
// { dg-do run { target c++26 xfail *-*-* } }
// { dg-require-debug-mode "" }
#include <inplace_vector>
#include <debug/checks.h>
void test01()
{
__gnu_test::check_insert4<std::inplace_vector<int, 10>>();
}
int main()
{
test01();
return 0;
}

View File

@ -0,0 +1,24 @@
// { dg-do run { target c++26 xfail *-*-* } }
#include <memory>
#include <iterator>
#include <debug/inplace_vector>
void
test01()
{
__gnu_debug::inplace_vector<std::unique_ptr<int>, 10> v;
v.emplace_back(new int(0));
v.emplace_back(new int(1));
v.insert(begin(v) + 1,
make_move_iterator(begin(v)),
make_move_iterator(end(v)));
}
int
main()
{
test01();
}

View File

@ -0,0 +1,33 @@
// { dg-do run { target c++26 } }
#include <debug/inplace_vector>
#include <testsuite_hooks.h>
using __gnu_debug::inplace_vector;
// Assignment
void test01()
{
inplace_vector<int, 30> v1;
inplace_vector<int, 30> v2;
auto i = v1.end();
VERIFY(!i._M_dereferenceable() && !i._M_singular());
v1 = v2;
VERIFY(i._M_singular());
i = v1.end();
v1.assign(v2.begin(), v2.end());
VERIFY( !i._M_singular() );
i = v1.end();
v1.assign(17, 42);
VERIFY(i._M_singular());
}
int main()
{
test01();
return 0;
}

View File

@ -0,0 +1,34 @@
// { dg-do run { target c++26 } }
#include <debug/inplace_vector>
#include <testsuite_hooks.h>
using __gnu_debug::inplace_vector;
// Resize
void test01()
{
inplace_vector<int, 50> v(10, 17);
v.reserve(20);
auto before = v.begin() + 6;
auto at = before + 1;
auto after = at + 1;
// Shrink.
v.resize(7);
VERIFY(before._M_dereferenceable());
VERIFY(at._M_singular());
VERIFY(after._M_singular());
// Grow.
before = v.begin() + 6;
v.resize(17);
VERIFY(before._M_dereferenceable());
}
int main()
{
test01();
return 0;
}

View File

@ -0,0 +1,43 @@
// { dg-do run { target c++26 } }
#include <debug/inplace_vector>
#include <testsuite_hooks.h>
using __gnu_debug::inplace_vector;
// Insert
void test01()
{
inplace_vector<int, 100> v(10, 17);
v.reserve(30);
// Insert a single element
auto before = v.begin() + 6;
auto at = before + 1;
auto after = at;
at = v.insert(at, 42);
VERIFY(before._M_dereferenceable());
VERIFY(at._M_dereferenceable());
VERIFY(after._M_singular());
// Insert multiple copies
before = v.begin() + 6;
at = before + 1;
v.insert(at, 3, 42);
VERIFY(before._M_dereferenceable());
VERIFY(at._M_singular());
// Insert iterator range
static int data[] = { 2, 3, 5, 7 };
before = v.begin() + 6;
at = before + 1;
v.insert(at, &data[0], &data[0] + 4);
VERIFY(before._M_dereferenceable());
VERIFY(at._M_singular());
}
int main()
{
test01();
return 0;
}

View File

@ -0,0 +1,40 @@
// { dg-do run { target c++26 } }
#include <debug/inplace_vector>
#include <testsuite_hooks.h>
using __gnu_debug::inplace_vector;
// Erase
void test04()
{
inplace_vector<int, 30> v(20, 42);
// Single element erase
auto before = v.begin();
auto at = before + 3;
auto after = at;
at = v.erase(at);
VERIFY(before._M_dereferenceable());
VERIFY(at._M_dereferenceable());
VERIFY(after._M_singular());
// Multiple element erase
before = v.begin();
at = before + 3;
v.erase(at, at + 3);
VERIFY(before._M_dereferenceable());
VERIFY(at._M_singular());
// clear()
before = v.begin();
VERIFY(before._M_dereferenceable());
v.clear();
VERIFY(before._M_singular());
}
int main()
{
test04();
return 0;
}

View File

@ -0,0 +1,45 @@
// { dg-do run { target c++26 } }
#include <debug/inplace_vector>
#include <testsuite_hooks.h>
using __gnu_debug::inplace_vector;
void test01()
{
inplace_vector<int, 100> v(10, 17);
inplace_vector<int, 10> v1(10, 19);
auto before = v.begin() + 6;
auto last = v.end();
auto end = last--;
v.append_range(v1);
VERIFY(before._M_dereferenceable());
VERIFY(last._M_dereferenceable());
VERIFY(end._M_singular());
}
void test02()
{
inplace_vector<int, 100> v(10, 17);
inplace_vector<int, 0> v1;
auto before = v.begin() + 6;
auto last = v.end();
auto end = last--;
v.append_range(v1);
VERIFY(before._M_dereferenceable());
VERIFY(last._M_dereferenceable());
VERIFY(!end._M_singular());
}
int main()
{
test01();
test02();
return 0;
}

View File

@ -0,0 +1,36 @@
// { dg-do run { target c++26 } }
#include <debug/inplace_vector>
#include <testsuite_hooks.h>
using __gnu_debug::inplace_vector;
void test01()
{
inplace_vector<int, 10> v;
for (int i = 0; i != 10; ++i)
v.push_back(i);
auto before = v.begin() + 4;
auto last = v.end() - 1;
VERIFY( std::erase(v, 6) == 1 );
VERIFY(before._M_dereferenceable());
VERIFY(last._M_singular());
}
void test02()
{
inplace_vector<int, 0> v;
VERIFY( std::erase(v, 6) == 0 );
}
int main()
{
test01();
test02();
return 0;
}

View File

@ -0,0 +1,27 @@
// { dg-do run { target c++26 } }
#include <debug/inplace_vector>
#include <testsuite_hooks.h>
using __gnu_debug::inplace_vector;
void test01()
{
inplace_vector<int, 100> v(10, 17);
auto before = v.begin() + 6;
auto last = v.end();
auto end = last--;
v.pop_back();
VERIFY(before._M_dereferenceable());
VERIFY(last._M_singular());
VERIFY(end._M_singular());
}
int main()
{
test01();
return 0;
}

View File

@ -0,0 +1,53 @@
// { dg-do run { target c++26 } }
#include <debug/inplace_vector>
#include <testsuite_hooks.h>
using __gnu_debug::inplace_vector;
void test01()
{
inplace_vector<int, 100> v(10, 17);
auto before = v.begin() + 6;
auto last = v.end();
auto end = last--;
v.push_back(42);
VERIFY(before._M_dereferenceable());
VERIFY(last._M_dereferenceable());
VERIFY(end._M_singular());
}
#if __cpp_exceptions
void test02()
{
inplace_vector<int, 10> v(10, 17);
auto before = v.begin() + 6;
auto last = v.end();
auto end = last--;
try
{
v.push_back(42);
VERIFY( false );
}
catch (std::bad_alloc&)
{
}
VERIFY(before._M_dereferenceable());
VERIFY(last._M_dereferenceable());
VERIFY(!end._M_singular());
}
#endif
int main()
{
test01();
#if __cpp_exceptions
test02();
#endif
return 0;
}

View File

@ -0,0 +1,53 @@
// { dg-do run { target c++26 } }
#include <debug/inplace_vector>
#include <testsuite_hooks.h>
using __gnu_debug::inplace_vector;
void test01()
{
inplace_vector<int, 10> v1;
inplace_vector<int, 10> v2;
for (int i = 0; i != 10; ++i)
{
v1.push_back(i);
v2.push_back(i);
}
auto it1 = v1.begin();
auto it2 = v2.begin();
std::swap(v1, v2);
VERIFY(it1._M_singular());
VERIFY(it2._M_singular());
}
void test02()
{
inplace_vector<int, 10> v1;
inplace_vector<int, 10> v2;
for (int i = 0; i != 10; ++i)
{
v1.push_back(i);
v2.push_back(i);
}
auto it1 = v1.begin();
auto it2 = v2.begin();
swap(v1, v2);
VERIFY(it1._M_singular());
VERIFY(it2._M_singular());
}
int main()
{
test01();
test02();
return 0;
}

View File

@ -0,0 +1,45 @@
// { dg-do run { target c++26 } }
#include <debug/inplace_vector>
#include <testsuite_hooks.h>
using __gnu_debug::inplace_vector;
void test01()
{
inplace_vector<int, 100> v(10, 17);
inplace_vector<int, 10> v1(10, 19);
auto before = v.begin() + 6;
auto last = v.end();
auto end = last--;
v.try_append_range(v1);
VERIFY(before._M_dereferenceable());
VERIFY(last._M_dereferenceable());
VERIFY(end._M_singular());
}
void test02()
{
inplace_vector<int, 100> v(10, 17);
inplace_vector<int, 0> v1;
auto before = v.begin() + 6;
auto last = v.end();
auto end = last--;
v.try_append_range(v1);
VERIFY(before._M_dereferenceable());
VERIFY(last._M_dereferenceable());
VERIFY(!end._M_singular());
}
int main()
{
test01();
test02();
return 0;
}

View File

@ -0,0 +1,27 @@
// { dg-do run { target c++26 } }
#include <debug/inplace_vector>
#include <testsuite_hooks.h>
using __gnu_debug::inplace_vector;
void test01()
{
inplace_vector<int, 100> v(10, 17);
auto before = v.begin() + 6;
auto last = v.end();
auto end = last--;
VERIFY( v.try_emplace_back(42) != nullptr );
VERIFY(before._M_dereferenceable());
VERIFY(last._M_dereferenceable());
VERIFY(end._M_singular());
}
int main()
{
test01();
return 0;
}

View File

@ -0,0 +1,45 @@
// { dg-do run { target c++26 } }
#include <debug/inplace_vector>
#include <vector>
#include <testsuite_hooks.h>
using __gnu_debug::inplace_vector;
void test01()
{
inplace_vector<int, 100> v(10, 17);
auto before = v.begin() + 6;
auto last = v.end();
auto end = last--;
VERIFY( v.try_push_back(42) != nullptr );
VERIFY(before._M_dereferenceable());
VERIFY(last._M_dereferenceable());
VERIFY(end._M_singular());
}
void test02()
{
std::vector<int> vv { 0, 1, 2, 3, 4, 5 };
inplace_vector<std::vector<int>, 100> v(10, vv);
auto before = v.begin() + 6;
auto last = v.end();
auto end = last--;
VERIFY( v.try_push_back(std::move(vv)) != nullptr );
VERIFY(before._M_dereferenceable());
VERIFY(last._M_dereferenceable());
VERIFY(end._M_singular());
}
int main()
{
test01();
test02();
return 0;
}

View File

@ -0,0 +1,27 @@
// { dg-do run { target c++26 } }
#include <debug/inplace_vector>
#include <testsuite_hooks.h>
using __gnu_debug::inplace_vector;
void test01()
{
inplace_vector<int, 100> v(10, 17);
auto before = v.begin() + 6;
auto last = v.end();
auto end = last--;
v.unchecked_emplace_back(42);
VERIFY(before._M_dereferenceable());
VERIFY(last._M_dereferenceable());
VERIFY(end._M_singular());
}
int main()
{
test01();
return 0;
}

View File

@ -91,12 +91,14 @@ static_assert(!std::is_nothrow_move_constructible_v<std::inplace_vector<N<false,
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>>);
#if !_GLIBCXX_DEBUG
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>>);
#endif
static_assert(std::is_move_assignable_v<std::inplace_vector<int, 2>>);
static_assert(std::is_move_assignable_v<std::inplace_vector<X, 2>>);
@ -115,12 +117,14 @@ static_assert(!std::is_nothrow_move_assignable_v<std::inplace_vector<N<false, fa
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>>);
#if !_GLIBCXX_DEBUG
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>>);
#endif
static_assert(std::is_nothrow_swappable_v<std::inplace_vector<int, 2>>);
static_assert(!std::is_nothrow_swappable_v<std::inplace_vector<X, 2>>);

View File

@ -19,10 +19,12 @@
#include <vector>
#include <deque>
#include <list>
#include <inplace_vector>
#ifndef _GLIBCXX_DEBUG
# include <debug/vector>
# include <debug/deque>
# include <debug/list>
# include <debug/inplace_vector>
#endif
#include <testsuite_hooks.h>
@ -88,10 +90,11 @@ namespace __gnu_test
void
check_assign1()
{
using namespace std;
typedef _Tp cont_type;
typedef typename cont_type::value_type cont_val_type;
typedef typename CopyableValueType<cont_val_type>::value_type val_type;
typedef std::vector<val_type> vector_type;
typedef _GLIBCXX_STD_C::vector<val_type> vector_type;
generate_unique<val_type> gu;
@ -116,10 +119,11 @@ namespace __gnu_test
void
check_assign2()
{
using namespace std;
typedef _Tp cont_type;
typedef typename cont_type::value_type cont_val_type;
typedef typename CopyableValueType<cont_val_type>::value_type val_type;
typedef std::vector<val_type> vector_type;
typedef _GLIBCXX_STD_C::vector<val_type> vector_type;
generate_unique<val_type> gu;
@ -170,10 +174,11 @@ namespace __gnu_test
void
check_construct1()
{
using namespace std;
typedef _Tp cont_type;
typedef typename cont_type::value_type cont_val_type;
typedef typename CopyableValueType<cont_val_type>::value_type val_type;
typedef std::vector<val_type> vector_type;
typedef _GLIBCXX_STD_C::vector<val_type> vector_type;
generate_unique<val_type> gu;
@ -193,10 +198,11 @@ namespace __gnu_test
void
check_construct2()
{
using namespace std;
typedef _Tp cont_type;
typedef typename cont_type::value_type cont_val_type;
typedef typename CopyableValueType<cont_val_type>::value_type val_type;
typedef std::vector<val_type> vector_type;
typedef _GLIBCXX_STD_C::vector<val_type> vector_type;
generate_unique<val_type> gu;
@ -267,6 +273,13 @@ namespace __gnu_test
: InsertRangeHelperAux<std::list<_Tp1, _Tp2> >
{ };
#ifdef __glibcxx_inplace_vector // C++ >= 26
template<typename _Tp, size_t _Nm>
struct InsertRangeHelper<std::inplace_vector<_Tp, _Nm> >
: InsertRangeHelperAux<std::inplace_vector<_Tp, _Nm> >
{ };
#endif
#ifndef _GLIBCXX_DEBUG
template <typename _Tp1, typename _Tp2>
struct InsertRangeHelper<__gnu_debug::vector<_Tp1, _Tp2> >
@ -282,16 +295,24 @@ namespace __gnu_test
struct InsertRangeHelper<__gnu_debug::list<_Tp1, _Tp2> >
: InsertRangeHelperAux<__gnu_debug::list<_Tp1, _Tp2> >
{ };
# ifdef __glibcxx_inplace_vector // C++ >= 26
template<typename _Tp, size_t _Nm>
struct InsertRangeHelper<__gnu_debug::inplace_vector<_Tp, _Nm> >
: InsertRangeHelperAux<__gnu_debug::inplace_vector<_Tp, _Nm> >
{ };
# endif
#endif
template<typename _Tp>
void
check_insert1()
{
using namespace std;
typedef _Tp cont_type;
typedef typename cont_type::value_type cont_val_type;
typedef typename CopyableValueType<cont_val_type>::value_type val_type;
typedef std::vector<val_type> vector_type;
typedef _GLIBCXX_STD_C::vector<val_type> vector_type;
generate_unique<val_type> gu;
@ -315,10 +336,11 @@ namespace __gnu_test
void
check_insert2()
{
using namespace std;
typedef _Tp cont_type;
typedef typename cont_type::value_type cont_val_type;
typedef typename CopyableValueType<cont_val_type>::value_type val_type;
typedef std::vector<val_type> vector_type;
typedef _GLIBCXX_STD_C::vector<val_type> vector_type;
generate_unique<val_type> gu;
@ -369,10 +391,11 @@ namespace __gnu_test
void
check_insert4()
{
using namespace std;
typedef _Tp cont_type;
typedef typename cont_type::value_type cont_val_type;
typedef typename CopyableValueType<cont_val_type>::value_type val_type;
typedef std::list<val_type> list_type;
typedef _GLIBCXX_STD_C::list<val_type> list_type;
generate_unique<val_type> gu;