libstdc++
functions.h
Go to the documentation of this file.
1// Debugging support implementation -*- C++ -*-
2
3// Copyright (C) 2003-2025 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/stl_function.h> // for less
33
34#if __cplusplus >= 201103L
35# include <bits/stl_iterator.h> // for __miter_base
36# include <type_traits> // for is_lvalue_reference and __conditional_t.
37#endif
38
40#include <debug/formatter.h>
41
42namespace __gnu_debug
43{
44 template<typename _Sequence>
45 struct _Insert_range_from_self_is_safe
46 { enum { __value = 0 }; };
47
48 template<typename _Sequence>
49 struct _Is_contiguous_sequence : std::__false_type { };
50
51 /* Checks that [first, last) is a valid range, and then returns
52 * __first. This routine is useful when we can't use a separate
53 * assertion statement because, e.g., we are in a constructor.
54 */
55 template<typename _InputIterator>
56 _GLIBCXX20_CONSTEXPR inline _InputIterator
57 __check_valid_range(const _InputIterator& __first,
58 const _InputIterator& __last,
59 const char* __file,
60 unsigned int __line,
61 const char* __function)
62 {
63 if (!std::__is_constant_evaluated())
64 {
65 __glibcxx_check_valid_range_at(__first, __last,
66 __file, __line, __function);
67 }
68
69 return __first;
70 }
71
72 /* Handle the case where __other is a pointer to _Sequence::value_type. */
73 template<typename _Iterator, typename _Sequence, typename _Category>
74 inline bool
75 __foreign_iterator_aux4(
77 const typename _Sequence::value_type* __other)
78 {
79 typedef const typename _Sequence::value_type* _PointerType;
80 typedef std::less<_PointerType> _Less;
81#if __cplusplus >= 201103L
82 constexpr _Less __l{};
83#else
84 const _Less __l = _Less();
85#endif
86 const _Sequence* __seq = __it._M_get_sequence();
87 const _PointerType __begin = std::__addressof(*__seq->_M_base().begin());
88 const _PointerType __end = std::__addressof(*(__seq->_M_base().end()-1));
89
90 // Check whether __other points within the contiguous storage.
91 return __l(__other, __begin) || __l(__end, __other);
92 }
93
94 /* Fallback overload for when we can't tell, assume it is valid. */
95 template<typename _Iterator, typename _Sequence, typename _Category>
96 inline bool
97 __foreign_iterator_aux4(
99 { return true; }
100
101 /* Handle sequences with contiguous storage */
102 template<typename _Iterator, typename _Sequence, typename _Category,
103 typename _InputIterator>
104 inline bool
105 __foreign_iterator_aux3(
107 const _InputIterator& __other, const _InputIterator& __other_end,
108 std::__true_type)
109 {
110 if (__other == __other_end)
111 return true; // inserting nothing is safe even if not foreign iters
112 if (__it._M_get_sequence()->empty())
113 return true; // can't be self-inserting if self is empty
114 return __foreign_iterator_aux4(__it, std::__addressof(*__other));
115 }
116
117 /* Handle non-contiguous containers, assume it is valid. */
118 template<typename _Iterator, typename _Sequence, typename _Category,
119 typename _InputIterator>
120 inline bool
121 __foreign_iterator_aux3(
123 const _InputIterator&, const _InputIterator&,
124 std::__false_type)
125 { return true; }
126
127 /** Handle debug iterators from the same type of container. */
128 template<typename _Iterator, typename _Sequence, typename _Category,
129 typename _OtherIterator>
130 inline bool
135 { return __it._M_get_sequence() != __other._M_get_sequence(); }
136
137 /** Handle debug iterators from different types of container. */
138 template<typename _Iterator, typename _Sequence, typename _Category,
139 typename _OtherIterator, typename _OtherSequence,
140 typename _OtherCategory>
141 inline bool
144 const _Safe_iterator<_OtherIterator, _OtherSequence,
145 _OtherCategory>&,
146 const _Safe_iterator<_OtherIterator, _OtherSequence,
147 _OtherCategory>&)
148 { return true; }
149
150 /* Handle non-debug iterators. */
151 template<typename _Iterator, typename _Sequence, typename _Category,
152 typename _InputIterator>
153 inline bool
155 const _Safe_iterator<_Iterator, _Sequence, _Category>& __it,
156 const _InputIterator& __other,
157 const _InputIterator& __other_end)
158 {
159#if __cplusplus < 201103L
160 typedef _Is_contiguous_sequence<_Sequence> __tag;
161#else
162 using __lvalref = std::is_lvalue_reference<
164 using __contiguous = _Is_contiguous_sequence<_Sequence>;
165 using __tag = std::__conditional_t<__lvalref::value, __contiguous,
166 std::__false_type>;
167#endif
168 return __foreign_iterator_aux3(__it, __other, __other_end, __tag());
169 }
170
171 /* Handle the case where we aren't really inserting a range after all */
172 template<typename _Iterator, typename _Sequence, typename _Category,
173 typename _Integral>
174 inline bool
175 __foreign_iterator_aux(
177 _Integral, _Integral, std::__true_type)
178 { return true; }
179
180 /* Handle all iterators. */
181 template<typename _Iterator, typename _Sequence, typename _Category,
182 typename _InputIterator>
183 inline bool
184 __foreign_iterator_aux(
186 _InputIterator __other, _InputIterator __other_end,
187 std::__false_type)
188 {
189 return _Insert_range_from_self_is_safe<_Sequence>::__value
190 || __foreign_iterator_aux2(__it, std::__miter_base(__other),
191 std::__miter_base(__other_end));
192 }
193
194 template<typename _Iterator, typename _Sequence, typename _Category,
195 typename _InputIterator>
196 inline bool
197 __foreign_iterator(
199 _InputIterator __other, _InputIterator __other_end)
200 {
201 typedef typename std::__is_integer<_InputIterator>::__type _Integral;
202 return __foreign_iterator_aux(__it, __other, __other_end, _Integral());
203 }
204
205 // Can't check if an input iterator sequence is sorted, because we
206 // can't step through the sequence.
207 template<typename _InputIterator>
208 _GLIBCXX20_CONSTEXPR
209 inline bool
210 __check_sorted_aux(const _InputIterator&, const _InputIterator&,
211 std::input_iterator_tag)
212 { return true; }
213
214 // Can verify if a forward iterator sequence is in fact sorted using
215 // std::__is_sorted
216 template<typename _ForwardIterator>
217 _GLIBCXX20_CONSTEXPR
218 inline bool
219 __check_sorted_aux(_ForwardIterator __first, _ForwardIterator __last,
220 std::forward_iterator_tag)
221 {
222 if (__first == __last)
223 return true;
224
225 _ForwardIterator __next = __first;
226 for (++__next; __next != __last; __first = __next, (void)++__next)
227 if (*__next < *__first)
228 return false;
229
230 return true;
231 }
232
233 // Can't check if an input iterator sequence is sorted, because we can't step
234 // through the sequence.
235 template<typename _InputIterator, typename _Predicate>
236 _GLIBCXX20_CONSTEXPR
237 inline bool
238 __check_sorted_aux(const _InputIterator&, const _InputIterator&,
239 _Predicate, std::input_iterator_tag)
240 { return true; }
241
242 // Can verify if a forward iterator sequence is in fact sorted using
243 // std::__is_sorted
244 template<typename _ForwardIterator, typename _Predicate>
245 _GLIBCXX20_CONSTEXPR
246 inline bool
247 __check_sorted_aux(_ForwardIterator __first, _ForwardIterator __last,
248 _Predicate __pred, std::forward_iterator_tag)
249 {
250 if (__first == __last)
251 return true;
252
253 _ForwardIterator __next = __first;
254 for (++__next; __next != __last; __first = __next, (void)++__next)
255 if (__pred(*__next, *__first))
256 return false;
257
258 return true;
259 }
260
261 // Determine if a sequence is sorted.
262 template<typename _InputIterator>
263 _GLIBCXX20_CONSTEXPR
264 inline bool
265 __check_sorted(const _InputIterator& __first, const _InputIterator& __last)
266 {
267 return __check_sorted_aux(__first, __last,
268 std::__iterator_category(__first));
269 }
270
271 template<typename _InputIterator, typename _Predicate>
272 _GLIBCXX20_CONSTEXPR
273 inline bool
274 __check_sorted(const _InputIterator& __first, const _InputIterator& __last,
275 _Predicate __pred)
276 {
277 return __check_sorted_aux(__first, __last, __pred,
278 std::__iterator_category(__first));
279 }
280
281 template<typename _InputIterator>
282 _GLIBCXX20_CONSTEXPR
283 inline bool
284 __check_sorted_set_aux(const _InputIterator& __first,
285 const _InputIterator& __last,
286 std::__true_type)
287 { return __check_sorted(__first, __last); }
288
289 template<typename _InputIterator>
290 _GLIBCXX20_CONSTEXPR
291 inline bool
292 __check_sorted_set_aux(const _InputIterator&,
293 const _InputIterator&,
294 std::__false_type)
295 { return true; }
296
297 template<typename _InputIterator, typename _Predicate>
298 _GLIBCXX20_CONSTEXPR
299 inline bool
300 __check_sorted_set_aux(const _InputIterator& __first,
301 const _InputIterator& __last,
302 _Predicate __pred, std::__true_type)
303 { return __check_sorted(__first, __last, __pred); }
304
305 template<typename _InputIterator, typename _Predicate>
306 _GLIBCXX20_CONSTEXPR
307 inline bool
308 __check_sorted_set_aux(const _InputIterator&,
309 const _InputIterator&, _Predicate,
310 std::__false_type)
311 { return true; }
312
313 // ... special variant used in std::merge, std::includes, std::set_*.
314 template<typename _InputIterator1, typename _InputIterator2>
315 _GLIBCXX20_CONSTEXPR
316 inline bool
317 __check_sorted_set(const _InputIterator1& __first,
318 const _InputIterator1& __last,
319 const _InputIterator2&)
320 {
321 typedef typename std::iterator_traits<_InputIterator1>::value_type
322 _ValueType1;
323 typedef typename std::iterator_traits<_InputIterator2>::value_type
324 _ValueType2;
325
326 typedef typename std::__are_same<_ValueType1, _ValueType2>::__type
327 _SameType;
328 return __check_sorted_set_aux(__first, __last, _SameType());
329 }
330
331 template<typename _InputIterator1, typename _InputIterator2,
332 typename _Predicate>
333 _GLIBCXX20_CONSTEXPR
334 inline bool
335 __check_sorted_set(const _InputIterator1& __first,
336 const _InputIterator1& __last,
337 const _InputIterator2&, _Predicate __pred)
338 {
339 typedef typename std::iterator_traits<_InputIterator1>::value_type
340 _ValueType1;
341 typedef typename std::iterator_traits<_InputIterator2>::value_type
342 _ValueType2;
343
344 typedef typename std::__are_same<_ValueType1, _ValueType2>::__type
345 _SameType;
346 return __check_sorted_set_aux(__first, __last, __pred, _SameType());
347 }
348
349 // _GLIBCXX_RESOLVE_LIB_DEFECTS
350 // 270. Binary search requirements overly strict
351 // Determine if a sequence is partitioned w.r.t. this element.
352 template<typename _ForwardIterator, typename _Tp>
353 _GLIBCXX20_CONSTEXPR
354 inline bool
355 __check_partitioned_lower(_ForwardIterator __first,
356 _ForwardIterator __last, const _Tp& __value)
357 {
358 while (__first != __last && *__first < __value)
359 ++__first;
360 if (__first != __last)
361 {
362 ++__first;
363 while (__first != __last && !(*__first < __value))
364 ++__first;
365 }
366 return __first == __last;
367 }
368
369 template<typename _ForwardIterator, typename _Tp>
370 _GLIBCXX20_CONSTEXPR
371 inline bool
372 __check_partitioned_upper(_ForwardIterator __first,
373 _ForwardIterator __last, const _Tp& __value)
374 {
375 while (__first != __last && !(__value < *__first))
376 ++__first;
377 if (__first != __last)
378 {
379 ++__first;
380 while (__first != __last && __value < *__first)
381 ++__first;
382 }
383 return __first == __last;
384 }
385
386 // Determine if a sequence is partitioned w.r.t. this element.
387 template<typename _ForwardIterator, typename _Tp, typename _Pred>
388 _GLIBCXX20_CONSTEXPR
389 inline bool
390 __check_partitioned_lower(_ForwardIterator __first,
391 _ForwardIterator __last, const _Tp& __value,
392 _Pred __pred)
393 {
394 while (__first != __last && bool(__pred(*__first, __value)))
395 ++__first;
396 if (__first != __last)
397 {
398 ++__first;
399 while (__first != __last && !bool(__pred(*__first, __value)))
400 ++__first;
401 }
402 return __first == __last;
403 }
404
405 template<typename _ForwardIterator, typename _Tp, typename _Pred>
406 _GLIBCXX20_CONSTEXPR
407 inline bool
408 __check_partitioned_upper(_ForwardIterator __first,
409 _ForwardIterator __last, const _Tp& __value,
410 _Pred __pred)
411 {
412 while (__first != __last && !bool(__pred(__value, *__first)))
413 ++__first;
414 if (__first != __last)
415 {
416 ++__first;
417 while (__first != __last && bool(__pred(__value, *__first)))
418 ++__first;
419 }
420 return __first == __last;
421 }
422
423#if __cplusplus >= 201103L
424 struct _Irreflexive_checker
425 {
426 template<typename _It>
427 static typename std::iterator_traits<_It>::reference
428 __ref();
429
430 template<typename _It,
431 typename = decltype(__ref<_It>() < __ref<_It>())>
432 _GLIBCXX20_CONSTEXPR
433 static bool
434 _S_is_valid(_It __it)
435 { return !(*__it < *__it); }
436
437 // Fallback method if operator doesn't exist.
438 template<typename... _Args>
439 _GLIBCXX20_CONSTEXPR
440 static bool
441 _S_is_valid(_Args...)
442 { return true; }
443
444 template<typename _It, typename _Pred, typename
445 = decltype(std::declval<_Pred>()(__ref<_It>(), __ref<_It>()))>
446 _GLIBCXX20_CONSTEXPR
447 static bool
448 _S_is_valid_pred(_It __it, _Pred __pred)
449 { return !__pred(*__it, *__it); }
450
451 // Fallback method if predicate can't be invoked.
452 template<typename... _Args>
453 _GLIBCXX20_CONSTEXPR
454 static bool
455 _S_is_valid_pred(_Args...)
456 { return true; }
457 };
458
459 template<typename _Iterator>
460 _GLIBCXX20_CONSTEXPR
461 inline bool
462 __is_irreflexive(_Iterator __it)
463 { return _Irreflexive_checker::_S_is_valid(__it); }
464
465 template<typename _Iterator, typename _Pred>
466 _GLIBCXX20_CONSTEXPR
467 inline bool
468 __is_irreflexive_pred(_Iterator __it, _Pred __pred)
469 { return _Irreflexive_checker::_S_is_valid_pred(__it, __pred); }
470#endif
471
472} // namespace __gnu_debug
473
474#endif
auto declval() noexcept -> decltype(__declval< _Tp >(0))
Definition type_traits:2680
constexpr _Tp * __addressof(_Tp &__r) noexcept
Same as C++11 std::addressof.
Definition move.h:52
constexpr iterator_traits< _Iter >::iterator_category __iterator_category(const _Iter &)
GNU debug classes for public use.
bool __foreign_iterator_aux2(const _Safe_iterator< _Iterator, _Sequence, _Category > &__it, const _Safe_iterator< _OtherIterator, _Sequence, _Category > &__other, const _Safe_iterator< _OtherIterator, _Sequence, _Category > &)
Definition functions.h:131
is_lvalue_reference
Definition type_traits:601
Safe iterator wrapper.
Traits class for iterators.