1 /* A range adapter that wraps multiple ranges 2 Copyright (C) 2022-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 GDBSUPPORT_RANGE_CHAIN_H 20 #define GDBSUPPORT_RANGE_CHAIN_H 21 22 /* A range adapter that presents a number of ranges as if it were a 23 single range. That is, iterating over a range_chain will iterate 24 over each sub-range in order. */ 25 template<typename Range> 26 struct range_chain 27 { 28 /* The type of the iterator that is created by this range. */ 29 class iterator 30 { 31 public: 32 33 iterator (const std::vector<Range> &ranges, size_t idx) 34 : m_index (idx), 35 m_ranges (ranges) 36 { 37 skip_empty (); 38 } 39 40 bool operator== (const iterator &other) const 41 { 42 if (m_index != other.m_index || &m_ranges != &other.m_ranges) 43 return false; 44 if (m_current.has_value () != other.m_current.has_value ()) 45 return false; 46 if (m_current.has_value ()) 47 return *m_current == *other.m_current; 48 return true; 49 } 50 51 bool operator!= (const iterator &other) const 52 { 53 return !(*this == other); 54 } 55 56 iterator &operator++ () 57 { 58 ++*m_current; 59 if (*m_current == m_ranges[m_index].end ()) 60 { 61 ++m_index; 62 skip_empty (); 63 } 64 return *this; 65 } 66 67 typename Range::iterator::value_type operator* () const 68 { 69 return **m_current; 70 } 71 72 private: 73 /* Skip empty sub-ranges. If this finds a valid sub-range, 74 m_current is updated to point to its start; otherwise, 75 m_current is reset. */ 76 void skip_empty () 77 { 78 for (; m_index < m_ranges.size (); ++m_index) 79 { 80 m_current = m_ranges[m_index].begin (); 81 if (*m_current != m_ranges[m_index].end ()) 82 return; 83 } 84 m_current.reset (); 85 } 86 87 /* Index into the vector indicating where the current iterator 88 comes from. */ 89 size_t m_index; 90 /* The current iterator into one of the vector ranges. If no 91 value then this (outer) iterator is at the end of the overall 92 range. */ 93 std::optional<typename Range::iterator> m_current; 94 /* Vector of ranges. */ 95 const std::vector<Range> &m_ranges; 96 }; 97 98 /* Create a new range_chain. */ 99 template<typename T> 100 range_chain (T &&ranges) 101 : m_ranges (std::forward<T> (ranges)) 102 { 103 } 104 105 iterator begin () const 106 { 107 return iterator (m_ranges, 0); 108 } 109 110 iterator end () const 111 { 112 return iterator (m_ranges, m_ranges.size ()); 113 } 114 115 private: 116 117 /* The sub-ranges. */ 118 std::vector<Range> m_ranges; 119 }; 120 121 #endif /* GDBSUPPORT_RANGE_CHAIN_H */ 122