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
587 template<typename _Iterator, typename _Sequence>
588 class _Safe_iterator<_Iterator, _Sequence, std::bidirectional_iterator_tag>
589 : public _Safe_iterator<_Iterator, _Sequence, std::forward_iterator_tag>
590 {
591 typedef _Safe_iterator<_Iterator, _Sequence,
592 std::forward_iterator_tag> _Safe_base;
593
594 protected:
595 typedef typename _Safe_base::_OtherIterator _OtherIterator;
596
597 typedef typename _Safe_base::_Unchecked _Unchecked;
598
599 _GLIBCXX20_CONSTEXPR
600 _Safe_iterator(const _Safe_iterator& __x,
601 _Unchecked __unchecked) _GLIBCXX_NOEXCEPT
602 : _Safe_base(__x, __unchecked)
603 { }
604
605 public:
606 /// @post the iterator is singular and unattached
607 _GLIBCXX20_CONSTEXPR
608 _Safe_iterator() _GLIBCXX_NOEXCEPT { }
609
610 /**
611 * @brief Safe iterator construction from an unsafe iterator and
612 * its sequence.
613 *
614 * @pre @p seq is not NULL
615 * @post this is not singular
616 */
617 _GLIBCXX20_CONSTEXPR
618 _Safe_iterator(_Iterator __i, const _Safe_sequence_base* __seq)
619 _GLIBCXX_NOEXCEPT
620 : _Safe_base(__i, __seq)
621 { }
622
623 /**
624 * @brief Copy construction.
625 */
626 _GLIBCXX20_CONSTEXPR
627 _Safe_iterator(const _Safe_iterator& __x) _GLIBCXX_NOEXCEPT
628 : _Safe_base(__x)
629 { }
630
631#if __cplusplus >= 201103L
632 /** @brief Move construction. */
633 _GLIBCXX20_CONSTEXPR
634 _Safe_iterator(_Safe_iterator&&) = default;
635#endif
636
637 /**
638 * @brief Converting constructor from a mutable iterator to a
639 * constant iterator.
640 */
641 template<typename _MutableIterator>
642 _GLIBCXX20_CONSTEXPR
644 const _Safe_iterator<_MutableIterator, _Sequence,
645 typename __gnu_cxx::__enable_if<_Safe_base::_IsConstant::__value &&
646 std::__are_same<_MutableIterator, _OtherIterator>::__value,
647 std::bidirectional_iterator_tag>::__type>& __x)
648 _GLIBCXX_NOEXCEPT
649 : _Safe_base(__x)
650 { }
651
652#if __cplusplus >= 201103L
653 /** @brief Copy assignment. */
654 _Safe_iterator&
655 operator=(const _Safe_iterator&) = default;
656
657 /** @brief Move assignment. */
658 _Safe_iterator&
659 operator=(_Safe_iterator&&) = default;
660#else
661 /** @brief Copy assignment. */
662 _Safe_iterator&
663 operator=(const _Safe_iterator& __x)
664 {
665 _Safe_base::operator=(__x);
666 return *this;
667 }
668#endif
669
670 // ------ Input iterator requirements ------
671 /**
672 * @brief Iterator preincrement
673 * @pre iterator is incrementable
674 */
675 _GLIBCXX20_CONSTEXPR
676 _Safe_iterator&
677 operator++() _GLIBCXX_NOEXCEPT
678 {
679 _Safe_base::operator++();
680 return *this;
681 }
682
683 /**
684 * @brief Iterator postincrement
685 * @pre iterator is incrementable
686 */
687 _Safe_iterator
688 operator++(int) _GLIBCXX_NOEXCEPT
689 {
690 _GLIBCXX_DEBUG_VERIFY(this->_M_incrementable(),
691 _M_message(__msg_bad_inc)
692 ._M_iterator(*this, "this"));
693 _Safe_iterator __ret(*this, _Unchecked());
694 ++*this;
695 return __ret;
696 }
697
698 // ------ Bidirectional iterator requirements ------
699 /**
700 * @brief Iterator predecrement
701 * @pre iterator is decrementable
702 */
703 _GLIBCXX20_CONSTEXPR
704 _Safe_iterator&
705 operator--() _GLIBCXX_NOEXCEPT
706 {
707 if (std::__is_constant_evaluated())
708 {
709 --this->base();
710 return *this;
711 }
712
713 _GLIBCXX_DEBUG_VERIFY(this->_M_decrementable(),
714 _M_message(__msg_bad_dec)
715 ._M_iterator(*this, "this"));
716 _GLIBCXX20_CONSTEXPR_NON_LITERAL_SCOPE_BEGIN {
717 __gnu_cxx::__scoped_lock __l(this->_M_get_mutex());
718 --this->base();
719 } _GLIBCXX20_CONSTEXPR_NON_LITERAL_SCOPE_END
720 return *this;
721 }
722
723 /**
724 * @brief Iterator postdecrement
725 * @pre iterator is decrementable
726 */
727 _Safe_iterator
728 operator--(int) _GLIBCXX_NOEXCEPT
729 {
730 _GLIBCXX_DEBUG_VERIFY(this->_M_decrementable(),
731 _M_message(__msg_bad_dec)
732 ._M_iterator(*this, "this"));
733 _Safe_iterator __ret(*this, _Unchecked());
734 --*this;
735 return __ret;
736 }
737
738 // ------ Utilities ------
739
740 // Is the iterator decrementable?
741 bool
742 _M_decrementable() const
743 { return !this->_M_singular() && !this->_M_is_begin(); }
744 };
745
746 template<typename _Iterator, typename _Sequence>
747 class _Safe_iterator<_Iterator, _Sequence, std::random_access_iterator_tag>
748 : public _Safe_iterator<_Iterator, _Sequence,
749 std::bidirectional_iterator_tag>
750 {
751 typedef _Safe_iterator<_Iterator, _Sequence,
752 std::bidirectional_iterator_tag> _Safe_base;
753 typedef typename _Safe_base::_OtherIterator _OtherIterator;
754
755 typedef typename _Safe_base::_Self _Self;
756 typedef _Safe_iterator<_OtherIterator, _Sequence,
757 std::random_access_iterator_tag> _OtherSelf;
758
759 typedef typename _Safe_base::_Unchecked _Unchecked;
760
761 _GLIBCXX20_CONSTEXPR
762 _Safe_iterator(const _Safe_iterator& __x,
763 _Unchecked __unchecked) _GLIBCXX_NOEXCEPT
764 : _Safe_base(__x, __unchecked)
765 { }
766
767 public:
768 typedef typename _Safe_base::difference_type difference_type;
769 typedef typename _Safe_base::reference reference;
770
771 /// @post the iterator is singular and unattached
772 _GLIBCXX20_CONSTEXPR
773 _Safe_iterator() _GLIBCXX_NOEXCEPT { }
774
775 /**
776 * @brief Safe iterator construction from an unsafe iterator and
777 * its sequence.
778 *
779 * @pre @p seq is not NULL
780 * @post this is not singular
781 */
782 _GLIBCXX20_CONSTEXPR
783 _Safe_iterator(_Iterator __i, const _Safe_sequence_base* __seq)
784 _GLIBCXX_NOEXCEPT
785 : _Safe_base(__i, __seq)
786 { }
787
788 /**
789 * @brief Copy construction.
790 */
791 _GLIBCXX20_CONSTEXPR
792 _Safe_iterator(const _Safe_iterator& __x) _GLIBCXX_NOEXCEPT
793 : _Safe_base(__x)
794 { }
795
796#if __cplusplus >= 201103L
797 /** @brief Move construction. */
798 _Safe_iterator(_Safe_iterator&&) = default;
799#endif
800
801 /**
802 * @brief Converting constructor from a mutable iterator to a
803 * constant iterator.
804 */
805 template<typename _MutableIterator>
806 _GLIBCXX20_CONSTEXPR
808 const _Safe_iterator<_MutableIterator, _Sequence,
809 typename __gnu_cxx::__enable_if<_Safe_base::_IsConstant::__value &&
810 std::__are_same<_MutableIterator, _OtherIterator>::__value,
811 std::random_access_iterator_tag>::__type>& __x)
812 _GLIBCXX_NOEXCEPT
813 : _Safe_base(__x)
814 { }
815
816#if __cplusplus >= 201103L
817 /** @brief Copy assignment. */
818 _Safe_iterator&
819 operator=(const _Safe_iterator&) = default;
820
821 /** @brief Move assignment. */
822 _Safe_iterator&
823 operator=(_Safe_iterator&&) = default;
824#else
825 /** @brief Copy assignment. */
826 _Safe_iterator&
827 operator=(const _Safe_iterator& __x)
828 {
829 _Safe_base::operator=(__x);
830 return *this;
831 }
832#endif
833
834 // Is the iterator range [*this, __rhs) valid?
835 bool
836 _M_valid_range(const _Safe_iterator& __rhs,
837 std::pair<difference_type,
838 _Distance_precision>& __dist) const;
839
840 // ------ Input iterator requirements ------
841 /**
842 * @brief Iterator preincrement
843 * @pre iterator is incrementable
844 */
845 _GLIBCXX20_CONSTEXPR
846 _Safe_iterator&
847 operator++() _GLIBCXX_NOEXCEPT
848 {
849 _Safe_base::operator++();
850 return *this;
851 }
852
853 /**
854 * @brief Iterator postincrement
855 * @pre iterator is incrementable
856 */
857 _GLIBCXX20_CONSTEXPR
858 _Safe_iterator
859 operator++(int) _GLIBCXX_NOEXCEPT
860 {
861 if (!std::__is_constant_evaluated())
862 {
863 _GLIBCXX_DEBUG_VERIFY(this->_M_incrementable(),
864 _M_message(__msg_bad_inc)
865 ._M_iterator(*this, "this"));
866 }
867 _Safe_iterator __ret(*this, _Unchecked());
868 ++*this;
869 return __ret;
870 }
871
872 // ------ Bidirectional iterator requirements ------
873 /**
874 * @brief Iterator predecrement
875 * @pre iterator is decrementable
876 */
877 _GLIBCXX20_CONSTEXPR
878 _Safe_iterator&
879 operator--() _GLIBCXX_NOEXCEPT
880 {
881 _Safe_base::operator--();
882 return *this;
883 }
884
885 /**
886 * @brief Iterator postdecrement
887 * @pre iterator is decrementable
888 */
889 _GLIBCXX20_CONSTEXPR
890 _Safe_iterator
891 operator--(int) _GLIBCXX_NOEXCEPT
892 {
893 if (!std::__is_constant_evaluated())
894 {
895 _GLIBCXX_DEBUG_VERIFY(this->_M_decrementable(),
896 _M_message(__msg_bad_dec)
897 ._M_iterator(*this, "this"));
898 }
899 _Safe_iterator __ret(*this, _Unchecked());
900 --*this;
901 return __ret;
902 }
903
904 // ------ Random access iterator requirements ------
905 _GLIBCXX_NODISCARD
906 _GLIBCXX20_CONSTEXPR
907 reference
908 operator[](difference_type __n) const _GLIBCXX_NOEXCEPT
909 {
910 if (!std::__is_constant_evaluated())
911 {
912 _GLIBCXX_DEBUG_VERIFY(this->_M_can_advance(__n)
913 && this->_M_can_advance(__n + 1),
914 _M_message(__msg_iter_subscript_oob)
915 ._M_iterator(*this)._M_integer(__n));
916 }
917 return this->base()[__n];
918 }
919
920 _GLIBCXX20_CONSTEXPR
921 _Safe_iterator&
922 operator+=(difference_type __n) _GLIBCXX_NOEXCEPT
923 {
924 if (std::__is_constant_evaluated())
925 {
926 this->base() += __n;
927 return *this;
928 }
929
930 _GLIBCXX_DEBUG_VERIFY(this->_M_can_advance(__n),
931 _M_message(__msg_advance_oob)
932 ._M_iterator(*this)._M_integer(__n));
933 _GLIBCXX20_CONSTEXPR_NON_LITERAL_SCOPE_BEGIN {
934 __gnu_cxx::__scoped_lock __l(this->_M_get_mutex());
935 this->base() += __n;
936 } _GLIBCXX20_CONSTEXPR_NON_LITERAL_SCOPE_END
937 return *this;
938 }
939
940 _GLIBCXX20_CONSTEXPR
941 _Safe_iterator&
942 operator-=(difference_type __n) _GLIBCXX_NOEXCEPT
943 {
944 if (std::__is_constant_evaluated())
945 {
946 this->base() -= __n;
947 return *this;
948 }
949
950 _GLIBCXX_DEBUG_VERIFY(this->_M_can_advance(-__n),
951 _M_message(__msg_retreat_oob)
952 ._M_iterator(*this)._M_integer(__n));
953 _GLIBCXX20_CONSTEXPR_NON_LITERAL_SCOPE_BEGIN {
954 __gnu_cxx::__scoped_lock __l(this->_M_get_mutex());
955 this->base() -= __n;
956 } _GLIBCXX20_CONSTEXPR_NON_LITERAL_SCOPE_END
957 return *this;
958 }
959
960#if __cpp_lib_three_way_comparison
961 [[nodiscard]]
962 _GLIBCXX20_CONSTEXPR
963 friend auto
964 operator<=>(const _Self& __lhs, const _Self& __rhs) noexcept
965 {
966 _GLIBCXX_DEBUG_VERIFY_REL_OPERANDS(__lhs, __rhs);
967 return __lhs.base() <=> __rhs.base();
968 }
969
970 [[nodiscard]]
971 _GLIBCXX20_CONSTEXPR
972 friend auto
973 operator<=>(const _Self& __lhs, const _OtherSelf& __rhs) noexcept
974 {
975 _GLIBCXX_DEBUG_VERIFY_REL_OPERANDS(__lhs, __rhs);
976 return __lhs.base() <=> __rhs.base();
977 }
978#else
979 _GLIBCXX_NODISCARD
980 friend bool
981 operator<(const _Self& __lhs, const _Self& __rhs) _GLIBCXX_NOEXCEPT
982 {
983 _GLIBCXX_DEBUG_VERIFY_REL_OPERANDS(__lhs, __rhs);
984 return __lhs.base() < __rhs.base();
985 }
986
987 _GLIBCXX_NODISCARD
988 friend bool
989 operator<(const _Self& __lhs, const _OtherSelf& __rhs) _GLIBCXX_NOEXCEPT
990 {
991 _GLIBCXX_DEBUG_VERIFY_REL_OPERANDS(__lhs, __rhs);
992 return __lhs.base() < __rhs.base();
993 }
994
995 _GLIBCXX_NODISCARD
996 friend bool
997 operator<=(const _Self& __lhs, const _Self& __rhs) _GLIBCXX_NOEXCEPT
998 {
999 _GLIBCXX_DEBUG_VERIFY_REL_OPERANDS(__lhs, __rhs);
1000 return __lhs.base() <= __rhs.base();
1001 }
1002
1003 _GLIBCXX_NODISCARD
1004 friend bool
1005 operator<=(const _Self& __lhs, const _OtherSelf& __rhs) _GLIBCXX_NOEXCEPT
1006 {
1007 _GLIBCXX_DEBUG_VERIFY_REL_OPERANDS(__lhs, __rhs);
1008 return __lhs.base() <= __rhs.base();
1009 }
1010
1011 _GLIBCXX_NODISCARD
1012 friend bool
1013 operator>(const _Self& __lhs, const _Self& __rhs) _GLIBCXX_NOEXCEPT
1014 {
1015 _GLIBCXX_DEBUG_VERIFY_REL_OPERANDS(__lhs, __rhs);
1016 return __lhs.base() > __rhs.base();
1017 }
1018
1019 _GLIBCXX_NODISCARD
1020 friend bool
1021 operator>(const _Self& __lhs, const _OtherSelf& __rhs) _GLIBCXX_NOEXCEPT
1022 {
1023 _GLIBCXX_DEBUG_VERIFY_REL_OPERANDS(__lhs, __rhs);
1024 return __lhs.base() > __rhs.base();
1025 }
1026
1027 _GLIBCXX_NODISCARD
1028 friend bool
1029 operator>=(const _Self& __lhs, const _Self& __rhs) _GLIBCXX_NOEXCEPT
1030 {
1031 _GLIBCXX_DEBUG_VERIFY_REL_OPERANDS(__lhs, __rhs);
1032 return __lhs.base() >= __rhs.base();
1033 }
1034
1035 _GLIBCXX_NODISCARD
1036 friend bool
1037 operator>=(const _Self& __lhs, const _OtherSelf& __rhs) _GLIBCXX_NOEXCEPT
1038 {
1039 _GLIBCXX_DEBUG_VERIFY_REL_OPERANDS(__lhs, __rhs);
1040 return __lhs.base() >= __rhs.base();
1041 }
1042#endif // three-way comparison
1043
1044 // _GLIBCXX_RESOLVE_LIB_DEFECTS
1045 // According to the resolution of DR179 not only the various comparison
1046 // operators but also operator- must accept mixed iterator/const_iterator
1047 // parameters.
1048 _GLIBCXX_NODISCARD
1049 _GLIBCXX20_CONSTEXPR
1050 friend difference_type
1051 operator-(const _Self& __lhs, const _OtherSelf& __rhs) _GLIBCXX_NOEXCEPT
1052 {
1053 _GLIBCXX_DEBUG_VERIFY_DIST_OPERANDS(__lhs, __rhs);
1054 return __lhs.base() - __rhs.base();
1055 }
1056
1057 _GLIBCXX_NODISCARD
1058 _GLIBCXX20_CONSTEXPR
1059 friend difference_type
1060 operator-(const _Self& __lhs, const _Self& __rhs) _GLIBCXX_NOEXCEPT
1061 {
1062 _GLIBCXX_DEBUG_VERIFY_DIST_OPERANDS(__lhs, __rhs);
1063 return __lhs.base() - __rhs.base();
1064 }
1065
1066 _GLIBCXX_NODISCARD
1067 _GLIBCXX20_CONSTEXPR
1068 friend _Self
1069 operator+(const _Self& __x, difference_type __n) _GLIBCXX_NOEXCEPT
1070 {
1071 if (!std::__is_constant_evaluated())
1072 {
1073 _GLIBCXX_DEBUG_VERIFY(__x._M_can_advance(__n),
1074 _M_message(__msg_advance_oob)
1075 ._M_iterator(__x)._M_integer(__n));
1076 }
1077 return _Safe_iterator(__x.base() + __n, __x._M_sequence);
1078 }
1079
1080 _GLIBCXX_NODISCARD
1081 _GLIBCXX20_CONSTEXPR
1082 friend _Self
1083 operator+(difference_type __n, const _Self& __x) _GLIBCXX_NOEXCEPT
1084 {
1085 if (!std::__is_constant_evaluated())
1086 {
1087 _GLIBCXX_DEBUG_VERIFY(__x._M_can_advance(__n),
1088 _M_message(__msg_advance_oob)
1089 ._M_iterator(__x)._M_integer(__n));
1090 }
1091 return _Safe_iterator(__n + __x.base(), __x._M_sequence);
1092 }
1093
1094 _GLIBCXX_NODISCARD
1095 _GLIBCXX20_CONSTEXPR
1096 friend _Self
1097 operator-(const _Self& __x, difference_type __n) _GLIBCXX_NOEXCEPT
1098 {
1099 if (!std::__is_constant_evaluated())
1100 {
1101 _GLIBCXX_DEBUG_VERIFY(__x._M_can_advance(-__n),
1102 _M_message(__msg_retreat_oob)
1103 ._M_iterator(__x)._M_integer(__n));
1104 }
1105 return _Safe_iterator(__x.base() - __n, __x._M_sequence);
1106 }
1107 };
1108
1109 /** Safe iterators know how to check if they form a valid range. */
1110 template<typename _Iterator, typename _Sequence, typename _Category>
1111 _GLIBCXX20_CONSTEXPR
1112 inline bool
1113 __valid_range(const _Safe_iterator<_Iterator, _Sequence,
1114 _Category>& __first,
1115 const _Safe_iterator<_Iterator, _Sequence,
1116 _Category>& __last,
1117 typename _Distance_traits<_Iterator>::__type& __dist)
1118 {
1119 if (std::__is_constant_evaluated())
1120 return true;
1121
1122 return __first._M_valid_range(__last, __dist);
1123 }
1124
1125 template<typename _Iterator, typename _Sequence, typename _Category>
1126 _GLIBCXX20_CONSTEXPR
1127 inline bool
1128 __valid_range(const _Safe_iterator<_Iterator, _Sequence,
1129 _Category>& __first,
1130 const _Safe_iterator<_Iterator, _Sequence,
1131 _Category>& __last)
1132 {
1133 if (std::__is_constant_evaluated())
1134 return true;
1135
1136 typename _Distance_traits<_Iterator>::__type __dist;
1137 return __first._M_valid_range(__last, __dist);
1138 }
1139
1140 template<typename _Iterator, typename _Sequence, typename _Category,
1141 typename _Size>
1142 _GLIBCXX20_CONSTEXPR
1143 inline bool
1144 __can_advance(const _Safe_iterator<_Iterator, _Sequence, _Category>& __it,
1145 _Size __n)
1146 {
1147 if (std::__is_constant_evaluated())
1148 return true;
1149
1150 return __it._M_can_advance(__n);
1151 }
1152
1153 template<typename _Iterator, typename _Sequence, typename _Category,
1154 typename _Diff>
1155 _GLIBCXX20_CONSTEXPR
1156 inline bool
1157 __can_advance(const _Safe_iterator<_Iterator, _Sequence, _Category>& __it,
1159 int __way)
1160 {
1161 if (std::__is_constant_evaluated())
1162 return true;
1163
1164 return __it._M_can_advance(__dist, __way);
1165 }
1166
1167 template<typename _Iterator, typename _Sequence>
1168 _GLIBCXX20_CONSTEXPR _Iterator
1169 __base(const _Safe_iterator<_Iterator, _Sequence,
1170 std::random_access_iterator_tag>& __it)
1171 { return __it.base(); }
1172
1173#if __cplusplus < 201103L
1174 template<typename _Iterator, typename _Sequence>
1175 struct _Unsafe_type<_Safe_iterator<_Iterator, _Sequence> >
1176 { typedef _Iterator _Type; };
1177#endif
1178
1179 template<typename _Iterator, typename _Sequence>
1180 inline _Iterator
1181 __unsafe(const _Safe_iterator<_Iterator, _Sequence>& __it)
1182 { return __it.base(); }
1183
1184} // namespace __gnu_debug
1185
1186#undef _GLIBCXX20_CONSTEXPR_NON_LITERAL_SCOPE_END
1187#undef _GLIBCXX20_CONSTEXPR_NON_LITERAL_SCOPE_BEGIN
1188#undef _GLIBCXX_DEBUG_VERIFY_DIST_OPERANDS
1189#undef _GLIBCXX_DEBUG_VERIFY_REL_OPERANDS
1190#undef _GLIBCXX_DEBUG_VERIFY_EQ_OPERANDS
1191#undef _GLIBCXX_DEBUG_VERIFY_OPERANDS
1192
1193#include <debug/safe_iterator.tcc>
1194
1195#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.