]>
Commit | Line | Data |
---|---|---|
24167c42 FD |
1 | // Debugging support implementation -*- C++ -*- |
2 | ||
6441eb6d | 3 | // Copyright (C) 2003-2025 Free Software Foundation, Inc. |
24167c42 FD |
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 | ||
af4e8d4d | 32 | #include <bits/move.h> // for __addressof |
24167c42 FD |
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 | { | |
e9afbed0 | 41 | template<typename _Iterator, typename _Sequence, typename _Category> |
eb04ee1d FD |
42 | class _Safe_iterator; |
43 | ||
e9afbed0 FD |
44 | #if __cplusplus >= 201103L |
45 | template<typename _Iterator, typename _Sequence> | |
46 | class _Safe_local_iterator; | |
47 | #endif | |
48 | ||
24167c42 FD |
49 | /** The precision to which we can calculate the distance between |
50 | * two iterators. | |
51 | */ | |
52 | enum _Distance_precision | |
53 | { | |
36edf9ca FD |
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 | |
24167c42 FD |
59 | }; |
60 | ||
61 | template<typename _Iterator, | |
62 | typename = typename std::__is_integer<_Iterator>::__type> | |
63 | struct _Distance_traits | |
64 | { | |
65 | private: | |
66 | typedef | |
cc796820 | 67 | typename std::iterator_traits<_Iterator>::difference_type _ItDiffType; |
24167c42 | 68 | |
51cc7767 | 69 | template<typename _DiffType, typename = _DiffType> // PR c++/85282 |
24167c42 FD |
70 | struct _DiffTraits |
71 | { typedef _DiffType __type; }; | |
72 | ||
73 | template<typename _DiffType> | |
51cc7767 | 74 | struct _DiffTraits<_DiffType, void> |
24167c42 FD |
75 | { typedef std::ptrdiff_t __type; }; |
76 | ||
77 | typedef typename _DiffTraits<_ItDiffType>::__type _DiffType; | |
78 | ||
79 | public: | |
80 | typedef std::pair<_DiffType, _Distance_precision> __type; | |
81 | }; | |
82 | ||
83 | template<typename _Integral> | |
84 | struct _Distance_traits<_Integral, std::__true_type> | |
85 | { typedef std::pair<std::ptrdiff_t, _Distance_precision> __type; }; | |
86 | ||
87 | /** Determine the distance between two iterators with some known | |
88 | * precision. | |
89 | */ | |
90 | template<typename _Iterator> | |
97d57665 | 91 | _GLIBCXX_CONSTEXPR |
24167c42 | 92 | inline typename _Distance_traits<_Iterator>::__type |
e9afbed0 | 93 | __get_distance(_Iterator __lhs, _Iterator __rhs, |
24167c42 FD |
94 | std::random_access_iterator_tag) |
95 | { return std::make_pair(__rhs - __lhs, __dp_exact); } | |
96 | ||
97 | template<typename _Iterator> | |
3cb0c7cc | 98 | _GLIBCXX14_CONSTEXPR |
24167c42 | 99 | inline typename _Distance_traits<_Iterator>::__type |
e9afbed0 | 100 | __get_distance(_Iterator __lhs, _Iterator __rhs, |
24167c42 FD |
101 | std::input_iterator_tag) |
102 | { | |
103 | if (__lhs == __rhs) | |
104 | return std::make_pair(0, __dp_exact); | |
105 | ||
106 | return std::make_pair(1, __dp_equality); | |
107 | } | |
108 | ||
109 | template<typename _Iterator> | |
97d57665 | 110 | _GLIBCXX_CONSTEXPR |
24167c42 | 111 | inline typename _Distance_traits<_Iterator>::__type |
e9afbed0 | 112 | __get_distance(_Iterator __lhs, _Iterator __rhs) |
fa98bc42 JW |
113 | { |
114 | return __gnu_debug::__get_distance(__lhs, __rhs, | |
115 | std::__iterator_category(__lhs)); | |
116 | } | |
24167c42 | 117 | |
af4e8d4d FD |
118 | // An arbitrary iterator pointer is not singular. |
119 | inline bool | |
120 | __check_singular_aux(const void*) { return false; } | |
121 | ||
fa98bc42 JW |
122 | // Defined in <debug/safe_base.h> |
123 | bool | |
124 | __check_singular_aux(const class _Safe_iterator_base*); | |
125 | ||
af4e8d4d FD |
126 | // We may have an iterator that derives from _Safe_iterator_base but isn't |
127 | // a _Safe_iterator. | |
128 | template<typename _Iterator> | |
38b17c27 | 129 | _GLIBCXX_CONSTEXPR |
af4e8d4d FD |
130 | inline bool |
131 | __check_singular(_Iterator const& __x) | |
38b17c27 | 132 | { |
74d14778 | 133 | return ! std::__is_constant_evaluated() |
fa98bc42 | 134 | && __gnu_debug::__check_singular_aux(std::__addressof(__x)); |
38b17c27 | 135 | } |
af4e8d4d FD |
136 | |
137 | /** Non-NULL pointers are nonsingular. */ | |
138 | template<typename _Tp> | |
38b17c27 | 139 | _GLIBCXX_CONSTEXPR |
af4e8d4d FD |
140 | inline bool |
141 | __check_singular(_Tp* const& __ptr) | |
74d14778 | 142 | { return __ptr == 0; } |
af4e8d4d | 143 | |
24167c42 FD |
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 | |
146 | * iterators. | |
147 | */ | |
148 | template<typename _Integral> | |
97d57665 FD |
149 | _GLIBCXX_CONSTEXPR |
150 | inline bool | |
151 | __valid_range_aux(_Integral, _Integral, std::__true_type) | |
152 | { return true; } | |
153 | ||
154 | template<typename _Integral> | |
155 | _GLIBCXX20_CONSTEXPR | |
24167c42 | 156 | inline bool |
e9afbed0 | 157 | __valid_range_aux(_Integral, _Integral, |
24167c42 FD |
158 | typename _Distance_traits<_Integral>::__type& __dist, |
159 | std::__true_type) | |
160 | { | |
161 | __dist = std::make_pair(0, __dp_none); | |
162 | return true; | |
163 | } | |
164 | ||
97d57665 FD |
165 | template<typename _InputIterator> |
166 | _GLIBCXX_CONSTEXPR | |
167 | inline bool | |
168 | __valid_range_aux(_InputIterator __first, _InputIterator __last, | |
169 | std::input_iterator_tag) | |
af4e8d4d | 170 | { |
9616deb2 JW |
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()) | |
174 | return true; | |
175 | ||
af4e8d4d | 176 | return __first == __last |
fa98bc42 JW |
177 | || (!__gnu_debug::__check_singular(__first) |
178 | && !__gnu_debug::__check_singular(__last)); | |
af4e8d4d | 179 | } |
97d57665 FD |
180 | |
181 | template<typename _InputIterator> | |
182 | _GLIBCXX_CONSTEXPR | |
183 | inline bool | |
184 | __valid_range_aux(_InputIterator __first, _InputIterator __last, | |
185 | std::random_access_iterator_tag) | |
af4e8d4d | 186 | { |
fa98bc42 JW |
187 | return __gnu_debug::__valid_range_aux(__first, __last, |
188 | std::input_iterator_tag()) | |
af4e8d4d FD |
189 | && __first <= __last; |
190 | } | |
97d57665 | 191 | |
e9afbed0 | 192 | /** We have iterators, so figure out what kind of iterators they are |
24167c42 FD |
193 | * to see if we can check the range ahead of time. |
194 | */ | |
195 | template<typename _InputIterator> | |
97d57665 FD |
196 | _GLIBCXX_CONSTEXPR |
197 | inline bool | |
198 | __valid_range_aux(_InputIterator __first, _InputIterator __last, | |
199 | std::__false_type) | |
200 | { | |
fa98bc42 JW |
201 | return __gnu_debug::__valid_range_aux(__first, __last, |
202 | std::__iterator_category(__first)); | |
97d57665 FD |
203 | } |
204 | ||
205 | template<typename _InputIterator> | |
206 | _GLIBCXX20_CONSTEXPR | |
24167c42 | 207 | inline bool |
e9afbed0 | 208 | __valid_range_aux(_InputIterator __first, _InputIterator __last, |
24167c42 FD |
209 | typename _Distance_traits<_InputIterator>::__type& __dist, |
210 | std::__false_type) | |
211 | { | |
fa98bc42 JW |
212 | if (!__gnu_debug::__valid_range_aux(__first, __last, |
213 | std::input_iterator_tag())) | |
af4e8d4d FD |
214 | return false; |
215 | ||
fa98bc42 | 216 | __dist = __gnu_debug::__get_distance(__first, __last); |
24167c42 FD |
217 | switch (__dist.second) |
218 | { | |
219 | case __dp_none: | |
220 | break; | |
221 | case __dp_equality: | |
222 | if (__dist.first == 0) | |
223 | return true; | |
224 | break; | |
225 | case __dp_sign: | |
36edf9ca | 226 | case __dp_sign_max_size: |
24167c42 FD |
227 | case __dp_exact: |
228 | return __dist.first >= 0; | |
229 | } | |
230 | ||
bd2ee798 | 231 | // Can't tell so assume it is fine. |
24167c42 FD |
232 | return true; |
233 | } | |
234 | ||
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 | |
238 | * otherwise. | |
239 | */ | |
240 | template<typename _InputIterator> | |
97d57665 | 241 | _GLIBCXX20_CONSTEXPR |
24167c42 | 242 | inline bool |
e9afbed0 | 243 | __valid_range(_InputIterator __first, _InputIterator __last, |
24167c42 FD |
244 | typename _Distance_traits<_InputIterator>::__type& __dist) |
245 | { | |
246 | typedef typename std::__is_integer<_InputIterator>::__type _Integral; | |
fa98bc42 JW |
247 | return __gnu_debug::__valid_range_aux(__first, __last, __dist, |
248 | _Integral()); | |
24167c42 FD |
249 | } |
250 | ||
e9afbed0 FD |
251 | template<typename _Iterator, typename _Sequence, typename _Category> |
252 | bool | |
253 | __valid_range(const _Safe_iterator<_Iterator, _Sequence, _Category>&, | |
254 | const _Safe_iterator<_Iterator, _Sequence, _Category>&, | |
255 | typename _Distance_traits<_Iterator>::__type&); | |
256 | ||
257 | #if __cplusplus >= 201103L | |
258 | template<typename _Iterator,typename _Sequence> | |
259 | bool | |
260 | __valid_range(const _Safe_local_iterator<_Iterator, _Sequence>&, | |
261 | const _Safe_local_iterator<_Iterator, _Sequence>&, | |
262 | typename _Distance_traits<_Iterator>::__type&); | |
263 | #endif | |
264 | ||
24167c42 | 265 | template<typename _InputIterator> |
30a761c4 | 266 | _GLIBCXX14_CONSTEXPR |
24167c42 | 267 | inline bool |
e9afbed0 | 268 | __valid_range(_InputIterator __first, _InputIterator __last) |
24167c42 | 269 | { |
97d57665 | 270 | typedef typename std::__is_integer<_InputIterator>::__type _Integral; |
fa98bc42 | 271 | return __gnu_debug::__valid_range_aux(__first, __last, _Integral()); |
24167c42 FD |
272 | } |
273 | ||
e9afbed0 FD |
274 | template<typename _Iterator, typename _Sequence, typename _Category> |
275 | bool | |
276 | __valid_range(const _Safe_iterator<_Iterator, _Sequence, _Category>&, | |
277 | const _Safe_iterator<_Iterator, _Sequence, _Category>&); | |
278 | ||
279 | #if __cplusplus >= 201103L | |
280 | template<typename _Iterator, typename _Sequence> | |
281 | bool | |
282 | __valid_range(const _Safe_local_iterator<_Iterator, _Sequence>&, | |
283 | const _Safe_local_iterator<_Iterator, _Sequence>&); | |
284 | #endif | |
285 | ||
eb04ee1d FD |
286 | // Fallback method, always ok. |
287 | template<typename _InputIterator, typename _Size> | |
97d57665 | 288 | _GLIBCXX_CONSTEXPR |
eb04ee1d FD |
289 | inline bool |
290 | __can_advance(_InputIterator, _Size) | |
291 | { return true; } | |
292 | ||
e9afbed0 FD |
293 | template<typename _Iterator, typename _Sequence, typename _Category, |
294 | typename _Size> | |
eb04ee1d | 295 | bool |
e9afbed0 FD |
296 | __can_advance(const _Safe_iterator<_Iterator, _Sequence, _Category>&, |
297 | _Size); | |
24167c42 | 298 | |
cc796820 FD |
299 | template<typename _InputIterator, typename _Diff> |
300 | _GLIBCXX_CONSTEXPR | |
301 | inline bool | |
302 | __can_advance(_InputIterator, const std::pair<_Diff, _Distance_precision>&, int) | |
303 | { return true; } | |
304 | ||
305 | template<typename _Iterator, typename _Sequence, typename _Category, | |
306 | typename _Diff> | |
307 | bool | |
308 | __can_advance(const _Safe_iterator<_Iterator, _Sequence, _Category>&, | |
309 | const std::pair<_Diff, _Distance_precision>&, int); | |
310 | ||
24167c42 | 311 | /** Helper function to extract base iterator of random access safe iterator |
e9afbed0 FD |
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. | |
316 | */ | |
24167c42 | 317 | template<typename _Iterator> |
97d57665 | 318 | _GLIBCXX_CONSTEXPR |
24167c42 FD |
319 | inline _Iterator |
320 | __base(_Iterator __it) | |
321 | { return __it; } | |
24167c42 FD |
322 | |
323 | #if __cplusplus < 201103L | |
324 | template<typename _Iterator> | |
325 | struct _Unsafe_type | |
326 | { typedef _Iterator _Type; }; | |
327 | #endif | |
328 | ||
329 | /* Remove debug mode safe iterator layer, if any. */ | |
330 | template<typename _Iterator> | |
7d00a592 | 331 | _GLIBCXX_CONSTEXPR |
24167c42 FD |
332 | inline _Iterator |
333 | __unsafe(_Iterator __it) | |
334 | { return __it; } | |
335 | } | |
336 | ||
337 | #endif |