libstdc++
safe_iterator.h
Go to the documentation of this file.
1// Safe iterator implementation -*- C++ -*-
2
3// Copyright (C) 2003-2026 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/safe_iterator.h
26 * This file is a GNU debug extension to the Standard C++ Library.
27 */
28
29#ifndef _GLIBCXX_DEBUG_SAFE_ITERATOR_H
30#define _GLIBCXX_DEBUG_SAFE_ITERATOR_H 1
31
32#include <debug/assertions.h>
33#include <debug/macros.h>
34#include <debug/functions.h>
35#include <debug/safe_base.h>
36#include <bits/stl_pair.h>
37#include <ext/type_traits.h>
38#if __cplusplus > 201703L
39# include <compare>
40#endif
41
42#define _GLIBCXX_DEBUG_VERIFY_OPERANDS(_Lhs, _Rhs, _BadMsgId, _DiffMsgId) \
43 if (!std::__is_constant_evaluated()) { \
44 _GLIBCXX_DEBUG_VERIFY((!_Lhs._M_singular() && !_Rhs._M_singular()) \
45 || (_Lhs._M_value_initialized() \
46 && _Rhs._M_value_initialized()), \
47 _M_message(_BadMsgId) \
48 ._M_iterator(_Lhs, #_Lhs) \
49 ._M_iterator(_Rhs, #_Rhs)); \
50 _GLIBCXX_DEBUG_VERIFY(_Lhs._M_can_compare(_Rhs), \
51 _M_message(_DiffMsgId) \
52 ._M_iterator(_Lhs, #_Lhs) \
53 ._M_iterator(_Rhs, #_Rhs)); \
54 }
55
56#define _GLIBCXX_DEBUG_VERIFY_EQ_OPERANDS(_Lhs, _Rhs) \
57 _GLIBCXX_DEBUG_VERIFY_OPERANDS(_Lhs, _Rhs, __msg_iter_compare_bad, \
58 __msg_compare_different)
59
60#define _GLIBCXX_DEBUG_VERIFY_REL_OPERANDS(_Lhs, _Rhs) \
61 _GLIBCXX_DEBUG_VERIFY_OPERANDS(_Lhs, _Rhs, __msg_iter_order_bad, \
62 __msg_order_different)
63
64#define _GLIBCXX_DEBUG_VERIFY_DIST_OPERANDS(_Lhs, _Rhs) \
65 _GLIBCXX_DEBUG_VERIFY_OPERANDS(_Lhs, _Rhs, __msg_distance_bad, \
66 __msg_distance_different)
67
68// This pair of macros helps with writing valid C++20 constexpr functions that
69// contain a non-constexpr code path that defines a non-literal variable, which
70// was otherwise disallowed until P2242R3 for C++23. We use them below around
71// __gnu_cxx::__scoped_lock variables so that the containing functions are still
72// considered valid C++20 constexpr functions.
73
74#if __cplusplus >= 202002L && __cpp_constexpr < 202110L
75# define _GLIBCXX20_CONSTEXPR_NON_LITERAL_SCOPE_BEGIN [&]() -> void
76# define _GLIBCXX20_CONSTEXPR_NON_LITERAL_SCOPE_END ();
77#else
78# define _GLIBCXX20_CONSTEXPR_NON_LITERAL_SCOPE_BEGIN
79# define _GLIBCXX20_CONSTEXPR_NON_LITERAL_SCOPE_END
80#endif
81
82namespace __gnu_debug
83{
84 /** Helper struct to deal with sequence offering a before_begin
85 * iterator.
86 **/
87 template<typename _Sequence>
89 {
90 template<typename _Iterator, typename _Category>
91 static bool
93 { return false; }
94
95 template<typename _Iterator, typename _Category>
96 static bool
97 _S_Is_Beginnest(const _Safe_iterator<_Iterator, _Sequence, _Category>& __it)
98 { return __it.base() == __it._M_get_sequence()->_M_base().begin(); }
99 };
100
101 /** Sequence traits giving the size of a container if possible. */
102 template<typename _Sequence>
104 {
105 typedef _Distance_traits<typename _Sequence::iterator> _DistTraits;
106
107 static typename _DistTraits::__type
108 _S_size(const _Sequence& __seq)
109 { return std::make_pair(__seq.size(), __dp_exact); }
110 };
111
112 /** \brief Safe iterator wrapper.
113 *
114 * The class template %_Safe_iterator is a wrapper around an
115 * iterator that tracks the iterator's movement among sequences and
116 * checks that operations performed on the "safe" iterator are
117 * legal. In additional to the basic iterator operations (which are
118 * validated, and then passed to the underlying iterator),
119 * %_Safe_iterator has member functions for iterator invalidation,
120 * attaching/detaching the iterator from sequences, and querying
121 * the iterator's state.
122 *
123 * Note that _Iterator must be the first base class so that it gets
124 * initialized before the iterator is being attached to the container's list
125 * of iterators and it is being detached before _Iterator get
126 * destroyed. Otherwise it would result in a data race.
127 */
128 template<typename _Iterator, typename _Sequence, typename _Category
130 class _Safe_iterator
131 : private _Iterator,
133 {
134 typedef std::iterator_traits<_Iterator> _Traits;
135
136 protected:
137 typedef std::__are_same<typename _Sequence::_Base::const_iterator,
138 _Iterator> _IsConstant;
139
140 typedef typename __gnu_cxx::__conditional_type<
141 _IsConstant::__value,
142 typename _Sequence::_Base::iterator,
143 typename _Sequence::_Base::const_iterator>::__type _OtherIterator;
144
145 struct _Unchecked { };
146
147 _GLIBCXX20_CONSTEXPR
148 _Safe_iterator(const _Safe_iterator& __x, _Unchecked) _GLIBCXX_NOEXCEPT
149 : _Iterator(__x), _Safe_iterator_base(__x, _S_constant())
150 { }
151
152 public:
153 typedef _Iterator iterator_type;
154 typedef typename _Traits::iterator_category iterator_category;
155 typedef typename _Traits::value_type value_type;
156 typedef typename _Traits::difference_type difference_type;
157 typedef typename _Traits::reference reference;
158 typedef typename _Traits::pointer pointer;
159
160#if __cplusplus > 201703L && __cpp_lib_concepts
161 using iterator_concept = std::__detail::__iter_concept<_Iterator>;
162#endif
163
164 /// @post the iterator is singular and unattached
165 _GLIBCXX20_CONSTEXPR
166 _Safe_iterator() _GLIBCXX_NOEXCEPT : _Iterator() { }
167
168 /**
169 * @brief Safe iterator construction from an unsafe iterator and
170 * its sequence.
171 *
172 * @pre @p seq is not NULL
173 * @post this is not singular
174 */
175 _GLIBCXX20_CONSTEXPR
176 _Safe_iterator(_Iterator __i, const _Safe_sequence_base* __seq)
177 _GLIBCXX_NOEXCEPT
178 : _Iterator(__i), _Safe_iterator_base(__seq, _S_constant())
179 { }
180
181 /**
182 * @brief Copy construction.
183 */
184 _GLIBCXX20_CONSTEXPR
185 _Safe_iterator(const _Safe_iterator& __x) _GLIBCXX_NOEXCEPT
186 : _Iterator(__x), _Safe_iterator_base()
187 {
188 if (std::__is_constant_evaluated())
189 return;
190
191 // _GLIBCXX_RESOLVE_LIB_DEFECTS
192 // DR 408. Is vector<reverse_iterator<char*> > forbidden?
193 _GLIBCXX_DEBUG_VERIFY(!__x._M_singular()
194 || __x._M_value_initialized(),
195 _M_message(__msg_init_copy_singular)
196 ._M_iterator(*this, "this")
197 ._M_iterator(__x, "other"));
199 }
200
201#if __cplusplus >= 201103L
202 /**
203 * @brief Move construction.
204 * @post __x is singular and unattached
205 */
206 _GLIBCXX20_CONSTEXPR
207 _Safe_iterator(_Safe_iterator&& __x) noexcept
208 : _Iterator()
209 {
210 if (std::__is_constant_evaluated())
211 {
212 base() = __x.base();
213 return;
214 }
215
216 _GLIBCXX_DEBUG_VERIFY(!__x._M_singular()
217 || __x._M_value_initialized(),
218 _M_message(__msg_init_copy_singular)
219 ._M_iterator(*this, "this")
220 ._M_iterator(__x, "other"));
221 const _Safe_sequence_base* __seq = __x._M_sequence;
222 __x._M_detach();
223 std::swap(base(), __x.base());
224 _M_attach(__seq);
225 }
226#endif
227
228 /**
229 * @brief Converting constructor from a mutable iterator to a
230 * constant iterator.
231 */
232 template<typename _MutableIterator>
233 _GLIBCXX20_CONSTEXPR
235 const _Safe_iterator<_MutableIterator, _Sequence,
236 typename __gnu_cxx::__enable_if<_IsConstant::__value &&
237 std::__are_same<_MutableIterator, _OtherIterator>::__value,
238 _Category>::__type>& __x)
239 _GLIBCXX_NOEXCEPT
240 : _Iterator(__x.base())
241 {
242 if (std::__is_constant_evaluated())
243 return;
244
245 // _GLIBCXX_RESOLVE_LIB_DEFECTS
246 // DR 408. Is vector<reverse_iterator<char*> > forbidden?
247 _GLIBCXX_DEBUG_VERIFY(!__x._M_singular()
248 || __x._M_value_initialized(),
249 _M_message(__msg_init_const_singular)
250 ._M_iterator(*this, "this")
251 ._M_iterator(__x, "other"));
253 }
254
255 /**
256 * @brief Copy assignment.
257 */
258 _GLIBCXX20_CONSTEXPR
260 operator=(const _Safe_iterator& __x) _GLIBCXX_NOEXCEPT
261 {
262 if (std::__is_constant_evaluated())
263 {
264 base() = __x.base();
265 return *this;
266 }
267
268 // _GLIBCXX_RESOLVE_LIB_DEFECTS
269 // DR 408. Is vector<reverse_iterator<char*> > forbidden?
270 _GLIBCXX_DEBUG_VERIFY(!__x._M_singular()
271 || __x._M_value_initialized(),
272 _M_message(__msg_copy_singular)
273 ._M_iterator(*this, "this")
274 ._M_iterator(__x, "other"));
275
276 if (this->_M_sequence && this->_M_sequence == __x._M_sequence)
277 _GLIBCXX20_CONSTEXPR_NON_LITERAL_SCOPE_BEGIN {
279 base() = __x.base();
281 } _GLIBCXX20_CONSTEXPR_NON_LITERAL_SCOPE_END
282 else
283 {
284 _M_detach();
285 base() = __x.base();
287 }
288
289 return *this;
290 }
291
292#if __cplusplus >= 201103L
293 /**
294 * @brief Move assignment.
295 * @post __x is singular and unattached
296 */
297 _GLIBCXX20_CONSTEXPR
299 operator=(_Safe_iterator&& __x) noexcept
300 {
301 if (std::__is_constant_evaluated())
302 {
303 base() = __x.base();
304 return *this;
305 }
306
307 _GLIBCXX_DEBUG_VERIFY(!__x._M_singular()
308 || __x._M_value_initialized(),
309 _M_message(__msg_copy_singular)
310 ._M_iterator(*this, "this")
311 ._M_iterator(__x, "other"));
312
313 if (std::__addressof(__x) == this)
314 return *this;
315
316 if (this->_M_sequence && this->_M_sequence == __x._M_sequence)
317 _GLIBCXX20_CONSTEXPR_NON_LITERAL_SCOPE_BEGIN {
319 base() = __x.base();
321 } _GLIBCXX20_CONSTEXPR_NON_LITERAL_SCOPE_END
322 else
323 {
324 _M_detach();
325 base() = __x.base();
327 }
328
329 __x._M_detach();
330 __x.base() = _Iterator();
331 return *this;
332 }
333#endif
334
335 /**
336 * @brief Iterator dereference.
337 * @pre iterator is dereferenceable
338 */
339 _GLIBCXX_NODISCARD
340 _GLIBCXX20_CONSTEXPR
341 reference
342 operator*() const _GLIBCXX_NOEXCEPT
343 {
344 if (!std::__is_constant_evaluated())
345 {
346 _GLIBCXX_DEBUG_VERIFY(this->_M_dereferenceable(),
347 _M_message(__msg_bad_deref)
348 ._M_iterator(*this, "this"));
349 }
350 return *base();
351 }
352
353 /**
354 * @brief Iterator dereference.
355 * @pre iterator is dereferenceable
356 */
357 _GLIBCXX_NODISCARD
358 _GLIBCXX20_CONSTEXPR
359 pointer
360 operator->() const _GLIBCXX_NOEXCEPT
361 {
362 if (!std::__is_constant_evaluated())
363 {
364 _GLIBCXX_DEBUG_VERIFY(this->_M_dereferenceable(),
365 _M_message(__msg_bad_deref)
366 ._M_iterator(*this, "this"));
367 }
368 return base().operator->();
369 }
370
371 // ------ Input iterator requirements ------
372 /**
373 * @brief Iterator preincrement
374 * @pre iterator is incrementable
375 */
376 _GLIBCXX20_CONSTEXPR
378 operator++() _GLIBCXX_NOEXCEPT
379 {
380 if (std::__is_constant_evaluated())
381 {
382 ++base();
383 return *this;
384 }
385
386 _GLIBCXX_DEBUG_VERIFY(this->_M_incrementable(),
387 _M_message(__msg_bad_inc)
388 ._M_iterator(*this, "this"));
389 _GLIBCXX20_CONSTEXPR_NON_LITERAL_SCOPE_BEGIN {
391 ++base();
392 } _GLIBCXX20_CONSTEXPR_NON_LITERAL_SCOPE_END
393 return *this;
394 }
395
396 /**
397 * @brief Iterator postincrement
398 * @pre iterator is incrementable
399 */
400 _GLIBCXX20_CONSTEXPR
402 operator++(int) _GLIBCXX_NOEXCEPT
403 {
404 if (!std::__is_constant_evaluated())
405 {
406 _GLIBCXX_DEBUG_VERIFY(this->_M_incrementable(),
407 _M_message(__msg_bad_inc)
408 ._M_iterator(*this, "this"));
409 }
410 _Safe_iterator __ret(*this, _Unchecked());
411 ++*this;
412 return __ret;
413 }
414
415 // ------ Utilities ------
416
417 /// Determine if this is a constant iterator.
418 static _GLIBCXX_CONSTEXPR bool
420 { return _IsConstant::__value; }
421
422 /**
423 * @brief Return the underlying iterator
424 */
425 _GLIBCXX20_CONSTEXPR
426 _Iterator&
427 base() _GLIBCXX_NOEXCEPT { return *this; }
428
429 _GLIBCXX20_CONSTEXPR
430 const _Iterator&
431 base() const _GLIBCXX_NOEXCEPT { return *this; }
432
433 /**
434 * @brief Conversion to underlying non-debug iterator to allow
435 * better interaction with non-debug containers.
436 */
437 _GLIBCXX20_CONSTEXPR
438 operator _Iterator() const _GLIBCXX_NOEXCEPT { return *this; }
439
440 /** Attach iterator to the given sequence. */
441 void
442 _M_attach(const _Safe_sequence_base* __seq)
444
445 /** Likewise, but not thread-safe. */
446 void
447 _M_attach_single(const _Safe_sequence_base* __seq)
449
450 /// Is the iterator dereferenceable?
451 bool
453 { return !this->_M_singular() && !_M_is_end() && !_M_is_before_begin(); }
454
455 /// Is the iterator before a dereferenceable one?
456 bool
458 {
459 if (this->_M_incrementable())
460 {
461 _Iterator __base = base();
462 return ++__base != _M_get_sequence()->_M_base().end();
463 }
464 return false;
465 }
466
467 /// Is the iterator incrementable?
468 bool
470 { return !this->_M_singular() && !_M_is_end(); }
471
472 /// Is the iterator value-initialized?
473 bool
475 { return _M_version == 0 && base() == _Iterator(); }
476
477 // Can we advance the iterator @p __n steps (@p __n may be negative)
478 bool
479 _M_can_advance(difference_type __n, bool __strict = false) const;
480
481 // Can we advance the iterator using @p __dist in @p __way direction.
482 template<typename _Diff>
483 bool
484 _M_can_advance(const std::pair<_Diff, _Distance_precision>& __dist,
485 int __way) const;
486
487 // Is the iterator range [*this, __rhs) valid?
488 bool
489 _M_valid_range(const _Safe_iterator& __rhs,
491 bool __check_dereferenceable = true) const;
492
493 // The sequence this iterator references.
494 typename __gnu_cxx::__conditional_type<
495 _IsConstant::__value, const _Sequence*, _Sequence*>::__type
496 _M_get_sequence() const
497 {
498 // Looks like not const-correct, but if _IsConstant the constness
499 // is restored when returning the sequence pointer and if not
500 // _IsConstant we are allowed to remove constness.
501 return static_cast<_Sequence*>
502 (const_cast<_Safe_sequence_base*>(_M_sequence));
503 }
504
505 // Get distance to __rhs.
506 typename _Distance_traits<_Iterator>::__type
507 _M_get_distance_to(const _Safe_iterator& __rhs) const;
508
509 // Get distance from sequence begin up to *this.
510 typename _Distance_traits<_Iterator>::__type
511 _M_get_distance_from_begin() const;
512
513 // Get distance from *this to sequence end.
514 typename _Distance_traits<_Iterator>::__type
515 _M_get_distance_to_end() const;
516
517 /// Is this iterator equal to the sequence's begin() iterator?
518 _GLIBCXX20_CONSTEXPR
519 bool
521 { return base() == _M_get_sequence()->_M_base().begin(); }
522
523 /// Is this iterator equal to the sequence's end() iterator?
524 bool
525 _M_is_end() const
526 { return base() == _M_get_sequence()->_M_base().end(); }
527
528 /// Is this iterator equal to the sequence's before_begin() iterator if
529 /// any?
530 bool
532 { return _BeforeBeginHelper<_Sequence>::_S_Is(*this); }
533
534 /// Is this iterator equal to the sequence's before_begin() iterator if
535 /// any or begin() otherwise?
536 bool
538 { return _BeforeBeginHelper<_Sequence>::_S_Is_Beginnest(*this); }
539
540 // ------ Operators ------
541
543
544 _GLIBCXX_NODISCARD
545 _GLIBCXX20_CONSTEXPR
546 friend bool
547 operator==(const _Self& __lhs, const _Self& __rhs) _GLIBCXX_NOEXCEPT
548 {
549 _GLIBCXX_DEBUG_VERIFY_EQ_OPERANDS(__lhs, __rhs);
550 return __lhs.base() == __rhs.base();
551 }
552
553 template<typename _IteR>
554 _GLIBCXX_NODISCARD
555 _GLIBCXX20_CONSTEXPR
556 friend bool
557 operator==(const _Self& __lhs,
559 _GLIBCXX_NOEXCEPT
560 {
561 _GLIBCXX_DEBUG_VERIFY_EQ_OPERANDS(__lhs, __rhs);
562 return __lhs.base() == __rhs.base();
563 }
564
565#if ! __cpp_lib_three_way_comparison
566 _GLIBCXX_NODISCARD
567 friend bool
568 operator!=(const _Self& __lhs, const _Self& __rhs) _GLIBCXX_NOEXCEPT
569 {
570 _GLIBCXX_DEBUG_VERIFY_EQ_OPERANDS(__lhs, __rhs);
571 return __lhs.base() != __rhs.base();
572 }
573
574 template<typename _IteR>
575 _GLIBCXX_NODISCARD
576 friend bool
577 operator!=(const _Self& __lhs,
578 const _Safe_iterator<_IteR, _Sequence, iterator_category>& __rhs)
579 _GLIBCXX_NOEXCEPT
580 {
581 _GLIBCXX_DEBUG_VERIFY_EQ_OPERANDS(__lhs, __rhs);
582 return __lhs.base() != __rhs.base();
583 }
584#endif // three-way comparison
585
586 template<typename _Fn>
587 static _GLIBCXX14_CONSTEXPR _Self
588 _S_for_each_segment(_Self __first, _Self __last, _Fn __func)
589 {
590 __glibcxx_check_valid_range(__first, __last);
591 _Iterator __ret
592 = _Iterator::_S_for_each_segment(__first.base(), __last.base(), __func);
593 return _Self(__ret, __first._M_sequence);
594 }
595
596 static const bool _S_enable_for_each_segment
597 = std::__enable_for_each_segment<_Iterator>;
598 };
599
600 template<typename _Iterator, typename _Sequence>
601 class _Safe_iterator<_Iterator, _Sequence, std::bidirectional_iterator_tag>
602 : public _Safe_iterator<_Iterator, _Sequence, std::forward_iterator_tag>
603 {
604 typedef _Safe_iterator<_Iterator, _Sequence,
605 std::forward_iterator_tag> _Safe_base;
606
607 protected:
608 typedef typename _Safe_base::_OtherIterator _OtherIterator;
609
610 typedef typename _Safe_base::_Unchecked _Unchecked;
611
612 _GLIBCXX20_CONSTEXPR
613 _Safe_iterator(const _Safe_iterator& __x,
614 _Unchecked __unchecked) _GLIBCXX_NOEXCEPT
615 : _Safe_base(__x, __unchecked)
616 { }
617
618 public:
619 /// @post the iterator is singular and unattached
620 _GLIBCXX20_CONSTEXPR
621 _Safe_iterator() _GLIBCXX_NOEXCEPT { }
622
623 /**
624 * @brief Safe iterator construction from an unsafe iterator and
625 * its sequence.
626 *
627 * @pre @p seq is not NULL
628 * @post this is not singular
629 */
630 _GLIBCXX20_CONSTEXPR
631 _Safe_iterator(_Iterator __i, const _Safe_sequence_base* __seq)
632 _GLIBCXX_NOEXCEPT
633 : _Safe_base(__i, __seq)
634 { }
635
636 /**
637 * @brief Copy construction.
638 */
639 _GLIBCXX20_CONSTEXPR
640 _Safe_iterator(const _Safe_iterator& __x) _GLIBCXX_NOEXCEPT
641 : _Safe_base(__x)
642 { }
643
644#if __cplusplus >= 201103L
645 /** @brief Move construction. */
646 _GLIBCXX20_CONSTEXPR
647 _Safe_iterator(_Safe_iterator&&) = default;
648#endif
649
650 /**
651 * @brief Converting constructor from a mutable iterator to a
652 * constant iterator.
653 */
654 template<typename _MutableIterator>
655 _GLIBCXX20_CONSTEXPR
657 const _Safe_iterator<_MutableIterator, _Sequence,
658 typename __gnu_cxx::__enable_if<_Safe_base::_IsConstant::__value &&
659 std::__are_same<_MutableIterator, _OtherIterator>::__value,
660 std::bidirectional_iterator_tag>::__type>& __x)
661 _GLIBCXX_NOEXCEPT
662 : _Safe_base(__x)
663 { }
664
665#if __cplusplus >= 201103L
666 /** @brief Copy assignment. */
667 _Safe_iterator&
668 operator=(const _Safe_iterator&) = default;
669
670 /** @brief Move assignment. */
671 _Safe_iterator&
672 operator=(_Safe_iterator&&) = default;
673#else
674 /** @brief Copy assignment. */
675 _Safe_iterator&
676 operator=(const _Safe_iterator& __x)
677 {
678 _Safe_base::operator=(__x);
679 return *this;
680 }
681#endif
682
683 // ------ Input iterator requirements ------
684 /**
685 * @brief Iterator preincrement
686 * @pre iterator is incrementable
687 */
688 _GLIBCXX20_CONSTEXPR
689 _Safe_iterator&
690 operator++() _GLIBCXX_NOEXCEPT
691 {
692 _Safe_base::operator++();
693 return *this;
694 }
695
696 /**
697 * @brief Iterator postincrement
698 * @pre iterator is incrementable
699 */
700 _Safe_iterator
701 operator++(int) _GLIBCXX_NOEXCEPT
702 {
703 _GLIBCXX_DEBUG_VERIFY(this->_M_incrementable(),
704 _M_message(__msg_bad_inc)
705 ._M_iterator(*this, "this"));
706 _Safe_iterator __ret(*this, _Unchecked());
707 ++*this;
708 return __ret;
709 }
710
711 // ------ Bidirectional iterator requirements ------
712 /**
713 * @brief Iterator predecrement
714 * @pre iterator is decrementable
715 */
716 _GLIBCXX20_CONSTEXPR
717 _Safe_iterator&
718 operator--() _GLIBCXX_NOEXCEPT
719 {
720 if (std::__is_constant_evaluated())
721 {
722 --this->base();
723 return *this;
724 }
725
726 _GLIBCXX_DEBUG_VERIFY(this->_M_decrementable(),
727 _M_message(__msg_bad_dec)
728 ._M_iterator(*this, "this"));
729 _GLIBCXX20_CONSTEXPR_NON_LITERAL_SCOPE_BEGIN {
730 __gnu_cxx::__scoped_lock __l(this->_M_get_mutex());
731 --this->base();
732 } _GLIBCXX20_CONSTEXPR_NON_LITERAL_SCOPE_END
733 return *this;
734 }
735
736 /**
737 * @brief Iterator postdecrement
738 * @pre iterator is decrementable
739 */
740 _Safe_iterator
741 operator--(int) _GLIBCXX_NOEXCEPT
742 {
743 _GLIBCXX_DEBUG_VERIFY(this->_M_decrementable(),
744 _M_message(__msg_bad_dec)
745 ._M_iterator(*this, "this"));
746 _Safe_iterator __ret(*this, _Unchecked());
747 --*this;
748 return __ret;
749 }
750
751 // ------ Utilities ------
752
753 // Is the iterator decrementable?
754 bool
755 _M_decrementable() const
756 { return !this->_M_singular() && !this->_M_is_begin(); }
757 };
758
759 template<typename _Iterator, typename _Sequence>
760 class _Safe_iterator<_Iterator, _Sequence, std::random_access_iterator_tag>
761 : public _Safe_iterator<_Iterator, _Sequence,
762 std::bidirectional_iterator_tag>
763 {
764 typedef _Safe_iterator<_Iterator, _Sequence,
765 std::bidirectional_iterator_tag> _Safe_base;
766 typedef typename _Safe_base::_OtherIterator _OtherIterator;
767
768 typedef typename _Safe_base::_Self _Self;
769 typedef _Safe_iterator<_OtherIterator, _Sequence,
770 std::random_access_iterator_tag> _OtherSelf;
771
772 typedef typename _Safe_base::_Unchecked _Unchecked;
773
774 _GLIBCXX20_CONSTEXPR
775 _Safe_iterator(const _Safe_iterator& __x,
776 _Unchecked __unchecked) _GLIBCXX_NOEXCEPT
777 : _Safe_base(__x, __unchecked)
778 { }
779
780 public:
781 typedef typename _Safe_base::difference_type difference_type;
782 typedef typename _Safe_base::reference reference;
783
784 /// @post the iterator is singular and unattached
785 _GLIBCXX20_CONSTEXPR
786 _Safe_iterator() _GLIBCXX_NOEXCEPT { }
787
788 /**
789 * @brief Safe iterator construction from an unsafe iterator and
790 * its sequence.
791 *
792 * @pre @p seq is not NULL
793 * @post this is not singular
794 */
795 _GLIBCXX20_CONSTEXPR
796 _Safe_iterator(_Iterator __i, const _Safe_sequence_base* __seq)
797 _GLIBCXX_NOEXCEPT
798 : _Safe_base(__i, __seq)
799 { }
800
801 /**
802 * @brief Copy construction.
803 */
804 _GLIBCXX20_CONSTEXPR
805 _Safe_iterator(const _Safe_iterator& __x) _GLIBCXX_NOEXCEPT
806 : _Safe_base(__x)
807 { }
808
809#if __cplusplus >= 201103L
810 /** @brief Move construction. */
811 _Safe_iterator(_Safe_iterator&&) = default;
812#endif
813
814 /**
815 * @brief Converting constructor from a mutable iterator to a
816 * constant iterator.
817 */
818 template<typename _MutableIterator>
819 _GLIBCXX20_CONSTEXPR
821 const _Safe_iterator<_MutableIterator, _Sequence,
822 typename __gnu_cxx::__enable_if<_Safe_base::_IsConstant::__value &&
823 std::__are_same<_MutableIterator, _OtherIterator>::__value,
824 std::random_access_iterator_tag>::__type>& __x)
825 _GLIBCXX_NOEXCEPT
826 : _Safe_base(__x)
827 { }
828
829#if __cplusplus >= 201103L
830 /** @brief Copy assignment. */
831 _Safe_iterator&
832 operator=(const _Safe_iterator&) = default;
833
834 /** @brief Move assignment. */
835 _Safe_iterator&
836 operator=(_Safe_iterator&&) = default;
837#else
838 /** @brief Copy assignment. */
839 _Safe_iterator&
840 operator=(const _Safe_iterator& __x)
841 {
842 _Safe_base::operator=(__x);
843 return *this;
844 }
845#endif
846
847 // Is the iterator range [*this, __rhs) valid?
848 bool
849 _M_valid_range(const _Safe_iterator& __rhs,
850 std::pair<difference_type,
851 _Distance_precision>& __dist) const;
852
853 // ------ Input iterator requirements ------
854 /**
855 * @brief Iterator preincrement
856 * @pre iterator is incrementable
857 */
858 _GLIBCXX20_CONSTEXPR
859 _Safe_iterator&
860 operator++() _GLIBCXX_NOEXCEPT
861 {
862 _Safe_base::operator++();
863 return *this;
864 }
865
866 /**
867 * @brief Iterator postincrement
868 * @pre iterator is incrementable
869 */
870 _GLIBCXX20_CONSTEXPR
871 _Safe_iterator
872 operator++(int) _GLIBCXX_NOEXCEPT
873 {
874 if (!std::__is_constant_evaluated())
875 {
876 _GLIBCXX_DEBUG_VERIFY(this->_M_incrementable(),
877 _M_message(__msg_bad_inc)
878 ._M_iterator(*this, "this"));
879 }
880 _Safe_iterator __ret(*this, _Unchecked());
881 ++*this;
882 return __ret;
883 }
884
885 // ------ Bidirectional iterator requirements ------
886 /**
887 * @brief Iterator predecrement
888 * @pre iterator is decrementable
889 */
890 _GLIBCXX20_CONSTEXPR
891 _Safe_iterator&
892 operator--() _GLIBCXX_NOEXCEPT
893 {
894 _Safe_base::operator--();
895 return *this;
896 }
897
898 /**
899 * @brief Iterator postdecrement
900 * @pre iterator is decrementable
901 */
902 _GLIBCXX20_CONSTEXPR
903 _Safe_iterator
904 operator--(int) _GLIBCXX_NOEXCEPT
905 {
906 if (!std::__is_constant_evaluated())
907 {
908 _GLIBCXX_DEBUG_VERIFY(this->_M_decrementable(),
909 _M_message(__msg_bad_dec)
910 ._M_iterator(*this, "this"));
911 }
912 _Safe_iterator __ret(*this, _Unchecked());
913 --*this;
914 return __ret;
915 }
916
917 // ------ Random access iterator requirements ------
918 _GLIBCXX_NODISCARD
919 _GLIBCXX20_CONSTEXPR
920 reference
921 operator[](difference_type __n) const _GLIBCXX_NOEXCEPT
922 {
923 if (!std::__is_constant_evaluated())
924 {
925 _GLIBCXX_DEBUG_VERIFY(this->_M_can_advance(__n)
926 && this->_M_can_advance(__n + 1),
927 _M_message(__msg_iter_subscript_oob)
928 ._M_iterator(*this)._M_integer(__n));
929 }
930 return this->base()[__n];
931 }
932
933 _GLIBCXX20_CONSTEXPR
934 _Safe_iterator&
935 operator+=(difference_type __n) _GLIBCXX_NOEXCEPT
936 {
937 if (std::__is_constant_evaluated())
938 {
939 this->base() += __n;
940 return *this;
941 }
942
943 _GLIBCXX_DEBUG_VERIFY(this->_M_can_advance(__n),
944 _M_message(__msg_advance_oob)
945 ._M_iterator(*this)._M_integer(__n));
946 _GLIBCXX20_CONSTEXPR_NON_LITERAL_SCOPE_BEGIN {
947 __gnu_cxx::__scoped_lock __l(this->_M_get_mutex());
948 this->base() += __n;
949 } _GLIBCXX20_CONSTEXPR_NON_LITERAL_SCOPE_END
950 return *this;
951 }
952
953 _GLIBCXX20_CONSTEXPR
954 _Safe_iterator&
955 operator-=(difference_type __n) _GLIBCXX_NOEXCEPT
956 {
957 if (std::__is_constant_evaluated())
958 {
959 this->base() -= __n;
960 return *this;
961 }
962
963 _GLIBCXX_DEBUG_VERIFY(this->_M_can_advance(-__n),
964 _M_message(__msg_retreat_oob)
965 ._M_iterator(*this)._M_integer(__n));
966 _GLIBCXX20_CONSTEXPR_NON_LITERAL_SCOPE_BEGIN {
967 __gnu_cxx::__scoped_lock __l(this->_M_get_mutex());
968 this->base() -= __n;
969 } _GLIBCXX20_CONSTEXPR_NON_LITERAL_SCOPE_END
970 return *this;
971 }
972
973#if __cpp_lib_three_way_comparison
974 [[nodiscard]]
975 _GLIBCXX20_CONSTEXPR
976 friend auto
977 operator<=>(const _Self& __lhs, const _Self& __rhs) noexcept
978 {
979 _GLIBCXX_DEBUG_VERIFY_REL_OPERANDS(__lhs, __rhs);
980 return __lhs.base() <=> __rhs.base();
981 }
982
983 [[nodiscard]]
984 _GLIBCXX20_CONSTEXPR
985 friend auto
986 operator<=>(const _Self& __lhs, const _OtherSelf& __rhs) noexcept
987 {
988 _GLIBCXX_DEBUG_VERIFY_REL_OPERANDS(__lhs, __rhs);
989 return __lhs.base() <=> __rhs.base();
990 }
991#else
992 _GLIBCXX_NODISCARD
993 friend bool
994 operator<(const _Self& __lhs, const _Self& __rhs) _GLIBCXX_NOEXCEPT
995 {
996 _GLIBCXX_DEBUG_VERIFY_REL_OPERANDS(__lhs, __rhs);
997 return __lhs.base() < __rhs.base();
998 }
999
1000 _GLIBCXX_NODISCARD
1001 friend bool
1002 operator<(const _Self& __lhs, const _OtherSelf& __rhs) _GLIBCXX_NOEXCEPT
1003 {
1004 _GLIBCXX_DEBUG_VERIFY_REL_OPERANDS(__lhs, __rhs);
1005 return __lhs.base() < __rhs.base();
1006 }
1007
1008 _GLIBCXX_NODISCARD
1009 friend bool
1010 operator<=(const _Self& __lhs, const _Self& __rhs) _GLIBCXX_NOEXCEPT
1011 {
1012 _GLIBCXX_DEBUG_VERIFY_REL_OPERANDS(__lhs, __rhs);
1013 return __lhs.base() <= __rhs.base();
1014 }
1015
1016 _GLIBCXX_NODISCARD
1017 friend bool
1018 operator<=(const _Self& __lhs, const _OtherSelf& __rhs) _GLIBCXX_NOEXCEPT
1019 {
1020 _GLIBCXX_DEBUG_VERIFY_REL_OPERANDS(__lhs, __rhs);
1021 return __lhs.base() <= __rhs.base();
1022 }
1023
1024 _GLIBCXX_NODISCARD
1025 friend bool
1026 operator>(const _Self& __lhs, const _Self& __rhs) _GLIBCXX_NOEXCEPT
1027 {
1028 _GLIBCXX_DEBUG_VERIFY_REL_OPERANDS(__lhs, __rhs);
1029 return __lhs.base() > __rhs.base();
1030 }
1031
1032 _GLIBCXX_NODISCARD
1033 friend bool
1034 operator>(const _Self& __lhs, const _OtherSelf& __rhs) _GLIBCXX_NOEXCEPT
1035 {
1036 _GLIBCXX_DEBUG_VERIFY_REL_OPERANDS(__lhs, __rhs);
1037 return __lhs.base() > __rhs.base();
1038 }
1039
1040 _GLIBCXX_NODISCARD
1041 friend bool
1042 operator>=(const _Self& __lhs, const _Self& __rhs) _GLIBCXX_NOEXCEPT
1043 {
1044 _GLIBCXX_DEBUG_VERIFY_REL_OPERANDS(__lhs, __rhs);
1045 return __lhs.base() >= __rhs.base();
1046 }
1047
1048 _GLIBCXX_NODISCARD
1049 friend bool
1050 operator>=(const _Self& __lhs, const _OtherSelf& __rhs) _GLIBCXX_NOEXCEPT
1051 {
1052 _GLIBCXX_DEBUG_VERIFY_REL_OPERANDS(__lhs, __rhs);
1053 return __lhs.base() >= __rhs.base();
1054 }
1055#endif // three-way comparison
1056
1057 // _GLIBCXX_RESOLVE_LIB_DEFECTS
1058 // According to the resolution of DR179 not only the various comparison
1059 // operators but also operator- must accept mixed iterator/const_iterator
1060 // parameters.
1061 _GLIBCXX_NODISCARD
1062 _GLIBCXX20_CONSTEXPR
1063 friend difference_type
1064 operator-(const _Self& __lhs, const _OtherSelf& __rhs) _GLIBCXX_NOEXCEPT
1065 {
1066 _GLIBCXX_DEBUG_VERIFY_DIST_OPERANDS(__lhs, __rhs);
1067 return __lhs.base() - __rhs.base();
1068 }
1069
1070 _GLIBCXX_NODISCARD
1071 _GLIBCXX20_CONSTEXPR
1072 friend difference_type
1073 operator-(const _Self& __lhs, const _Self& __rhs) _GLIBCXX_NOEXCEPT
1074 {
1075 _GLIBCXX_DEBUG_VERIFY_DIST_OPERANDS(__lhs, __rhs);
1076 return __lhs.base() - __rhs.base();
1077 }
1078
1079 _GLIBCXX_NODISCARD
1080 _GLIBCXX20_CONSTEXPR
1081 friend _Self
1082 operator+(const _Self& __x, difference_type __n) _GLIBCXX_NOEXCEPT
1083 {
1084 if (!std::__is_constant_evaluated())
1085 {
1086 _GLIBCXX_DEBUG_VERIFY(__x._M_can_advance(__n),
1087 _M_message(__msg_advance_oob)
1088 ._M_iterator(__x)._M_integer(__n));
1089 }
1090 return _Safe_iterator(__x.base() + __n, __x._M_sequence);
1091 }
1092
1093 _GLIBCXX_NODISCARD
1094 _GLIBCXX20_CONSTEXPR
1095 friend _Self
1096 operator+(difference_type __n, const _Self& __x) _GLIBCXX_NOEXCEPT
1097 {
1098 if (!std::__is_constant_evaluated())
1099 {
1100 _GLIBCXX_DEBUG_VERIFY(__x._M_can_advance(__n),
1101 _M_message(__msg_advance_oob)
1102 ._M_iterator(__x)._M_integer(__n));
1103 }
1104 return _Safe_iterator(__n + __x.base(), __x._M_sequence);
1105 }
1106
1107 _GLIBCXX_NODISCARD
1108 _GLIBCXX20_CONSTEXPR
1109 friend _Self
1110 operator-(const _Self& __x, difference_type __n) _GLIBCXX_NOEXCEPT
1111 {
1112 if (!std::__is_constant_evaluated())
1113 {
1114 _GLIBCXX_DEBUG_VERIFY(__x._M_can_advance(-__n),
1115 _M_message(__msg_retreat_oob)
1116 ._M_iterator(__x)._M_integer(__n));
1117 }
1118 return _Safe_iterator(__x.base() - __n, __x._M_sequence);
1119 }
1120 };
1121
1122 /** Safe iterators know how to check if they form a valid range. */
1123 template<typename _Iterator, typename _Sequence, typename _Category>
1124 _GLIBCXX20_CONSTEXPR
1125 inline bool
1126 __valid_range(const _Safe_iterator<_Iterator, _Sequence,
1127 _Category>& __first,
1128 const _Safe_iterator<_Iterator, _Sequence,
1129 _Category>& __last,
1130 typename _Distance_traits<_Iterator>::__type& __dist)
1131 {
1132 if (std::__is_constant_evaluated())
1133 return true;
1134
1135 return __first._M_valid_range(__last, __dist);
1136 }
1137
1138 template<typename _Iterator, typename _Sequence, typename _Category>
1139 _GLIBCXX20_CONSTEXPR
1140 inline bool
1141 __valid_range(const _Safe_iterator<_Iterator, _Sequence,
1142 _Category>& __first,
1143 const _Safe_iterator<_Iterator, _Sequence,
1144 _Category>& __last)
1145 {
1146 if (std::__is_constant_evaluated())
1147 return true;
1148
1149 typename _Distance_traits<_Iterator>::__type __dist;
1150 return __first._M_valid_range(__last, __dist);
1151 }
1152
1153 template<typename _Iterator, typename _Sequence, typename _Category,
1154 typename _Size>
1155 _GLIBCXX20_CONSTEXPR
1156 inline bool
1157 __can_advance(const _Safe_iterator<_Iterator, _Sequence, _Category>& __it,
1158 _Size __n)
1159 {
1160 if (std::__is_constant_evaluated())
1161 return true;
1162
1163 return __it._M_can_advance(__n);
1164 }
1165
1166 template<typename _Iterator, typename _Sequence, typename _Category,
1167 typename _Diff>
1168 _GLIBCXX20_CONSTEXPR
1169 inline bool
1170 __can_advance(const _Safe_iterator<_Iterator, _Sequence, _Category>& __it,
1172 int __way)
1173 {
1174 if (std::__is_constant_evaluated())
1175 return true;
1176
1177 return __it._M_can_advance(__dist, __way);
1178 }
1179
1180 template<typename _Iterator, typename _Sequence>
1181 _GLIBCXX20_CONSTEXPR _Iterator
1182 __base(const _Safe_iterator<_Iterator, _Sequence,
1183 std::random_access_iterator_tag>& __it)
1184 { return __it.base(); }
1185
1186#if __cplusplus < 201103L
1187 template<typename _Iterator, typename _Sequence>
1188 struct _Unsafe_type<_Safe_iterator<_Iterator, _Sequence> >
1189 { typedef _Iterator _Type; };
1190#endif
1191
1192 template<typename _Iterator, typename _Sequence>
1193 inline _Iterator
1194 __unsafe(const _Safe_iterator<_Iterator, _Sequence>& __it)
1195 { return __it.base(); }
1196
1197} // namespace __gnu_debug
1198
1199#undef _GLIBCXX20_CONSTEXPR_NON_LITERAL_SCOPE_END
1200#undef _GLIBCXX20_CONSTEXPR_NON_LITERAL_SCOPE_BEGIN
1201#undef _GLIBCXX_DEBUG_VERIFY_DIST_OPERANDS
1202#undef _GLIBCXX_DEBUG_VERIFY_REL_OPERANDS
1203#undef _GLIBCXX_DEBUG_VERIFY_EQ_OPERANDS
1204#undef _GLIBCXX_DEBUG_VERIFY_OPERANDS
1205
1206#include <debug/safe_iterator.tcc>
1207
1208#endif
constexpr bool operator<=(const duration< _Rep1, _Period1 > &__lhs, const duration< _Rep2, _Period2 > &__rhs)
Definition chrono.h:863
constexpr bool operator>=(const duration< _Rep1, _Period1 > &__lhs, const duration< _Rep2, _Period2 > &__rhs)
Definition chrono.h:877
constexpr bool operator<(const duration< _Rep1, _Period1 > &__lhs, const duration< _Rep2, _Period2 > &__rhs)
Definition chrono.h:830
constexpr bool operator>(const duration< _Rep1, _Period1 > &__lhs, const duration< _Rep2, _Period2 > &__rhs)
Definition chrono.h:870
constexpr complex< _Tp > operator-(const complex< _Tp > &__x, const complex< _Tp > &__y)
Return new complex value x minus y.
Definition complex:404
constexpr complex< _Tp > operator+(const complex< _Tp > &__x, const complex< _Tp > &__y)
Return new complex value x plus y.
Definition complex:374
pair(_T1, _T2) -> pair< _T1, _T2 >
Two pairs are equal iff their members are equal.
constexpr pair< typename __decay_and_strip< _T1 >::__type, typename __decay_and_strip< _T2 >::__type > make_pair(_T1 &&__x, _T2 &&__y)
A convenience wrapper for creating a pair from two objects.
Definition stl_pair.h:1169
constexpr _Tp * __addressof(_Tp &__r) noexcept
Same as C++11 std::addressof.
Definition move.h:52
GNU debug classes for public use.
constexpr _Iterator __base(_Iterator __it)
Safe iterator wrapper.
bool _M_incrementable() const
Is the iterator incrementable?
void _M_attach_single(const _Safe_sequence_base *__seq)
constexpr _Iterator & base() noexcept
Return the underlying iterator.
bool _M_dereferenceable() const
Is the iterator dereferenceable?
constexpr bool _M_is_begin() const
Is this iterator equal to the sequence's begin() iterator?
constexpr _Safe_iterator(const _Safe_iterator< _MutableIterator, _Sequence, typename __gnu_cxx::__enable_if< _IsConstant::__value &&std::__are_same< _MutableIterator, _OtherIterator >::__value, _Category >::__type > &__x) noexcept
Converting constructor from a mutable iterator to a constant iterator.
constexpr _Safe_iterator & operator++() noexcept
Iterator preincrement.
void _M_attach(const _Safe_sequence_base *__seq)
bool _M_before_dereferenceable() const
Is the iterator before a dereferenceable one?
constexpr _Safe_iterator & operator=(_Safe_iterator &&__x) noexcept
Move assignment.
constexpr _Safe_iterator(_Iterator __i, const _Safe_sequence_base *__seq) noexcept
Safe iterator construction from an unsafe iterator and its sequence.
constexpr pointer operator->() const noexcept
Iterator dereference.
constexpr _Safe_iterator(const _Safe_iterator &__x) noexcept
Copy construction.
constexpr reference operator*() const noexcept
Iterator dereference.
constexpr _Safe_iterator() noexcept
bool _M_is_beginnest() const
Is this iterator equal to the sequence's before_begin() iterator if any or begin() otherwise?
bool _M_value_initialized() const
Is the iterator value-initialized?
bool _M_is_end() const
Is this iterator equal to the sequence's end() iterator?
constexpr _Safe_iterator operator++(int) noexcept
Iterator postincrement.
bool _M_is_before_begin() const
Is this iterator equal to the sequence's before_begin() iterator if any?
constexpr _Safe_iterator(_Safe_iterator &&__x) noexcept
Move construction.
static constexpr bool _S_constant()
Determine if this is a constant iterator.
constexpr _Safe_iterator & operator=(const _Safe_iterator &__x) noexcept
Copy assignment.
Traits class for iterators.
Struct holding two objects (or references) of arbitrary type.
Definition stl_pair.h:307
bool _M_singular() const noexcept
__gnu_cxx::__mutex & _M_get_mutex() noexcept
const _Safe_sequence_base * _M_sequence
Definition safe_base.h:59
void _M_attach(const _Safe_sequence_base *__seq, bool __constant)
void _M_attach_single(const _Safe_sequence_base *__seq, bool __constant) noexcept
Base class that supports tracking of iterators that reference a sequence.
Definition safe_base.h:219
unsigned int _M_version
The container version number. This number may never be 0.
Definition safe_base.h:230
Scoped lock idiom.