// Safe iterator implementation -*- C++ -*-
-// Copyright (C) 2003, 2004, 2005, 2006, 2009, 2010, 2011
-// Free Software Foundation, Inc.
+// Copyright (C) 2003-2014 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
#include <debug/functions.h>
#include <debug/safe_base.h>
#include <bits/stl_pair.h>
-#include <bits/stl_iterator_base_types.h> // for _Iter_base
#include <ext/type_traits.h>
namespace __gnu_debug
template <typename _Sequence>
struct _BeforeBeginHelper
{
- typedef typename _Sequence::const_iterator _It;
- typedef typename _It::iterator_type _BaseIt;
-
- static bool
- _M_Is(_BaseIt __it, const _Sequence* __seq)
- { return false; }
+ template<typename _Iterator>
+ static bool
+ _S_Is(const _Safe_iterator<_Iterator, _Sequence>&)
+ { return false; }
+
+ template<typename _Iterator>
+ static bool
+ _S_Is_Beginnest(const _Safe_iterator<_Iterator, _Sequence>& __it)
+ { return __it.base() == __it._M_get_sequence()->_M_base().begin(); }
};
- /** Iterators that derive from _Safe_iterator_base but that aren't
- * _Safe_iterators can be determined singular or non-singular via
- * _Safe_iterator_base.
- */
+ /** Iterators that derive from _Safe_iterator_base can be determined singular
+ * or non-singular.
+ **/
inline bool
__check_singular_aux(const _Safe_iterator_base* __x)
{ return __x->_M_singular(); }
+ /** The precision to which we can calculate the distance between
+ * two iterators.
+ */
+ enum _Distance_precision
+ {
+ __dp_equality, //< Can compare iterator equality, only
+ __dp_sign, //< Can determine equality and ordering
+ __dp_exact //< Can determine distance precisely
+ };
+
+ /** Determine the distance between two iterators with some known
+ * precision.
+ */
+ template<typename _Iterator>
+ inline std::pair<typename std::iterator_traits<_Iterator>::difference_type,
+ _Distance_precision>
+ __get_distance(const _Iterator& __lhs, const _Iterator& __rhs,
+ std::random_access_iterator_tag)
+ { return std::make_pair(__rhs - __lhs, __dp_exact); }
+
+ template<typename _Iterator>
+ inline std::pair<typename std::iterator_traits<_Iterator>::difference_type,
+ _Distance_precision>
+ __get_distance(const _Iterator& __lhs, const _Iterator& __rhs,
+ std::forward_iterator_tag)
+ { return std::make_pair(__lhs == __rhs? 0 : 1, __dp_equality); }
+
+ template<typename _Iterator>
+ inline std::pair<typename std::iterator_traits<_Iterator>::difference_type,
+ _Distance_precision>
+ __get_distance(const _Iterator& __lhs, const _Iterator& __rhs)
+ {
+ typedef typename std::iterator_traits<_Iterator>::iterator_category
+ _Category;
+ return __get_distance(__lhs, __rhs, _Category());
+ }
+
/** \brief Safe iterator wrapper.
*
* The class template %_Safe_iterator is a wrapper around an
class _Safe_iterator : public _Safe_iterator_base
{
typedef _Safe_iterator _Self;
-
- /** The precision to which we can calculate the distance between
- * two iterators.
- */
- enum _Distance_precision
- {
- __dp_equality, //< Can compare iterator equality, only
- __dp_sign, //< Can determine equality and ordering
- __dp_exact //< Can determine distance precisely
- };
+ typedef typename _Sequence::const_iterator _Const_iterator;
/// The underlying iterator
_Iterator _M_current;
/// Determine if this is a constant iterator.
bool
_M_constant() const
- {
- typedef typename _Sequence::const_iterator const_iterator;
- return std::__are_same<const_iterator, _Safe_iterator>::__value;
- }
+ { return std::__are_same<_Const_iterator, _Safe_iterator>::__value; }
typedef std::iterator_traits<_Iterator> _Traits;
typedef typename _Traits::pointer pointer;
/// @post the iterator is singular and unattached
- _Safe_iterator() : _M_current() { }
+ _Safe_iterator() _GLIBCXX_NOEXCEPT : _M_current() { }
/**
* @brief Safe iterator construction from an unsafe iterator and
* @post this is not singular
*/
_Safe_iterator(const _Iterator& __i, const _Sequence* __seq)
+ _GLIBCXX_NOEXCEPT
: _Safe_iterator_base(__seq, _M_constant()), _M_current(__i)
{
_GLIBCXX_DEBUG_VERIFY(! this->_M_singular(),
/**
* @brief Copy construction.
*/
- _Safe_iterator(const _Safe_iterator& __x)
+ _Safe_iterator(const _Safe_iterator& __x) _GLIBCXX_NOEXCEPT
: _Safe_iterator_base(__x, _M_constant()), _M_current(__x._M_current)
{
// _GLIBCXX_RESOLVE_LIB_DEFECTS
._M_iterator(__x, "other"));
}
+#if __cplusplus >= 201103L
+ /**
+ * @brief Move construction.
+ * @post __x is singular and unattached
+ */
+ _Safe_iterator(_Safe_iterator&& __x) noexcept : _M_current()
+ {
+ _GLIBCXX_DEBUG_VERIFY(!__x._M_singular()
+ || __x._M_current == _Iterator(),
+ _M_message(__msg_init_copy_singular)
+ ._M_iterator(*this, "this")
+ ._M_iterator(__x, "other"));
+ std::swap(_M_current, __x._M_current);
+ this->_M_attach(__x._M_sequence);
+ __x._M_detach();
+ }
+#endif
+
/**
* @brief Converting constructor from a mutable iterator to a
* constant iterator.
const _Safe_iterator<_MutableIterator,
typename __gnu_cxx::__enable_if<(std::__are_same<_MutableIterator,
typename _Sequence::iterator::iterator_type>::__value),
- _Sequence>::__type>& __x)
+ _Sequence>::__type>& __x) _GLIBCXX_NOEXCEPT
: _Safe_iterator_base(__x, _M_constant()), _M_current(__x.base())
{
// _GLIBCXX_RESOLVE_LIB_DEFECTS
* @brief Copy assignment.
*/
_Safe_iterator&
- operator=(const _Safe_iterator& __x)
+ operator=(const _Safe_iterator& __x) _GLIBCXX_NOEXCEPT
{
// _GLIBCXX_RESOLVE_LIB_DEFECTS
// DR 408. Is vector<reverse_iterator<char*> > forbidden?
return *this;
}
+#if __cplusplus >= 201103L
+ /**
+ * @brief Move assignment.
+ * @post __x is singular and unattached
+ */
+ _Safe_iterator&
+ operator=(_Safe_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._M_current == _Iterator(),
+ _M_message(__msg_copy_singular)
+ ._M_iterator(*this, "this")
+ ._M_iterator(__x, "other"));
+ _M_current = __x._M_current;
+ _M_attach(__x._M_sequence);
+ __x._M_detach();
+ __x._M_current = _Iterator();
+ return *this;
+ }
+#endif
+
/**
* @brief Iterator dereference.
* @pre iterator is dereferenceable
*/
reference
- operator*() const
+ operator*() const _GLIBCXX_NOEXCEPT
{
_GLIBCXX_DEBUG_VERIFY(this->_M_dereferenceable(),
_M_message(__msg_bad_deref)
* @brief Iterator dereference.
* @pre iterator is dereferenceable
* @todo Make this correct w.r.t. iterators that return proxies
- * @todo Use addressof() instead of & operator
*/
pointer
- operator->() const
+ operator->() const _GLIBCXX_NOEXCEPT
{
_GLIBCXX_DEBUG_VERIFY(this->_M_dereferenceable(),
_M_message(__msg_bad_deref)
._M_iterator(*this, "this"));
- return &*_M_current;
+ return std::__addressof(*_M_current);
}
// ------ Input iterator requirements ------
* @pre iterator is incrementable
*/
_Safe_iterator&
- operator++()
+ operator++() _GLIBCXX_NOEXCEPT
{
_GLIBCXX_DEBUG_VERIFY(this->_M_incrementable(),
_M_message(__msg_bad_inc)
* @pre iterator is incrementable
*/
_Safe_iterator
- operator++(int)
+ operator++(int) _GLIBCXX_NOEXCEPT
{
_GLIBCXX_DEBUG_VERIFY(this->_M_incrementable(),
_M_message(__msg_bad_inc)
* @pre iterator is decrementable
*/
_Safe_iterator&
- operator--()
+ operator--() _GLIBCXX_NOEXCEPT
{
_GLIBCXX_DEBUG_VERIFY(this->_M_decrementable(),
_M_message(__msg_bad_dec)
* @pre iterator is decrementable
*/
_Safe_iterator
- operator--(int)
+ operator--(int) _GLIBCXX_NOEXCEPT
{
_GLIBCXX_DEBUG_VERIFY(this->_M_decrementable(),
_M_message(__msg_bad_dec)
// ------ Random access iterator requirements ------
reference
- operator[](const difference_type& __n) const
+ operator[](const difference_type& __n) const _GLIBCXX_NOEXCEPT
{
_GLIBCXX_DEBUG_VERIFY(this->_M_can_advance(__n)
&& this->_M_can_advance(__n+1),
}
_Safe_iterator&
- operator+=(const difference_type& __n)
+ operator+=(const difference_type& __n) _GLIBCXX_NOEXCEPT
{
_GLIBCXX_DEBUG_VERIFY(this->_M_can_advance(__n),
_M_message(__msg_advance_oob)
}
_Safe_iterator
- operator+(const difference_type& __n) const
+ operator+(const difference_type& __n) const _GLIBCXX_NOEXCEPT
{
_Safe_iterator __tmp(*this);
__tmp += __n;
}
_Safe_iterator&
- operator-=(const difference_type& __n)
+ operator-=(const difference_type& __n) _GLIBCXX_NOEXCEPT
{
_GLIBCXX_DEBUG_VERIFY(this->_M_can_advance(-__n),
_M_message(__msg_retreat_oob)
}
_Safe_iterator
- operator-(const difference_type& __n) const
+ operator-(const difference_type& __n) const _GLIBCXX_NOEXCEPT
{
_Safe_iterator __tmp(*this);
__tmp -= __n;
* @brief Return the underlying iterator
*/
_Iterator
- base() const { return _M_current; }
+ base() const _GLIBCXX_NOEXCEPT { return _M_current; }
/**
* @brief Conversion to underlying non-debug iterator to allow
* better interaction with non-debug containers.
*/
- operator _Iterator() const { return _M_current; }
+ operator _Iterator() const _GLIBCXX_NOEXCEPT { return _M_current; }
/** Attach iterator to the given sequence. */
void
bool
_M_before_dereferenceable() const
{
- _Self __it = *this;
- return __it._M_incrementable() && (++__it)._M_dereferenceable();
+ if (this->_M_incrementable())
+ {
+ _Iterator __base = base();
+ return ++__base != _M_get_sequence()->_M_base().end();
+ }
+ return false;
}
/// Is the iterator incrementable?
_M_can_advance(const difference_type& __n) const;
// Is the iterator range [*this, __rhs) valid?
- template<typename _Other>
- bool
- _M_valid_range(const _Safe_iterator<_Other, _Sequence>& __rhs) const;
+ bool
+ _M_valid_range(const _Safe_iterator& __rhs) const;
// The sequence this iterator references.
- const _Sequence*
+ typename
+ __gnu_cxx::__conditional_type<std::__are_same<_Const_iterator,
+ _Safe_iterator>::__value,
+ const _Sequence*,
+ _Sequence*>::__type
_M_get_sequence() const
- { return static_cast<const _Sequence*>(_M_sequence); }
-
- /** Determine the distance between two iterators with some known
- * precision.
- */
- template<typename _Iterator1, typename _Iterator2>
- static std::pair<difference_type, _Distance_precision>
- _M_get_distance(const _Iterator1& __lhs, const _Iterator2& __rhs)
- {
- typedef typename std::iterator_traits<_Iterator1>::iterator_category
- _Category;
- return _M_get_distance(__lhs, __rhs, _Category());
- }
-
- template<typename _Iterator1, typename _Iterator2>
- static std::pair<difference_type, _Distance_precision>
- _M_get_distance(const _Iterator1& __lhs, const _Iterator2& __rhs,
- std::random_access_iterator_tag)
- { return std::make_pair(__rhs - __lhs, __dp_exact); }
-
- template<typename _Iterator1, typename _Iterator2>
- static std::pair<difference_type, _Distance_precision>
- _M_get_distance(const _Iterator1& __lhs, const _Iterator2& __rhs,
- std::forward_iterator_tag)
- { return std::make_pair(__lhs == __rhs? 0 : 1, __dp_equality); }
+ { return static_cast<_Sequence*>(_M_sequence); }
/// Is this iterator equal to the sequence's begin() iterator?
- bool _M_is_begin() const
+ bool
+ _M_is_begin() const
{ return base() == _M_get_sequence()->_M_base().begin(); }
/// Is this iterator equal to the sequence's end() iterator?
- bool _M_is_end() const
+ bool
+ _M_is_end() const
{ return base() == _M_get_sequence()->_M_base().end(); }
/// Is this iterator equal to the sequence's before_begin() iterator if
/// any?
- bool _M_is_before_begin() const
- { return _BeforeBeginHelper<_Sequence>::_M_Is(base(), _M_get_sequence()); }
+ bool
+ _M_is_before_begin() const
+ { return _BeforeBeginHelper<_Sequence>::_S_Is(*this); }
+
+ /// Is this iterator equal to the sequence's before_begin() iterator if
+ /// any or begin() otherwise?
+ bool
+ _M_is_beginnest() const
+ { return _BeforeBeginHelper<_Sequence>::_S_Is_Beginnest(*this); }
};
template<typename _IteratorL, typename _IteratorR, typename _Sequence>
inline bool
operator==(const _Safe_iterator<_IteratorL, _Sequence>& __lhs,
const _Safe_iterator<_IteratorR, _Sequence>& __rhs)
+ _GLIBCXX_NOEXCEPT
{
_GLIBCXX_DEBUG_VERIFY(! __lhs._M_singular() && ! __rhs._M_singular(),
_M_message(__msg_iter_compare_bad)
inline bool
operator==(const _Safe_iterator<_Iterator, _Sequence>& __lhs,
const _Safe_iterator<_Iterator, _Sequence>& __rhs)
+ _GLIBCXX_NOEXCEPT
{
_GLIBCXX_DEBUG_VERIFY(! __lhs._M_singular() && ! __rhs._M_singular(),
_M_message(__msg_iter_compare_bad)
inline bool
operator!=(const _Safe_iterator<_IteratorL, _Sequence>& __lhs,
const _Safe_iterator<_IteratorR, _Sequence>& __rhs)
+ _GLIBCXX_NOEXCEPT
{
_GLIBCXX_DEBUG_VERIFY(! __lhs._M_singular() && ! __rhs._M_singular(),
_M_message(__msg_iter_compare_bad)
inline bool
operator!=(const _Safe_iterator<_Iterator, _Sequence>& __lhs,
const _Safe_iterator<_Iterator, _Sequence>& __rhs)
+ _GLIBCXX_NOEXCEPT
{
_GLIBCXX_DEBUG_VERIFY(! __lhs._M_singular() && ! __rhs._M_singular(),
_M_message(__msg_iter_compare_bad)
inline bool
operator<(const _Safe_iterator<_IteratorL, _Sequence>& __lhs,
const _Safe_iterator<_IteratorR, _Sequence>& __rhs)
+ _GLIBCXX_NOEXCEPT
{
_GLIBCXX_DEBUG_VERIFY(! __lhs._M_singular() && ! __rhs._M_singular(),
_M_message(__msg_iter_order_bad)
inline bool
operator<(const _Safe_iterator<_Iterator, _Sequence>& __lhs,
const _Safe_iterator<_Iterator, _Sequence>& __rhs)
+ _GLIBCXX_NOEXCEPT
{
_GLIBCXX_DEBUG_VERIFY(! __lhs._M_singular() && ! __rhs._M_singular(),
_M_message(__msg_iter_order_bad)
inline bool
operator<=(const _Safe_iterator<_IteratorL, _Sequence>& __lhs,
const _Safe_iterator<_IteratorR, _Sequence>& __rhs)
+ _GLIBCXX_NOEXCEPT
{
_GLIBCXX_DEBUG_VERIFY(! __lhs._M_singular() && ! __rhs._M_singular(),
_M_message(__msg_iter_order_bad)
inline bool
operator<=(const _Safe_iterator<_Iterator, _Sequence>& __lhs,
const _Safe_iterator<_Iterator, _Sequence>& __rhs)
+ _GLIBCXX_NOEXCEPT
{
_GLIBCXX_DEBUG_VERIFY(! __lhs._M_singular() && ! __rhs._M_singular(),
_M_message(__msg_iter_order_bad)
inline bool
operator>(const _Safe_iterator<_IteratorL, _Sequence>& __lhs,
const _Safe_iterator<_IteratorR, _Sequence>& __rhs)
+ _GLIBCXX_NOEXCEPT
{
_GLIBCXX_DEBUG_VERIFY(! __lhs._M_singular() && ! __rhs._M_singular(),
_M_message(__msg_iter_order_bad)
inline bool
operator>(const _Safe_iterator<_Iterator, _Sequence>& __lhs,
const _Safe_iterator<_Iterator, _Sequence>& __rhs)
+ _GLIBCXX_NOEXCEPT
{
_GLIBCXX_DEBUG_VERIFY(! __lhs._M_singular() && ! __rhs._M_singular(),
_M_message(__msg_iter_order_bad)
inline bool
operator>=(const _Safe_iterator<_IteratorL, _Sequence>& __lhs,
const _Safe_iterator<_IteratorR, _Sequence>& __rhs)
+ _GLIBCXX_NOEXCEPT
{
_GLIBCXX_DEBUG_VERIFY(! __lhs._M_singular() && ! __rhs._M_singular(),
_M_message(__msg_iter_order_bad)
inline bool
operator>=(const _Safe_iterator<_Iterator, _Sequence>& __lhs,
const _Safe_iterator<_Iterator, _Sequence>& __rhs)
+ _GLIBCXX_NOEXCEPT
{
_GLIBCXX_DEBUG_VERIFY(! __lhs._M_singular() && ! __rhs._M_singular(),
_M_message(__msg_iter_order_bad)
inline typename _Safe_iterator<_IteratorL, _Sequence>::difference_type
operator-(const _Safe_iterator<_IteratorL, _Sequence>& __lhs,
const _Safe_iterator<_IteratorR, _Sequence>& __rhs)
+ _GLIBCXX_NOEXCEPT
{
_GLIBCXX_DEBUG_VERIFY(! __lhs._M_singular() && ! __rhs._M_singular(),
_M_message(__msg_distance_bad)
inline typename _Safe_iterator<_Iterator, _Sequence>::difference_type
operator-(const _Safe_iterator<_Iterator, _Sequence>& __lhs,
const _Safe_iterator<_Iterator, _Sequence>& __rhs)
+ _GLIBCXX_NOEXCEPT
{
_GLIBCXX_DEBUG_VERIFY(! __lhs._M_singular() && ! __rhs._M_singular(),
_M_message(__msg_distance_bad)
template<typename _Iterator, typename _Sequence>
inline _Safe_iterator<_Iterator, _Sequence>
operator+(typename _Safe_iterator<_Iterator,_Sequence>::difference_type __n,
- const _Safe_iterator<_Iterator, _Sequence>& __i)
+ const _Safe_iterator<_Iterator, _Sequence>& __i) _GLIBCXX_NOEXCEPT
{ return __i + __n; }
-
- // Helper struct to detect random access safe iterators.
- template<typename _Iterator>
- struct __is_safe_random_iterator
- {
- enum { __value = 0 };
- typedef std::__false_type __type;
- };
-
- template<typename _Iterator, typename _Sequence>
- struct __is_safe_random_iterator<_Safe_iterator<_Iterator, _Sequence> >
- : std::__are_same<std::random_access_iterator_tag,
- typename std::iterator_traits<_Iterator>::
- iterator_category>
- { };
-
- template<typename _Iterator>
- struct _Siter_base
- : std::_Iter_base<_Iterator, __is_safe_random_iterator<_Iterator>::__value>
- { };
-
- /** Helper function to extract base iterator of random access safe iterator
- in order to reduce performance impact of debug mode. Limited to random
- access iterator because it is the only category for which it is possible
- to check for correct iterators order in the __valid_range function
- thanks to the < operator.
- */
- template<typename _Iterator>
- inline typename _Siter_base<_Iterator>::iterator_type
- __base(_Iterator __it)
- { return _Siter_base<_Iterator>::_S_base(__it); }
} // namespace __gnu_debug
#include <debug/safe_iterator.tcc>