Files
gcc/libstdc++-v3/include/debug/list
François Dumont 2fd6f42c17 libstdc++: Make debug iterator pointer sequence const [PR116369]
In revision a35dd276cb the debug sequence
have been made mutable to allow attach iterators to const containers.
This change completes this fix by also declaring debug unordered container
members mutable.

Additionally the debug iterator sequence is now a pointer-to-const and so
_Safe_sequence_base _M_attach and all other methods are const qualified.
Not-const methods exported are preserved for abi backward compatibility.

libstdc++-v3/ChangeLog:

	PR c++/116369
	* config/abi/pre/gnu-versioned-namespace.ver: Use new const qualified symbols.
	* config/abi/pre/gnu.ver: Add new const qualified symbols.
	* include/debug/safe_base.h
	(_Safe_iterator_base::_M_sequence): Declare as pointer-to-const.
	(_Safe_iterator_base::_M_attach, _M_attach_single): New, take pointer-to-const
	_Safe_sequence_base.
	(_Safe_sequence_base::_M_detach_all, _M_detach_singular, _M_revalidate_singular)
	(_M_swap, _M_get_mutex): New, const qualified.
	(_Safe_sequence_base::_M_attach, _M_attach_single, _M_detach, _M_detach_single):
	const qualify.
	* include/debug/safe_container.h (_Safe_container<>::_M_cont): Add const qualifier.
	(_Safe_container<>::_M_swap_base): New.
	(_Safe_container(_Safe_container&&, const _Alloc&, std::false_type)):
	Adapt to use latter.
	(_Safe_container<>::operator=(_Safe_container&&)): Likewise.
	(_Safe_container<>::_M_swap): Likewise and take parameter as const reference.
	* include/debug/safe_unordered_base.h
	(_Safe_local_iterator_base::_M_safe_container): New.
	(_Safe_local_iterator_base::_Safe_local_iterator_base): Take
	_Safe_unordered_container_base as pointer-to-const.
	(_Safe_unordered_container_base::_M_attach, _M_attach_single): New, take
	container as _Safe_unordered_container_base pointer-to-const.
	(_Safe_unordered_container_base::_M_local_iterators, _M_const_local_iterators):
	Add mutable.
	(_Safe_unordered_container_base::_M_detach_all, _M_swap): New, const qualify.
	(_Safe_unordered_container_base::_M_attach_local, _M_attach_local_single)
	(_M_detach_local, _M_detach_local_single): Add const qualifier.
	* include/debug/safe_unordered_container.h (_Safe_unordered_container::_M_self()): New.
	* include/debug/safe_unordered_container.tcc
	(_Safe_unordered_container::_M_invalidate_if, _M_invalidated_local_if): Use latter.
	* include/debug/safe_iterator.h (_Safe_iterator<>::_M_attach, _M_attach_single):
	Take _Safe_sequence_base as pointer-to-const.
	(_Safe_iterator<>::_M_get_sequence): Add const_cast and comment about it.
	* include/debug/safe_local_iterator.h (_Safe_local_iterator<>): Replace usages
	of _M_sequence member by _M_safe_container().
	(_Safe_local_iterator<>::_M_attach, _M_attach_single): Take
	_Safe_unordered_container_base as pointer-to-const.
	(_Safe_local_iterator<>::_M_get_sequence): Rename into...
	(_Safe_local_iterator<>::_M_get_ucontainer): ...this. Add necessary const_cast and
	comment to explain it.
	(_Safe_local_iterator<>::_M_is_begin, _M_is_end): Adapt.
	* include/debug/safe_local_iterator.tcc: Adapt.
	* include/debug/safe_sequence.h
	(_Safe_sequence<>::_M_invalidate_if, _M_transfer_from_if): Add const qualifier.
	* include/debug/safe_sequence.tcc: Adapt.
	* include/debug/deque (std::__debug::deque::erase): Adapt to use new const
	qualified methods.
	* include/debug/formatter.h: Adapt.
	* include/debug/forward_list (_Safe_forward_list::_M_this): Add const
	qualification and return pointer for consistency with 'this' keyword.
	(_Safe_forward_list::_M_swap_aux): Rename into...
	(_Safe_forward_list::_S_swap_aux): ...this and take sequence as const reference.
	(forward_list<>::resize): Adapt to use const methods.
	* include/debug/list (list<>::resize): Likewise.
	* src/c++11/debug.cc: Adapt to const qualification.
	* testsuite/util/testsuite_containers.h
	(forward_members_unordered::forward_members_unordered): Add check on local_iterator
	conversion to const_local_iterator.
	(forward_members::forward_members): Add check on iterator conversion to
	const_iterator.
	* testsuite/23_containers/unordered_map/const_container.cc: New test case.
	* testsuite/23_containers/unordered_multimap/const_container.cc: New test case.
	* testsuite/23_containers/unordered_multiset/const_container.cc: New test case.
	* testsuite/23_containers/unordered_set/const_container.cc: New test case.
	* testsuite/23_containers/vector/debug/mutex_association.cc: Adapt.
