1 /* A safe iterator for GDB, the GNU debugger. 2 Copyright (C) 2018-2024 Free Software Foundation, Inc. 3 4 This file is part of GDB. 5 6 This program is free software; you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by 8 the Free Software Foundation; either version 3 of the License, or 9 (at your option) any later version. 10 11 This program 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 You should have received a copy of the GNU General Public License 17 along with this program. If not, see <http://www.gnu.org/licenses/>. */ 18 19 #ifndef COMMON_SAFE_ITERATOR_H 20 #define COMMON_SAFE_ITERATOR_H 21 22 #include <type_traits> 23 24 /* A forward iterator that wraps Iterator, such that when iterating 25 with iterator IT, it is possible to delete *IT without invalidating 26 IT. Suitably wrapped in a range type and used with range-for, this 27 allow convenient patterns like this: 28 29 // range_safe() returns a range type whose begin()/end() methods 30 // return safe iterators. 31 for (foo *f : range_safe ()) 32 { 33 if (f->should_delete ()) 34 { 35 // The ++it operation implicitly done by the range-for is 36 // still OK after this. 37 delete f; 38 } 39 } 40 */ 41 42 template<typename Iterator> 43 class basic_safe_iterator 44 { 45 public: 46 typedef basic_safe_iterator self_type; 47 typedef typename Iterator::value_type value_type; 48 typedef typename Iterator::reference reference; 49 typedef typename Iterator::pointer pointer; 50 typedef typename Iterator::iterator_category iterator_category; 51 typedef typename Iterator::difference_type difference_type; 52 53 /* Construct the begin iterator using the given arguments; the end iterator is 54 default constructed. */ 55 template<typename... Args> 56 explicit basic_safe_iterator (Args &&...args) 57 : m_it (std::forward<Args> (args)...), 58 m_next (m_it) 59 { 60 if (m_it != m_end) 61 ++m_next; 62 } 63 64 /* Construct the iterator using the first argument, and construct 65 the end iterator using the second argument. */ 66 template<typename Arg> 67 explicit basic_safe_iterator (Arg &&arg, Arg &&arg2) 68 : m_it (std::forward<Arg> (arg)), 69 m_next (m_it), 70 m_end (std::forward<Arg> (arg2)) 71 { 72 if (m_it != m_end) 73 ++m_next; 74 } 75 76 /* Create a one-past-end iterator. */ 77 basic_safe_iterator () 78 {} 79 80 typename std::invoke_result<decltype(&Iterator::operator*), Iterator>::type 81 operator* () const 82 { return *m_it; } 83 84 self_type &operator++ () 85 { 86 m_it = m_next; 87 if (m_it != m_end) 88 ++m_next; 89 return *this; 90 } 91 92 bool operator== (const self_type &other) const 93 { return m_it == other.m_it; } 94 95 bool operator!= (const self_type &other) const 96 { return m_it != other.m_it; } 97 98 private: 99 /* The current element. */ 100 Iterator m_it {}; 101 102 /* The next element. Always one element ahead of M_IT. */ 103 Iterator m_next {}; 104 105 /* A one-past-end iterator. */ 106 Iterator m_end {}; 107 }; 108 109 /* A range adapter that wraps another range, and then returns safe 110 iterators wrapping the original range's iterators. */ 111 112 template<typename Range> 113 class basic_safe_range 114 { 115 public: 116 117 typedef basic_safe_iterator<typename Range::iterator> iterator; 118 119 explicit basic_safe_range (Range range) 120 : m_range (range) 121 { 122 } 123 124 iterator begin () 125 { 126 return iterator (m_range.begin (), m_range.end ()); 127 } 128 129 iterator end () 130 { 131 return iterator (m_range.end (), m_range.end ()); 132 } 133 134 private: 135 136 Range m_range; 137 }; 138 139 #endif /* COMMON_SAFE_ITERATOR_H */ 140