Home | History | Annotate | Line # | Download | only in gdbsupport
      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