openMSX
view.hh
Go to the documentation of this file.
1#ifndef VIEW_HH
2#define VIEW_HH
3
4#ifndef _MSC_VER
5#include "semiregular.hh"
6#endif
7#include <algorithm>
8#include <functional>
9#include <iterator>
10#include <tuple>
11#include <type_traits>
12
13namespace view {
14namespace detail {
15
16template<typename Iterator>
17[[nodiscard]] constexpr Iterator safe_next(Iterator first, Iterator last, size_t n, std::input_iterator_tag)
18{
19 while (n-- && (first != last)) ++first;
20 return first;
21}
22
23template<typename Iterator>
24[[nodiscard]] constexpr Iterator safe_next(Iterator first, Iterator last, size_t n, std::random_access_iterator_tag)
25{
26 return first + std::min<size_t>(n, last - first);
27}
28
29template<typename Iterator>
30[[nodiscard]] constexpr Iterator safe_prev(Iterator first, Iterator last, size_t n, std::bidirectional_iterator_tag)
31{
32 while (n-- && (first != last)) --last;
33 return last;
34}
35
36template<typename Iterator>
37[[nodiscard]] constexpr Iterator safe_prev(Iterator first, Iterator last, size_t n, std::random_access_iterator_tag)
38{
39 return last - std::min<size_t>(n, last - first);
40}
41
42
43template<typename Range>
44class Drop
45{
46public:
47 constexpr Drop(Range&& range_, size_t n_)
48 : range(std::forward<Range>(range_))
49 , n(n_)
50 {
51 }
52
53 [[nodiscard]] constexpr auto begin() const {
54 using Iterator = decltype(std::begin(range));
55 return safe_next(std::begin(range), std::end(range), n,
56 typename std::iterator_traits<Iterator>::iterator_category());
57 }
58
59 [[nodiscard]] constexpr auto end() const {
60 return std::end(range);
61 }
62
63private:
64 Range range;
65 size_t n;
66};
67
68
69template<typename Range>
71{
72public:
73 constexpr DropBack(Range&& range_, size_t n_)
74 : range(std::forward<Range>(range_))
75 , n(n_)
76 {
77 }
78
79 [[nodiscard]] constexpr auto begin() const {
80 return std::begin(range);
81 }
82
83 [[nodiscard]] constexpr auto end() const {
84 using Iterator = decltype(std::begin(range));
85 return safe_prev(std::begin(range), std::end(range), n,
86 typename std::iterator_traits<Iterator>::iterator_category());
87 }
88
89private:
90 Range range;
91 size_t n;
92};
93
94
95template<typename Range>
97{
98public:
99 constexpr explicit Reverse(Range&& range_)
100 : range(std::forward<Range>(range_))
101 {
102 }
103
104 [[nodiscard]] constexpr auto begin() const { return range.rbegin(); }
105 [[nodiscard]] constexpr auto begin() { return range.rbegin(); }
106 [[nodiscard]] constexpr auto end() const { return range.rend(); }
107 [[nodiscard]] constexpr auto end() { return range.rend(); }
108 [[nodiscard]] constexpr auto rbegin() const { return range.begin(); }
109 [[nodiscard]] constexpr auto rbegin() { return range.begin(); }
110 [[nodiscard]] constexpr auto rend() const { return range.end(); }
111 [[nodiscard]] constexpr auto rend() { return range.end(); }
112
113private:
114 Range range;
115};
116
117
118template<typename Iterator, typename UnaryOp> class TransformIterator
119{
120public:
121 using return_type = std::invoke_result_t<UnaryOp, decltype(*std::declval<Iterator>())>;
122 using value_type = std::remove_reference_t<return_type>;
125 using difference_type = typename std::iterator_traits<Iterator>::difference_type;
126 using iterator_category = typename std::iterator_traits<Iterator>::iterator_category;
127
128public:
129 constexpr TransformIterator() = default;
130
131 constexpr TransformIterator(Iterator it_, UnaryOp op_)
132 : it(it_), op(op_)
133 {
134 }
135
136 // InputIterator, ForwardIterator
137
138 [[nodiscard]] constexpr return_type operator*() const { return std::invoke(op, *it); }
139
140 // pointer operator->() const not defined
141
143 {
144 ++it;
145 return *this;
146 }
147
149 {
150 auto copy = *this;
151 ++it;
152 return copy;
153 }
154
155 [[nodiscard]] constexpr friend bool operator==(const TransformIterator& x, const TransformIterator& y)
156 {
157 return x.it == y.it;
158 }
159
160 // BidirectionalIterator
161
163 {
164 --it;
165 return *this;
166 }
167
169 {
170 auto copy = *this;
171 --it;
172 return copy;
173 }
174
175 // RandomAccessIterator
176
178 {
179 it += n;
180 return *this;
181 }
182
184 {
185 it -= n;
186 return *this;
187 }
188
190 {
191 x += n;
192 return x;
193 }
195 {
196 x += n;
197 return x;
198 }
199
201 {
202 x -= n;
203 return x;
204 }
205
206 [[nodiscard]] constexpr friend difference_type operator-(const TransformIterator& x, const TransformIterator& y)
207 {
208 return x.it - y.it;
209 }
210
211 [[nodiscard]] constexpr reference operator[](difference_type n)
212 {
213 return *(*this + n);
214 }
215
216 [[nodiscard]] constexpr auto operator<=>(const TransformIterator& other) const
217 {
218 return it <=> other.it;
219 }
220
221private:
222 Iterator it;
223
224#ifndef _MSC_VER
225 // Wrapping in 'semiregular_t' is needed on libc++,
226 // see commit e81b34b5ed9f for more details.
227 using UO = semiregular_t<UnaryOp>;
228#else
229 // But it triggers compile errors on visual studio, though only in c++20
230 // mode. Hopefully we can remove this workaround in the future when we
231 // use std::views::transform().
232 using UO = UnaryOp;
233#endif
234 [[no_unique_address]] UO op;
235};
236
237template<typename Range, typename UnaryOp> class Transform
238{
239public:
240 constexpr Transform(Range&& range_, UnaryOp op_)
241 : range(std::forward<Range>(range_)), op(op_)
242 {
243 }
244
245 [[nodiscard]] constexpr auto begin() const
246 {
247 return TransformIterator(std::begin(range), op);
248 }
249 [[nodiscard]] constexpr auto end() const
250 {
251 return TransformIterator(std::end(range), op);
252 }
253 [[nodiscard]] constexpr auto rbegin() const
254 {
255 return TransformIterator(std::rbegin(range), op);
256 }
257 [[nodiscard]] constexpr auto rend() const
258 {
259 return TransformIterator(std::rend(range), op);
260 }
261
262 [[nodiscard]] constexpr auto size() const { return range.size(); }
263 [[nodiscard]] constexpr auto empty() const { return range.empty(); }
264
265 [[nodiscard]] constexpr auto front() const { return op(range.front()); }
266 [[nodiscard]] constexpr auto back() const { return op(range.back()); }
267
268 [[nodiscard]] constexpr auto operator[](size_t idx) const {
269 return std::invoke(op, range[idx]);
270 }
271
272private:
273 Range range;
274 [[no_unique_address]] UnaryOp op;
275};
276
277
278template<typename Iterator, typename Sentinel, typename Predicate>
280{
281public:
282 using value_type = typename std::iterator_traits<Iterator>::value_type;
283 using reference = typename std::iterator_traits<Iterator>::reference;
284 using pointer = typename std::iterator_traits<Iterator>::pointer;
285 using difference_type = typename std::iterator_traits<Iterator>::difference_type;
286 using iterator_category = std::forward_iterator_tag;
287
288 constexpr FilteredIterator(Iterator it_, Sentinel last_, Predicate pred_)
289 : it(it_), last(last_), pred(pred_)
290 {
291 while (isFiltered()) ++it;
292 }
293
294 [[nodiscard]] constexpr friend bool operator==(const FilteredIterator& x, const FilteredIterator& y)
295 {
296 return x.it == y.it;
297 }
298
299 [[nodiscard]] constexpr reference operator*() const { return *it; }
300 [[nodiscard]] constexpr pointer operator->() const { return &*it; }
301
303 {
304 do {
305 ++it;
306 } while (isFiltered());
307 return *this;
308 }
310 {
311 FilteredIterator result = *this;
312 ++(*this);
313 return result;
314 }
315
316private:
317 [[nodiscard]] constexpr bool isFiltered()
318 {
319 return (it != last) && !std::invoke(pred, *it);
320 }
321
322private:
323 Iterator it;
324 Sentinel last;
325 [[no_unique_address]] Predicate pred;
326};
327
328template<typename Range, typename Predicate>
330{
331public:
332 using Iterator = decltype(std::begin(std::declval<Range>()));
333 using Sentinel = decltype(std::end (std::declval<Range>()));
335
336 constexpr Filter(Range&& range_, Predicate pred_)
337 : range(std::forward<Range>(range_)), pred(pred_)
338 {
339 }
340
341 [[nodiscard]] constexpr F_Iterator begin() const
342 {
343 return {std::begin(range), std::end(range), pred};
344 }
345 [[nodiscard]] constexpr F_Iterator end() const
346 {
347 // TODO should be a 'FilteredSentinel', but that only works well
348 // in c++20 (and c++20 already has 'std::views::filter').
349 return {std::end(range), std::end(range), pred};
350 }
351
352private:
353 Range range;
354 [[no_unique_address]] Predicate pred;
355};
356
357} // namespace detail
358
359template<typename Range>
360[[nodiscard]] constexpr auto drop(Range&& range, size_t n)
361{
362 return detail::Drop<Range>(std::forward<Range>(range), n);
363}
364
365template<typename Range>
366[[nodiscard]] constexpr auto drop_back(Range&& range, size_t n)
367{
368 return detail::DropBack<Range>(std::forward<Range>(range), n);
369}
370
371template<typename Range>
372[[nodiscard]] constexpr auto reverse(Range&& range)
373{
374 return detail::Reverse<Range>(std::forward<Range>(range));
375}
376
377template<typename Range, typename UnaryOp>
378[[nodiscard]] constexpr auto transform(Range&& range, UnaryOp op)
379{
380 return detail::Transform<Range, UnaryOp>(std::forward<Range>(range), op);
381}
382
383template<typename Map> [[nodiscard]] constexpr auto keys(Map&& map)
384{
385 return transform(std::forward<Map>(map),
386 [](const auto& t) -> auto& { return std::get<0>(t); });
387}
388
389template<typename Map> [[nodiscard]] constexpr auto values(Map&& map)
390{
391 return transform(std::forward<Map>(map),
392 [](const auto& t) -> auto& { return std::get<1>(t); });
393}
394
395template<typename ForwardRange, typename Predicate>
396[[nodiscard]] auto filter(ForwardRange&& range, Predicate pred)
397{
398 return detail::Filter<ForwardRange, Predicate>{std::forward<ForwardRange>(range), pred};
399}
400
401} // namespace view
402
403#endif
TclObject t
constexpr DropBack(Range &&range_, size_t n_)
Definition: view.hh:73
constexpr auto begin() const
Definition: view.hh:79
constexpr auto end() const
Definition: view.hh:83
constexpr Drop(Range &&range_, size_t n_)
Definition: view.hh:47
constexpr auto begin() const
Definition: view.hh:53
constexpr auto end() const
Definition: view.hh:59
constexpr F_Iterator end() const
Definition: view.hh:345
decltype(std::end(std::declval< Range >())) Sentinel
Definition: view.hh:333
constexpr Filter(Range &&range_, Predicate pred_)
Definition: view.hh:336
constexpr F_Iterator begin() const
Definition: view.hh:341
decltype(std::begin(std::declval< Range >())) Iterator
Definition: view.hh:332
constexpr pointer operator->() const
Definition: view.hh:300
typename std::iterator_traits< Iterator >::value_type value_type
Definition: view.hh:282
typename std::iterator_traits< Iterator >::difference_type difference_type
Definition: view.hh:285
constexpr reference operator*() const
Definition: view.hh:299
constexpr FilteredIterator operator++(int)
Definition: view.hh:309
typename std::iterator_traits< Iterator >::pointer pointer
Definition: view.hh:284
constexpr FilteredIterator & operator++()
Definition: view.hh:302
typename std::iterator_traits< Iterator >::reference reference
Definition: view.hh:283
constexpr friend bool operator==(const FilteredIterator &x, const FilteredIterator &y)
Definition: view.hh:294
constexpr FilteredIterator(Iterator it_, Sentinel last_, Predicate pred_)
Definition: view.hh:288
std::forward_iterator_tag iterator_category
Definition: view.hh:286
constexpr auto rend() const
Definition: view.hh:110
constexpr auto end()
Definition: view.hh:107
constexpr auto rend()
Definition: view.hh:111
constexpr auto end() const
Definition: view.hh:106
constexpr auto begin() const
Definition: view.hh:104
constexpr auto rbegin()
Definition: view.hh:109
constexpr auto rbegin() const
Definition: view.hh:108
constexpr auto begin()
Definition: view.hh:105
constexpr Reverse(Range &&range_)
Definition: view.hh:99
constexpr auto operator<=>(const TransformIterator &other) const
Definition: view.hh:216
std::invoke_result_t< UnaryOp, decltype(*std::declval< Iterator >())> return_type
Definition: view.hh:121
constexpr TransformIterator(Iterator it_, UnaryOp op_)
Definition: view.hh:131
constexpr TransformIterator & operator--()
Definition: view.hh:162
constexpr friend difference_type operator-(const TransformIterator &x, const TransformIterator &y)
Definition: view.hh:206
std::remove_reference_t< return_type > value_type
Definition: view.hh:122
constexpr TransformIterator()=default
constexpr TransformIterator operator++(int)
Definition: view.hh:148
constexpr return_type operator*() const
Definition: view.hh:138
constexpr TransformIterator & operator-=(difference_type n)
Definition: view.hh:183
constexpr TransformIterator & operator++()
Definition: view.hh:142
constexpr TransformIterator operator--(int)
Definition: view.hh:168
typename std::iterator_traits< Iterator >::difference_type difference_type
Definition: view.hh:125
typename std::iterator_traits< Iterator >::iterator_category iterator_category
Definition: view.hh:126
constexpr friend bool operator==(const TransformIterator &x, const TransformIterator &y)
Definition: view.hh:155
constexpr friend TransformIterator operator+(difference_type n, TransformIterator x)
Definition: view.hh:194
constexpr friend TransformIterator operator+(TransformIterator x, difference_type n)
Definition: view.hh:189
constexpr friend TransformIterator operator-(TransformIterator x, difference_type n)
Definition: view.hh:200
constexpr reference operator[](difference_type n)
Definition: view.hh:211
constexpr TransformIterator & operator+=(difference_type n)
Definition: view.hh:177
constexpr auto operator[](size_t idx) const
Definition: view.hh:268
constexpr auto rbegin() const
Definition: view.hh:253
constexpr auto back() const
Definition: view.hh:266
constexpr auto begin() const
Definition: view.hh:245
constexpr auto empty() const
Definition: view.hh:263
constexpr Transform(Range &&range_, UnaryOp op_)
Definition: view.hh:240
constexpr auto rend() const
Definition: view.hh:257
constexpr auto size() const
Definition: view.hh:262
constexpr auto front() const
Definition: view.hh:265
constexpr auto end() const
Definition: view.hh:249
Definition: join.hh:10
constexpr KeyMatrixPosition x
Keyboard bindings.
Definition: Keyboard.cc:127
auto copy(InputRange &&range, OutputIter out)
Definition: ranges.hh:208
STL namespace.
constexpr Iterator safe_next(Iterator first, Iterator last, size_t n, std::input_iterator_tag)
Definition: view.hh:17
constexpr Iterator safe_prev(Iterator first, Iterator last, size_t n, std::bidirectional_iterator_tag)
Definition: view.hh:30
Definition: view.hh:13
auto filter(ForwardRange &&range, Predicate pred)
Definition: view.hh:396
constexpr auto transform(Range &&range, UnaryOp op)
Definition: view.hh:378
constexpr auto reverse(Range &&range)
Definition: view.hh:372
constexpr auto drop(Range &&range, size_t n)
Definition: view.hh:360
constexpr auto drop_back(Range &&range, size_t n)
Definition: view.hh:366
constexpr auto keys(Map &&map)
Definition: view.hh:383
constexpr auto values(Map &&map)
Definition: view.hh:389
std::conditional_t< std::is_default_constructible_v< T > &&std::is_copy_assignable_v< T >, T, sreg_impl::semiregular< T > > semiregular_t
Definition: semiregular.hh:176
constexpr auto begin(const zstring_view &x)
constexpr auto end(const zstring_view &x)