mirror of git://gcc.gnu.org/git/gcc.git
re PR libstdc++/62313 (Data race in debug iterators)
2014-09-29 François Dumont <fdumont@gcc.gnu.org> PR libstdc++/62313 * include/debug/safe_base.h (_Safe_iterator_base(const _Safe_iterator_base&)): Delete declaration. (_Safe_iterator_base& operator=(const _Safe_iterator_base&)): Likewise. * include/debug/safe_iterator.h (_Safe_iterator<>): Move normal iterator before _Safe_iterator_base in memory. Lock before modifying the iterator in numerous places. * include/debug/safe_local_iterator.h (_Safe_local_iterator_base(const _Safe_local_iterator_base&)): Delete declaration. (_Safe_local_iterator_base& operator=(const _Safe_local_iterator_base&)): Likewise. * include/debug/safe_unordered_base.h (_Safe_local_iterator<>): Move normal iterator before _Safe_iterator_base in memory. Lock before modifying the iterator in numerous places. * include/debug/forward_list (_Safe_forward_list<>::_M_swap_aux): Adapt. * include/debug/safe_sequence.tcc (_Safe_sequence<>::_M_transfer_from_if): Adapt. From-SVN: r215693
This commit is contained in:
parent
a3052d316c
commit
ebd4c354b3
|
|
@ -1,3 +1,24 @@
|
||||||
|
2014-09-29 François Dumont <fdumont@gcc.gnu.org>
|
||||||
|
|
||||||
|
PR libstdc++/62313
|
||||||
|
* include/debug/safe_base.h
|
||||||
|
(_Safe_iterator_base(const _Safe_iterator_base&)): Delete declaration.
|
||||||
|
(_Safe_iterator_base& operator=(const _Safe_iterator_base&)): Likewise.
|
||||||
|
* include/debug/safe_iterator.h (_Safe_iterator<>): Move normal iterator
|
||||||
|
before _Safe_iterator_base in memory. Lock before modifying the iterator
|
||||||
|
in numerous places.
|
||||||
|
* include/debug/safe_local_iterator.h
|
||||||
|
(_Safe_local_iterator_base(const _Safe_local_iterator_base&)): Delete
|
||||||
|
declaration.
|
||||||
|
(_Safe_local_iterator_base& operator=(const _Safe_local_iterator_base&)):
|
||||||
|
Likewise.
|
||||||
|
* include/debug/safe_unordered_base.h (_Safe_local_iterator<>): Move
|
||||||
|
normal iterator before _Safe_iterator_base in memory. Lock before
|
||||||
|
modifying the iterator in numerous places.
|
||||||
|
* include/debug/forward_list (_Safe_forward_list<>::_M_swap_aux): Adapt.
|
||||||
|
* include/debug/safe_sequence.tcc
|
||||||
|
(_Safe_sequence<>::_M_transfer_from_if): Adapt.
|
||||||
|
|
||||||
2014-09-25 Jonathan Wakely <jwakely@redhat.com>
|
2014-09-25 Jonathan Wakely <jwakely@redhat.com>
|
||||||
|
|
||||||
DR 1339
|
DR 1339
|
||||||
|
|
|
||||||
|
|
@ -86,24 +86,26 @@ namespace __gnu_debug
|
||||||
for (_Safe_iterator_base* __iter = __lhs_iterators; __iter;)
|
for (_Safe_iterator_base* __iter = __lhs_iterators; __iter;)
|
||||||
{
|
{
|
||||||
// Even iterator is cast to const_iterator, not a problem.
|
// Even iterator is cast to const_iterator, not a problem.
|
||||||
const_iterator* __victim = static_cast<const_iterator*>(__iter);
|
_Safe_iterator_base* __victim_base = __iter;
|
||||||
|
const_iterator* __victim =
|
||||||
|
static_cast<const_iterator*>(__victim_base);
|
||||||
__iter = __iter->_M_next;
|
__iter = __iter->_M_next;
|
||||||
if (__victim->base() == __rseq._M_base().cbefore_begin())
|
if (__victim->base() == __rseq._M_base().cbefore_begin())
|
||||||
{
|
{
|
||||||
__victim->_M_unlink();
|
__victim->_M_unlink();
|
||||||
if (__lhs_iterators == __victim)
|
if (__lhs_iterators == __victim_base)
|
||||||
__lhs_iterators = __victim->_M_next;
|
__lhs_iterators = __victim_base->_M_next;
|
||||||
if (__bbegin_its)
|
if (__bbegin_its)
|
||||||
{
|
{
|
||||||
__victim->_M_next = __bbegin_its;
|
__victim_base->_M_next = __bbegin_its;
|
||||||
__bbegin_its->_M_prior = __victim;
|
__bbegin_its->_M_prior = __victim_base;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
__last_bbegin = __victim;
|
__last_bbegin = __victim_base;
|
||||||
__bbegin_its = __victim;
|
__bbegin_its = __victim_base;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
__victim->_M_sequence = &__lhs;
|
__victim_base->_M_sequence = &__lhs;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (__bbegin_its)
|
if (__bbegin_its)
|
||||||
|
|
|
||||||
|
|
@ -95,12 +95,6 @@ namespace __gnu_debug
|
||||||
: _M_sequence(0), _M_version(0), _M_prior(0), _M_next(0)
|
: _M_sequence(0), _M_version(0), _M_prior(0), _M_next(0)
|
||||||
{ this->_M_attach(__x._M_sequence, __constant); }
|
{ this->_M_attach(__x._M_sequence, __constant); }
|
||||||
|
|
||||||
_Safe_iterator_base&
|
|
||||||
operator=(const _Safe_iterator_base&);
|
|
||||||
|
|
||||||
explicit
|
|
||||||
_Safe_iterator_base(const _Safe_iterator_base&);
|
|
||||||
|
|
||||||
~_Safe_iterator_base() { this->_M_detach(); }
|
~_Safe_iterator_base() { this->_M_detach(); }
|
||||||
|
|
||||||
/** For use in _Safe_iterator. */
|
/** For use in _Safe_iterator. */
|
||||||
|
|
|
||||||
|
|
@ -109,16 +109,21 @@ namespace __gnu_debug
|
||||||
* %_Safe_iterator has member functions for iterator invalidation,
|
* %_Safe_iterator has member functions for iterator invalidation,
|
||||||
* attaching/detaching the iterator from sequences, and querying
|
* attaching/detaching the iterator from sequences, and querying
|
||||||
* the iterator's state.
|
* the iterator's state.
|
||||||
|
*
|
||||||
|
* Note that _Iterator must be the first base class so that it gets
|
||||||
|
* initialized before the iterator is being attached to the container's list
|
||||||
|
* of iterators and it is being detached before _Iterator get
|
||||||
|
* destroyed. Otherwise it would result in a data race.
|
||||||
*/
|
*/
|
||||||
template<typename _Iterator, typename _Sequence>
|
template<typename _Iterator, typename _Sequence>
|
||||||
class _Safe_iterator : public _Safe_iterator_base
|
class _Safe_iterator
|
||||||
|
: private _Iterator,
|
||||||
|
public _Safe_iterator_base
|
||||||
{
|
{
|
||||||
typedef _Safe_iterator _Self;
|
typedef _Iterator _Iter_base;
|
||||||
|
typedef _Safe_iterator_base _Safe_base;
|
||||||
typedef typename _Sequence::const_iterator _Const_iterator;
|
typedef typename _Sequence::const_iterator _Const_iterator;
|
||||||
|
|
||||||
/// The underlying iterator
|
|
||||||
_Iterator _M_current;
|
|
||||||
|
|
||||||
/// Determine if this is a constant iterator.
|
/// Determine if this is a constant iterator.
|
||||||
bool
|
bool
|
||||||
_M_constant() const
|
_M_constant() const
|
||||||
|
|
@ -126,6 +131,15 @@ namespace __gnu_debug
|
||||||
|
|
||||||
typedef std::iterator_traits<_Iterator> _Traits;
|
typedef std::iterator_traits<_Iterator> _Traits;
|
||||||
|
|
||||||
|
struct _Attach_single
|
||||||
|
{ };
|
||||||
|
|
||||||
|
_Safe_iterator(const _Iterator& __i, _Safe_sequence_base* __seq,
|
||||||
|
_Attach_single)
|
||||||
|
_GLIBCXX_NOEXCEPT
|
||||||
|
: _Iter_base(__i)
|
||||||
|
{ _M_attach_single(__seq); }
|
||||||
|
|
||||||
public:
|
public:
|
||||||
typedef _Iterator iterator_type;
|
typedef _Iterator iterator_type;
|
||||||
typedef typename _Traits::iterator_category iterator_category;
|
typedef typename _Traits::iterator_category iterator_category;
|
||||||
|
|
@ -135,7 +149,7 @@ namespace __gnu_debug
|
||||||
typedef typename _Traits::pointer pointer;
|
typedef typename _Traits::pointer pointer;
|
||||||
|
|
||||||
/// @post the iterator is singular and unattached
|
/// @post the iterator is singular and unattached
|
||||||
_Safe_iterator() _GLIBCXX_NOEXCEPT : _M_current() { }
|
_Safe_iterator() _GLIBCXX_NOEXCEPT : _Iter_base() { }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Safe iterator construction from an unsafe iterator and
|
* @brief Safe iterator construction from an unsafe iterator and
|
||||||
|
|
@ -144,11 +158,11 @@ namespace __gnu_debug
|
||||||
* @pre @p seq is not NULL
|
* @pre @p seq is not NULL
|
||||||
* @post this is not singular
|
* @post this is not singular
|
||||||
*/
|
*/
|
||||||
_Safe_iterator(const _Iterator& __i, const _Sequence* __seq)
|
_Safe_iterator(const _Iterator& __i, const _Safe_sequence_base* __seq)
|
||||||
_GLIBCXX_NOEXCEPT
|
_GLIBCXX_NOEXCEPT
|
||||||
: _Safe_iterator_base(__seq, _M_constant()), _M_current(__i)
|
: _Iter_base(__i), _Safe_base(__seq, _M_constant())
|
||||||
{
|
{
|
||||||
_GLIBCXX_DEBUG_VERIFY(! this->_M_singular(),
|
_GLIBCXX_DEBUG_VERIFY(!this->_M_singular(),
|
||||||
_M_message(__msg_init_singular)
|
_M_message(__msg_init_singular)
|
||||||
._M_iterator(*this, "this"));
|
._M_iterator(*this, "this"));
|
||||||
}
|
}
|
||||||
|
|
@ -157,15 +171,16 @@ namespace __gnu_debug
|
||||||
* @brief Copy construction.
|
* @brief Copy construction.
|
||||||
*/
|
*/
|
||||||
_Safe_iterator(const _Safe_iterator& __x) _GLIBCXX_NOEXCEPT
|
_Safe_iterator(const _Safe_iterator& __x) _GLIBCXX_NOEXCEPT
|
||||||
: _Safe_iterator_base(__x, _M_constant()), _M_current(__x._M_current)
|
: _Iter_base(__x.base())
|
||||||
{
|
{
|
||||||
// _GLIBCXX_RESOLVE_LIB_DEFECTS
|
// _GLIBCXX_RESOLVE_LIB_DEFECTS
|
||||||
// DR 408. Is vector<reverse_iterator<char*> > forbidden?
|
// DR 408. Is vector<reverse_iterator<char*> > forbidden?
|
||||||
_GLIBCXX_DEBUG_VERIFY(!__x._M_singular()
|
_GLIBCXX_DEBUG_VERIFY(!__x._M_singular()
|
||||||
|| __x._M_current == _Iterator(),
|
|| __x.base() == _Iterator(),
|
||||||
_M_message(__msg_init_copy_singular)
|
_M_message(__msg_init_copy_singular)
|
||||||
._M_iterator(*this, "this")
|
._M_iterator(*this, "this")
|
||||||
._M_iterator(__x, "other"));
|
._M_iterator(__x, "other"));
|
||||||
|
_M_attach(__x._M_sequence);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if __cplusplus >= 201103L
|
#if __cplusplus >= 201103L
|
||||||
|
|
@ -173,16 +188,18 @@ namespace __gnu_debug
|
||||||
* @brief Move construction.
|
* @brief Move construction.
|
||||||
* @post __x is singular and unattached
|
* @post __x is singular and unattached
|
||||||
*/
|
*/
|
||||||
_Safe_iterator(_Safe_iterator&& __x) noexcept : _M_current()
|
_Safe_iterator(_Safe_iterator&& __x) noexcept
|
||||||
|
: _Iter_base()
|
||||||
{
|
{
|
||||||
_GLIBCXX_DEBUG_VERIFY(!__x._M_singular()
|
_GLIBCXX_DEBUG_VERIFY(!__x._M_singular()
|
||||||
|| __x._M_current == _Iterator(),
|
|| __x.base() == _Iterator(),
|
||||||
_M_message(__msg_init_copy_singular)
|
_M_message(__msg_init_copy_singular)
|
||||||
._M_iterator(*this, "this")
|
._M_iterator(*this, "this")
|
||||||
._M_iterator(__x, "other"));
|
._M_iterator(__x, "other"));
|
||||||
std::swap(_M_current, __x._M_current);
|
_Safe_sequence_base* __seq = __x._M_sequence;
|
||||||
this->_M_attach(__x._M_sequence);
|
|
||||||
__x._M_detach();
|
__x._M_detach();
|
||||||
|
std::swap(base(), __x.base());
|
||||||
|
_M_attach(__seq);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
@ -196,7 +213,7 @@ namespace __gnu_debug
|
||||||
typename __gnu_cxx::__enable_if<(std::__are_same<_MutableIterator,
|
typename __gnu_cxx::__enable_if<(std::__are_same<_MutableIterator,
|
||||||
typename _Sequence::iterator::iterator_type>::__value),
|
typename _Sequence::iterator::iterator_type>::__value),
|
||||||
_Sequence>::__type>& __x) _GLIBCXX_NOEXCEPT
|
_Sequence>::__type>& __x) _GLIBCXX_NOEXCEPT
|
||||||
: _Safe_iterator_base(__x, _M_constant()), _M_current(__x.base())
|
: _Iter_base(__x.base())
|
||||||
{
|
{
|
||||||
// _GLIBCXX_RESOLVE_LIB_DEFECTS
|
// _GLIBCXX_RESOLVE_LIB_DEFECTS
|
||||||
// DR 408. Is vector<reverse_iterator<char*> > forbidden?
|
// DR 408. Is vector<reverse_iterator<char*> > forbidden?
|
||||||
|
|
@ -205,6 +222,7 @@ namespace __gnu_debug
|
||||||
_M_message(__msg_init_const_singular)
|
_M_message(__msg_init_const_singular)
|
||||||
._M_iterator(*this, "this")
|
._M_iterator(*this, "this")
|
||||||
._M_iterator(__x, "other"));
|
._M_iterator(__x, "other"));
|
||||||
|
_M_attach(__x._M_sequence);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -216,12 +234,24 @@ namespace __gnu_debug
|
||||||
// _GLIBCXX_RESOLVE_LIB_DEFECTS
|
// _GLIBCXX_RESOLVE_LIB_DEFECTS
|
||||||
// DR 408. Is vector<reverse_iterator<char*> > forbidden?
|
// DR 408. Is vector<reverse_iterator<char*> > forbidden?
|
||||||
_GLIBCXX_DEBUG_VERIFY(!__x._M_singular()
|
_GLIBCXX_DEBUG_VERIFY(!__x._M_singular()
|
||||||
|| __x._M_current == _Iterator(),
|
|| __x.base() == _Iterator(),
|
||||||
_M_message(__msg_copy_singular)
|
_M_message(__msg_copy_singular)
|
||||||
._M_iterator(*this, "this")
|
._M_iterator(*this, "this")
|
||||||
._M_iterator(__x, "other"));
|
._M_iterator(__x, "other"));
|
||||||
_M_current = __x._M_current;
|
|
||||||
this->_M_attach(__x._M_sequence);
|
if (this->_M_sequence && this->_M_sequence == __x._M_sequence)
|
||||||
|
{
|
||||||
|
__gnu_cxx::__scoped_lock __l(this->_M_get_mutex());
|
||||||
|
base() = __x.base();
|
||||||
|
_M_version = __x._M_sequence->_M_version;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_M_detach();
|
||||||
|
base() = __x.base();
|
||||||
|
_M_attach(__x._M_sequence);
|
||||||
|
}
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -237,14 +267,26 @@ namespace __gnu_debug
|
||||||
_M_message(__msg_self_move_assign)
|
_M_message(__msg_self_move_assign)
|
||||||
._M_iterator(*this, "this"));
|
._M_iterator(*this, "this"));
|
||||||
_GLIBCXX_DEBUG_VERIFY(!__x._M_singular()
|
_GLIBCXX_DEBUG_VERIFY(!__x._M_singular()
|
||||||
|| __x._M_current == _Iterator(),
|
|| __x.base() == _Iterator(),
|
||||||
_M_message(__msg_copy_singular)
|
_M_message(__msg_copy_singular)
|
||||||
._M_iterator(*this, "this")
|
._M_iterator(*this, "this")
|
||||||
._M_iterator(__x, "other"));
|
._M_iterator(__x, "other"));
|
||||||
_M_current = __x._M_current;
|
|
||||||
_M_attach(__x._M_sequence);
|
if (this->_M_sequence && this->_M_sequence == __x._M_sequence)
|
||||||
|
{
|
||||||
|
__gnu_cxx::__scoped_lock __l(this->_M_get_mutex());
|
||||||
|
base() = __x.base();
|
||||||
|
_M_version = __x._M_sequence->_M_version;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_M_detach();
|
||||||
|
base() = __x.base();
|
||||||
|
_M_attach(__x._M_sequence);
|
||||||
|
}
|
||||||
|
|
||||||
__x._M_detach();
|
__x._M_detach();
|
||||||
__x._M_current = _Iterator();
|
__x.base() = _Iterator();
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -259,7 +301,7 @@ namespace __gnu_debug
|
||||||
_GLIBCXX_DEBUG_VERIFY(this->_M_dereferenceable(),
|
_GLIBCXX_DEBUG_VERIFY(this->_M_dereferenceable(),
|
||||||
_M_message(__msg_bad_deref)
|
_M_message(__msg_bad_deref)
|
||||||
._M_iterator(*this, "this"));
|
._M_iterator(*this, "this"));
|
||||||
return *_M_current;
|
return *base();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -273,7 +315,7 @@ namespace __gnu_debug
|
||||||
_GLIBCXX_DEBUG_VERIFY(this->_M_dereferenceable(),
|
_GLIBCXX_DEBUG_VERIFY(this->_M_dereferenceable(),
|
||||||
_M_message(__msg_bad_deref)
|
_M_message(__msg_bad_deref)
|
||||||
._M_iterator(*this, "this"));
|
._M_iterator(*this, "this"));
|
||||||
return std::__addressof(*_M_current);
|
return std::__addressof(*base());
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------ Input iterator requirements ------
|
// ------ Input iterator requirements ------
|
||||||
|
|
@ -287,7 +329,8 @@ namespace __gnu_debug
|
||||||
_GLIBCXX_DEBUG_VERIFY(this->_M_incrementable(),
|
_GLIBCXX_DEBUG_VERIFY(this->_M_incrementable(),
|
||||||
_M_message(__msg_bad_inc)
|
_M_message(__msg_bad_inc)
|
||||||
._M_iterator(*this, "this"));
|
._M_iterator(*this, "this"));
|
||||||
++_M_current;
|
__gnu_cxx::__scoped_lock(this->_M_get_mutex());
|
||||||
|
++base();
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -301,9 +344,8 @@ namespace __gnu_debug
|
||||||
_GLIBCXX_DEBUG_VERIFY(this->_M_incrementable(),
|
_GLIBCXX_DEBUG_VERIFY(this->_M_incrementable(),
|
||||||
_M_message(__msg_bad_inc)
|
_M_message(__msg_bad_inc)
|
||||||
._M_iterator(*this, "this"));
|
._M_iterator(*this, "this"));
|
||||||
_Safe_iterator __tmp(*this);
|
__gnu_cxx::__scoped_lock __l(this->_M_get_mutex());
|
||||||
++_M_current;
|
return _Safe_iterator(base()++, this->_M_sequence, _Attach_single());
|
||||||
return __tmp;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------ Bidirectional iterator requirements ------
|
// ------ Bidirectional iterator requirements ------
|
||||||
|
|
@ -317,7 +359,8 @@ namespace __gnu_debug
|
||||||
_GLIBCXX_DEBUG_VERIFY(this->_M_decrementable(),
|
_GLIBCXX_DEBUG_VERIFY(this->_M_decrementable(),
|
||||||
_M_message(__msg_bad_dec)
|
_M_message(__msg_bad_dec)
|
||||||
._M_iterator(*this, "this"));
|
._M_iterator(*this, "this"));
|
||||||
--_M_current;
|
__gnu_cxx::__scoped_lock __l(this->_M_get_mutex());
|
||||||
|
--base();
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -331,9 +374,8 @@ namespace __gnu_debug
|
||||||
_GLIBCXX_DEBUG_VERIFY(this->_M_decrementable(),
|
_GLIBCXX_DEBUG_VERIFY(this->_M_decrementable(),
|
||||||
_M_message(__msg_bad_dec)
|
_M_message(__msg_bad_dec)
|
||||||
._M_iterator(*this, "this"));
|
._M_iterator(*this, "this"));
|
||||||
_Safe_iterator __tmp(*this);
|
__gnu_cxx::__scoped_lock __l(this->_M_get_mutex());
|
||||||
--_M_current;
|
return _Safe_iterator(base()--, this->_M_sequence, _Attach_single());
|
||||||
return __tmp;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------ Random access iterator requirements ------
|
// ------ Random access iterator requirements ------
|
||||||
|
|
@ -344,8 +386,7 @@ namespace __gnu_debug
|
||||||
&& this->_M_can_advance(__n+1),
|
&& this->_M_can_advance(__n+1),
|
||||||
_M_message(__msg_iter_subscript_oob)
|
_M_message(__msg_iter_subscript_oob)
|
||||||
._M_iterator(*this)._M_integer(__n));
|
._M_iterator(*this)._M_integer(__n));
|
||||||
|
return base()[__n];
|
||||||
return _M_current[__n];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_Safe_iterator&
|
_Safe_iterator&
|
||||||
|
|
@ -354,16 +395,18 @@ namespace __gnu_debug
|
||||||
_GLIBCXX_DEBUG_VERIFY(this->_M_can_advance(__n),
|
_GLIBCXX_DEBUG_VERIFY(this->_M_can_advance(__n),
|
||||||
_M_message(__msg_advance_oob)
|
_M_message(__msg_advance_oob)
|
||||||
._M_iterator(*this)._M_integer(__n));
|
._M_iterator(*this)._M_integer(__n));
|
||||||
_M_current += __n;
|
__gnu_cxx::__scoped_lock __l(this->_M_get_mutex());
|
||||||
|
base() += __n;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
_Safe_iterator
|
_Safe_iterator
|
||||||
operator+(const difference_type& __n) const _GLIBCXX_NOEXCEPT
|
operator+(const difference_type& __n) const _GLIBCXX_NOEXCEPT
|
||||||
{
|
{
|
||||||
_Safe_iterator __tmp(*this);
|
_GLIBCXX_DEBUG_VERIFY(this->_M_can_advance(__n),
|
||||||
__tmp += __n;
|
_M_message(__msg_advance_oob)
|
||||||
return __tmp;
|
._M_iterator(*this)._M_integer(__n));
|
||||||
|
return _Safe_iterator(base() + __n, this->_M_sequence);
|
||||||
}
|
}
|
||||||
|
|
||||||
_Safe_iterator&
|
_Safe_iterator&
|
||||||
|
|
@ -372,44 +415,45 @@ namespace __gnu_debug
|
||||||
_GLIBCXX_DEBUG_VERIFY(this->_M_can_advance(-__n),
|
_GLIBCXX_DEBUG_VERIFY(this->_M_can_advance(-__n),
|
||||||
_M_message(__msg_retreat_oob)
|
_M_message(__msg_retreat_oob)
|
||||||
._M_iterator(*this)._M_integer(__n));
|
._M_iterator(*this)._M_integer(__n));
|
||||||
_M_current += -__n;
|
__gnu_cxx::__scoped_lock __l(this->_M_get_mutex());
|
||||||
|
base() -= __n;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
_Safe_iterator
|
_Safe_iterator
|
||||||
operator-(const difference_type& __n) const _GLIBCXX_NOEXCEPT
|
operator-(const difference_type& __n) const _GLIBCXX_NOEXCEPT
|
||||||
{
|
{
|
||||||
_Safe_iterator __tmp(*this);
|
_GLIBCXX_DEBUG_VERIFY(this->_M_can_advance(-__n),
|
||||||
__tmp -= __n;
|
_M_message(__msg_retreat_oob)
|
||||||
return __tmp;
|
._M_iterator(*this)._M_integer(__n));
|
||||||
|
return _Safe_iterator(base() - __n, this->_M_sequence);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------ Utilities ------
|
// ------ Utilities ------
|
||||||
/**
|
/**
|
||||||
* @brief Return the underlying iterator
|
* @brief Return the underlying iterator
|
||||||
*/
|
*/
|
||||||
_Iterator
|
_Iterator&
|
||||||
base() const _GLIBCXX_NOEXCEPT { return _M_current; }
|
base() _GLIBCXX_NOEXCEPT { return *this; }
|
||||||
|
|
||||||
|
const _Iterator&
|
||||||
|
base() const _GLIBCXX_NOEXCEPT { return *this; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Conversion to underlying non-debug iterator to allow
|
* @brief Conversion to underlying non-debug iterator to allow
|
||||||
* better interaction with non-debug containers.
|
* better interaction with non-debug containers.
|
||||||
*/
|
*/
|
||||||
operator _Iterator() const _GLIBCXX_NOEXCEPT { return _M_current; }
|
operator _Iterator() const _GLIBCXX_NOEXCEPT { return *this; }
|
||||||
|
|
||||||
/** Attach iterator to the given sequence. */
|
/** Attach iterator to the given sequence. */
|
||||||
void
|
void
|
||||||
_M_attach(_Safe_sequence_base* __seq)
|
_M_attach(_Safe_sequence_base* __seq)
|
||||||
{
|
{ _Safe_base::_M_attach(__seq, _M_constant()); }
|
||||||
_Safe_iterator_base::_M_attach(__seq, _M_constant());
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Likewise, but not thread-safe. */
|
/** Likewise, but not thread-safe. */
|
||||||
void
|
void
|
||||||
_M_attach_single(_Safe_sequence_base* __seq)
|
_M_attach_single(_Safe_sequence_base* __seq)
|
||||||
{
|
{ _Safe_base::_M_attach_single(__seq, _M_constant()); }
|
||||||
_Safe_iterator_base::_M_attach_single(__seq, _M_constant());
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Is the iterator dereferenceable?
|
/// Is the iterator dereferenceable?
|
||||||
bool
|
bool
|
||||||
|
|
|
||||||
|
|
@ -49,15 +49,15 @@ namespace __gnu_debug
|
||||||
* the iterator's state.
|
* the iterator's state.
|
||||||
*/
|
*/
|
||||||
template<typename _Iterator, typename _Sequence>
|
template<typename _Iterator, typename _Sequence>
|
||||||
class _Safe_local_iterator : public _Safe_local_iterator_base
|
class _Safe_local_iterator
|
||||||
|
: private _Iterator
|
||||||
|
, public _Safe_local_iterator_base
|
||||||
{
|
{
|
||||||
typedef _Safe_local_iterator _Self;
|
typedef _Iterator _Iter_base;
|
||||||
|
typedef _Safe_local_iterator_base _Safe_base;
|
||||||
typedef typename _Sequence::const_local_iterator _Const_local_iterator;
|
typedef typename _Sequence::const_local_iterator _Const_local_iterator;
|
||||||
typedef typename _Sequence::size_type size_type;
|
typedef typename _Sequence::size_type size_type;
|
||||||
|
|
||||||
/// The underlying iterator
|
|
||||||
_Iterator _M_current;
|
|
||||||
|
|
||||||
/// Determine if this is a constant iterator.
|
/// Determine if this is a constant iterator.
|
||||||
bool
|
bool
|
||||||
_M_constant() const
|
_M_constant() const
|
||||||
|
|
@ -68,6 +68,14 @@ namespace __gnu_debug
|
||||||
|
|
||||||
typedef std::iterator_traits<_Iterator> _Traits;
|
typedef std::iterator_traits<_Iterator> _Traits;
|
||||||
|
|
||||||
|
struct _Attach_single
|
||||||
|
{ };
|
||||||
|
|
||||||
|
_Safe_local_iterator(const _Iterator& __i, _Safe_sequence_base* __cont,
|
||||||
|
_Attach_single) noexcept
|
||||||
|
: _Iter_base(__i)
|
||||||
|
{ _M_attach_single(__cont); }
|
||||||
|
|
||||||
public:
|
public:
|
||||||
typedef _Iterator iterator_type;
|
typedef _Iterator iterator_type;
|
||||||
typedef typename _Traits::iterator_category iterator_category;
|
typedef typename _Traits::iterator_category iterator_category;
|
||||||
|
|
@ -77,7 +85,7 @@ namespace __gnu_debug
|
||||||
typedef typename _Traits::pointer pointer;
|
typedef typename _Traits::pointer pointer;
|
||||||
|
|
||||||
/// @post the iterator is singular and unattached
|
/// @post the iterator is singular and unattached
|
||||||
_Safe_local_iterator() : _M_current() { }
|
_Safe_local_iterator() noexcept : _Iter_base() { }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Safe iterator construction from an unsafe iterator and
|
* @brief Safe iterator construction from an unsafe iterator and
|
||||||
|
|
@ -86,8 +94,9 @@ namespace __gnu_debug
|
||||||
* @pre @p seq is not NULL
|
* @pre @p seq is not NULL
|
||||||
* @post this is not singular
|
* @post this is not singular
|
||||||
*/
|
*/
|
||||||
_Safe_local_iterator(const _Iterator& __i, const _Sequence* __seq)
|
_Safe_local_iterator(const _Iterator& __i,
|
||||||
: _Safe_local_iterator_base(__seq, _M_constant()), _M_current(__i)
|
const _Safe_sequence_base* __cont)
|
||||||
|
: _Iter_base(__i), _Safe_base(__cont, _M_constant())
|
||||||
{
|
{
|
||||||
_GLIBCXX_DEBUG_VERIFY(!this->_M_singular(),
|
_GLIBCXX_DEBUG_VERIFY(!this->_M_singular(),
|
||||||
_M_message(__msg_init_singular)
|
_M_message(__msg_init_singular)
|
||||||
|
|
@ -97,9 +106,8 @@ namespace __gnu_debug
|
||||||
/**
|
/**
|
||||||
* @brief Copy construction.
|
* @brief Copy construction.
|
||||||
*/
|
*/
|
||||||
_Safe_local_iterator(const _Safe_local_iterator& __x)
|
_Safe_local_iterator(const _Safe_local_iterator& __x) noexcept
|
||||||
: _Safe_local_iterator_base(__x, _M_constant()),
|
: _Iter_base(__x.base())
|
||||||
_M_current(__x._M_current)
|
|
||||||
{
|
{
|
||||||
// _GLIBCXX_RESOLVE_LIB_DEFECTS
|
// _GLIBCXX_RESOLVE_LIB_DEFECTS
|
||||||
// DR 408. Is vector<reverse_iterator<char*> > forbidden?
|
// DR 408. Is vector<reverse_iterator<char*> > forbidden?
|
||||||
|
|
@ -108,6 +116,25 @@ namespace __gnu_debug
|
||||||
_M_message(__msg_init_copy_singular)
|
_M_message(__msg_init_copy_singular)
|
||||||
._M_iterator(*this, "this")
|
._M_iterator(*this, "this")
|
||||||
._M_iterator(__x, "other"));
|
._M_iterator(__x, "other"));
|
||||||
|
_M_attach(__x._M_sequence);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Move construction.
|
||||||
|
* @post __x is singular and unattached
|
||||||
|
*/
|
||||||
|
_Safe_local_iterator(_Safe_local_iterator&& __x) noexcept
|
||||||
|
: _Iter_base()
|
||||||
|
{
|
||||||
|
_GLIBCXX_DEBUG_VERIFY(!__x._M_singular()
|
||||||
|
|| __x.base() == _Iterator(),
|
||||||
|
_M_message(__msg_init_copy_singular)
|
||||||
|
._M_iterator(*this, "this")
|
||||||
|
._M_iterator(__x, "other"));
|
||||||
|
auto __cont = __x._M_sequence;
|
||||||
|
__x._M_detach();
|
||||||
|
std::swap(base(), __x.base());
|
||||||
|
_M_attach(__cont);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -121,8 +148,7 @@ namespace __gnu_debug
|
||||||
_MutableIterator,
|
_MutableIterator,
|
||||||
typename _Sequence::local_iterator::iterator_type>::__value,
|
typename _Sequence::local_iterator::iterator_type>::__value,
|
||||||
_Sequence>::__type>& __x)
|
_Sequence>::__type>& __x)
|
||||||
: _Safe_local_iterator_base(__x, _M_constant()),
|
: _Iter_base(__x.base())
|
||||||
_M_current(__x.base())
|
|
||||||
{
|
{
|
||||||
// _GLIBCXX_RESOLVE_LIB_DEFECTS
|
// _GLIBCXX_RESOLVE_LIB_DEFECTS
|
||||||
// DR 408. Is vector<reverse_iterator<char*> > forbidden?
|
// DR 408. Is vector<reverse_iterator<char*> > forbidden?
|
||||||
|
|
@ -131,6 +157,7 @@ namespace __gnu_debug
|
||||||
_M_message(__msg_init_const_singular)
|
_M_message(__msg_init_const_singular)
|
||||||
._M_iterator(*this, "this")
|
._M_iterator(*this, "this")
|
||||||
._M_iterator(__x, "other"));
|
._M_iterator(__x, "other"));
|
||||||
|
_M_attach(__x._M_sequence);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -146,8 +173,54 @@ namespace __gnu_debug
|
||||||
_M_message(__msg_copy_singular)
|
_M_message(__msg_copy_singular)
|
||||||
._M_iterator(*this, "this")
|
._M_iterator(*this, "this")
|
||||||
._M_iterator(__x, "other"));
|
._M_iterator(__x, "other"));
|
||||||
_M_current = __x._M_current;
|
|
||||||
this->_M_attach(__x._M_sequence);
|
if (this->_M_sequence && this->_M_sequence == __x._M_sequence)
|
||||||
|
{
|
||||||
|
__gnu_cxx::__scoped_lock __l(this->_M_get_mutex());
|
||||||
|
base() = __x.base();
|
||||||
|
_M_version = __x._M_sequence->_M_version;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_M_detach();
|
||||||
|
base() = __x.base();
|
||||||
|
_M_attach(__x._M_sequence);
|
||||||
|
}
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Move assignment.
|
||||||
|
* @post __x is singular and unattached
|
||||||
|
*/
|
||||||
|
_Safe_local_iterator&
|
||||||
|
operator=(_Safe_local_iterator&& __x) noexcept
|
||||||
|
{
|
||||||
|
_GLIBCXX_DEBUG_VERIFY(this != &__x,
|
||||||
|
_M_message(__msg_self_move_assign)
|
||||||
|
._M_iterator(*this, "this"));
|
||||||
|
_GLIBCXX_DEBUG_VERIFY(!__x._M_singular()
|
||||||
|
|| __x.base() == _Iterator(),
|
||||||
|
_M_message(__msg_copy_singular)
|
||||||
|
._M_iterator(*this, "this")
|
||||||
|
._M_iterator(__x, "other"));
|
||||||
|
|
||||||
|
if (this->_M_sequence && this->_M_sequence == __x._M_sequence)
|
||||||
|
{
|
||||||
|
__gnu_cxx::__scoped_lock __l(this->_M_get_mutex());
|
||||||
|
base() = __x.base();
|
||||||
|
_M_version = __x._M_sequence->_M_version;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_M_detach();
|
||||||
|
base() = __x.base();
|
||||||
|
_M_attach(__x._M_sequence);
|
||||||
|
}
|
||||||
|
|
||||||
|
__x._M_detach();
|
||||||
|
__x.base() = _Iterator();
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -161,7 +234,7 @@ namespace __gnu_debug
|
||||||
_GLIBCXX_DEBUG_VERIFY(this->_M_dereferenceable(),
|
_GLIBCXX_DEBUG_VERIFY(this->_M_dereferenceable(),
|
||||||
_M_message(__msg_bad_deref)
|
_M_message(__msg_bad_deref)
|
||||||
._M_iterator(*this, "this"));
|
._M_iterator(*this, "this"));
|
||||||
return *_M_current;
|
return *base();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -175,7 +248,7 @@ namespace __gnu_debug
|
||||||
_GLIBCXX_DEBUG_VERIFY(this->_M_dereferenceable(),
|
_GLIBCXX_DEBUG_VERIFY(this->_M_dereferenceable(),
|
||||||
_M_message(__msg_bad_deref)
|
_M_message(__msg_bad_deref)
|
||||||
._M_iterator(*this, "this"));
|
._M_iterator(*this, "this"));
|
||||||
return std::__addressof(*_M_current);
|
return std::__addressof(*base());
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------ Input iterator requirements ------
|
// ------ Input iterator requirements ------
|
||||||
|
|
@ -189,7 +262,8 @@ namespace __gnu_debug
|
||||||
_GLIBCXX_DEBUG_VERIFY(this->_M_incrementable(),
|
_GLIBCXX_DEBUG_VERIFY(this->_M_incrementable(),
|
||||||
_M_message(__msg_bad_inc)
|
_M_message(__msg_bad_inc)
|
||||||
._M_iterator(*this, "this"));
|
._M_iterator(*this, "this"));
|
||||||
++_M_current;
|
__gnu_cxx::__scoped_lock __l(this->_M_get_mutex());
|
||||||
|
++base();
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -203,39 +277,42 @@ namespace __gnu_debug
|
||||||
_GLIBCXX_DEBUG_VERIFY(this->_M_incrementable(),
|
_GLIBCXX_DEBUG_VERIFY(this->_M_incrementable(),
|
||||||
_M_message(__msg_bad_inc)
|
_M_message(__msg_bad_inc)
|
||||||
._M_iterator(*this, "this"));
|
._M_iterator(*this, "this"));
|
||||||
_Safe_local_iterator __tmp(*this);
|
__gnu_cxx::__scoped_lock __l(this->_M_get_mutex());
|
||||||
++_M_current;
|
return _Safe_local_iterator(base()++, this->_M_sequence,
|
||||||
return __tmp;
|
_Attach_single());
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------ Utilities ------
|
// ------ Utilities ------
|
||||||
/**
|
/**
|
||||||
* @brief Return the underlying iterator
|
* @brief Return the underlying iterator
|
||||||
*/
|
*/
|
||||||
_Iterator
|
_Iterator&
|
||||||
base() const { return _M_current; }
|
base() noexcept { return *this; }
|
||||||
|
|
||||||
|
const _Iterator&
|
||||||
|
base() const noexcept { return *this; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Return the bucket
|
* @brief Return the bucket
|
||||||
*/
|
*/
|
||||||
size_type
|
size_type
|
||||||
bucket() const { return _M_current._M_get_bucket(); }
|
bucket() const { return base()._M_get_bucket(); }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Conversion to underlying non-debug iterator to allow
|
* @brief Conversion to underlying non-debug iterator to allow
|
||||||
* better interaction with non-debug containers.
|
* better interaction with non-debug containers.
|
||||||
*/
|
*/
|
||||||
operator _Iterator() const { return _M_current; }
|
operator _Iterator() const { return *this; }
|
||||||
|
|
||||||
/** Attach iterator to the given sequence. */
|
/** Attach iterator to the given sequence. */
|
||||||
void
|
void
|
||||||
_M_attach(_Safe_sequence_base* __seq)
|
_M_attach(_Safe_sequence_base* __seq)
|
||||||
{ _Safe_iterator_base::_M_attach(__seq, _M_constant()); }
|
{ _Safe_base::_M_attach(__seq, _M_constant()); }
|
||||||
|
|
||||||
/** Likewise, but not thread-safe. */
|
/** Likewise, but not thread-safe. */
|
||||||
void
|
void
|
||||||
_M_attach_single(_Safe_sequence_base* __seq)
|
_M_attach_single(_Safe_sequence_base* __seq)
|
||||||
{ _Safe_iterator_base::_M_attach_single(__seq, _M_constant()); }
|
{ _Safe_base::_M_attach_single(__seq, _M_constant()); }
|
||||||
|
|
||||||
/// Is the iterator dereferenceable?
|
/// Is the iterator dereferenceable?
|
||||||
bool
|
bool
|
||||||
|
|
|
||||||
|
|
@ -81,42 +81,45 @@ namespace __gnu_debug
|
||||||
|
|
||||||
for (_Safe_iterator_base* __iter = __from._M_iterators; __iter;)
|
for (_Safe_iterator_base* __iter = __from._M_iterators; __iter;)
|
||||||
{
|
{
|
||||||
iterator* __victim = static_cast<iterator*>(__iter);
|
_Safe_iterator_base* __victim_base = __iter;
|
||||||
|
iterator* __victim = static_cast<iterator*>(__victim_base);
|
||||||
__iter = __iter->_M_next;
|
__iter = __iter->_M_next;
|
||||||
if (!__victim->_M_singular() && __pred(__victim->base()))
|
if (!__victim->_M_singular() && __pred(__victim->base()))
|
||||||
{
|
{
|
||||||
__victim->_M_detach_single();
|
__victim->_M_detach_single();
|
||||||
if (__transfered_iterators)
|
if (__transfered_iterators)
|
||||||
{
|
{
|
||||||
__victim->_M_next = __transfered_iterators;
|
__victim_base->_M_next = __transfered_iterators;
|
||||||
__transfered_iterators->_M_prior = __victim;
|
__transfered_iterators->_M_prior = __victim_base;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
__last_iterator = __victim;
|
__last_iterator = __victim_base;
|
||||||
__victim->_M_sequence = this;
|
__victim_base->_M_sequence = this;
|
||||||
__victim->_M_version = this->_M_version;
|
__victim_base->_M_version = this->_M_version;
|
||||||
__transfered_iterators = __victim;
|
__transfered_iterators = __victim_base;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (_Safe_iterator_base* __iter2 = __from._M_const_iterators;
|
for (_Safe_iterator_base* __iter2 = __from._M_const_iterators;
|
||||||
__iter2;)
|
__iter2;)
|
||||||
{
|
{
|
||||||
const_iterator* __victim = static_cast<const_iterator*>(__iter2);
|
_Safe_iterator_base* __victim_base = __iter2;
|
||||||
|
const_iterator* __victim =
|
||||||
|
static_cast<const_iterator*>(__victim_base);
|
||||||
__iter2 = __iter2->_M_next;
|
__iter2 = __iter2->_M_next;
|
||||||
if (!__victim->_M_singular() && __pred(__victim->base()))
|
if (!__victim->_M_singular() && __pred(__victim->base()))
|
||||||
{
|
{
|
||||||
__victim->_M_detach_single();
|
__victim->_M_detach_single();
|
||||||
if (__transfered_const_iterators)
|
if (__transfered_const_iterators)
|
||||||
{
|
{
|
||||||
__victim->_M_next = __transfered_const_iterators;
|
__victim_base->_M_next = __transfered_const_iterators;
|
||||||
__transfered_const_iterators->_M_prior = __victim;
|
__transfered_const_iterators->_M_prior = __victim_base;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
__last_const_iterator = __victim;
|
__last_const_iterator = __victim;
|
||||||
__victim->_M_sequence = this;
|
__victim_base->_M_sequence = this;
|
||||||
__victim->_M_version = this->_M_version;
|
__victim_base->_M_version = this->_M_version;
|
||||||
__transfered_const_iterators = __victim;
|
__transfered_const_iterators = __victim_base;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -71,12 +71,6 @@ namespace __gnu_debug
|
||||||
bool __constant)
|
bool __constant)
|
||||||
{ this->_M_attach(__x._M_sequence, __constant); }
|
{ this->_M_attach(__x._M_sequence, __constant); }
|
||||||
|
|
||||||
_Safe_local_iterator_base&
|
|
||||||
operator=(const _Safe_local_iterator_base&);
|
|
||||||
|
|
||||||
explicit
|
|
||||||
_Safe_local_iterator_base(const _Safe_local_iterator_base&);
|
|
||||||
|
|
||||||
~_Safe_local_iterator_base() { this->_M_detach(); }
|
~_Safe_local_iterator_base() { this->_M_detach(); }
|
||||||
|
|
||||||
_Safe_unordered_container_base*
|
_Safe_unordered_container_base*
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue