xref: /netbsd-src/external/gpl3/gdb/dist/gdbsupport/range-chain.h (revision 5ba1f45f2a09259cc846f20c7c5501604d633c90)
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