1 // Debugging support implementation -*- C++ -*-
2 
3 // Copyright (C) 2003-2014 Free Software Foundation, Inc.
4 //
5 // This file is part of the GNU ISO C++ Library.  This library is free
6 // software; you can redistribute it and/or modify it under the
7 // terms of the GNU General Public License as published by the
8 // Free Software Foundation; either version 3, or (at your option)
9 // any later version.
10 
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 // GNU General Public License for more details.
15 
16 // Under Section 7 of GPL version 3, you are granted additional
17 // permissions described in the GCC Runtime Library Exception, version
18 // 3.1, as published by the Free Software Foundation.
19 
20 // You should have received a copy of the GNU General Public License and
21 // a copy of the GCC Runtime Library Exception along with this program;
22 // see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
23 // <http://www.gnu.org/licenses/>.
24 
25 /** @file debug/functions.h
26  *  This file is a GNU debug extension to the Standard C++ Library.
27  */
28 
29 #ifndef _GLIBCXX_DEBUG_FUNCTIONS_H
30 #define _GLIBCXX_DEBUG_FUNCTIONS_H 1
31 
32 #include <bits/c++config.h>
33 #include <bits/stl_iterator_base_types.h> // for iterator_traits, categories and
34 					  // _Iter_base
35 #include <bits/cpp_type_traits.h>	  // for __is_integer
36 #include <bits/move.h>                    // for __addressof and addressof
37 #include <bits/stl_function.h>		  // for less
38 #if __cplusplus >= 201103L
39 # include <type_traits>			  // for is_lvalue_reference and __and_
40 #endif
41 #include <debug/formatter.h>
42 
43 namespace __gnu_debug
44 {
45   template<typename _Iterator, typename _Sequence>
46     class _Safe_iterator;
47 
48   template<typename _Iterator, typename _Sequence>
49     class _Safe_local_iterator;
50 
51   template<typename _Sequence>
52     struct _Insert_range_from_self_is_safe
53     { enum { __value = 0 }; };
54 
55   template<typename _Sequence>
56     struct _Is_contiguous_sequence : std::__false_type { };
57 
58   // An arbitrary iterator pointer is not singular.
59   inline bool
__check_singular_aux(const void *)60   __check_singular_aux(const void*) { return false; }
61 
62   // We may have an iterator that derives from _Safe_iterator_base but isn't
63   // a _Safe_iterator.
64   template<typename _Iterator>
65     inline bool
__check_singular(const _Iterator & __x)66     __check_singular(const _Iterator& __x)
67     { return __check_singular_aux(&__x); }
68 
69   /** Non-NULL pointers are nonsingular. */
70   template<typename _Tp>
71     inline bool
__check_singular(const _Tp * __ptr)72     __check_singular(const _Tp* __ptr)
73     { return __ptr == 0; }
74 
75   /** Assume that some arbitrary iterator is dereferenceable, because we
76       can't prove that it isn't. */
77   template<typename _Iterator>
78     inline bool
__check_dereferenceable(const _Iterator &)79     __check_dereferenceable(const _Iterator&)
80     { return true; }
81 
82   /** Non-NULL pointers are dereferenceable. */
83   template<typename _Tp>
84     inline bool
__check_dereferenceable(const _Tp * __ptr)85     __check_dereferenceable(const _Tp* __ptr)
86     { return __ptr; }
87 
88   /** Safe iterators know if they are dereferenceable. */
89   template<typename _Iterator, typename _Sequence>
90     inline bool
__check_dereferenceable(const _Safe_iterator<_Iterator,_Sequence> & __x)91     __check_dereferenceable(const _Safe_iterator<_Iterator, _Sequence>& __x)
92     { return __x._M_dereferenceable(); }
93 
94   /** Safe local iterators know if they are dereferenceable. */
95   template<typename _Iterator, typename _Sequence>
96     inline bool
__check_dereferenceable(const _Safe_local_iterator<_Iterator,_Sequence> & __x)97     __check_dereferenceable(const _Safe_local_iterator<_Iterator,
98 						       _Sequence>& __x)
99     { return __x._M_dereferenceable(); }
100 
101   /** If the distance between two random access iterators is
102    *  nonnegative, assume the range is valid.
103   */
104   template<typename _RandomAccessIterator>
105     inline bool
__valid_range_aux2(const _RandomAccessIterator & __first,const _RandomAccessIterator & __last,std::random_access_iterator_tag)106     __valid_range_aux2(const _RandomAccessIterator& __first,
107 		       const _RandomAccessIterator& __last,
108 		       std::random_access_iterator_tag)
109     { return __last - __first >= 0; }
110 
111   /** Can't test for a valid range with input iterators, because
112    *  iteration may be destructive. So we just assume that the range
113    *  is valid.
114   */
115   template<typename _InputIterator>
116     inline bool
__valid_range_aux2(const _InputIterator &,const _InputIterator &,std::input_iterator_tag)117     __valid_range_aux2(const _InputIterator&, const _InputIterator&,
118 		       std::input_iterator_tag)
119     { return true; }
120 
121   /** We say that integral types for a valid range, and defer to other
122    *  routines to realize what to do with integral types instead of
123    *  iterators.
124   */
125   template<typename _Integral>
126     inline bool
__valid_range_aux(const _Integral &,const _Integral &,std::__true_type)127     __valid_range_aux(const _Integral&, const _Integral&, std::__true_type)
128     { return true; }
129 
130   /** We have iterators, so figure out what kind of iterators that are
131    *  to see if we can check the range ahead of time.
132   */
133   template<typename _InputIterator>
134     inline bool
__valid_range_aux(const _InputIterator & __first,const _InputIterator & __last,std::__false_type)135     __valid_range_aux(const _InputIterator& __first,
136 		      const _InputIterator& __last, std::__false_type)
137     { return __valid_range_aux2(__first, __last,
138 				std::__iterator_category(__first)); }
139 
140   /** Don't know what these iterators are, or if they are even
141    *  iterators (we may get an integral type for InputIterator), so
142    *  see if they are integral and pass them on to the next phase
143    *  otherwise.
144   */
145   template<typename _InputIterator>
146     inline bool
__valid_range(const _InputIterator & __first,const _InputIterator & __last)147     __valid_range(const _InputIterator& __first, const _InputIterator& __last)
148     {
149       typedef typename std::__is_integer<_InputIterator>::__type _Integral;
150       return __valid_range_aux(__first, __last, _Integral());
151     }
152 
153   /** Safe iterators know how to check if they form a valid range. */
154   template<typename _Iterator, typename _Sequence>
155     inline bool
__valid_range(const _Safe_iterator<_Iterator,_Sequence> & __first,const _Safe_iterator<_Iterator,_Sequence> & __last)156     __valid_range(const _Safe_iterator<_Iterator, _Sequence>& __first,
157 		  const _Safe_iterator<_Iterator, _Sequence>& __last)
158     { return __first._M_valid_range(__last); }
159 
160   /** Safe local iterators know how to check if they form a valid range. */
161   template<typename _Iterator, typename _Sequence>
162     inline bool
__valid_range(const _Safe_local_iterator<_Iterator,_Sequence> & __first,const _Safe_local_iterator<_Iterator,_Sequence> & __last)163     __valid_range(const _Safe_local_iterator<_Iterator, _Sequence>& __first,
164 		  const _Safe_local_iterator<_Iterator, _Sequence>& __last)
165     { return __first._M_valid_range(__last); }
166 
167   /* Checks that [first, last) is a valid range, and then returns
168    * __first. This routine is useful when we can't use a separate
169    * assertion statement because, e.g., we are in a constructor.
170   */
171   template<typename _InputIterator>
172     inline _InputIterator
__check_valid_range(const _InputIterator & __first,const _InputIterator & __last)173     __check_valid_range(const _InputIterator& __first,
174 			const _InputIterator& __last
175 			__attribute__((__unused__)))
176     {
177       __glibcxx_check_valid_range(__first, __last);
178       return __first;
179     }
180 
181   /* Handle the case where __other is a pointer to _Sequence::value_type. */
182   template<typename _Iterator, typename _Sequence>
183     inline bool
__foreign_iterator_aux4(const _Safe_iterator<_Iterator,_Sequence> & __it,const typename _Sequence::value_type * __other)184     __foreign_iterator_aux4(const _Safe_iterator<_Iterator, _Sequence>& __it,
185 			    const typename _Sequence::value_type* __other)
186     {
187       typedef const typename _Sequence::value_type* _PointerType;
188       typedef std::less<_PointerType> _Less;
189 #if __cplusplus >= 201103L
190       constexpr _Less __l{};
191 #else
192       const _Less __l = _Less();
193 #endif
194       const _Sequence* __seq = __it._M_get_sequence();
195       const _PointerType __begin = std::__addressof(*__seq->_M_base().begin());
196       const _PointerType __end = std::__addressof(*(__seq->_M_base().end()-1));
197 
198       // Check whether __other points within the contiguous storage.
199       return __l(__other, __begin) || __l(__end, __other);
200     }
201 
202   /* Fallback overload for when we can't tell, assume it is valid. */
203   template<typename _Iterator, typename _Sequence>
204     inline bool
__foreign_iterator_aux4(const _Safe_iterator<_Iterator,_Sequence> &,...)205     __foreign_iterator_aux4(const _Safe_iterator<_Iterator, _Sequence>&, ...)
206     { return true; }
207 
208   /* Handle sequences with contiguous storage */
209   template<typename _Iterator, typename _Sequence, typename _InputIterator>
210     inline bool
__foreign_iterator_aux3(const _Safe_iterator<_Iterator,_Sequence> & __it,const _InputIterator & __other,const _InputIterator & __other_end,std::__true_type)211     __foreign_iterator_aux3(const _Safe_iterator<_Iterator, _Sequence>& __it,
212 			    const _InputIterator& __other,
213 			    const _InputIterator& __other_end,
214 			    std::__true_type)
215     {
216       if (__other == __other_end)
217 	return true;  // inserting nothing is safe even if not foreign iters
218       if (__it._M_get_sequence()->begin() == __it._M_get_sequence()->end())
219 	return true;  // can't be self-inserting if self is empty
220       return __foreign_iterator_aux4(__it, std::__addressof(*__other));
221     }
222 
223   /* Handle non-contiguous containers, assume it is valid. */
224   template<typename _Iterator, typename _Sequence, typename _InputIterator>
225     inline bool
__foreign_iterator_aux3(const _Safe_iterator<_Iterator,_Sequence> &,const _InputIterator &,const _InputIterator &,std::__false_type)226     __foreign_iterator_aux3(const _Safe_iterator<_Iterator, _Sequence>&,
227 			    const _InputIterator&, const _InputIterator&,
228 			    std::__false_type)
229     { return true; }
230 
231   /** Handle debug iterators from the same type of container. */
232   template<typename _Iterator, typename _Sequence, typename _OtherIterator>
233     inline bool
__foreign_iterator_aux2(const _Safe_iterator<_Iterator,_Sequence> & __it,const _Safe_iterator<_OtherIterator,_Sequence> & __other,const _Safe_iterator<_OtherIterator,_Sequence> &)234     __foreign_iterator_aux2(const _Safe_iterator<_Iterator, _Sequence>& __it,
235 		const _Safe_iterator<_OtherIterator, _Sequence>& __other,
236 		const _Safe_iterator<_OtherIterator, _Sequence>&)
237     { return __it._M_get_sequence() != __other._M_get_sequence(); }
238 
239   /** Handle debug iterators from different types of container. */
240   template<typename _Iterator, typename _Sequence, typename _OtherIterator,
241 	   typename _OtherSequence>
242     inline bool
__foreign_iterator_aux2(const _Safe_iterator<_Iterator,_Sequence> & __it,const _Safe_iterator<_OtherIterator,_OtherSequence> &,const _Safe_iterator<_OtherIterator,_OtherSequence> &)243     __foreign_iterator_aux2(const _Safe_iterator<_Iterator, _Sequence>& __it,
244 		const _Safe_iterator<_OtherIterator, _OtherSequence>&,
245 		const _Safe_iterator<_OtherIterator, _OtherSequence>&)
246     { return true; }
247 
248   /* Handle non-debug iterators. */
249   template<typename _Iterator, typename _Sequence, typename _InputIterator>
250     inline bool
__foreign_iterator_aux2(const _Safe_iterator<_Iterator,_Sequence> & __it,const _InputIterator & __other,const _InputIterator & __other_end)251     __foreign_iterator_aux2(const _Safe_iterator<_Iterator, _Sequence>& __it,
252 			    const _InputIterator& __other,
253 			    const _InputIterator& __other_end)
254     {
255 #if __cplusplus < 201103L
256       typedef _Is_contiguous_sequence<_Sequence> __tag;
257 #else
258       using __lvalref = std::is_lvalue_reference<
259 	typename std::iterator_traits<_InputIterator>::reference>;
260       using __contiguous = _Is_contiguous_sequence<_Sequence>;
261       using __tag = typename std::conditional<__lvalref::value, __contiguous,
262 					      std::__false_type>::type;
263 #endif
264       return __foreign_iterator_aux3(__it, __other, __other_end, __tag());
265     }
266 
267   /* Handle the case where we aren't really inserting a range after all */
268   template<typename _Iterator, typename _Sequence, typename _Integral>
269     inline bool
__foreign_iterator_aux(const _Safe_iterator<_Iterator,_Sequence> &,_Integral,_Integral,std::__true_type)270     __foreign_iterator_aux(const _Safe_iterator<_Iterator, _Sequence>&,
271 			   _Integral, _Integral,
272 			   std::__true_type)
273     { return true; }
274 
275   /* Handle all iterators. */
276   template<typename _Iterator, typename _Sequence,
277 	   typename _InputIterator>
278     inline bool
__foreign_iterator_aux(const _Safe_iterator<_Iterator,_Sequence> & __it,_InputIterator __other,_InputIterator __other_end,std::__false_type)279     __foreign_iterator_aux(const _Safe_iterator<_Iterator, _Sequence>& __it,
280 			   _InputIterator __other, _InputIterator __other_end,
281 			   std::__false_type)
282     {
283       return _Insert_range_from_self_is_safe<_Sequence>::__value
284 	     || __foreign_iterator_aux2(__it, __other, __other_end);
285     }
286 
287   template<typename _Iterator, typename _Sequence,
288 	   typename _InputIterator>
289     inline bool
__foreign_iterator(const _Safe_iterator<_Iterator,_Sequence> & __it,_InputIterator __other,_InputIterator __other_end)290     __foreign_iterator(const _Safe_iterator<_Iterator, _Sequence>& __it,
291 		       _InputIterator __other, _InputIterator __other_end)
292     {
293       typedef typename std::__is_integer<_InputIterator>::__type _Integral;
294       return __foreign_iterator_aux(__it, __other, __other_end, _Integral());
295     }
296 
297   /** Checks that __s is non-NULL or __n == 0, and then returns __s. */
298   template<typename _CharT, typename _Integer>
299     inline const _CharT*
__check_string(const _CharT * __s,const _Integer & __n)300     __check_string(const _CharT* __s,
301 		   const _Integer& __n __attribute__((__unused__)))
302     {
303 #ifdef _GLIBCXX_DEBUG_PEDANTIC
304       __glibcxx_assert(__s != 0 || __n == 0);
305 #endif
306       return __s;
307     }
308 
309   /** Checks that __s is non-NULL and then returns __s. */
310   template<typename _CharT>
311     inline const _CharT*
__check_string(const _CharT * __s)312     __check_string(const _CharT* __s)
313     {
314 #ifdef _GLIBCXX_DEBUG_PEDANTIC
315       __glibcxx_assert(__s != 0);
316 #endif
317       return __s;
318     }
319 
320   // Can't check if an input iterator sequence is sorted, because we
321   // can't step through the sequence.
322   template<typename _InputIterator>
323     inline bool
__check_sorted_aux(const _InputIterator &,const _InputIterator &,std::input_iterator_tag)324     __check_sorted_aux(const _InputIterator&, const _InputIterator&,
325                        std::input_iterator_tag)
326     { return true; }
327 
328   // Can verify if a forward iterator sequence is in fact sorted using
329   // std::__is_sorted
330   template<typename _ForwardIterator>
331     inline bool
__check_sorted_aux(_ForwardIterator __first,_ForwardIterator __last,std::forward_iterator_tag)332     __check_sorted_aux(_ForwardIterator __first, _ForwardIterator __last,
333                        std::forward_iterator_tag)
334     {
335       if (__first == __last)
336         return true;
337 
338       _ForwardIterator __next = __first;
339       for (++__next; __next != __last; __first = __next, ++__next)
340         if (*__next < *__first)
341           return false;
342 
343       return true;
344     }
345 
346   // Can't check if an input iterator sequence is sorted, because we can't step
347   // through the sequence.
348   template<typename _InputIterator, typename _Predicate>
349     inline bool
__check_sorted_aux(const _InputIterator &,const _InputIterator &,_Predicate,std::input_iterator_tag)350     __check_sorted_aux(const _InputIterator&, const _InputIterator&,
351                        _Predicate, std::input_iterator_tag)
352     { return true; }
353 
354   // Can verify if a forward iterator sequence is in fact sorted using
355   // std::__is_sorted
356   template<typename _ForwardIterator, typename _Predicate>
357     inline bool
__check_sorted_aux(_ForwardIterator __first,_ForwardIterator __last,_Predicate __pred,std::forward_iterator_tag)358     __check_sorted_aux(_ForwardIterator __first, _ForwardIterator __last,
359                        _Predicate __pred, std::forward_iterator_tag)
360     {
361       if (__first == __last)
362         return true;
363 
364       _ForwardIterator __next = __first;
365       for (++__next; __next != __last; __first = __next, ++__next)
366         if (__pred(*__next, *__first))
367           return false;
368 
369       return true;
370     }
371 
372   // Determine if a sequence is sorted.
373   template<typename _InputIterator>
374     inline bool
__check_sorted(const _InputIterator & __first,const _InputIterator & __last)375     __check_sorted(const _InputIterator& __first, const _InputIterator& __last)
376     {
377       // Verify that the < operator for elements in the sequence is a
378       // StrictWeakOrdering by checking that it is irreflexive.
379       __glibcxx_assert(__first == __last || !(*__first < *__first));
380 
381       return __check_sorted_aux(__first, __last,
382 				std::__iterator_category(__first));
383     }
384 
385   template<typename _InputIterator, typename _Predicate>
386     inline bool
__check_sorted(const _InputIterator & __first,const _InputIterator & __last,_Predicate __pred)387     __check_sorted(const _InputIterator& __first, const _InputIterator& __last,
388                    _Predicate __pred)
389     {
390       // Verify that the predicate is StrictWeakOrdering by checking that it
391       // is irreflexive.
392       __glibcxx_assert(__first == __last || !__pred(*__first, *__first));
393 
394       return __check_sorted_aux(__first, __last, __pred,
395 				std::__iterator_category(__first));
396     }
397 
398   template<typename _InputIterator>
399     inline bool
__check_sorted_set_aux(const _InputIterator & __first,const _InputIterator & __last,std::__true_type)400     __check_sorted_set_aux(const _InputIterator& __first,
401 			   const _InputIterator& __last,
402 			   std::__true_type)
403     { return __check_sorted(__first, __last); }
404 
405   template<typename _InputIterator>
406     inline bool
__check_sorted_set_aux(const _InputIterator &,const _InputIterator &,std::__false_type)407     __check_sorted_set_aux(const _InputIterator&,
408 			   const _InputIterator&,
409 			   std::__false_type)
410     { return true; }
411 
412   template<typename _InputIterator, typename _Predicate>
413     inline bool
__check_sorted_set_aux(const _InputIterator & __first,const _InputIterator & __last,_Predicate __pred,std::__true_type)414     __check_sorted_set_aux(const _InputIterator& __first,
415 			   const _InputIterator& __last,
416 			   _Predicate __pred, std::__true_type)
417     { return __check_sorted(__first, __last, __pred); }
418 
419   template<typename _InputIterator, typename _Predicate>
420     inline bool
__check_sorted_set_aux(const _InputIterator &,const _InputIterator &,_Predicate,std::__false_type)421     __check_sorted_set_aux(const _InputIterator&,
422 			   const _InputIterator&, _Predicate,
423 			   std::__false_type)
424     { return true; }
425 
426   // ... special variant used in std::merge, std::includes, std::set_*.
427   template<typename _InputIterator1, typename _InputIterator2>
428     inline bool
__check_sorted_set(const _InputIterator1 & __first,const _InputIterator1 & __last,const _InputIterator2 &)429     __check_sorted_set(const _InputIterator1& __first,
430 		       const _InputIterator1& __last,
431 		       const _InputIterator2&)
432     {
433       typedef typename std::iterator_traits<_InputIterator1>::value_type
434 	_ValueType1;
435       typedef typename std::iterator_traits<_InputIterator2>::value_type
436 	_ValueType2;
437 
438       typedef typename std::__are_same<_ValueType1, _ValueType2>::__type
439 	_SameType;
440       return __check_sorted_set_aux(__first, __last, _SameType());
441     }
442 
443   template<typename _InputIterator1, typename _InputIterator2,
444 	   typename _Predicate>
445     inline bool
__check_sorted_set(const _InputIterator1 & __first,const _InputIterator1 & __last,const _InputIterator2 &,_Predicate __pred)446     __check_sorted_set(const _InputIterator1& __first,
447 		       const _InputIterator1& __last,
448 		       const _InputIterator2&, _Predicate __pred)
449     {
450       typedef typename std::iterator_traits<_InputIterator1>::value_type
451 	_ValueType1;
452       typedef typename std::iterator_traits<_InputIterator2>::value_type
453 	_ValueType2;
454 
455       typedef typename std::__are_same<_ValueType1, _ValueType2>::__type
456 	_SameType;
457       return __check_sorted_set_aux(__first, __last, __pred, _SameType());
458    }
459 
460   // _GLIBCXX_RESOLVE_LIB_DEFECTS
461   // 270. Binary search requirements overly strict
462   // Determine if a sequence is partitioned w.r.t. this element.
463   template<typename _ForwardIterator, typename _Tp>
464     inline bool
__check_partitioned_lower(_ForwardIterator __first,_ForwardIterator __last,const _Tp & __value)465     __check_partitioned_lower(_ForwardIterator __first,
466 			      _ForwardIterator __last, const _Tp& __value)
467     {
468       while (__first != __last && *__first < __value)
469 	++__first;
470       if (__first != __last)
471 	{
472 	  ++__first;
473 	  while (__first != __last && !(*__first < __value))
474 	    ++__first;
475 	}
476       return __first == __last;
477     }
478 
479   template<typename _ForwardIterator, typename _Tp>
480     inline bool
__check_partitioned_upper(_ForwardIterator __first,_ForwardIterator __last,const _Tp & __value)481     __check_partitioned_upper(_ForwardIterator __first,
482 			      _ForwardIterator __last, const _Tp& __value)
483     {
484       while (__first != __last && !(__value < *__first))
485 	++__first;
486       if (__first != __last)
487 	{
488 	  ++__first;
489 	  while (__first != __last && __value < *__first)
490 	    ++__first;
491 	}
492       return __first == __last;
493     }
494 
495   // Determine if a sequence is partitioned w.r.t. this element.
496   template<typename _ForwardIterator, typename _Tp, typename _Pred>
497     inline bool
__check_partitioned_lower(_ForwardIterator __first,_ForwardIterator __last,const _Tp & __value,_Pred __pred)498     __check_partitioned_lower(_ForwardIterator __first,
499 			      _ForwardIterator __last, const _Tp& __value,
500 			      _Pred __pred)
501     {
502       while (__first != __last && bool(__pred(*__first, __value)))
503 	++__first;
504       if (__first != __last)
505 	{
506 	  ++__first;
507 	  while (__first != __last && !bool(__pred(*__first, __value)))
508 	    ++__first;
509 	}
510       return __first == __last;
511     }
512 
513   template<typename _ForwardIterator, typename _Tp, typename _Pred>
514     inline bool
__check_partitioned_upper(_ForwardIterator __first,_ForwardIterator __last,const _Tp & __value,_Pred __pred)515     __check_partitioned_upper(_ForwardIterator __first,
516 			      _ForwardIterator __last, const _Tp& __value,
517 			      _Pred __pred)
518     {
519       while (__first != __last && !bool(__pred(__value, *__first)))
520 	++__first;
521       if (__first != __last)
522 	{
523 	  ++__first;
524 	  while (__first != __last && bool(__pred(__value, *__first)))
525 	    ++__first;
526 	}
527       return __first == __last;
528     }
529 
530   // Helper struct to detect random access safe iterators.
531   template<typename _Iterator>
532     struct __is_safe_random_iterator
533     {
534       enum { __value = 0 };
535       typedef std::__false_type __type;
536     };
537 
538   template<typename _Iterator, typename _Sequence>
539     struct __is_safe_random_iterator<_Safe_iterator<_Iterator, _Sequence> >
540     : std::__are_same<std::random_access_iterator_tag,
541                       typename std::iterator_traits<_Iterator>::
542 		      iterator_category>
543     { };
544 
545   template<typename _Iterator>
546     struct _Siter_base
547     : std::_Iter_base<_Iterator, __is_safe_random_iterator<_Iterator>::__value>
548     { };
549 
550   /** Helper function to extract base iterator of random access safe iterator
551       in order to reduce performance impact of debug mode.  Limited to random
552       access iterator because it is the only category for which it is possible
553       to check for correct iterators order in the __valid_range function
554       thanks to the < operator.
555   */
556   template<typename _Iterator>
557     inline typename _Siter_base<_Iterator>::iterator_type
558     __base(_Iterator __it)
559     { return _Siter_base<_Iterator>::_S_base(__it); }
560 } // namespace __gnu_debug
561 
562 #endif
563