libstdc++
helper_functions.h
Go to the documentation of this file.
00001 // Debugging support implementation -*- C++ -*-
00002 
00003 // Copyright (C) 2003-2017 Free Software Foundation, Inc.
00004 //
00005 // This file is part of the GNU ISO C++ Library.  This library is free
00006 // software; you can redistribute it and/or modify it under the
00007 // terms of the GNU General Public License as published by the
00008 // Free Software Foundation; either version 3, or (at your option)
00009 // any later version.
00010 
00011 // This library is distributed in the hope that it will be useful,
00012 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00013 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014 // GNU General Public License for more details.
00015 
00016 // Under Section 7 of GPL version 3, you are granted additional
00017 // permissions described in the GCC Runtime Library Exception, version
00018 // 3.1, as published by the Free Software Foundation.
00019 
00020 // You should have received a copy of the GNU General Public License and
00021 // a copy of the GCC Runtime Library Exception along with this program;
00022 // see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
00023 // <http://www.gnu.org/licenses/>.
00024 
00025 /** @file debug/helper_functions.h
00026  *  This file is a GNU debug extension to the Standard C++ Library.
00027  */
00028 
00029 #ifndef _GLIBCXX_DEBUG_HELPER_FUNCTIONS_H
00030 #define _GLIBCXX_DEBUG_HELPER_FUNCTIONS_H 1
00031 
00032 #include <bits/stl_iterator_base_types.h>       // for iterator_traits,
00033                                                 // categories and _Iter_base
00034 #include <bits/cpp_type_traits.h>               // for __is_integer
00035 
00036 #include <bits/stl_pair.h>                      // for pair
00037 
00038 namespace __gnu_debug
00039 {
00040   /** The precision to which we can calculate the distance between
00041    *  two iterators.
00042    */
00043   enum _Distance_precision
00044     {
00045       __dp_none,        // Not even an iterator type
00046       __dp_equality,    //< Can compare iterator equality, only
00047       __dp_sign,        //< Can determine equality and ordering
00048       __dp_exact        //< Can determine distance precisely
00049     };
00050 
00051   template<typename _Iterator,
00052            typename = typename std::__is_integer<_Iterator>::__type>
00053     struct _Distance_traits
00054     {
00055     private:
00056       typedef
00057       typename std::iterator_traits<_Iterator>::difference_type _ItDiffType;
00058 
00059       template<typename _DiffType,
00060                typename = typename std::__is_void<_DiffType>::__type>
00061         struct _DiffTraits
00062         { typedef _DiffType __type; };
00063 
00064       template<typename _DiffType>
00065         struct _DiffTraits<_DiffType, std::__true_type>
00066         { typedef std::ptrdiff_t __type; };
00067 
00068       typedef typename _DiffTraits<_ItDiffType>::__type _DiffType;
00069 
00070     public:
00071       typedef std::pair<_DiffType, _Distance_precision> __type;
00072     };
00073 
00074   template<typename _Integral>
00075     struct _Distance_traits<_Integral, std::__true_type>
00076     { typedef std::pair<std::ptrdiff_t, _Distance_precision> __type; };
00077 
00078   /** Determine the distance between two iterators with some known
00079    *    precision.
00080   */
00081   template<typename _Iterator>
00082     inline typename _Distance_traits<_Iterator>::__type
00083     __get_distance(const _Iterator& __lhs, const _Iterator& __rhs,
00084                    std::random_access_iterator_tag)
00085     { return std::make_pair(__rhs - __lhs, __dp_exact); }
00086 
00087   template<typename _Iterator>
00088     inline typename _Distance_traits<_Iterator>::__type
00089     __get_distance(const _Iterator& __lhs, const _Iterator& __rhs,
00090                    std::input_iterator_tag)
00091     {
00092       if (__lhs == __rhs)
00093         return std::make_pair(0, __dp_exact);
00094 
00095       return std::make_pair(1, __dp_equality);
00096     }
00097 
00098   template<typename _Iterator>
00099     inline typename _Distance_traits<_Iterator>::__type
00100     __get_distance(const _Iterator& __lhs, const _Iterator& __rhs)
00101     { return __get_distance(__lhs, __rhs, std::__iterator_category(__lhs)); }
00102 
00103   /** We say that integral types for a valid range, and defer to other
00104    *  routines to realize what to do with integral types instead of
00105    *  iterators.
00106   */
00107   template<typename _Integral>
00108     inline bool
00109     __valid_range_aux(const _Integral&, const _Integral&,
00110                       typename _Distance_traits<_Integral>::__type& __dist,
00111                       std::__true_type)
00112     {
00113       __dist = std::make_pair(0, __dp_none);
00114       return true;
00115     }
00116 
00117   /** We have iterators, so figure out what kind of iterators that are
00118    *  to see if we can check the range ahead of time.
00119   */
00120   template<typename _InputIterator>
00121     inline bool
00122     __valid_range_aux(const _InputIterator& __first,
00123                       const _InputIterator& __last,
00124                       typename _Distance_traits<_InputIterator>::__type& __dist,
00125                       std::__false_type)
00126     {
00127       __dist = __get_distance(__first, __last);
00128       switch (__dist.second)
00129         {
00130         case __dp_none:
00131           break;
00132         case __dp_equality:
00133           if (__dist.first == 0)
00134             return true;
00135           break;
00136         case __dp_sign:
00137         case __dp_exact:
00138           return __dist.first >= 0;
00139         }
00140 
00141       // Can't tell so assume it is fine.
00142       return true;
00143     }
00144 
00145   /** Don't know what these iterators are, or if they are even
00146    *  iterators (we may get an integral type for InputIterator), so
00147    *  see if they are integral and pass them on to the next phase
00148    *  otherwise.
00149   */
00150   template<typename _InputIterator>
00151     inline bool
00152     __valid_range(const _InputIterator& __first, const _InputIterator& __last,
00153                   typename _Distance_traits<_InputIterator>::__type& __dist)
00154     {
00155       typedef typename std::__is_integer<_InputIterator>::__type _Integral;
00156       return __valid_range_aux(__first, __last, __dist, _Integral());
00157     }
00158 
00159   template<typename _InputIterator>
00160     inline bool
00161     __valid_range(const _InputIterator& __first, const _InputIterator& __last)
00162     {
00163       typename _Distance_traits<_InputIterator>::__type __dist;
00164       return __valid_range(__first, __last, __dist);
00165     }
00166 
00167 #if __cplusplus < 201103L
00168   // Helper struct to detect random access safe iterators.
00169   template<typename _Iterator>
00170     struct __is_safe_random_iterator
00171     {
00172       enum { __value = 0 };
00173       typedef std::__false_type __type;
00174     };
00175 
00176   template<typename _Iterator>
00177     struct _Siter_base
00178     : std::_Iter_base<_Iterator, __is_safe_random_iterator<_Iterator>::__value>
00179     { };
00180 
00181   /** Helper function to extract base iterator of random access safe iterator
00182       in order to reduce performance impact of debug mode.  Limited to random
00183       access iterator because it is the only category for which it is possible
00184       to check for correct iterators order in the __valid_range function
00185       thanks to the < operator.
00186   */
00187   template<typename _Iterator>
00188     inline typename _Siter_base<_Iterator>::iterator_type
00189     __base(_Iterator __it)
00190     { return _Siter_base<_Iterator>::_S_base(__it); }
00191 #else
00192   template<typename _Iterator>
00193     inline _Iterator
00194     __base(_Iterator __it)
00195     { return __it; }
00196 #endif
00197 
00198 #if __cplusplus < 201103L
00199   template<typename _Iterator>
00200     struct _Unsafe_type
00201     { typedef _Iterator _Type; };
00202 #endif
00203 
00204   /* Remove debug mode safe iterator layer, if any. */
00205   template<typename _Iterator>
00206     inline _Iterator
00207     __unsafe(_Iterator __it)
00208     { return __it; }
00209 }
00210 
00211 #endif