Home | History | Annotate | Line # | Download | only in debug
      1 // Debugging support implementation -*- C++ -*-
      2 
      3 // Copyright (C) 2003-2022 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/helper_functions.h
     26  *  This file is a GNU debug extension to the Standard C++ Library.
     27  */
     28 
     29 #ifndef _GLIBCXX_DEBUG_HELPER_FUNCTIONS_H
     30 #define _GLIBCXX_DEBUG_HELPER_FUNCTIONS_H 1
     31 
     32 #include <bits/move.h>				// for __addressof
     33 #include <bits/stl_iterator_base_types.h>	// for iterator_traits,
     34 						// categories and _Iter_base
     35 #include <bits/cpp_type_traits.h>		// for __is_integer
     36 
     37 #include <bits/stl_pair.h>			// for pair
     38 
     39 namespace __gnu_debug
     40 {
     41   template<typename _Iterator, typename _Sequence, typename _Category>
     42     class _Safe_iterator;
     43 
     44 #if __cplusplus >= 201103L
     45   template<typename _Iterator, typename _Sequence>
     46     class _Safe_local_iterator;
     47 #endif
     48 
     49   /** The precision to which we can calculate the distance between
     50    *  two iterators.
     51    */
     52   enum _Distance_precision
     53     {
     54       __dp_none,		// Not even an iterator type
     55       __dp_equality,		//< Can compare iterator equality, only
     56       __dp_sign,		//< Can determine equality and ordering
     57       __dp_sign_max_size,	//< __dp_sign and gives max range size
     58       __dp_exact		//< Can determine distance precisely
     59     };
     60 
     61   template<typename _Iterator,
     62 	   typename = typename std::__is_integer<_Iterator>::__type>
     63     struct _Distance_traits
     64     {
     65     private:
     66       typedef
     67 	typename std::iterator_traits<_Iterator>::difference_type _ItDiffType;
     68 
     69       template<typename _DiffType,
     70 	       typename = typename std::__is_void<_DiffType>::__type>
     71 	struct _DiffTraits
     72 	{ typedef _DiffType __type; };
     73 
     74       template<typename _DiffType>
     75 	struct _DiffTraits<_DiffType, std::__true_type>
     76 	{ typedef std::ptrdiff_t __type; };
     77 
     78       typedef typename _DiffTraits<_ItDiffType>::__type _DiffType;
     79 
     80     public:
     81       typedef std::pair<_DiffType, _Distance_precision> __type;
     82     };
     83 
     84   template<typename _Integral>
     85     struct _Distance_traits<_Integral, std::__true_type>
     86     { typedef std::pair<std::ptrdiff_t, _Distance_precision> __type; };
     87 
     88   /** Determine the distance between two iterators with some known
     89    *	precision.
     90   */
     91   template<typename _Iterator>
     92     _GLIBCXX_CONSTEXPR
     93     inline typename _Distance_traits<_Iterator>::__type
     94     __get_distance(_Iterator __lhs, _Iterator __rhs,
     95 		   std::random_access_iterator_tag)
     96     { return std::make_pair(__rhs - __lhs, __dp_exact); }
     97 
     98   template<typename _Iterator>
     99     _GLIBCXX14_CONSTEXPR
    100     inline typename _Distance_traits<_Iterator>::__type
    101     __get_distance(_Iterator __lhs, _Iterator __rhs,
    102 		   std::input_iterator_tag)
    103     {
    104       if (__lhs == __rhs)
    105 	return std::make_pair(0, __dp_exact);
    106 
    107       return std::make_pair(1, __dp_equality);
    108     }
    109 
    110   template<typename _Iterator>
    111     _GLIBCXX_CONSTEXPR
    112     inline typename _Distance_traits<_Iterator>::__type
    113     __get_distance(_Iterator __lhs, _Iterator __rhs)
    114     {
    115       return __gnu_debug::__get_distance(__lhs, __rhs,
    116 					 std::__iterator_category(__lhs));
    117     }
    118 
    119   // An arbitrary iterator pointer is not singular.
    120   inline bool
    121   __check_singular_aux(const void*) { return false; }
    122 
    123   // Defined in <debug/safe_base.h>
    124   bool
    125   __check_singular_aux(const class _Safe_iterator_base*);
    126 
    127   // We may have an iterator that derives from _Safe_iterator_base but isn't
    128   // a _Safe_iterator.
    129   template<typename _Iterator>
    130     _GLIBCXX_CONSTEXPR
    131     inline bool
    132     __check_singular(_Iterator const& __x)
    133     {
    134       return ! std::__is_constant_evaluated()
    135 	       && __gnu_debug::__check_singular_aux(std::__addressof(__x));
    136     }
    137 
    138   /** Non-NULL pointers are nonsingular. */
    139   template<typename _Tp>
    140     _GLIBCXX_CONSTEXPR
    141     inline bool
    142     __check_singular(_Tp* const& __ptr)
    143     { return __ptr == 0; }
    144 
    145   /** We say that integral types for a valid range, and defer to other
    146    *  routines to realize what to do with integral types instead of
    147    *  iterators.
    148   */
    149   template<typename _Integral>
    150     _GLIBCXX_CONSTEXPR
    151     inline bool
    152     __valid_range_aux(_Integral, _Integral, std::__true_type)
    153     { return true; }
    154 
    155   template<typename _Integral>
    156     _GLIBCXX20_CONSTEXPR
    157     inline bool
    158     __valid_range_aux(_Integral, _Integral,
    159 		      typename _Distance_traits<_Integral>::__type& __dist,
    160 		      std::__true_type)
    161     {
    162       __dist = std::make_pair(0, __dp_none);
    163       return true;
    164     }
    165 
    166   template<typename _InputIterator>
    167     _GLIBCXX_CONSTEXPR
    168     inline bool
    169     __valid_range_aux(_InputIterator __first, _InputIterator __last,
    170 		      std::input_iterator_tag)
    171     {
    172       return __first == __last
    173 	|| (!__gnu_debug::__check_singular(__first)
    174 	      && !__gnu_debug::__check_singular(__last));
    175     }
    176 
    177   template<typename _InputIterator>
    178     _GLIBCXX_CONSTEXPR
    179     inline bool
    180     __valid_range_aux(_InputIterator __first, _InputIterator __last,
    181 		      std::random_access_iterator_tag)
    182     {
    183       return __gnu_debug::__valid_range_aux(__first, __last,
    184 					    std::input_iterator_tag())
    185 	&& __first <= __last;
    186     }
    187 
    188   /** We have iterators, so figure out what kind of iterators they are
    189    *  to see if we can check the range ahead of time.
    190   */
    191   template<typename _InputIterator>
    192     _GLIBCXX_CONSTEXPR
    193     inline bool
    194     __valid_range_aux(_InputIterator __first, _InputIterator __last,
    195 		      std::__false_type)
    196     {
    197       return __gnu_debug::__valid_range_aux(__first, __last,
    198 					    std::__iterator_category(__first));
    199     }
    200 
    201   template<typename _InputIterator>
    202     _GLIBCXX20_CONSTEXPR
    203     inline bool
    204     __valid_range_aux(_InputIterator __first, _InputIterator __last,
    205 		      typename _Distance_traits<_InputIterator>::__type& __dist,
    206 		      std::__false_type)
    207     {
    208       if (!__gnu_debug::__valid_range_aux(__first, __last,
    209 					  std::input_iterator_tag()))
    210 	return false;
    211 
    212       __dist = __gnu_debug::__get_distance(__first, __last);
    213       switch (__dist.second)
    214 	{
    215 	case __dp_none:
    216 	  break;
    217 	case __dp_equality:
    218 	  if (__dist.first == 0)
    219 	    return true;
    220 	  break;
    221 	case __dp_sign:
    222 	case __dp_sign_max_size:
    223 	case __dp_exact:
    224 	  return __dist.first >= 0;
    225 	}
    226 
    227       // Can't tell so assume it is fine.
    228       return true;
    229     }
    230 
    231   /** Don't know what these iterators are, or if they are even
    232    *  iterators (we may get an integral type for InputIterator), so
    233    *  see if they are integral and pass them on to the next phase
    234    *  otherwise.
    235   */
    236   template<typename _InputIterator>
    237     _GLIBCXX20_CONSTEXPR
    238     inline bool
    239     __valid_range(_InputIterator __first, _InputIterator __last,
    240 		  typename _Distance_traits<_InputIterator>::__type& __dist)
    241     {
    242       typedef typename std::__is_integer<_InputIterator>::__type _Integral;
    243       return __gnu_debug::__valid_range_aux(__first, __last, __dist,
    244 					    _Integral());
    245     }
    246 
    247   template<typename _Iterator, typename _Sequence, typename _Category>
    248     bool
    249     __valid_range(const _Safe_iterator<_Iterator, _Sequence, _Category>&,
    250 		  const _Safe_iterator<_Iterator, _Sequence, _Category>&,
    251 		  typename _Distance_traits<_Iterator>::__type&);
    252 
    253 #if __cplusplus >= 201103L
    254   template<typename _Iterator,typename _Sequence>
    255     bool
    256     __valid_range(const _Safe_local_iterator<_Iterator, _Sequence>&,
    257 		  const _Safe_local_iterator<_Iterator, _Sequence>&,
    258 		  typename _Distance_traits<_Iterator>::__type&);
    259 #endif
    260 
    261   template<typename _InputIterator>
    262     _GLIBCXX14_CONSTEXPR
    263     inline bool
    264     __valid_range(_InputIterator __first, _InputIterator __last)
    265     {
    266       typedef typename std::__is_integer<_InputIterator>::__type _Integral;
    267       return __gnu_debug::__valid_range_aux(__first, __last, _Integral());
    268     }
    269 
    270   template<typename _Iterator, typename _Sequence, typename _Category>
    271     bool
    272     __valid_range(const _Safe_iterator<_Iterator, _Sequence, _Category>&,
    273 		  const _Safe_iterator<_Iterator, _Sequence, _Category>&);
    274 
    275 #if __cplusplus >= 201103L
    276   template<typename _Iterator, typename _Sequence>
    277     bool
    278     __valid_range(const _Safe_local_iterator<_Iterator, _Sequence>&,
    279 		  const _Safe_local_iterator<_Iterator, _Sequence>&);
    280 #endif
    281 
    282   // Fallback method, always ok.
    283   template<typename _InputIterator, typename _Size>
    284     _GLIBCXX_CONSTEXPR
    285     inline bool
    286     __can_advance(_InputIterator, _Size)
    287     { return true; }
    288 
    289   template<typename _Iterator, typename _Sequence, typename _Category,
    290 	   typename _Size>
    291     bool
    292     __can_advance(const _Safe_iterator<_Iterator, _Sequence, _Category>&,
    293 		  _Size);
    294 
    295   template<typename _InputIterator, typename _Diff>
    296     _GLIBCXX_CONSTEXPR
    297     inline bool
    298     __can_advance(_InputIterator, const std::pair<_Diff, _Distance_precision>&, int)
    299     { return true; }
    300 
    301   template<typename _Iterator, typename _Sequence, typename _Category,
    302 	   typename _Diff>
    303     bool
    304     __can_advance(const _Safe_iterator<_Iterator, _Sequence, _Category>&,
    305 		  const std::pair<_Diff, _Distance_precision>&, int);
    306 
    307   /** Helper function to extract base iterator of random access safe iterator
    308    *  in order to reduce performance impact of debug mode.  Limited to random
    309    *  access iterator because it is the only category for which it is possible
    310    *  to check for correct iterators order in the __valid_range function
    311    *  thanks to the < operator.
    312    */
    313   template<typename _Iterator>
    314     _GLIBCXX_CONSTEXPR
    315     inline _Iterator
    316     __base(_Iterator __it)
    317     { return __it; }
    318 
    319 #if __cplusplus < 201103L
    320   template<typename _Iterator>
    321     struct _Unsafe_type
    322     { typedef _Iterator _Type; };
    323 #endif
    324 
    325   /* Remove debug mode safe iterator layer, if any. */
    326   template<typename _Iterator>
    327     inline _Iterator
    328     __unsafe(_Iterator __it)
    329     { return __it; }
    330 }
    331 
    332 #endif
    333