OpenTTD Source 20250702-master-g226b098c55
alternating_iterator.hpp
Go to the documentation of this file.
1/*
2 * This file is part of OpenTTD.
3 * OpenTTD 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, version 2.
4 * OpenTTD 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.
5 * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
6 */
7
10#ifndef ALTERNATING_ITERATOR_HPP
11#define ALTERNATING_ITERATOR_HPP
12
13#include <ranges>
14
19template <typename Titer>
21public:
22 using value_type = typename Titer::value_type;
23 using difference_type = std::ptrdiff_t;
24 using iterator_category = std::forward_iterator_tag;
25 using pointer = typename Titer::pointer;
26 using reference = typename Titer::reference;
27
28 AlternatingIterator() = default;
29
37 AlternatingIterator(Titer first, Titer last, Titer middle, bool begin) : first(first), last(last), middle(middle)
38 {
39 /* Starting from the end is not supported, unless the range is empty. */
40 assert(first == last || middle != last);
41
42 this->position = begin ? 0 : std::distance(this->first, this->last);
43 this->before = middle;
44 this->after = middle;
45 this->next_state = this->before == this->first;
46 this->state = this->next_state;
47 }
48
49 bool operator==(const AlternatingIterator &rhs) const
50 {
51 assert(this->first == rhs.first);
52 assert(this->last == rhs.last);
53 assert(this->middle == rhs.middle);
54 return this->position == rhs.position;
55 }
56
57 std::strong_ordering operator<=>(const AlternatingIterator &rhs) const
58 {
59 assert(this->first == rhs.first);
60 assert(this->last == rhs.last);
61 assert(this->middle == rhs.middle);
62 return this->position <=> rhs.position;
63 }
64
65 inline reference operator*() const
66 {
67 return *this->Base();
68 }
69
70 AlternatingIterator &operator++()
71 {
72 size_t size = static_cast<size_t>(std::distance(this->first, this->last));
73 assert(this->position < size);
74
75 ++this->position;
76 if (this->position < size) this->Next();
77
78 return *this;
79 }
80
81 AlternatingIterator operator++(int)
82 {
83 AlternatingIterator result = *this;
84 ++*this;
85 return result;
86 }
87
88 inline Titer Base() const
89 {
90 return this->state ? this->after : this->before;
91 }
92
93private:
94 Titer first;
95 Titer last;
96 Titer middle;
97
98 Titer after;
99 Titer before;
100
101 size_t position;
102
104 bool state;
105
106 void Next()
107 {
108 this->state = this->next_state;
109 if (this->next_state) {
110 assert(this->after != this->last);
111 ++this->after;
112 this->next_state = this->before == this->first;
113 } else {
114 assert(this->before != this->first);
115 --this->before;
116 this->next_state = std::next(this->after) != this->last;
117 }
118 }
119};
120
121template <typename Titer>
122class AlternatingView : public std::ranges::view_interface<AlternatingIterator<Titer>> {
123public:
124 AlternatingView(std::ranges::viewable_range auto &&range, Titer middle) :
125 first(std::ranges::begin(range)), last(std::ranges::end(range)), middle(middle)
126 {
127 }
128
129 auto begin() const
130 {
131 return AlternatingIterator{first, last, middle, true};
132 }
133
134 auto end() const
135 {
136 return AlternatingIterator{first, last, middle, false};
137 }
138
139private:
140 Titer first;
141 Titer last;
142 Titer middle;
143};
144
145#endif /* ALTERNATING_ITERATOR_HPP */
Iterator that alternately takes from the "middle" of a range.
Titer last
Initial last iterator.
Titer before
Current iterator before the middle.
bool next_state
Next state for advancing iterator. If true take from after middle, otherwise take from before middle.
size_t position
Position within the entire range.
Titer middle
Initial middle iterator.
AlternatingIterator(Titer first, Titer last, Titer middle, bool begin)
Construct an AlternatingIterator.
Titer first
Initial first iterator.
bool state
Current state for reading iterator. If true take from after middle, otherwise take from before middle...
Titer after
Current iterator after the middle.
Titer middle
Iterator to middle element.
Titer first
Iterator to first element.
Titer last
Iterator to last element.