1 // Debugging support implementation -*- C++ -*-
3 // Copyright (C) 2003-2025 Free Software Foundation, Inc.
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)
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.
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.
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/>.
25 /** @file debug/helper_functions.h
26 * This file is a GNU debug extension to the Standard C++ Library.
29 #ifndef _GLIBCXX_DEBUG_HELPER_FUNCTIONS_H
30 #define _GLIBCXX_DEBUG_HELPER_FUNCTIONS_H 1
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
37 #include <bits/stl_pair.h> // for pair
41 template<typename _Iterator
, typename _Sequence
, typename _Category
>
44 #if __cplusplus >= 201103L
45 template<typename _Iterator
, typename _Sequence
>
46 class _Safe_local_iterator
;
49 /** The precision to which we can calculate the distance between
52 enum _Distance_precision
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
61 template<typename _Iterator
,
62 typename
= typename
std::__is_integer
<_Iterator
>::__type
>
63 struct _Distance_traits
67 typename
std::iterator_traits
<_Iterator
>::difference_type _ItDiffType
;
69 template<typename _DiffType
, typename
= _DiffType
> // PR c++/85282
71 { typedef _DiffType __type
; };
73 template<typename _DiffType
>
74 struct _DiffTraits
<_DiffType
, void>
75 { typedef std::ptrdiff_t __type
; };
77 typedef typename _DiffTraits
<_ItDiffType
>::__type _DiffType
;
80 typedef std::pair
<_DiffType
, _Distance_precision
> __type
;
83 template<typename _Integral
>
84 struct _Distance_traits
<_Integral
, std::__true_type
>
85 { typedef std::pair
<std::ptrdiff_t, _Distance_precision
> __type
; };
87 /** Determine the distance between two iterators with some known
90 template<typename _Iterator
>
92 inline typename _Distance_traits
<_Iterator
>::__type
93 __get_distance(_Iterator __lhs
, _Iterator __rhs
,
94 std::random_access_iterator_tag
)
95 { return std::make_pair(__rhs
- __lhs
, __dp_exact
); }
97 template<typename _Iterator
>
99 inline typename _Distance_traits
<_Iterator
>::__type
100 __get_distance(_Iterator __lhs
, _Iterator __rhs
,
101 std::input_iterator_tag
)
104 return std::make_pair(0, __dp_exact
);
106 return std::make_pair(1, __dp_equality
);
109 template<typename _Iterator
>
111 inline typename _Distance_traits
<_Iterator
>::__type
112 __get_distance(_Iterator __lhs
, _Iterator __rhs
)
114 return __gnu_debug::__get_distance(__lhs
, __rhs
,
115 std::__iterator_category(__lhs
));
118 // An arbitrary iterator pointer is not singular.
120 __check_singular_aux(const void*) { return false; }
122 // Defined in <debug/safe_base.h>
124 __check_singular_aux(const class _Safe_iterator_base
*);
126 // We may have an iterator that derives from _Safe_iterator_base but isn't
128 template<typename _Iterator
>
131 __check_singular(_Iterator
const& __x
)
133 return ! std::__is_constant_evaluated()
134 && __gnu_debug::__check_singular_aux(std::__addressof(__x
));
137 /** Non-NULL pointers are nonsingular. */
138 template<typename _Tp
>
141 __check_singular(_Tp
* const& __ptr
)
142 { return __ptr
== 0; }
144 /** We say that integral types for a valid range, and defer to other
145 * routines to realize what to do with integral types instead of
148 template<typename _Integral
>
151 __valid_range_aux(_Integral
, _Integral
, std::__true_type
)
154 template<typename _Integral
>
157 __valid_range_aux(_Integral
, _Integral
,
158 typename _Distance_traits
<_Integral
>::__type
& __dist
,
161 __dist
= std::make_pair(0, __dp_none
);
165 template<typename _InputIterator
>
168 __valid_range_aux(_InputIterator __first
, _InputIterator __last
,
169 std::input_iterator_tag
)
171 // FIXME: The checks for singular iterators fail during constant eval
172 // due to PR c++/85944. e.g. PR libstdc++/109517 and PR libstdc++/109976.
173 if (std::__is_constant_evaluated())
176 return __first
== __last
177 || (!__gnu_debug::__check_singular(__first
)
178 && !__gnu_debug::__check_singular(__last
));
181 template<typename _InputIterator
>
184 __valid_range_aux(_InputIterator __first
, _InputIterator __last
,
185 std::random_access_iterator_tag
)
187 return __gnu_debug::__valid_range_aux(__first
, __last
,
188 std::input_iterator_tag())
189 && __first
<= __last
;
192 /** We have iterators, so figure out what kind of iterators they are
193 * to see if we can check the range ahead of time.
195 template<typename _InputIterator
>
198 __valid_range_aux(_InputIterator __first
, _InputIterator __last
,
201 return __gnu_debug::__valid_range_aux(__first
, __last
,
202 std::__iterator_category(__first
));
205 template<typename _InputIterator
>
208 __valid_range_aux(_InputIterator __first
, _InputIterator __last
,
209 typename _Distance_traits
<_InputIterator
>::__type
& __dist
,
212 if (!__gnu_debug::__valid_range_aux(__first
, __last
,
213 std::input_iterator_tag()))
216 __dist
= __gnu_debug::__get_distance(__first
, __last
);
217 switch (__dist
.second
)
222 if (__dist
.first
== 0)
226 case __dp_sign_max_size
:
228 return __dist
.first
>= 0;
231 // Can't tell so assume it is fine.
235 /** Don't know what these iterators are, or if they are even
236 * iterators (we may get an integral type for InputIterator), so
237 * see if they are integral and pass them on to the next phase
240 template<typename _InputIterator
>
243 __valid_range(_InputIterator __first
, _InputIterator __last
,
244 typename _Distance_traits
<_InputIterator
>::__type
& __dist
)
246 typedef typename
std::__is_integer
<_InputIterator
>::__type _Integral
;
247 return __gnu_debug::__valid_range_aux(__first
, __last
, __dist
,
251 template<typename _Iterator
, typename _Sequence
, typename _Category
>
253 __valid_range(const _Safe_iterator
<_Iterator
, _Sequence
, _Category
>&,
254 const _Safe_iterator
<_Iterator
, _Sequence
, _Category
>&,
255 typename _Distance_traits
<_Iterator
>::__type
&);
257 #if __cplusplus >= 201103L
258 template<typename _Iterator
,typename _Sequence
>
260 __valid_range(const _Safe_local_iterator
<_Iterator
, _Sequence
>&,
261 const _Safe_local_iterator
<_Iterator
, _Sequence
>&,
262 typename _Distance_traits
<_Iterator
>::__type
&);
265 template<typename _InputIterator
>
268 __valid_range(_InputIterator __first
, _InputIterator __last
)
270 typedef typename
std::__is_integer
<_InputIterator
>::__type _Integral
;
271 return __gnu_debug::__valid_range_aux(__first
, __last
, _Integral());
274 template<typename _Iterator
, typename _Sequence
, typename _Category
>
276 __valid_range(const _Safe_iterator
<_Iterator
, _Sequence
, _Category
>&,
277 const _Safe_iterator
<_Iterator
, _Sequence
, _Category
>&);
279 #if __cplusplus >= 201103L
280 template<typename _Iterator
, typename _Sequence
>
282 __valid_range(const _Safe_local_iterator
<_Iterator
, _Sequence
>&,
283 const _Safe_local_iterator
<_Iterator
, _Sequence
>&);
286 // Fallback method, always ok.
287 template<typename _InputIterator
, typename _Size
>
290 __can_advance(_InputIterator
, _Size
)
293 template<typename _Iterator
, typename _Sequence
, typename _Category
,
296 __can_advance(const _Safe_iterator
<_Iterator
, _Sequence
, _Category
>&,
299 template<typename _InputIterator
, typename _Diff
>
302 __can_advance(_InputIterator
, const std::pair
<_Diff
, _Distance_precision
>&, int)
305 template<typename _Iterator
, typename _Sequence
, typename _Category
,
308 __can_advance(const _Safe_iterator
<_Iterator
, _Sequence
, _Category
>&,
309 const std::pair
<_Diff
, _Distance_precision
>&, int);
311 /** Helper function to extract base iterator of random access safe iterator
312 * in order to reduce performance impact of debug mode. Limited to random
313 * access iterator because it is the only category for which it is possible
314 * to check for correct iterators order in the __valid_range function
315 * thanks to the < operator.
317 template<typename _Iterator
>
320 __base(_Iterator __it
)
323 #if __cplusplus < 201103L
324 template<typename _Iterator
>
326 { typedef _Iterator _Type
; };
329 /* Remove debug mode safe iterator layer, if any. */
330 template<typename _Iterator
>
333 __unsafe(_Iterator __it
)