This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Debug mode enhancements


Hi

    This is a patch to:

- Enhance __get_distance to get a better feedback about distance between
iterators so that we can take sharper decision about what is right or
not. This function is now aware about safe iterators and leverage on
those a little like std::distance does with C++ 11 list::iterator.
- Make debug mode aware about iterator adapters reverse_iterator and
move_iterator.
- Thanks to previous points this patch also extend situations where it
is possible to remove debug layers on iterators to lower performance
hint of this mode. We now detect at runtime if we know enough about the
iterator range to get rid of the potential debug layer.

    For the last point I introduced __gnu_debug::__unsafe which remove
debug layer unconditionally in opposition to __gnu_debug::__base which
do so only for random access iterator. The latter has been kept to be
used in context of constructors.

    I had to introduced new debug headers to limit impact in
stl_iterator.h. We shall not include debug.h here as the purpose is not
to inject debug checks in the normal code.

    Note that the new __get_distance will be very useful to implement
proper debug algos

    Here is the tricky part for me, the ChangeLog entry, much more
complicated than the code :-)

    * include/bits/stl_iterator_base_types.h (_Iter_base): Limit definition
    to pre-C++11 mode.
    * include/debug/functions.h
    (__gnu_debug::__valid_range, __gnu_debug::__base): Move...
    * include/debug/safe_iterator.h
    (__gnu_debug::_Sequence_traits): New.
    (__gnu_debug::__get_distance_from_begin): New.
    (__gnu_debug::__get_distance_to_end): New.
    (__gnu_debug::_Safe_iterator<>::_M_valid_range): Expose iterator range
    distance information. Add optional check_dereferenceable parameter,
    default true.
    (__gnu_debug::_Distance_precision, __gnu_debug::__get_distance): Move
    default definition...
    (__gnu_debug::__get_distance): New overload for _Safe_iterator.
    (__gnu_debug::__unsafe): Likewise.
    * include/debug/helper_functions.h: ...here. New.
    (__gnu_debug::__unsafe): New helper function to remove safe iterator
    layer.
    * include/debug/stl_iterator.h: New. Include latter.
    * include/bits/stl_iterator.h: Include latter in debug mode.
    * include/debug/stl_iterator.tcc: Adapt.
    * include/debug/safe_local_iterator.h (__gnu_debug::__get_distance): Add
    overload for _Safe_local_iterator.
    (__gnu_debug::__unsafe): Likewise.
    * include/debug/safe_local_iterator.tcc: Adapt.
    * include/debug/macros.h (__glibcxx_check_valid_range2): New.
    (__glibcxx_check_insert_range): Add _Dist parameter.
    (__glibcxx_check_insert_range_after): Likewise.
    * include/debug/deque (deque<>::assign): Remove iterator debug layer
    when possible.
    (deque<>::insert): Likewise.
    * include/debug/forward_list (__glibcxx_check_valid_fl_range): New.
    (forward_list<>::splice_after): Use latter.
    (forward_list<>::assign): Remove iterator debug layer when possible.
    (forward_list<>::insert_after): Likewise.
    (__gnu_debug::_Sequence_traits<>): Partial specialization.
    * include/debug/list (list<>::assign): Remove iterator debug layer when
    possible.
    (list<>::insert): Likewise.
    [__gnu_debug::_Sequence_traits<>]: Partial specialization pre C++11 ABI.
    * include/debug/map.h (map<>::insert): Remove iterator debug layer when
    possible.
    * include/debug/multimap.h (multimap<>::insert): Likewise.
    * include/debug/set.h (set<>::insert): Likewise.
    * include/debug/multiset.h (multiset<>::insert): Likewise.
    * include/debug/string (basic_string<>::append, basic_string<>::assign,
    basic_string<>::insert, basic_string<>::replace): Likewise.
    * include/debug/unordered_map
    (unordered_map<>::insert, unordered_multimap<>::insert): Likewise.
    * include/debug/unordered_set
    (unordered_set<>::insert, unordered_multiset<>insert): Likewise.
    * include/debug/vector
    (vector<>::assign, vector<>::insert): Likewise.
    * include/Makefile.am: Add new debug headers.
    * include/Makefile.in: Regenerate.

Being fully tested under Linux x86_64.

FranÃois

Index: include/Makefile.am
===================================================================
--- include/Makefile.am	(revision 224246)
+++ include/Makefile.am	(working copy)
@@ -766,6 +766,7 @@
 	${debug_srcdir}/formatter.h \
 	${debug_srcdir}/forward_list \
 	${debug_srcdir}/functions.h \
+	${debug_srcdir}/helper_functions.h \
 	${debug_srcdir}/list \
 	${debug_srcdir}/map \
 	${debug_srcdir}/macros.h \
@@ -785,6 +786,7 @@
 	${debug_srcdir}/safe_unordered_container.tcc \
 	${debug_srcdir}/set \
 	${debug_srcdir}/set.h \
+	${debug_srcdir}/stl_iterator.h \
 	${debug_srcdir}/string \
 	${debug_srcdir}/unordered_map \
 	${debug_srcdir}/unordered_set \
Index: include/Makefile.in
===================================================================
--- include/Makefile.in	(revision 224246)
+++ include/Makefile.in	(working copy)
@@ -1047,6 +1047,7 @@
 	${debug_srcdir}/formatter.h \
 	${debug_srcdir}/forward_list \
 	${debug_srcdir}/functions.h \
+	${debug_srcdir}/helper_functions.h \
 	${debug_srcdir}/list \
 	${debug_srcdir}/map \
 	${debug_srcdir}/macros.h \
@@ -1066,6 +1067,7 @@
 	${debug_srcdir}/safe_unordered_container.tcc \
 	${debug_srcdir}/set \
 	${debug_srcdir}/set.h \
+	${debug_srcdir}/stl_iterator.h \
 	${debug_srcdir}/string \
 	${debug_srcdir}/unordered_map \
 	${debug_srcdir}/unordered_set \
Index: include/bits/stl_iterator.h
===================================================================
--- include/bits/stl_iterator.h	(revision 224246)
+++ include/bits/stl_iterator.h	(working copy)
@@ -1246,4 +1246,8 @@
 #define _GLIBCXX_MAKE_MOVE_IF_NOEXCEPT_ITERATOR(_Iter) (_Iter)
 #endif // C++11
 
+#ifdef _GLIBCXX_DEBUG
+# include <debug/stl_iterator.h>
 #endif
+
+#endif
Index: include/bits/stl_iterator_base_types.h
===================================================================
--- include/bits/stl_iterator_base_types.h	(revision 224246)
+++ include/bits/stl_iterator_base_types.h	(working copy)
@@ -206,6 +206,7 @@
 
   //@}
 
+#if __cplusplus < 201103L
   // If _Iterator has a base returns it otherwise _Iterator is returned
   // untouched
   template<typename _Iterator, bool _HasBase>
@@ -223,6 +224,7 @@
       static iterator_type _S_base(_Iterator __it)
       { return __it.base(); }
     };
+#endif
 
 #if __cplusplus >= 201103L
   template<typename _InIter>