2025-07-08 07:04:00 +02:00

1062 lines
28 KiB
C++

// Debugging list implementation -*- C++ -*-
// Copyright (C) 2003-2025 Free Software Foundation, Inc.
//
// 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/list
* This file is a GNU debug extension to the Standard C++ Library.
*/
#ifndef _GLIBCXX_DEBUG_LIST
#define _GLIBCXX_DEBUG_LIST 1
#ifdef _GLIBCXX_SYSHDR
#pragma GCC system_header
#endif
#include <bits/c++config.h>
namespace std _GLIBCXX_VISIBILITY(default) { namespace __debug {
template<typename _Tp, typename _Allocator> class list;
} } // namespace std::__debug
#include <list>
#include <debug/safe_sequence.h>
#include <debug/safe_container.h>
#include <debug/safe_iterator.h>
namespace std _GLIBCXX_VISIBILITY(default)
{
namespace __debug
{
/// Class std::list with safety/checking/debug instrumentation.
template<typename _Tp, typename _Allocator = std::allocator<_Tp> >
class list
: public __gnu_debug::_Safe_container<
list<_Tp, _Allocator>, _Allocator,
__gnu_debug::_Safe_node_sequence>,
public _GLIBCXX_STD_C::list<_Tp, _Allocator>
{
typedef _GLIBCXX_STD_C::list<_Tp, _Allocator> _Base;
typedef __gnu_debug::_Safe_container<
list, _Allocator, __gnu_debug::_Safe_node_sequence> _Safe;
typedef typename _Base::iterator _Base_iterator;
typedef typename _Base::const_iterator _Base_const_iterator;
typedef __gnu_debug::_Equal_to<_Base_const_iterator> _Equal;
typedef __gnu_debug::_Not_equal_to<_Base_const_iterator> _Not_equal;
template<typename _ItT, typename _SeqT, typename _CatT>
friend class ::__gnu_debug::_Safe_iterator;
// Reference wrapper for base class. Disambiguates list(const _Base&)
// from copy constructor by requiring a user-defined conversion.
// See PR libstdc++/90102.
struct _Base_ref
{
_Base_ref(const _Base& __r) : _M_ref(__r) { }
const _Base& _M_ref;
};
public:
typedef typename _Base::reference reference;
typedef typename _Base::const_reference const_reference;
typedef __gnu_debug::_Safe_iterator<_Base_iterator, list>
iterator;
typedef __gnu_debug::_Safe_iterator<_Base_const_iterator, list>
const_iterator;
typedef typename _Base::size_type size_type;
typedef typename _Base::difference_type difference_type;
typedef _Tp value_type;
typedef _Allocator allocator_type;
typedef typename _Base::pointer pointer;
typedef typename _Base::const_pointer const_pointer;
typedef std::reverse_iterator<iterator> reverse_iterator;
typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
// 23.2.2.1 construct/copy/destroy:
#if __cplusplus < 201103L
list()
: _Base() { }
list(const list& __x)
: _Base(__x) { }
~list() { }
#else
list() = default;
list(const list&) = default;
list(list&&) = default;
list(initializer_list<value_type> __l,
const allocator_type& __a = allocator_type())
: _Base(__l, __a) { }
~list() = default;
list(const list& __x, const __type_identity_t<allocator_type>& __a)
: _Base(__x, __a) { }
list(list&& __x, const __type_identity_t<allocator_type>& __a)
noexcept(
std::is_nothrow_constructible<_Base,
_Base, const allocator_type&>::value )
: _Safe(std::move(__x), __a),
_Base(std::move(__x), __a) { }
#endif
explicit
list(const _Allocator& __a) _GLIBCXX_NOEXCEPT
: _Base(__a) { }
#if __cplusplus >= 201103L
explicit
list(size_type __n, const allocator_type& __a = allocator_type())
: _Base(__n, __a) { }
list(size_type __n, const __type_identity_t<_Tp>& __value,
const _Allocator& __a = _Allocator())
: _Base(__n, __value, __a) { }
#else
explicit
list(size_type __n, const _Tp& __value = _Tp(),
const _Allocator& __a = _Allocator())
: _Base(__n, __value, __a) { }
#endif
#if __cplusplus >= 201103L
template<class _InputIterator,
typename = std::_RequireInputIter<_InputIterator>>
#else
template<class _InputIterator>
#endif
list(_InputIterator __first, _InputIterator __last,
const _Allocator& __a = _Allocator())
: _Base(__gnu_debug::__base(
__glibcxx_check_valid_constructor_range(__first, __last)),
__gnu_debug::__base(__last), __a)
{ }
#if __glibcxx_containers_ranges // C++ >= 23
template<__detail::__container_compatible_range<_Tp> _Rg>
list(from_range_t, _Rg&& __rg, const _Allocator& __a = _Allocator())
: _Base(std::from_range, std::forward<_Rg>(__rg), __a)
{ }
#endif
list(_Base_ref __x)
: _Base(__x._M_ref) { }
#if __cplusplus >= 201103L
list&
operator=(const list&) = default;
list&
operator=(list&&) = default;
list&
operator=(initializer_list<value_type> __l)
{
this->_M_invalidate_all();
_Base::operator=(__l);
return *this;
}
void
assign(initializer_list<value_type> __l)
{
_Base::assign(__l);
this->_M_invalidate_all();
}
#endif
#if __cplusplus >= 201103L
template<class _InputIterator,
typename = std::_RequireInputIter<_InputIterator>>
#else
template<class _InputIterator>
#endif
void
assign(_InputIterator __first, _InputIterator __last)
{
typename __gnu_debug::_Distance_traits<_InputIterator>::__type __dist;
__glibcxx_check_valid_range2(__first, __last, __dist);
if (__dist.second >= __gnu_debug::__dp_sign)
_Base::assign(__gnu_debug::__unsafe(__first),
__gnu_debug::__unsafe(__last));
else
_Base::assign(__first, __last);
this->_M_invalidate_all();
}
#if __glibcxx_containers_ranges // C++ >= 23
template<__detail::__container_compatible_range<_Tp> _Rg>
void
assign_range(_Rg&& __rg)
{
// Have to reimplement this function, so that we use the debug
// version of erase, which invalidates the correct iterators.
static_assert(assignable_from<_Tp&, ranges::range_reference_t<_Rg>>);
auto __first1 = _Base::begin();
const auto __last1 = _Base::end();
auto __first2 = ranges::begin(__rg);
const auto __last2 = ranges::end(__rg);
for (; __first1 != __last1 && __first2 != __last2;
++__first1, (void)++__first2)
*__first1 = *__first2;
if (__first2 == __last2)
erase(const_iterator(__first1, this),
const_iterator(__last1, this));
else
_Base::insert_range(__last1,
ranges::subrange(std::move(__first2), __last2));
}
#endif
void
assign(size_type __n, const _Tp& __t)
{
_Base::assign(__n, __t);
this->_M_invalidate_all();
}
using _Base::get_allocator;
// iterators:
_GLIBCXX_NODISCARD
iterator
begin() _GLIBCXX_NOEXCEPT
{ return iterator(_Base::begin(), this); }
_GLIBCXX_NODISCARD
const_iterator
begin() const _GLIBCXX_NOEXCEPT
{ return const_iterator(_Base::begin(), this); }
_GLIBCXX_NODISCARD
iterator
end() _GLIBCXX_NOEXCEPT
{ return iterator(_Base::end(), this); }
_GLIBCXX_NODISCARD
const_iterator
end() const _GLIBCXX_NOEXCEPT
{ return const_iterator(_Base::end(), this); }
_GLIBCXX_NODISCARD
reverse_iterator
rbegin() _GLIBCXX_NOEXCEPT
{ return reverse_iterator(end()); }
_GLIBCXX_NODISCARD
const_reverse_iterator
rbegin() const _GLIBCXX_NOEXCEPT
{ return const_reverse_iterator(end()); }
_GLIBCXX_NODISCARD
reverse_iterator
rend() _GLIBCXX_NOEXCEPT
{ return reverse_iterator(begin()); }
_GLIBCXX_NODISCARD
const_reverse_iterator
rend() const _GLIBCXX_NOEXCEPT
{ return const_reverse_iterator(begin()); }
#if __cplusplus >= 201103L
[[__nodiscard__]]
const_iterator
cbegin() const noexcept
{ return const_iterator(_Base::begin(), this); }
[[__nodiscard__]]
const_iterator
cend() const noexcept
{ return const_iterator(_Base::end(), this); }
[[__nodiscard__]]
const_reverse_iterator
crbegin() const noexcept
{ return const_reverse_iterator(end()); }
[[__nodiscard__]]
const_reverse_iterator
crend() const noexcept
{ return const_reverse_iterator(begin()); }
#endif
// 23.2.2.2 capacity:
using _Base::empty;
using _Base::size;
using _Base::max_size;
#if __cplusplus >= 201103L
void
resize(size_type __sz)
{
const list* __this = this;
__this->_M_detach_singular();
// if __sz < size(), invalidate all iterators in [begin + __sz, end())
_Base_iterator __victim = _Base::begin();
_Base_iterator __end = _Base::end();
for (size_type __i = __sz; __victim != __end && __i > 0; --__i)
++__victim;
for (; __victim != __end; ++__victim)
this->_M_invalidate_if(_Equal(__victim));
__try
{
_Base::resize(__sz);
}
__catch(...)
{
__this->_M_revalidate_singular();
__throw_exception_again;
}
}
void
resize(size_type __sz, const _Tp& __c)
{
const list* __this = this;
__this->_M_detach_singular();
// if __sz < size(), invalidate all iterators in [begin + __sz, end())
_Base_iterator __victim = _Base::begin();
_Base_iterator __end = _Base::end();
for (size_type __i = __sz; __victim != __end && __i > 0; --__i)
++__victim;
for (; __victim != __end; ++__victim)
this->_M_invalidate_if(_Equal(__victim));
__try
{
_Base::resize(__sz, __c);
}
__catch(...)
{
__this->_M_revalidate_singular();
__throw_exception_again;
}
}
#else
void
resize(size_type __sz, _Tp __c = _Tp())
{
const list* __this = this;
__this->_M_detach_singular();
// if __sz < size(), invalidate all iterators in [begin + __sz, end())
_Base_iterator __victim = _Base::begin();
_Base_iterator __end = _Base::end();
for (size_type __i = __sz; __victim != __end && __i > 0; --__i)
++__victim;
for (; __victim != __end; ++__victim)
this->_M_invalidate_if(_Equal(__victim));
__try
{
_Base::resize(__sz, __c);
}
__catch(...)
{
__this->_M_revalidate_singular();
__throw_exception_again;
}
}
#endif
// element access:
_GLIBCXX_NODISCARD
reference
front() _GLIBCXX_NOEXCEPT
{
__glibcxx_check_nonempty();
return _Base::front();
}
_GLIBCXX_NODISCARD
const_reference
front() const _GLIBCXX_NOEXCEPT
{
__glibcxx_check_nonempty();
return _Base::front();
}
_GLIBCXX_NODISCARD
reference
back() _GLIBCXX_NOEXCEPT
{
__glibcxx_check_nonempty();
return _Base::back();
}
_GLIBCXX_NODISCARD
const_reference
back() const _GLIBCXX_NOEXCEPT
{
__glibcxx_check_nonempty();
return _Base::back();
}
// 23.2.2.3 modifiers:
using _Base::push_front;
#if __cplusplus >= 201103L
using _Base::emplace_front;
#endif
#if __glibcxx_containers_ranges // C++ >= 23
using _Base::prepend_range;
using _Base::append_range;
#endif
void
pop_front() _GLIBCXX_NOEXCEPT
{
__glibcxx_check_nonempty();
this->_M_invalidate_if(_Equal(_Base::begin()));
_Base::pop_front();
}
using _Base::push_back;
#if __cplusplus >= 201103L
using _Base::emplace_back;
#endif
void
pop_back() _GLIBCXX_NOEXCEPT
{
__glibcxx_check_nonempty();
this->_M_invalidate_if(_Equal(--_Base::end()));
_Base::pop_back();
}
#if __cplusplus >= 201103L
template<typename... _Args>
iterator
emplace(const_iterator __position, _Args&&... __args)
{
__glibcxx_check_insert(__position);
return { _Base::emplace(__position.base(),
std::forward<_Args>(__args)...), this };
}
#endif
iterator
#if __cplusplus >= 201103L
insert(const_iterator __position, const _Tp& __x)
#else
insert(iterator __position, const _Tp& __x)
#endif
{
__glibcxx_check_insert(__position);
return iterator(_Base::insert(__position.base(), __x), this);
}
#if __cplusplus >= 201103L
iterator
insert(const_iterator __position, _Tp&& __x)
{ return emplace(__position, std::move(__x)); }
iterator
insert(const_iterator __p, initializer_list<value_type> __l)
{
__glibcxx_check_insert(__p);
return { _Base::insert(__p.base(), __l), this };
}
#endif
#if __cplusplus >= 201103L
iterator
insert(const_iterator __position, size_type __n, const _Tp& __x)
{
__glibcxx_check_insert(__position);
return { _Base::insert(__position.base(), __n, __x), this };
}
#else
void
insert(iterator __position, size_type __n, const _Tp& __x)
{
__glibcxx_check_insert(__position);
_Base::insert(__position.base(), __n, __x);
}
#endif
#if __cplusplus >= 201103L
template<class _InputIterator,
typename = std::_RequireInputIter<_InputIterator>>
iterator
insert(const_iterator __position, _InputIterator __first,
_InputIterator __last)
{
typename __gnu_debug::_Distance_traits<_InputIterator>::__type __dist;
__glibcxx_check_insert_range(__position, __first, __last, __dist);
if (__dist.second >= __gnu_debug::__dp_sign)
return
{
_Base::insert(__position.base(),
__gnu_debug::__unsafe(__first),
__gnu_debug::__unsafe(__last)),
this
};
else
return { _Base::insert(__position.base(), __first, __last), this };
}
#else
template<class _InputIterator>
void
insert(iterator __position, _InputIterator __first,
_InputIterator __last)
{
typename __gnu_debug::_Distance_traits<_InputIterator>::__type __dist;
__glibcxx_check_insert_range(__position, __first, __last, __dist);
if (__dist.second >= __gnu_debug::__dp_sign)
_Base::insert(__position.base(), __gnu_debug::__unsafe(__first),
__gnu_debug::__unsafe(__last));
else
_Base::insert(__position.base(), __first, __last);
}
#endif
#if __glibcxx_containers_ranges // C++ >= 23
template<__detail::__container_compatible_range<_Tp> _Rg>
iterator
insert_range(const_iterator __position, _Rg&& __rg)
{
auto __ret = _Base::insert_range(__position.base(),
std::forward<_Rg>(__rg));
return { __ret, this };
}
#endif
private:
_Base_iterator
#if __cplusplus >= 201103L
_M_erase(_Base_const_iterator __position) noexcept
#else
_M_erase(_Base_iterator __position)
#endif
{
this->_M_invalidate_if(_Equal(__position));
return _Base::erase(__position);
}
public:
iterator
#if __cplusplus >= 201103L
erase(const_iterator __position) noexcept
#else
erase(iterator __position)
#endif
{
__glibcxx_check_erase(__position);
return iterator(_M_erase(__position.base()), this);
}
iterator
#if __cplusplus >= 201103L
erase(const_iterator __first, const_iterator __last) noexcept
#else
erase(iterator __first, iterator __last)
#endif
{
// _GLIBCXX_RESOLVE_LIB_DEFECTS
// 151. can't currently clear() empty container
__glibcxx_check_erase_range(__first, __last);
for (_Base_const_iterator __victim = __first.base();
__victim != __last.base(); ++__victim)
{
_GLIBCXX_DEBUG_VERIFY(__victim != _Base::end(),
_M_message(__gnu_debug::__msg_valid_range)
._M_iterator(__first, "position")
._M_iterator(__last, "last"));
this->_M_invalidate_if(_Equal(__victim));
}
return iterator(_Base::erase(__first.base(), __last.base()), this);
}
void
swap(list& __x)
_GLIBCXX_NOEXCEPT_IF( noexcept(declval<_Base&>().swap(__x)) )
{
_Safe::_M_swap(__x);
_Base::swap(__x);
}
void
clear() _GLIBCXX_NOEXCEPT
{
_Base::clear();
this->_M_invalidate_all();
}
// 23.2.2.4 list operations:
void
#if __cplusplus >= 201103L
splice(const_iterator __position, list&& __x) noexcept
#else
splice(iterator __position, list& __x)
#endif
{
_GLIBCXX_DEBUG_VERIFY(std::__addressof(__x) != this,
_M_message(__gnu_debug::__msg_self_splice)
._M_sequence(*this, "this"));
this->_M_transfer_from_if(__x, _Not_equal(__x._M_base().end()));
_Base::splice(__position.base(), _GLIBCXX_MOVE(__x));
}
#if __cplusplus >= 201103L
void
splice(const_iterator __position, list& __x) noexcept
{ splice(__position, std::move(__x)); }
#endif
void
#if __cplusplus >= 201103L
splice(const_iterator __position, list&& __x, const_iterator __i) noexcept
#else
splice(iterator __position, list& __x, iterator __i)
#endif
{
__glibcxx_check_insert(__position);
// We used to perform the splice_alloc check: not anymore, redundant
// after implementing the relevant bits of N1599.
_GLIBCXX_DEBUG_VERIFY(__i._M_dereferenceable(),
_M_message(__gnu_debug::__msg_splice_bad)
._M_iterator(__i, "__i"));
_GLIBCXX_DEBUG_VERIFY(__i._M_attached_to(std::__addressof(__x)),
_M_message(__gnu_debug::__msg_splice_other)
._M_iterator(__i, "__i")._M_sequence(__x, "__x"));
// _GLIBCXX_RESOLVE_LIB_DEFECTS
// 250. splicing invalidates iterators
this->_M_transfer_from_if(__x, _Equal(__i.base()));
_Base::splice(__position.base(), _GLIBCXX_MOVE(__x),
__i.base());
}
#if __cplusplus >= 201103L
void
splice(const_iterator __position, list& __x, const_iterator __i) noexcept
{ splice(__position, std::move(__x), __i); }
#endif
void
#if __cplusplus >= 201103L
splice(const_iterator __position, list&& __x, const_iterator __first,
const_iterator __last) noexcept
#else
splice(iterator __position, list& __x, iterator __first,
iterator __last)
#endif
{
__glibcxx_check_insert(__position);
__glibcxx_check_valid_range(__first, __last);
_GLIBCXX_DEBUG_VERIFY(__first._M_attached_to(std::__addressof(__x)),
_M_message(__gnu_debug::__msg_splice_other)
._M_sequence(__x, "x")
._M_iterator(__first, "first"));
// We used to perform the splice_alloc check: not anymore, redundant
// after implementing the relevant bits of N1599.
for (_Base_const_iterator __tmp = __first.base();
__tmp != __last.base(); ++__tmp)
{
_GLIBCXX_DEBUG_VERIFY(__tmp != _Base::end(),
_M_message(__gnu_debug::__msg_valid_range)
._M_iterator(__first, "first")
._M_iterator(__last, "last"));
_GLIBCXX_DEBUG_VERIFY(std::__addressof(__x) != this
|| __tmp != __position.base(),
_M_message(__gnu_debug::__msg_splice_overlap)
._M_iterator(__tmp, "position")
._M_iterator(__first, "first")
._M_iterator(__last, "last"));
// _GLIBCXX_RESOLVE_LIB_DEFECTS
// 250. splicing invalidates iterators
this->_M_transfer_from_if(__x, _Equal(__tmp));
}
_Base::splice(__position.base(), _GLIBCXX_MOVE(__x),
__first.base(), __last.base());
}
#if __cplusplus >= 201103L
void
splice(const_iterator __position, list& __x,
const_iterator __first, const_iterator __last) noexcept
{ splice(__position, std::move(__x), __first, __last); }
#endif
private:
#if __cplusplus > 201703L
typedef size_type __remove_return_type;
# define _GLIBCXX_LIST_REMOVE_RETURN_TYPE_TAG \
__attribute__((__abi_tag__("__cxx20")))
# define _GLIBCXX20_ONLY(__expr) __expr
#else
typedef void __remove_return_type;
# define _GLIBCXX_LIST_REMOVE_RETURN_TYPE_TAG
# define _GLIBCXX20_ONLY(__expr)
#endif
public:
_GLIBCXX_LIST_REMOVE_RETURN_TYPE_TAG
__remove_return_type
remove(const _Tp& __value)
{
if (!this->_M_iterators && !this->_M_const_iterators)
return _Base::remove(__value);
#if !_GLIBCXX_USE_CXX11_ABI
size_type __removed __attribute__((__unused__)) = 0;
#endif
_Base __to_destroy(get_allocator());
_Base_iterator __first = _Base::begin();
_Base_iterator __last = _Base::end();
while (__first != __last)
{
_Base_iterator __next = __first;
++__next;
if (*__first == __value)
{
// _GLIBCXX_RESOLVE_LIB_DEFECTS
// 526. Is it undefined if a function in the standard changes
// in parameters?
this->_M_invalidate_if(_Equal(__first));
__to_destroy.splice(__to_destroy.begin(), *this, __first);
#if !_GLIBCXX_USE_CXX11_ABI
_GLIBCXX20_ONLY( __removed++ );
#endif
}
__first = __next;
}
#if !_GLIBCXX_USE_CXX11_ABI
return _GLIBCXX20_ONLY( __removed );
#else
return _GLIBCXX20_ONLY( __to_destroy.size() );
#endif
}
template<class _Predicate>
__remove_return_type
remove_if(_Predicate __pred)
{
if (!this->_M_iterators && !this->_M_const_iterators)
return _Base::remove_if(__pred);
#if !_GLIBCXX_USE_CXX11_ABI
size_type __removed __attribute__((__unused__)) = 0;
#endif
_Base __to_destroy(get_allocator());
for (_Base_iterator __x = _Base::begin(); __x != _Base::end(); )
{
_Base_iterator __next = __x;
++__next;
if (__pred(*__x))
{
this->_M_invalidate_if(_Equal(__x));
__to_destroy.splice(__to_destroy.begin(), *this, __x);
#if !_GLIBCXX_USE_CXX11_ABI
_GLIBCXX20_ONLY( __removed++ );
#endif
}
__x = __next;
}
#if !_GLIBCXX_USE_CXX11_ABI
return _GLIBCXX20_ONLY( __removed );
#else
return _GLIBCXX20_ONLY( __to_destroy.size() );
#endif
}
_GLIBCXX_LIST_REMOVE_RETURN_TYPE_TAG
__remove_return_type
unique()
{
if (!this->_M_iterators && !this->_M_const_iterators)
return _Base::unique();
if (empty())
return _GLIBCXX20_ONLY(0);
#if !_GLIBCXX_USE_CXX11_ABI
size_type __removed __attribute__((__unused__)) = 0;
#endif
_Base __to_destroy(get_allocator());
_Base_iterator __first = _Base::begin();
_Base_iterator __last = _Base::end();
_Base_iterator __next = __first;
while (++__next != __last)
if (*__first == *__next)
{
this->_M_invalidate_if(_Equal(__next));
__to_destroy.splice(__to_destroy.begin(), *this, __next);
__next = __first;
#if !_GLIBCXX_USE_CXX11_ABI
_GLIBCXX20_ONLY( __removed++ );
#endif
}
else
__first = __next;
#if !_GLIBCXX_USE_CXX11_ABI
return _GLIBCXX20_ONLY( __removed );
#else
return _GLIBCXX20_ONLY( __to_destroy.size() );
#endif
}
template<class _BinaryPredicate>
__remove_return_type
unique(_BinaryPredicate __binary_pred)
{
if (!this->_M_iterators && !this->_M_const_iterators)
return _Base::unique(__binary_pred);
if (empty())
return _GLIBCXX20_ONLY(0);
#if !_GLIBCXX_USE_CXX11_ABI
size_type __removed __attribute__((__unused__)) = 0;
#endif
_Base __to_destroy(get_allocator());
_Base_iterator __first = _Base::begin();
_Base_iterator __last = _Base::end();
_Base_iterator __next = __first;
while (++__next != __last)
if (__binary_pred(*__first, *__next))
{
this->_M_invalidate_if(_Equal(__next));
__to_destroy.splice(__to_destroy.begin(), *this, __next);
__next = __first;
#if !_GLIBCXX_USE_CXX11_ABI
_GLIBCXX20_ONLY( __removed++ );
#endif
}
else
__first = __next;
#if !_GLIBCXX_USE_CXX11_ABI
return _GLIBCXX20_ONLY( __removed );
#else
return _GLIBCXX20_ONLY( __to_destroy.size() );
#endif
}
#undef _GLIBCXX_LIST_REMOVE_RETURN_TYPE_TAG
#undef _GLIBCXX20_ONLY
void
#if __cplusplus >= 201103L
merge(list&& __x)
#else
merge(list& __x)
#endif
{
// _GLIBCXX_RESOLVE_LIB_DEFECTS
// 300. list::merge() specification incomplete
if (this != std::__addressof(__x))
{
__glibcxx_check_sorted(_Base::begin(), _Base::end());
__glibcxx_check_sorted(__x.begin().base(), __x.end().base());
this->_M_transfer_from_if(__x, _Not_equal(__x._M_base().end()));
_Base::merge(_GLIBCXX_MOVE(__x));
}
}
#if __cplusplus >= 201103L
void
merge(list& __x)
{ merge(std::move(__x)); }
#endif
template<class _Compare>
void
#if __cplusplus >= 201103L
merge(list&& __x, _Compare __comp)
#else
merge(list& __x, _Compare __comp)
#endif
{
// _GLIBCXX_RESOLVE_LIB_DEFECTS
// 300. list::merge() specification incomplete
if (this != std::__addressof(__x))
{
__glibcxx_check_sorted_pred(_Base::begin(), _Base::end(),
__comp);
__glibcxx_check_sorted_pred(__x.begin().base(), __x.end().base(),
__comp);
this->_M_transfer_from_if(__x, _Not_equal(__x._M_base().end()));
_Base::merge(_GLIBCXX_MOVE(__x), __comp);
}
}
#if __cplusplus >= 201103L
template<typename _Compare>
void
merge(list& __x, _Compare __comp)
{ merge(std::move(__x), __comp); }
#endif
void
sort() { _Base::sort(); }
template<typename _StrictWeakOrdering>
void
sort(_StrictWeakOrdering __pred) { _Base::sort(__pred); }
using _Base::reverse;
_Base&
_M_base() _GLIBCXX_NOEXCEPT { return *this; }
const _Base&
_M_base() const _GLIBCXX_NOEXCEPT { return *this; }
};
#if __cpp_deduction_guides >= 201606
template<typename _InputIterator, typename _ValT
= typename iterator_traits<_InputIterator>::value_type,
typename _Allocator = allocator<_ValT>,
typename = _RequireInputIter<_InputIterator>,
typename = _RequireAllocator<_Allocator>>
list(_InputIterator, _InputIterator, _Allocator = _Allocator())
-> list<_ValT, _Allocator>;
template<typename _Tp, typename _Allocator = allocator<_Tp>,
typename = _RequireAllocator<_Allocator>>
list(size_t, _Tp, _Allocator = _Allocator())
-> list<_Tp, _Allocator>;
#if __glibcxx_containers_ranges // C++ >= 23
template<ranges::input_range _Rg,
typename _Allocator = allocator<ranges::range_value_t<_Rg>>>
list(from_range_t, _Rg&&, _Allocator = _Allocator())
-> list<ranges::range_value_t<_Rg>, _Allocator>;
#endif
#endif
template<typename _Tp, typename _Alloc>
inline bool
operator==(const list<_Tp, _Alloc>& __lhs,
const list<_Tp, _Alloc>& __rhs)
{ return __lhs._M_base() == __rhs._M_base(); }
#if __cpp_lib_three_way_comparison
template<typename _Tp, typename _Alloc>
constexpr __detail::__synth3way_t<_Tp>
operator<=>(const list<_Tp, _Alloc>& __x, const list<_Tp, _Alloc>& __y)
{ return __x._M_base() <=> __y._M_base(); }
#else
template<typename _Tp, typename _Alloc>
inline bool
operator!=(const list<_Tp, _Alloc>& __lhs,
const list<_Tp, _Alloc>& __rhs)
{ return __lhs._M_base() != __rhs._M_base(); }
template<typename _Tp, typename _Alloc>
inline bool
operator<(const list<_Tp, _Alloc>& __lhs,
const list<_Tp, _Alloc>& __rhs)
{ return __lhs._M_base() < __rhs._M_base(); }
template<typename _Tp, typename _Alloc>
inline bool
operator<=(const list<_Tp, _Alloc>& __lhs,
const list<_Tp, _Alloc>& __rhs)
{ return __lhs._M_base() <= __rhs._M_base(); }
template<typename _Tp, typename _Alloc>
inline bool
operator>=(const list<_Tp, _Alloc>& __lhs,
const list<_Tp, _Alloc>& __rhs)
{ return __lhs._M_base() >= __rhs._M_base(); }
template<typename _Tp, typename _Alloc>
inline bool
operator>(const list<_Tp, _Alloc>& __lhs,
const list<_Tp, _Alloc>& __rhs)
{ return __lhs._M_base() > __rhs._M_base(); }
#endif // three-way comparison
template<typename _Tp, typename _Alloc>
inline void
swap(list<_Tp, _Alloc>& __lhs, list<_Tp, _Alloc>& __rhs)
_GLIBCXX_NOEXCEPT_IF(noexcept(__lhs.swap(__rhs)))
{ __lhs.swap(__rhs); }
} // namespace __debug
} // namespace std
namespace __gnu_debug
{
#ifndef _GLIBCXX_USE_CXX11_ABI
// If not using C++11 list::size() is not in O(1) so we do not use it.
template<typename _Tp, typename _Alloc>
struct _Sequence_traits<std::__debug::list<_Tp, _Alloc> >
{
typedef typename std::__debug::list<_Tp, _Alloc>::iterator _It;
static typename _Distance_traits<_It>::__type
_S_size(const std::__debug::list<_Tp, _Alloc>& __seq)
{
return __seq.empty()
? std::make_pair(0, __dp_exact) : std::make_pair(1, __dp_sign);
}
};
#endif
#ifndef _GLIBCXX_DEBUG_PEDANTIC
template<class _Tp, class _Alloc>
struct _Insert_range_from_self_is_safe<std::__debug::list<_Tp, _Alloc> >
{ enum { __value = 1 }; };
#endif
}
#endif