wxMaxima
Loading...
Searching...
No Matches
CellIterators.h
Go to the documentation of this file.
1// -*- mode: c++; c-file-style: "linux"; c-basic-offset: 2; indent-tabs-mode: nil -*-
2//
3// Copyright (C) 2020 Kuba Ober <kuba@bertec.com>
4//
5// This program is free software; you can redistribute it and/or modify
6// it under the terms of the GNU General Public License as published by
7// the Free Software Foundation; either version 2 of the License, or
8// (at your option) any later version.
9//
10// This program is distributed in the hope that it will be useful,
11// but WITHOUT ANY WARRANTY; without even the implied warranty of
12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13// GNU General Public License for more details.
14//
15//
16// You should have received a copy of the GNU General Public License
17// along with this program; if not, write to the Free Software
18// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19//
20// SPDX-License-Identifier: GPL-2.0+
21
27#ifndef CELLITERATORS_H
28#define CELLITERATORS_H
29
30#include <wx/debug.h>
31#include <memory>
32#include <type_traits>
33#include <iterator>
34#include <vector>
35
36template <typename Cell> class CellListIterator final {
37 static_assert(std::is_class<Cell>::value, "The type argument must be a class");
38 Cell *m_ptr = {};
39
40public:
41 using iterator_category = std::forward_iterator_tag;
42 using value_type = Cell;
43 using difference_type = std::ptrdiff_t;
44 using pointer = Cell *;
45 using reference = Cell &;
46
47 constexpr CellListIterator() = default;
48 constexpr explicit CellListIterator(const std::unique_ptr<Cell> &p)
49 : m_ptr(p.get()) {}
50 constexpr explicit CellListIterator(Cell *p) : m_ptr(p) {}
51 constexpr CellListIterator(const CellListIterator &o) = default;
52 constexpr CellListIterator &operator=(const CellListIterator &o) = default;
53 constexpr CellListIterator operator++(int) {
54 auto ret = *this;
55 return operator++(), ret;
56 }
57 // constexpr fails if wxASSERT contains assembler code, which is true on MinGW
58 CellListIterator &operator++() {
59 if (m_ptr)
60 {
61 const auto *const prev = m_ptr;
62 m_ptr = m_ptr->GetNext();
63 wxASSERT(prev != m_ptr);
64 }
65 return *this;
66 }
67 constexpr bool operator==(const CellListIterator &o) const {
68 return m_ptr == o.m_ptr;
69 }
70 constexpr bool operator!=(const CellListIterator &o) const {
71 return m_ptr != o.m_ptr;
72 }
73 constexpr operator bool() const { return m_ptr; }
74 constexpr operator Cell *() const { return m_ptr; }
75 constexpr Cell *operator->() const { return m_ptr; }
76};
77
78template <typename Cell> class CellListAdapter final {
79 static_assert(std::is_class<Cell>::value, "The type argument must be a class");
80 Cell *m_cell = {};
83
84public:
85 explicit CellListAdapter(Cell *cell) : m_cell(cell) {}
86 constexpr iterator begin() const { return iterator(m_cell); }
87 static constexpr iterator end() { return {}; }
88 constexpr const_iterator cbegin() const { return const_iterator(m_cell); }
89 static constexpr const_iterator cend() { return {}; }
90};
91
107template <typename Cell>
109 static_assert(std::is_class<Cell>::value, "The type argument must be a class");
110 struct Frame {
111 Cell *parent;
112 size_t nextIndex;
113 };
114 Cell *m_ptr = {};
115 std::vector<Frame> m_stack;
116
117public:
118 using iterator_category = std::forward_iterator_tag;
119 using value_type = Cell;
120 using difference_type = std::ptrdiff_t;
121 using pointer = Cell *;
122 using reference = Cell &;
123
124 CellDrawListIterator() = default;
125 explicit CellDrawListIterator(const std::unique_ptr<Cell> &p) : m_ptr(p.get()) {}
126 explicit CellDrawListIterator(Cell *p) : m_ptr(p) {}
127 CellDrawListIterator(const CellDrawListIterator &o) = default;
128 CellDrawListIterator &operator=(const CellDrawListIterator &o) = default;
129 CellDrawListIterator operator++(int) {
130 auto ret = *this;
131 return operator++(), ret;
132 }
133 CellDrawListIterator &operator++()
134 {
135 if (!m_ptr)
136 return *this;
137
138 const auto *const prev = m_ptr;
139 Cell *next = {};
140
141 if (prev->IsBrokenIntoLines() && prev->GetBrokenCellCount() > 0) {
142 // Descend into this cell's broken-form pieces. Once piece 0's own
143 // chain (and anything nested inside it) is exhausted, resume here
144 // at index 1.
145 m_stack.push_back(Frame{const_cast<Cell *>(prev), 1});
146 next = prev->GetBrokenCell(0);
147 } else {
148 next = prev->GetNext();
149 while (!next && !m_stack.empty()) {
150 Frame &frame = m_stack.back();
151 if (frame.nextIndex < frame.parent->GetBrokenCellCount()) {
152 next = frame.parent->GetBrokenCell(frame.nextIndex++);
153 continue;
154 }
155 // This broken cell's pieces are all done: resume with whatever
156 // originally followed it, or -- if it has no successor of its
157 // own -- keep unwinding into whatever enclosing broken cell (if
158 // any) we're nested inside of.
159 Cell *const afterParent = frame.parent->GetNext();
160 m_stack.pop_back();
161 next = afterParent;
162 }
163 }
164
165 m_ptr = next;
166 wxASSERT(prev != m_ptr);
167 return *this;
168 }
169 bool operator==(const CellDrawListIterator &o) const
170 { return m_ptr == o.m_ptr; }
171 bool operator!=(const CellDrawListIterator &o) const
172 { return m_ptr != o.m_ptr; }
173 operator bool() const { return m_ptr; }
174 operator Cell*() const { return m_ptr; }
175 Cell *operator->() const { return m_ptr; }
176};
177
178template <typename Cell> class CellDrawListAdapter final
179{
180 static_assert(std::is_class<Cell>::value, "The type argument must be a class");
181 Cell *m_cell = {};
184
185public:
186 explicit CellDrawListAdapter(Cell *cell) : m_cell(cell) {}
187 constexpr iterator begin() const { return iterator(m_cell); }
188 static constexpr iterator end() { return {}; }
189 constexpr const_iterator cbegin() const { return const_iterator(m_cell); }
190 static constexpr const_iterator cend() { return {}; }
191};
192
193class Cell;
194
197{
198 enum class Advance { Always, OnlyIfNull };
199 const Cell *m_parentCell = {};
200 Cell *m_innerCell = {};
201 size_t m_index = 0;
202 size_t m_endIndex = 0;
203
204 static size_t GetInnerCellCount(const Cell *cell);
205 static Cell *GetInnerCell(const Cell *cell, size_t index);
206public:
207 using iterator_category = std::forward_iterator_tag;
208 using value_type = Cell;
209 using difference_type = std::ptrdiff_t;
210 using pointer = Cell *;
211 using reference = Cell &;
212
213 InnerCellIterator() = default;
214 explicit InnerCellIterator(Cell *parentCell) :
215 m_parentCell(parentCell),
216 m_endIndex(parentCell ? GetInnerCellCount(parentCell) : 0)
217 {
218 FindFirstInnerCell();
219 }
220 InnerCellIterator(const InnerCellIterator &o) = default;
221 InnerCellIterator &operator=(const InnerCellIterator &o) = default;
222 InnerCellIterator operator++(int)
223 {
224 auto ret = *this;
225 return operator++(), ret;
226 }
227 InnerCellIterator &operator++()
228 {
229 if (m_parentCell)
230 AdvanceLoop(Advance::Always);
231 return *this;
232 }
233 bool operator==(const InnerCellIterator &o) const
234 { return m_innerCell == o.m_innerCell; }
235 bool operator!=(const InnerCellIterator &o) const
236 { return m_innerCell != o.m_innerCell; }
237 operator bool() const { return m_innerCell; }
238 operator Cell*() const { return m_innerCell; }
239 Cell *operator->() const { return m_innerCell; }
240
241private:
242 void FindFirstInnerCell();
243 void AdvanceLoop(Advance mode);
244};
245
246inline void InnerCellIterator::FindFirstInnerCell()
247{
248 if (m_endIndex)
249 {
250 m_innerCell = GetInnerCell(m_parentCell, 0);
251 AdvanceLoop(Advance::OnlyIfNull);
252 }
253}
254
255inline void InnerCellIterator::AdvanceLoop(Advance mode)
256{
257 const Cell *prev = m_innerCell;
258 if (mode == Advance::OnlyIfNull && prev)
259 return;
260 for (;;)
261 {
262 ++m_index;
263 if (m_index == m_endIndex)
264 {
265 m_innerCell = nullptr;
266 break;
267 }
268 m_innerCell = GetInnerCell(m_parentCell, m_index);
269 wxASSERT(!prev || prev != m_innerCell);
270 if (m_innerCell)
271 break;
272 }
273}
274
275class InnerCellAdapter final {
277 iterator const m_iter;
278
279public:
280 explicit InnerCellAdapter(const iterator &) = delete;
281 explicit InnerCellAdapter(Cell *cell) : m_iter(cell) {}
282 iterator begin() const { return m_iter; }
283 static iterator end() { return {}; }
284};
285
286#endif
Definition: CellIterators.h:179
Walks the "draw list": the flattened sequence of cells that make up one displayed line,...
Definition: CellIterators.h:108
Definition: CellIterators.h:78
Definition: CellIterators.h:36
The base class all cell types the worksheet can consist of are derived from.
Definition: Cell.h:148
Cell * GetNext() const
Get the next cell in the list.
Definition: Cell.h:803
virtual Cell * GetBrokenCell(size_t index) const
Retrieve a piece of this cell's broken (linear/1D) display; see GetBrokenCellCount().
Definition: Cell.h:829
Definition: CellIterators.h:275
Iterates the inner cells of a cell.
Definition: CellIterators.h:197