OpenTTD Source 20260208-master-g43af8e94d0
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 <https://www.gnu.org/licenses/old-licenses/gpl-2.0>.
6 */
7
9
10#ifndef ALTERNATING_ITERATOR_HPP
11#define ALTERNATING_ITERATOR_HPP
12
13#include <ranges>
14
19template <typename Titer>
20class AlternatingIterator {
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.
AlternatingIterator(Titer first, Titer last, Titer middle, bool begin)
Construct an AlternatingIterator.
Titer middle
Iterator to middle element.
Titer first
Iterator to first element.
Titer last
Iterator to last element.