Index: include/debug/deque
===================================================================
--- include/debug/deque	(revision 224246)
+++ include/debug/deque	(working copy)
@@ -169,9 +169,14 @@
 	void
 	assign(_InputIterator __first, _InputIterator __last)
 	{
-	  __glibcxx_check_valid_range(__first, __last);
-	  _Base::assign(__gnu_debug::__base(__first),
-			__gnu_debug::__base(__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();
 	}
 
@@ -460,10 +465,16 @@
 	insert(const_iterator __position,
 	       _InputIterator __first, _InputIterator __last)
 	{
-	  __glibcxx_check_insert_range(__position, __first, __last);
-	  _Base_iterator __res = _Base::insert(__position.base(),
-					       __gnu_debug::__base(__first),
-					       __gnu_debug::__base(__last));
+	  typename __gnu_debug::_Distance_traits<_InputIterator>::__type __dist;
+	  __glibcxx_check_insert_range(__position, __first, __last, __dist);
+	  _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);
+
 	  this->_M_invalidate_all();
 	  return iterator(__res, this);
 	}
@@ -473,9 +484,16 @@
 	insert(iterator __position,
 	       _InputIterator __first, _InputIterator __last)
 	{
-	  __glibcxx_check_insert_range(__position, __first, __last);
-	  _Base::insert(__position.base(), __gnu_debug::__base(__first),
-					   __gnu_debug::__base(__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);
+
 	  this->_M_invalidate_all();
 	}
 #endif
Index: include/debug/forward_list
===================================================================
--- include/debug/forward_list	(revision 224246)
+++ include/debug/forward_list	(working copy)
@@ -36,6 +36,13 @@
 #include <debug/safe_container.h>
 #include <debug/safe_iterator.h>
 
+// Special validity check for forward_list ranges.
+#define __glibcxx_check_valid_fl_range(_First,_Last,_Dist)		\
+_GLIBCXX_DEBUG_VERIFY(_First._M_valid_range(_Last, _Dist, false),	\
+		      _M_message(__gnu_debug::__msg_valid_range)	\
+		      ._M_iterator(_First, #_First)			\
+		      ._M_iterator(_Last, #_Last))
+
 namespace __gnu_debug
 {
   /// Special iterators swap and invalidation for forward_list because of the
@@ -266,9 +273,15 @@
 	void
 	assign(_InputIterator __first, _InputIterator __last)
 	{
-	  __glibcxx_check_valid_range(__first, __last);
-	  _Base::assign(__gnu_debug::__base(__first),
-			__gnu_debug::__base(__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();
 	}
 
@@ -398,11 +411,19 @@
 	insert_after(const_iterator __pos,
 		     _InputIterator __first, _InputIterator __last)
 	{
-	  __glibcxx_check_insert_range_after(__pos, __first, __last);
-	  return iterator(_Base::insert_after(__pos.base(),
-					      __gnu_debug::__base(__first),
-					      __gnu_debug::__base(__last)),
-			  this);
+	  typename __gnu_debug::_Distance_traits<_InputIterator>::__type __dist;
+	  __glibcxx_check_insert_range_after(__pos, __first, __last, __dist);
+
+	  if (__dist.second >= __gnu_debug::__dp_sign)
+	    return
+	      {
+		_Base::insert_after(__pos.base(),
+				    __gnu_debug::__unsafe(__first),
+				    __gnu_debug::__unsafe(__last)),
+		this
+	      };
+	  else
+	    return { _Base::insert_after(__pos.base(), __first, __last), this };
 	}
 
       iterator
@@ -577,8 +598,9 @@
       splice_after(const_iterator __pos, forward_list&& __list,
 		   const_iterator __before, const_iterator __last)
       {
+	typename __gnu_debug::_Distance_traits<const_iterator>::__type __dist;
 	__glibcxx_check_insert_after(__pos);
-	__glibcxx_check_valid_range(__before, __last);
+	__glibcxx_check_valid_fl_range(__before, __last, __dist);
 	_GLIBCXX_DEBUG_VERIFY(__before._M_attached_to(&__list),
 			      _M_message(__gnu_debug::__msg_splice_other)
 			      ._M_sequence(__list, "list")
@@ -797,7 +819,7 @@
 
 namespace __gnu_debug
 {
-  template<class _Tp, class _Alloc>
+  template<typename _Tp, typename _Alloc>
     struct _BeforeBeginHelper<std::__debug::forward_list<_Tp, _Alloc> >
     {
       typedef std::__debug::forward_list<_Tp, _Alloc> _Sequence;
@@ -816,6 +838,19 @@
 	{ return _S_Is(__it); }
     };
 
+  template<typename _Tp, typename _Alloc>
+    struct _Sequence_traits<std::__debug::forward_list<_Tp, _Alloc> >
+    {
+      typedef typename std::__debug::forward_list<_Tp, _Alloc>::iterator _It;
+
+      static typename _Distance_traits<_It>::__type
+      _S_size(const std::__debug::forward_list<_Tp, _Alloc>& __seq)
+      {
+	return __seq.empty()
+	  ? std::make_pair(0, __dp_exact) : std::make_pair(1, __dp_equality);
+      }
+    };
+
 #ifndef _GLIBCXX_DEBUG_PEDANTIC
   template<class _Tp, class _Alloc>
     struct _Insert_range_from_self_is_safe<
Index: include/debug/functions.h
===================================================================
--- include/debug/functions.h	(revision 224246)
+++ include/debug/functions.h	(working copy)
@@ -29,11 +29,6 @@
 #ifndef _GLIBCXX_DEBUG_FUNCTIONS_H
 #define _GLIBCXX_DEBUG_FUNCTIONS_H 1
 
-#include <bits/c++config.h>
-#include <bits/stl_iterator_base_types.h>	// for iterator_traits,
-						// categories and _Iter_base
-#include <bits/cpp_type_traits.h>		// for __is_integer
-
 #include <bits/move.h>				// for __addressof
 #include <bits/stl_function.h>			// for less
 #if __cplusplus >= 201103L
@@ -41,6 +36,7 @@
 						// conditional.
 #endif
 
+#include <debug/helper_functions.h>
 #include <debug/formatter.h>
 
 namespace __gnu_debug
@@ -85,58 +81,6 @@
     __check_dereferenceable(const _Tp* __ptr)
     { return __ptr; }
 
-  /** If the distance between two random access iterators is
-   *  nonnegative, assume the range is valid.
-  */
-  template<typename _RandomAccessIterator>
-    inline bool
-    __valid_range_aux2(const _RandomAccessIterator& __first,
-		       const _RandomAccessIterator& __last,
-		       std::random_access_iterator_tag)
-    { return __last - __first >= 0; }
-
-  /** Can't test for a valid range with input iterators, because
-   *  iteration may be destructive. So we just assume that the range
-   *  is valid.
-  */
-  template<typename _InputIterator>
-    inline bool
-    __valid_range_aux2(const _InputIterator&, const _InputIterator&,
-		       std::input_iterator_tag)
-    { return true; }
-
-  /** We say that integral types for a valid range, and defer to other
-   *  routines to realize what to do with integral types instead of
-   *  iterators.
-  */
-  template<typename _Integral>
-    inline bool
-    __valid_range_aux(const _Integral&, const _Integral&, std::__true_type)
-    { return true; }
-
-  /** We have iterators, so figure out what kind of iterators that are
-   *  to see if we can check the range ahead of time.
-  */
-  template<typename _InputIterator>
-    inline bool
-    __valid_range_aux(const _InputIterator& __first,
-		      const _InputIterator& __last, std::__false_type)
-    { return __valid_range_aux2(__first, __last,
-				std::__iterator_category(__first)); }
-
-  /** Don't know what these iterators are, or if they are even
-   *  iterators (we may get an integral type for InputIterator), so
-   *  see if they are integral and pass them on to the next phase
-   *  otherwise.
-  */
-  template<typename _InputIterator>
-    inline bool
-    __valid_range(const _InputIterator& __first, const _InputIterator& __last)
-    {
-      typedef typename std::__is_integer<_InputIterator>::__type _Integral;
-      return __valid_range_aux(__first, __last, _Integral());
-    }
-
   /* Checks that [first, last) is a valid range, and then returns
    * __first. This routine is useful when we can't use a separate
    * assertion statement because, e.g., we are in a constructor.
@@ -500,29 +444,6 @@
       return __first == __last;
     }
 
-  // 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>
-    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
 
 #endif
Index: include/debug/helper_functions.h
===================================================================
--- include/debug/helper_functions.h	(revision 0)
+++ include/debug/helper_functions.h	(working copy)
@@ -0,0 +1,210 @@
+// Debugging support implementation -*- C++ -*-
+
+// Copyright (C) 2003-2015 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/helper_functions.h
+ *  This file is a GNU debug extension to the Standard C++ Library.
+ */
+
+#ifndef _GLIBCXX_DEBUG_HELPER_FUNCTIONS_H
+#define _GLIBCXX_DEBUG_HELPER_FUNCTIONS_H 1
+
+#include <bits/stl_iterator_base_types.h>	// for iterator_traits,
+						// categories and _Iter_base
+#include <bits/cpp_type_traits.h>		// for __is_integer
+
+#include <bits/stl_pair.h>			// for pair
+
+namespace __gnu_debug
+{
+  /** The precision to which we can calculate the distance between
+   *  two iterators.
+   */
+  enum _Distance_precision
+    {
+      __dp_none,	// Not even an iterator type
+      __dp_equality,	//< Can compare iterator equality, only
+      __dp_sign,	//< Can determine equality and ordering
+      __dp_exact	//< Can determine distance precisely
+    };
+
+  template<typename _Iterator,
+	   typename = typename std::__is_integer<_Iterator>::__type>
+    struct _Distance_traits
+    {
+    private:
+      typedef
+      typename std::iterator_traits<_Iterator>::difference_type _ItDiffType;
+
+      template<typename _DiffType,
+	       typename = typename std::__is_void<_DiffType>::__type>
+	struct _DiffTraits
+	{ typedef _DiffType __type; };
+
+      template<typename _DiffType>
+	struct _DiffTraits<_DiffType, std::__true_type>
+	{ typedef std::ptrdiff_t __type; };
+
+      typedef typename _DiffTraits<_ItDiffType>::__type _DiffType;
+
+    public:
+      typedef std::pair<_DiffType, _Distance_precision> __type;
+    };
+
+  template<typename _Integral>
+    struct _Distance_traits<_Integral, std::__true_type>
+    { typedef std::pair<std::ptrdiff_t, _Distance_precision> __type; };
+
+  /** Determine the distance between two iterators with some known
+   *	precision.
+  */
+  template<typename _Iterator>
+    inline typename _Distance_traits<_Iterator>::__type
+    __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 typename _Distance_traits<_Iterator>::__type
+    __get_distance(const _Iterator& __lhs, const _Iterator& __rhs,
+		   std::input_iterator_tag)
+    {
+      if (__lhs == __rhs)
+	return std::make_pair(0, __dp_exact);
+
+      return std::make_pair(1, __dp_equality);
+    }
+
+  template<typename _Iterator>
+    inline typename _Distance_traits<_Iterator>::__type
+    __get_distance(const _Iterator& __lhs, const _Iterator& __rhs)
+    { return __get_distance(__lhs, __rhs, std::__iterator_category(__lhs)); }
+
+  /** We say that integral types for a valid range, and defer to other
+   *  routines to realize what to do with integral types instead of
+   *  iterators.
+  */
+  template<typename _Integral>
+    inline bool
+    __valid_range_aux(const _Integral&, const _Integral&,
+		      typename _Distance_traits<_Integral>::__type& __dist,
+		      std::__true_type)
+    {
+      __dist = std::make_pair(0, __dp_none);
+      return true;
+    }
+
+  /** We have iterators, so figure out what kind of iterators that are
+   *  to see if we can check the range ahead of time.
+  */
+  template<typename _InputIterator>
+    inline bool
+    __valid_range_aux(const _InputIterator& __first,
+		      const _InputIterator& __last,
+		      typename _Distance_traits<_InputIterator>::__type& __dist,
+		      std::__false_type)
+    {
+      __dist = __get_distance(__first, __last);
+      switch (__dist.second)
+	{
+	case __dp_none:
+	  break;
+	case __dp_equality:
+	  if (__dist.first == 0)
+	    return true;
+	  break;
+	case __dp_sign:
+	case __dp_exact:
+	  return __dist.first >= 0;
+	}
+
+      return true;
+    }
+
+  /** Don't know what these iterators are, or if they are even
+   *  iterators (we may get an integral type for InputIterator), so
+   *  see if they are integral and pass them on to the next phase
+   *  otherwise.
+  */
+  template<typename _InputIterator>
+    inline bool
+    __valid_range(const _InputIterator& __first, const _InputIterator& __last,
+		  typename _Distance_traits<_InputIterator>::__type& __dist)
+    {
+      typedef typename std::__is_integer<_InputIterator>::__type _Integral;
+      return __valid_range_aux(__first, __last, __dist, _Integral());
+    }
+
+  template<typename _InputIterator>
+    inline bool
+    __valid_range(const _InputIterator& __first, const _InputIterator& __last)
+    {
+      typename _Distance_traits<_InputIterator>::__type __dist;
+      return __valid_range(__first, __last, __dist);
+    }
+
+#if __cplusplus < 201103L
+  // 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>
+    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); }
+#else
+  template<typename _Iterator>
+    inline _Iterator
+    __base(_Iterator __it)
+    { return __it; }
+#endif
+
+#if __cplusplus < 201103L
+  template<typename _Iterator>
+    struct _Unsafe_type
+    { typedef _Iterator _Type; };
+#endif
+
+  /* Remove debug mode safe iterator layer, if any. */
+  template<typename _Iterator>
+    inline _Iterator
+    __unsafe(_Iterator __it)
+    { return __it; }
+}
+
+#endif
Index: include/debug/list
===================================================================
--- include/debug/list	(revision 224246)
+++ include/debug/list	(working copy)
@@ -171,9 +171,15 @@
 	void
 	assign(_InputIterator __first, _InputIterator __last)
 	{
-	  __glibcxx_check_valid_range(__first, __last);
-	  _Base::assign(__gnu_debug::__base(__first),
-			__gnu_debug::__base(__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();
 	}
 
@@ -435,11 +441,18 @@
 	insert(const_iterator __position, _InputIterator __first,
 	       _InputIterator __last)
 	{
-	  __glibcxx_check_insert_range(__position, __first, __last);
-	  return iterator(_Base::insert(__position.base(),
-					__gnu_debug::__base(__first),
-					__gnu_debug::__base(__last)),
-			  this);
+	  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>
@@ -447,9 +460,14 @@
 	insert(iterator __position, _InputIterator __first,
 	       _InputIterator __last)
 	{
-	  __glibcxx_check_insert_range(__position, __first, __last);
-	  _Base::insert(__position.base(), __gnu_debug::__base(__first),
-					   __gnu_debug::__base(__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
 
@@ -788,13 +806,29 @@
 } // namespace __debug
 } // namespace std
 
-#ifndef _GLIBCXX_DEBUG_PEDANTIC
 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_equality);
+      }
+    };
+#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
 
 #endif
Index: include/debug/macros.h
===================================================================
--- include/debug/macros.h	(revision 224246)
+++ include/debug/macros.h	(working copy)
@@ -56,6 +56,12 @@
 		      ._M_iterator(_First, #_First)			\
 		      ._M_iterator(_Last, #_Last))
 
+#define __glibcxx_check_valid_range2(_First,_Last,_Dist)		\
+_GLIBCXX_DEBUG_VERIFY(__gnu_debug::__valid_range(_First, _Last, _Dist),	\
+		      _M_message(__gnu_debug::__msg_valid_range)	\
+		      ._M_iterator(_First, #_First)			\
+		      ._M_iterator(_Last, #_Last))
+
 // Verify that [_First, _Last) forms a non-empty iterator range.
 #define __glibcxx_check_non_empty_range(_First,_Last)			\
 _GLIBCXX_DEBUG_VERIFY(_First != _Last,					\
@@ -104,8 +110,8 @@
  *  Note that this macro is only valid when the container is a
  *  _Safe_sequence and the _Position iterator is a _Safe_iterator.
 */
-#define __glibcxx_check_insert_range(_Position,_First,_Last)		\
-__glibcxx_check_valid_range(_First,_Last);				\
+#define __glibcxx_check_insert_range(_Position,_First,_Last,_Dist)	\
+__glibcxx_check_valid_range2(_First,_Last,_Dist);			\
 __glibcxx_check_insert(_Position);					\
 _GLIBCXX_DEBUG_VERIFY(__gnu_debug::__foreign_iterator(_Position,_First,_Last),\
 		      _M_message(__gnu_debug::__msg_insert_range_from_self)\
@@ -123,8 +129,8 @@
  *  Note that this macro is only valid when the container is a
  *  _Safe_sequence and the _Position iterator is a _Safe_iterator.
 */
-#define __glibcxx_check_insert_range_after(_Position,_First,_Last)	\
-__glibcxx_check_valid_range(_First,_Last);				\
+#define __glibcxx_check_insert_range_after(_Position,_First,_Last,_Dist)\
+  __glibcxx_check_valid_range2(_First,_Last,_Dist);			\
 __glibcxx_check_insert_after(_Position);				\
 _GLIBCXX_DEBUG_VERIFY(__gnu_debug::__foreign_iterator(_Position,_First,_Last),\
 		      _M_message(__gnu_debug::__msg_insert_range_from_self)\
Index: include/debug/map.h
===================================================================
--- include/debug/map.h	(revision 224246)
+++ include/debug/map.h	(working copy)
@@ -307,9 +307,14 @@
 	void
 	insert(_InputIterator __first, _InputIterator __last)
 	{
-	  __glibcxx_check_valid_range(__first, __last);
-	  _Base::insert(__gnu_debug::__base(__first),
-			__gnu_debug::__base(__last));
+	  typename __gnu_debug::_Distance_traits<_InputIterator>::__type __dist;
+	  __glibcxx_check_valid_range2(__first, __last, __dist);
+
+	  if (__dist.second >= __gnu_debug::__dp_sign)
+	    _Base::insert(__gnu_debug::__unsafe(__first),
+			  __gnu_debug::__unsafe(__last));
+	  else
+	    _Base::insert(__first, __last);
 	}
 
 #if __cplusplus >= 201103L
Index: include/debug/multimap.h
===================================================================
--- include/debug/multimap.h	(revision 224246)
+++ include/debug/multimap.h	(working copy)
@@ -286,9 +286,14 @@
 	void
 	insert(_InputIterator __first, _InputIterator __last)
 	{
-	  __glibcxx_check_valid_range(__first, __last);
-	  _Base::insert(__gnu_debug::__base(__first),
-			__gnu_debug::__base(__last));
+	  typename __gnu_debug::_Distance_traits<_InputIterator>::__type __dist;
+	  __glibcxx_check_valid_range2(__first, __last, __dist);
+
+	  if (__dist.second >= __gnu_debug::__dp_sign)
+	    _Base::insert(__gnu_debug::__unsafe(__first),
+			  __gnu_debug::__unsafe(__last));
+	  else
+	    _Base::insert(__first, __last);
 	}
 
 #if __cplusplus >= 201103L
Index: include/debug/multiset.h
===================================================================
--- include/debug/multiset.h	(revision 224246)
+++ include/debug/multiset.h	(working copy)
@@ -271,9 +271,14 @@
 	void
 	insert(_InputIterator __first, _InputIterator __last)
 	{
-	  __glibcxx_check_valid_range(__first, __last);
-	  _Base::insert(__gnu_debug::__base(__first),
-			__gnu_debug::__base(__last));
+	  typename __gnu_debug::_Distance_traits<_InputIterator>::__type __dist;
+	  __glibcxx_check_valid_range2(__first, __last, __dist);
+
+	  if (__dist.second >= __gnu_debug::__dp_sign)
+	    _Base::insert(__gnu_debug::__unsafe(__first),
+			  __gnu_debug::__unsafe(__last));
+	  else
+	    _Base::insert(__first, __last);
 	}
 
 #if __cplusplus >= 201103L
Index: include/debug/safe_iterator.h
===================================================================
--- include/debug/safe_iterator.h	(revision 224246)
+++ include/debug/safe_iterator.h	(working copy)
@@ -41,7 +41,7 @@
   /** Helper struct to deal with sequence offering a before_begin
    *  iterator.
    **/
-  template <typename _Sequence>
+  template<typename _Sequence>
     struct _BeforeBeginHelper
     {
       template<typename _Iterator>
@@ -55,39 +55,17 @@
 	{ return __it.base() == __it._M_get_sequence()->_M_base().begin(); }
     };
 
-  /** The precision to which we can calculate the distance between
-   *  two iterators.
-   */
-  enum _Distance_precision
+  /** Sequence traits giving the size of a container if possible. */
+  template<typename _Sequence>
+    struct _Sequence_traits
     {
-      __dp_equality, //< Can compare iterator equality, only
-      __dp_sign,     //< Can determine equality and ordering
-      __dp_exact     //< Can determine distance precisely
+      typedef _Distance_traits<typename _Sequence::iterator> _DistTraits;
+
+      static typename _DistTraits::__type
+      _S_size(const _Sequence& __seq)
+      { return std::make_pair(__seq.size(), __dp_exact); }
     };
 
-  /** 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)
-    { return __get_distance(__lhs, __rhs, std::__iterator_category(__lhs)); }
-
   /** \brief Safe iterator wrapper.
    *
    *  The class template %_Safe_iterator is a wrapper around an
@@ -476,7 +454,9 @@
 
       // Is the iterator range [*this, __rhs) valid?
       bool
-      _M_valid_range(const _Safe_iterator& __rhs) const;
+      _M_valid_range(const _Safe_iterator& __rhs,
+		     std::pair<difference_type, _Distance_precision>& __dist,
+		     bool __check_dereferenceable = true) const;
 
       // The sequence this iterator references.
       typename
@@ -768,16 +748,158 @@
   template<typename _Iterator, typename _Sequence>
     inline bool
     __valid_range(const _Safe_iterator<_Iterator, _Sequence>& __first,
-		  const _Safe_iterator<_Iterator, _Sequence>& __last)
-    { return __first._M_valid_range(__last); }
+		  const _Safe_iterator<_Iterator, _Sequence>& __last,
+		  typename _Distance_traits<_Iterator>::__type& __dist)
+    { return __first._M_valid_range(__last, __dist); }
 
+  /** Safe iterators can help to get better distance knowledge. */
   template<typename _Iterator, typename _Sequence>
+    inline typename _Distance_traits<_Iterator>::__type
+    __get_distance(const _Safe_iterator<_Iterator, _Sequence>& __first,
+		   const _Safe_iterator<_Iterator, _Sequence>& __last,
+		   std::random_access_iterator_tag)
+    { return std::make_pair(__last.base() - __first.base(), __dp_exact); }
+
+  template<typename _Iterator, typename _Sequence>
+    inline typename _Distance_traits<_Iterator>::__type
+    __get_distance(const _Safe_iterator<_Iterator, _Sequence>& __first,
+		   const _Safe_iterator<_Iterator, _Sequence>& __last,
+		   std::input_iterator_tag)
+    {
+      typedef typename _Distance_traits<_Iterator>::__type _Diff;
+      typedef _Sequence_traits<_Sequence> _SeqTraits;
+
+      if (__first.base() == __last.base())
+	return std::make_pair(0, __dp_exact);
+
+      if (__first._M_is_before_begin())
+	{
+	  if (__last._M_is_begin())
+	    return std::make_pair(1, __dp_exact);
+
+	  return std::make_pair(1, __dp_sign);
+	}
+
+      if (__first._M_is_begin())
+	{
+	  if (__last._M_is_before_begin())
+	    return std::make_pair(-1, __dp_exact);
+
+	  if (__last._M_is_end())
+	    return _SeqTraits::_S_size(*__first._M_get_sequence());
+
+	  return std::make_pair(1, __dp_sign);
+	}
+
+      if (__first._M_is_end())
+	{
+	  if (__last._M_is_before_begin())
+	    return std::make_pair(-1, __dp_exact);
+
+	  if (__last._M_is_begin())
+	    {
+	      _Diff __diff = _SeqTraits::_S_size(*__first._M_get_sequence());
+	      return std::make_pair(-__diff.first, __diff.second);
+	    }
+
+	  return std::make_pair(-1, __dp_sign);
+	}
+
+      if (__last._M_is_before_begin() || __last._M_is_begin())
+	return std::make_pair(-1, __dp_sign);
+
+      if (__last._M_is_end())
+	return std::make_pair(1, __dp_sign);
+
+      return std::make_pair(1, __dp_equality);
+    }
+
+  // Get distance from sequence begin to specified iterator.
+  template<typename _Iterator, typename _Sequence>
+    inline typename _Distance_traits<_Iterator>::__type
+    __get_distance_from_begin(const _Safe_iterator<_Iterator, _Sequence>& __it)
+    {
+      typedef _Sequence_traits<_Sequence> _SeqTraits;
+
+      // No need to consider before_begin as this function is only used in
+      // _M_can_advance which won't be used for forward_list iterators.
+      if (__it._M_is_begin())
+	return std::make_pair(0, __dp_exact);
+
+      if (__it._M_is_end())
+	return _SeqTraits::_S_size(*__it._M_get_sequence());
+
+      typename _Distance_traits<_Iterator>::__type __res
+	= __get_distance(__it._M_get_sequence()->_M_base().begin(), __it.base());
+
+      if (__res.second == __dp_equality)
+	return std::make_pair(1, __dp_sign);
+
+      return __res;
+    }
+
+  // Get distance from specified iterator to sequence end.
+  template<typename _Iterator, typename _Sequence>
+    inline typename _Distance_traits<_Iterator>::__type
+    __get_distance_to_end(const _Safe_iterator<_Iterator, _Sequence>& __it)
+    {
+      typedef _Sequence_traits<_Sequence> _SeqTraits;
+
+      // No need to consider before_begin as this function is only used in
+      // _M_can_advance which won't be used for forward_list iterators.
+      if (__it._M_is_begin())
+	return _SeqTraits::_S_size(*__it._M_get_sequence());
+
+      if (__it._M_is_end())
+	return std::make_pair(0, __dp_exact);
+
+      typename _Distance_traits<_Iterator>::__type __res
+	= __get_distance(__it.base(), __it._M_get_sequence()->_M_base().end());
+
+      if (__res.second == __dp_equality)
+	return std::make_pair(1, __dp_sign);
+
+      return __res;
+    }
+
+#if __cplusplus < 201103L
+  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>
     { };
+#else
+  template<typename _Iterator, typename _Sequence>
+    _Iterator
+    __base(const _Safe_iterator<_Iterator, _Sequence>& __it,
+	   std::random_access_iterator_tag)
+    { return __it.base(); }
 
+  template<typename _Iterator, typename _Sequence>
+    const _Safe_iterator<_Iterator, _Sequence>&
+    __base(const _Safe_iterator<_Iterator, _Sequence>& __it,
+	   std::input_iterator_tag)
+    { return __it; }
+
+  template<typename _Iterator, typename _Sequence>
+    auto
+    __base(const _Safe_iterator<_Iterator, _Sequence>& __it)
+    -> decltype(__base(__it, std::__iterator_category(__it)))
+    { return __base(__it, std::__iterator_category(__it)); }
+#endif
+
+#if __cplusplus <= 201103L
+  template<typename _Iterator, typename _Sequence>
+    struct _Unsafe_type<_Safe_iterator<_Iterator, _Sequence> >
+    { typedef _Iterator _Type; };
+#endif
+
+  template<typename _Iterator, typename _Sequence>
+    inline _Iterator
+    __unsafe(const _Safe_iterator<_Iterator, _Sequence>& __it)
+    { return __it.base(); }
+
 } // namespace __gnu_debug
 
 #include <debug/safe_iterator.tcc>
Index: include/debug/safe_iterator.tcc
===================================================================
--- include/debug/safe_iterator.tcc	(revision 224246)
+++ include/debug/safe_iterator.tcc	(working copy)
@@ -38,12 +38,14 @@
     {
       if (this->_M_singular())
 	return false;
+
       if (__n == 0)
 	return true;
+
       if (__n < 0)
 	{
 	  std::pair<difference_type, _Distance_precision> __dist =
-	    __get_distance(_M_get_sequence()->_M_base().begin(), base());
+	    __get_distance_from_begin(*this);
 	  bool __ok =  ((__dist.second == __dp_exact && __dist.first >= -__n)
 			|| (__dist.second != __dp_exact && __dist.first > 0));
 	  return __ok;
@@ -51,7 +53,7 @@
       else
 	{
 	  std::pair<difference_type, _Distance_precision> __dist =
-	    __get_distance(base(), _M_get_sequence()->_M_base().end());
+	    __get_distance_to_end(*this);
 	  bool __ok = ((__dist.second == __dp_exact && __dist.first >= __n)
 		       || (__dist.second != __dp_exact && __dist.first > 0));
 	  return __ok;
@@ -61,37 +63,31 @@
   template<typename _Iterator, typename _Sequence>
     bool
     _Safe_iterator<_Iterator, _Sequence>::
-    _M_valid_range(const _Safe_iterator& __rhs) const
+    _M_valid_range(const _Safe_iterator& __rhs,
+		   std::pair<difference_type, _Distance_precision>& __dist,
+		   bool __check_dereferenceable) const
     {
       if (!_M_can_compare(__rhs))
 	return false;
 
-      /* Determine if we can order the iterators without the help of
-	 the container */
-      std::pair<difference_type, _Distance_precision> __dist =
-	__get_distance(base(), __rhs.base());
-      switch (__dist.second) {
-      case __dp_equality:
-	if (__dist.first == 0)
-	  return true;
-	break;
+      /* Determine iterators order */
+      __dist = __get_distance(*this, __rhs);
+      switch (__dist.second)
+	{
+	case __dp_equality:
+	  if (__dist.first == 0)
+	    return true;
+	  break;
 
-      case __dp_sign:
-      case __dp_exact:
-	return __dist.first >= 0;
-      }
+	case __dp_sign:
+	case __dp_exact:
+	  // If range is not empty first iterator must be dereferenceable.
+	  if (__dist.first > 0)
+	    return !__check_dereferenceable || _M_dereferenceable();
+	  return __dist.first == 0;
+	}
 
-      /* We can only test for equality, but check if one of the
-	 iterators is at an extreme. */
-      /* Optim for classic [begin, it) or [it, end) ranges, limit checks
-       * when code is valid.  Note, for the special case of forward_list,
-       * before_begin replaces the role of begin.  */ 
-      if (_M_is_beginnest() || __rhs._M_is_end())
-	return true;
-      if (_M_is_end() || __rhs._M_is_beginnest())
-	return false;
-
-      // Assume that this is a valid range; we can't check anything else
+      // Assume that this is a valid range; we can't check anything else.
       return true;
     }
 } // namespace __gnu_debug
Index: include/debug/safe_local_iterator.h
===================================================================
--- include/debug/safe_local_iterator.h	(revision 224246)
+++ include/debug/safe_local_iterator.h	(working copy)
@@ -322,7 +322,9 @@
 
       // Is the iterator range [*this, __rhs) valid?
       bool
-      _M_valid_range(const _Safe_local_iterator& __rhs) const;
+      _M_valid_range(const _Safe_local_iterator& __rhs,
+		     std::pair<difference_type,
+			       _Distance_precision>& __dist_info) const;
 
       // The sequence this iterator references.
       typename
@@ -440,8 +442,66 @@
   template<typename _Iterator, typename _Sequence>
     inline bool
     __valid_range(const _Safe_local_iterator<_Iterator, _Sequence>& __first,
-		  const _Safe_local_iterator<_Iterator, _Sequence>& __last)
-    { return __first._M_valid_range(__last); }
+		  const _Safe_local_iterator<_Iterator, _Sequence>& __last,
+		  typename _Distance_traits<_Iterator>::__type& __dist_info)
+    { return __first._M_valid_range(__last, __dist_info); }
+
+  /** Safe local iterators need a special method to get distance between each
+      other. */
+  template<typename _Iterator, typename _Sequence>
+    inline std::pair<typename std::iterator_traits<_Iterator>::difference_type,
+		     _Distance_precision>
+    __get_distance(const _Safe_local_iterator<_Iterator, _Sequence>& __first,
+		   const _Safe_local_iterator<_Iterator, _Sequence>& __last,
+		   std::input_iterator_tag)
+    {
+      if (__first.base() == __last.base())
+	return { 0, __dp_exact };
+
+      if (__first._M_is_begin())
+	{
+	  if (__last._M_is_end())
+	    return
+	      {
+		__first._M_get_sequence()->bucket_size(__first.bucket()),
+		__dp_exact
+	      };
+
+	  return { 1, __dp_sign };
+	}
+
+      if (__first._M_is_end())
+	{
+	  if (__last._M_is_begin())
+	    return
+	      {
+		-__first._M_get_sequence()->bucket_size(__first.bucket()),
+		__dp_exact
+	      };
+
+	  return { -1, __dp_sign };
+	}
+
+      if (__last._M_is_begin())
+	return { -1, __dp_sign };
+
+      if (__last._M_is_end())
+	return { 1, __dp_sign };
+
+      return { 1, __dp_equality };
+    }
+
+#if __cplusplus < 201103L
+  template<typename _Iterator, typename _Sequence>
+    struct _Unsafe_type<_Safe_local_iterator<_Iterator, _Sequence> >
+    { typedef _Iterator _Type; };
+#endif
+
+  template<typename _Iterator, typename _Sequence>
+    inline _Iterator
+    __unsafe(const _Safe_local_iterator<_Iterator, _Sequence>& __it)
+    { return __it.base(); }
+
 } // namespace __gnu_debug
 
 #include <debug/safe_local_iterator.tcc>
Index: include/debug/safe_local_iterator.tcc
===================================================================
--- include/debug/safe_local_iterator.tcc	(revision 224246)
+++ include/debug/safe_local_iterator.tcc	(working copy)
@@ -34,17 +34,18 @@
   template<typename _Iterator, typename _Sequence>
     bool
     _Safe_local_iterator<_Iterator, _Sequence>::
-    _M_valid_range(const _Safe_local_iterator& __rhs) const
+    _M_valid_range(const _Safe_local_iterator& __rhs,
+		std::pair<difference_type, _Distance_precision>& __dist) const
     {
       if (!_M_can_compare(__rhs))
 	return false;
+
       if (bucket() != __rhs.bucket())
 	return false;
 
       /* Determine if we can order the iterators without the help of
 	 the container */
-      std::pair<difference_type, _Distance_precision> __dist =
-	__get_distance(base(), __rhs.base());
+      __dist = __get_distance(*this, __rhs);
       switch (__dist.second)
 	{
 	case __dp_equality:
@@ -57,15 +58,6 @@
 	  return __dist.first >= 0;
 	}
 
-      /* We can only test for equality, but check if one of the
-	 iterators is at an extreme. */
-      /* Optim for classic [begin, it) or [it, end) ranges, limit checks
-       * when code is valid. */
-      if (_M_is_begin() || __rhs._M_is_end())
-	return true;
-      if (_M_is_end() || __rhs._M_is_begin())
-	return false;
-
       // Assume that this is a valid range; we can't check anything else
       return true;
     }
Index: include/debug/set.h
===================================================================
--- include/debug/set.h	(revision 224246)
+++ include/debug/set.h	(working copy)
@@ -280,9 +280,14 @@
 	void
 	insert(_InputIterator __first, _InputIterator __last)
 	{
-	  __glibcxx_check_valid_range(__first, __last);
-	  _Base::insert(__gnu_debug::__base(__first),
-			__gnu_debug::__base(__last));
+	  typename __gnu_debug::_Distance_traits<_InputIterator>::__type __dist;
+	  __glibcxx_check_valid_range2(__first, __last, __dist);
+
+	  if (__dist.second >= __gnu_debug::__dp_sign)
+	    _Base::insert(__gnu_debug::__unsafe(__first),
+			  __gnu_debug::__unsafe(__last));
+	  else
+	    _Base::insert(__first, __last);
 	}
 
 #if __cplusplus >= 201103L
Index: include/debug/stl_iterator.h
===================================================================
--- include/debug/stl_iterator.h	(revision 0)
+++ include/debug/stl_iterator.h	(working copy)
@@ -0,0 +1,113 @@
+// Debugging support implementation -*- C++ -*-
+
+// Copyright (C) 2015 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/stl_iterator.h
+ *  This file is a GNU debug extension to the Standard C++ Library.
+ */
+
+#ifndef _GLIBCXX_DEBUG_STL_ITERATOR_H
+#define _GLIBCXX_DEBUG_STL_ITERATOR_H 1
+
+#include <debug/helper_functions.h>
+
+namespace __gnu_debug
+{
+  // Help Debug mode to see through reverse_iterator.
+  template<typename _Iterator>
+    inline bool
+    __valid_range(const std::reverse_iterator<_Iterator>& __first,
+		  const std::reverse_iterator<_Iterator>& __last,
+		  typename _Distance_traits<_Iterator>::__type& __dist)
+    { return __valid_range(__last.base(), __first.base(), __dist); }
+
+  template<typename _Iterator>
+    inline typename _Distance_traits<_Iterator>::__type
+    __get_distance(const std::reverse_iterator<_Iterator>& __first,
+		   const std::reverse_iterator<_Iterator>& __last)
+    { return __get_distance(__last.base(), __first.base()); }
+
+#if __cplusplus < 201103L
+  template<typename _Iterator>
+    struct __is_safe_random_iterator<std::reverse_iterator<_Iterator> >
+      : __is_safe_random_iterator<_Iterator>
+    { };
+
+  template<typename _Iterator>
+    struct _Unsafe_type<std::reverse_iterator<_Iterator> >
+    {
+      typedef typename _Unsafe_type<_Iterator>::_Type _UnsafeType;
+      typedef std::reverse_iterator<_UnsafeType> _Type;
+    };
+
+  template<typename _Iterator>
+    inline std::reverse_iterator<typename _Unsafe_type<_Iterator>::_Type>
+    __unsafe(const std::reverse_iterator<_Iterator>& __it)
+    {
+      typedef typename _Unsafe_type<_Iterator>::_Type _UnsafeType;
+      return std::reverse_iterator<_UnsafeType>(__unsafe(__it.base()));
+    }
+#else
+  template<typename _Iterator>
+    inline auto
+    __base(const std::reverse_iterator<_Iterator>& __it)
+    -> decltype(std::__make_reverse_iterator(__base(__it.base())))
+    { return std::__make_reverse_iterator(__base(__it.base())); }
+
+  template<typename _Iterator>
+    inline auto
+    __unsafe(const std::reverse_iterator<_Iterator>& __it)
+    -> decltype(std::__make_reverse_iterator(__unsafe(__it.base())))
+    { return std::__make_reverse_iterator(__unsafe(__it.base())); }
+#endif
+
+#if __cplusplus >= 201103L
+  // Help Debug mode to see through move_iterator.
+  template<typename _Iterator>
+    inline bool
+    __valid_range(const std::move_iterator<_Iterator>& __first,
+		  const std::move_iterator<_Iterator>& __last,
+		  typename _Distance_traits<_Iterator>::__type& __dist)
+    { return __valid_range(__first.base(), __last.base(), __dist); }
+
+  template<typename _Iterator>
+    inline typename _Distance_traits<_Iterator>::__type
+    __get_distance(const std::move_iterator<_Iterator>& __first,
+		   const std::move_iterator<_Iterator>& __last)
+    { return __get_distance(__first.base(), __last.base()); }
+
+  template<typename _Iterator>
+    inline auto
+    __unsafe(const std::move_iterator<_Iterator>& __it)
+    -> decltype(std::make_move_iterator(__unsafe(__it.base())))
+    { return std::make_move_iterator(__unsafe(__it.base())); }
+
+  template<typename _Iterator>
+    inline auto
+    __base(const std::move_iterator<_Iterator>& __it)
+    -> decltype(std::make_move_iterator(__base(__it.base())))
+    { return std::make_move_iterator(__base(__it.base())); }
+#endif
+}
+
+#endif
Index: include/debug/string
===================================================================
--- include/debug/string	(revision 224246)
+++ include/debug/string	(working copy)
@@ -379,9 +379,15 @@
       basic_string&
       append(_InputIterator __first, _InputIterator __last)
       {
-	__glibcxx_check_valid_range(__first, __last);
-	_Base::append(__gnu_debug::__base(__first),
-		      __gnu_debug::__base(__last));
+	typename __gnu_debug::_Distance_traits<_InputIterator>::__type __dist;
+	__glibcxx_check_valid_range2(__first, __last, __dist);
+
+	if (__dist.second >= __dp_sign)
+	  _Base::append(__gnu_debug::__unsafe(__first),
+			__gnu_debug::__unsafe(__last));
+	else
+	  _Base::append(__first, __last);
+
 	this->_M_invalidate_all();
 	return *this;
       }
@@ -451,9 +457,15 @@
       basic_string&
       assign(_InputIterator __first, _InputIterator __last)
       {
-	__glibcxx_check_valid_range(__first, __last);
-	_Base::assign(__gnu_debug::__base(__first),
-		      __gnu_debug::__base(__last));
+	typename __gnu_debug::_Distance_traits<_InputIterator>::__type __dist;
+	__glibcxx_check_valid_range2(__first, __last, __dist);
+
+	if (__dist.second >= __dp_sign)
+	  _Base::assign(__gnu_debug::__unsafe(__first),
+			__gnu_debug::__unsafe(__last));
+	else
+	  _Base::assign(__first, __last);
+
 	this->_M_invalidate_all();
 	return *this;
       }
@@ -532,9 +544,15 @@
       void
       insert(iterator __p, _InputIterator __first, _InputIterator __last)
       {
-	__glibcxx_check_insert_range(__p, __first, __last);
-	_Base::insert(__p.base(), __gnu_debug::__base(__first),
-				  __gnu_debug::__base(__last));
+	typename __gnu_debug::_Distance_traits<_InputIterator>::__type __dist;
+	__glibcxx_check_insert_range2(__p, __first, __last, __dist);
+
+	if (__dist.second >= __dp_sign)
+	  _Base::insert(__p.base(), __gnu_debug::__unsafe(__first),
+				    __gnu_debug::__unsafe(__last));
+	else
+	  _Base::insert(__p.base(), __first, __last);
+
 	this->_M_invalidate_all();
       }
 
@@ -675,8 +693,17 @@
 	      _InputIterator __j1, _InputIterator __j2)
       {
 	__glibcxx_check_erase_range(__i1, __i2);
-	__glibcxx_check_valid_range(__j1, __j2);
-	_Base::replace(__i1.base(), __i2.base(), __j1, __j2);
+
+	typename __gnu_debug::_Distance_traits<_InputIterator>::__type __dist;
+	__glibcxx_check_valid_range2(__j1, __j2, __dist);
+
+	if (__dist.second >= __dp_sign)
+	  _Base::replace(__i1.base(), __i2.base(),
+			 __gnu_debug::__unsafe(__j1),
+			 __gnu_debug::__unsafe(__j2));
+	else
+	  _Base::replace(__i1.base(), __i2.base(), __j1, __j2);
+
 	this->_M_invalidate_all();
 	return *this;
       }
Index: include/debug/unordered_map
===================================================================
--- include/debug/unordered_map	(revision 224246)
+++ include/debug/unordered_map	(working copy)
@@ -364,10 +364,16 @@
 	void
 	insert(_InputIterator __first, _InputIterator __last)
 	{
-	  __glibcxx_check_valid_range(__first, __last);
+	  typename __gnu_debug::_Distance_traits<_InputIterator>::__type __dist;
+	  __glibcxx_check_valid_range2(__first, __last, __dist);
 	  size_type __bucket_count = this->bucket_count();
-	  _Base::insert(__gnu_debug::__base(__first),
-			  __gnu_debug::__base(__last));
+
+	  if (__dist.second >= __gnu_debug::__dp_sign)
+	    _Base::insert(__gnu_debug::__unsafe(__first),
+			  __gnu_debug::__unsafe(__last));
+	  else
+	    _Base::insert(__first, __last);
+
 	  _M_check_rehashed(__bucket_count);
 	}
 
@@ -809,10 +815,16 @@
 	void
 	insert(_InputIterator __first, _InputIterator __last)
 	{
-	  __glibcxx_check_valid_range(__first, __last);
+	  typename __gnu_debug::_Distance_traits<_InputIterator>::__type __dist;
+	  __glibcxx_check_valid_range2(__first, __last, __dist);
 	  size_type __bucket_count = this->bucket_count();
-	  _Base::insert(__gnu_debug::__base(__first),
-			__gnu_debug::__base(__last));
+
+	  if (__dist.second >= __gnu_debug::__dp_sign)
+	    _Base::insert(__gnu_debug::__unsafe(__first),
+			  __gnu_debug::__unsafe(__last));
+	  else
+	    _Base::insert(__first, __last);
+
 	  _M_check_rehashed(__bucket_count);
 	}
 
Index: include/debug/unordered_set
===================================================================
--- include/debug/unordered_set	(revision 224246)
+++ include/debug/unordered_set	(working copy)
@@ -355,10 +355,16 @@
 	void
 	insert(_InputIterator __first, _InputIterator __last)
 	{
-	  __glibcxx_check_valid_range(__first, __last);
+	  typename __gnu_debug::_Distance_traits<_InputIterator>::__type __dist;
+	  __glibcxx_check_valid_range2(__first, __last, __dist);
 	  size_type __bucket_count = this->bucket_count();
-	  _Base::insert(__gnu_debug::__base(__first),
-			__gnu_debug::__base(__last));
+
+	  if (__dist.second >= __gnu_debug::__dp_sign)
+	    _Base::insert(__gnu_debug::__unsafe(__first),
+			  __gnu_debug::__unsafe(__last));
+	  else
+	    _Base::insert(__first, __last);
+
 	  _M_check_rehashed(__bucket_count);
 	}
 
@@ -799,10 +805,16 @@
 	void
 	insert(_InputIterator __first, _InputIterator __last)
 	{
-	  __glibcxx_check_valid_range(__first, __last);
+	  typename __gnu_debug::_Distance_traits<_InputIterator>::__type __dist;
+	  __glibcxx_check_valid_range2(__first, __last, __dist);
 	  size_type __bucket_count = this->bucket_count();
-	  _Base::insert(__gnu_debug::__base(__first),
-			__gnu_debug::__base(__last));
+
+	  if (__dist.second >= __gnu_debug::__dp_sign)
+	    _Base::insert(__gnu_debug::__unsafe(__first),
+			  __gnu_debug::__unsafe(__last));
+	  else
+	    _Base::insert(__first, __last);
+
 	  _M_check_rehashed(__bucket_count);
 	}
 
Index: include/debug/vector
===================================================================
--- include/debug/vector	(revision 224246)
+++ include/debug/vector	(working copy)
@@ -244,9 +244,15 @@
 	void
 	assign(_InputIterator __first, _InputIterator __last)
 	{
-	  __glibcxx_check_valid_range(__first, __last);
-	  _Base::assign(__gnu_debug::__base(__first),
-			__gnu_debug::__base(__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();
 	  this->_M_update_guaranteed_capacity();
 	}
@@ -574,7 +580,8 @@
 	insert(const_iterator __position,
 	       _InputIterator __first, _InputIterator __last)
 	{
-	  __glibcxx_check_insert_range(__position, __first, __last);
+	  typename __gnu_debug::_Distance_traits<_InputIterator>::__type __dist;
+	  __glibcxx_check_insert_range(__position, __first, __last, __dist);
 
 	  /* Hard to guess if invalidation will occur, because __last
 	     - __first can't be calculated in all cases, so we just
@@ -581,9 +588,13 @@
 	     punt here by checking if it did occur. */
 	  _Base_iterator __old_begin = _M_base().begin();
 	  difference_type __offset = __position.base() - _Base::cbegin();
-	  _Base_iterator __res = _Base::insert(__position.base(),
-					       __gnu_debug::__base(__first),
-					       __gnu_debug::__base(__last));
+	  _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);
 
 	  if (_M_base().begin() != __old_begin)
 	    this->_M_invalidate_all();
@@ -598,7 +609,8 @@
 	insert(iterator __position,
 	       _InputIterator __first, _InputIterator __last)
 	{
-	  __glibcxx_check_insert_range(__position, __first, __last);
+	  typename __gnu_debug::_Distance_traits<_InputIterator>::__type __dist;
+	  __glibcxx_check_insert_range(__position, __first, __last, __dist);
 
 	  /* Hard to guess if invalidation will occur, because __last
 	     - __first can't be calculated in all cases, so we just
@@ -605,8 +617,11 @@
 	     punt here by checking if it did occur. */
 	  _Base_iterator __old_begin = _M_base().begin();
 	  difference_type __offset = __position.base() - _Base::begin();
-	  _Base::insert(__position.base(), __gnu_debug::__base(__first),
-					   __gnu_debug::__base(__last));
+	  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);
 
 	  if (_M_base().begin() != __old_begin)
 	    this->_M_invalidate_all();


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]