| /* A range adapter that wraps multiple ranges |
| Copyright (C) 2022-2023 Free Software Foundation, Inc. |
| |
| This file is part of GDB. |
| |
| This program is free software; you can redistribute it and/or modify |
| it under the terms of the GNU General Public License as published by |
| the Free Software Foundation; either version 3 of the License, or |
| (at your option) any later version. |
| |
| This program is distributed in the hope that it will be useful, |
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| GNU General Public License for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with this program. If not, see <http://www.gnu.org/licenses/>. */ |
| |
| #ifndef GDBSUPPORT_RANGE_CHAIN_H |
| #define GDBSUPPORT_RANGE_CHAIN_H |
| |
| /* A range adapter that presents a number of ranges as if it were a |
| single range. That is, iterating over a range_chain will iterate |
| over each sub-range in order. */ |
| template<typename Range> |
| struct range_chain |
| { |
| /* The type of the iterator that is created by this range. */ |
| class iterator |
| { |
| public: |
| |
| iterator (const std::vector<Range> &ranges, size_t idx) |
| : m_index (idx), |
| m_ranges (ranges) |
| { |
| skip_empty (); |
| } |
| |
| bool operator== (const iterator &other) const |
| { |
| if (m_index != other.m_index || &m_ranges != &other.m_ranges) |
| return false; |
| if (m_current.has_value () != other.m_current.has_value ()) |
| return false; |
| if (m_current.has_value ()) |
| return *m_current == *other.m_current; |
| return true; |
| } |
| |
| bool operator!= (const iterator &other) const |
| { |
| return !(*this == other); |
| } |
| |
| iterator &operator++ () |
| { |
| ++*m_current; |
| if (*m_current == m_ranges[m_index].end ()) |
| { |
| ++m_index; |
| skip_empty (); |
| } |
| return *this; |
| } |
| |
| typename Range::iterator::value_type operator* () const |
| { |
| return **m_current; |
| } |
| |
| private: |
| /* Skip empty sub-ranges. If this finds a valid sub-range, |
| m_current is updated to point to its start; otherwise, |
| m_current is reset. */ |
| void skip_empty () |
| { |
| for (; m_index < m_ranges.size (); ++m_index) |
| { |
| m_current = m_ranges[m_index].begin (); |
| if (*m_current != m_ranges[m_index].end ()) |
| return; |
| } |
| m_current.reset (); |
| } |
| |
| /* Index into the vector indicating where the current iterator |
| comes from. */ |
| size_t m_index; |
| /* The current iterator into one of the vector ranges. If no |
| value then this (outer) iterator is at the end of the overall |
| range. */ |
| gdb::optional<typename Range::iterator> m_current; |
| /* Vector of ranges. */ |
| const std::vector<Range> &m_ranges; |
| }; |
| |
| /* Create a new range_chain. */ |
| template<typename T> |
| range_chain (T &&ranges) |
| : m_ranges (std::forward<T> (ranges)) |
| { |
| } |
| |
| iterator begin () const |
| { |
| return iterator (m_ranges, 0); |
| } |
| |
| iterator end () const |
| { |
| return iterator (m_ranges, m_ranges.size ()); |
| } |
| |
| private: |
| |
| /* The sub-ranges. */ |
| std::vector<Range> m_ranges; |
| }; |
| |
| #endif /* GDBSUPPORT_RANGE_CHAIN_H */ |