openMSX
xrange.hh
Go to the documentation of this file.
1#ifndef XRANGE_HH
2#define XRANGE_HH
3
4// Utility to iterate over a range of numbers,
5// modeled after python's xrange() function.
6//
7// Typically used as a more compact notation for some for-loop patterns:
8//
9// a) loop over [0, N)
10//
11// auto num = expensiveFunctionCall();
12// for (decltype(num) i = 0; i < num; ++i) { ... }
13//
14// for (auto i : xrange(expensiveFunctionCall()) { ... }
15//
16// b) loop over [B, E)
17//
18// auto i = func1();
19// auto end = func2();
20// for (/**/; i < end; ++i) { ... }
21//
22// for (auto i : xrange(func1(), func2()) { ... }
23//
24// Note that when using the xrange utility you also don't need to worry about
25// the correct type of the induction variable.
26//
27// Gcc is able to optimize the xrange() based loops to the same code as the
28// equivalent 'old-style' for loop.
29//
30// In an earlier version of this utility I also implemented the possibility to
31// specify a step size (currently the step size is always +1). Although I
32// believe that code was correct I still removed it because it was quite tricky
33// (getting the stop condition correct is not trivial) and we don't need it
34// currently.
35
36#include "narrow.hh"
37#include <cstddef>
38#include <iterator>
39#include <type_traits>
40
41template<typename T> struct XRange
42{
43 struct Iter
44 {
45 using difference_type = ptrdiff_t;
46 using value_type = T;
47 using pointer = T*;
48 using reference = T&;
49 using iterator_category = std::random_access_iterator_tag;
50
51 // ForwardIterator
52 [[nodiscard]] constexpr T operator*() const
53 {
54 return x;
55 }
56
57 constexpr Iter& operator++()
58 {
59 ++x;
60 return *this;
61 }
62 constexpr Iter operator++(int)
63 {
64 auto copy = *this;
65 ++x;
66 return copy;
67 }
68
69 // BidirectionalIterator
70 constexpr Iter& operator--()
71 {
72 --x;
73 return *this;
74 }
75 constexpr Iter operator--(int)
76 {
77 auto copy = *this;
78 --x;
79 return copy;
80 }
81
82 // RandomAccessIterator
84 {
85 x += narrow<T>(n);
86 return *this;
87 }
89 {
90 x -= narrow<T>(n);
91 return *this;
92 }
93
94 [[nodiscard]] constexpr friend Iter operator+(Iter i, difference_type n)
95 {
96 i += n;
97 return i;
98 }
99 [[nodiscard]] constexpr friend Iter operator+(difference_type n, Iter i)
100 {
101 i += n;
102 return i;
103 }
104 [[nodiscard]] constexpr friend Iter operator-(Iter i, difference_type n)
105 {
106 i -= n;
107 return i;
108 }
109
110 [[nodiscard]] constexpr friend difference_type operator-(const Iter& i, const Iter& j)
111 {
112 return i.x - j.x;
113 }
114
115 [[nodiscard]] constexpr T operator[](difference_type n)
116 {
117 return *(*this + n);
118 }
119
120 [[nodiscard]] /*constexpr*/ auto operator<=>(const Iter&) const = default;
121
122 T x;
123 };
124
125 [[nodiscard]] constexpr auto begin() const { return Iter{b}; }
126 [[nodiscard]] constexpr auto end() const { return Iter{e}; }
127
128 /*const*/ T b; // non-const to workaround msvc bug(?)
129 /*const*/ T e;
130};
131
132template<typename T> [[nodiscard]] constexpr auto xrange(T e)
133{
134 return XRange<T>{T(0), e < T(0) ? T(0) : e};
135}
136template<typename T1, typename T2> [[nodiscard]] constexpr auto xrange(T1 b, T2 e)
137{
138 static_assert(std::is_signed_v<T1> == std::is_signed_v<T2>);
139 using T = std::common_type_t<T1, T2>;
140 return XRange<T>{b, e < b ? b : e};
141}
142
143
146template<typename T, typename Op>
147constexpr void repeat(T n, Op op)
148{
149 for (auto i : xrange(n)) {
150 (void)i;
151 op();
152 }
153}
154
155#endif
constexpr friend Iter operator+(Iter i, difference_type n)
Definition xrange.hh:94
constexpr Iter & operator+=(difference_type n)
Definition xrange.hh:83
ptrdiff_t difference_type
Definition xrange.hh:45
auto operator<=>(const Iter &) const =default
constexpr Iter & operator--()
Definition xrange.hh:70
constexpr T operator[](difference_type n)
Definition xrange.hh:115
std::random_access_iterator_tag iterator_category
Definition xrange.hh:49
constexpr friend difference_type operator-(const Iter &i, const Iter &j)
Definition xrange.hh:110
constexpr friend Iter operator+(difference_type n, Iter i)
Definition xrange.hh:99
T * pointer
Definition xrange.hh:47
constexpr friend Iter operator-(Iter i, difference_type n)
Definition xrange.hh:104
constexpr Iter & operator++()
Definition xrange.hh:57
constexpr Iter operator++(int)
Definition xrange.hh:62
constexpr T operator*() const
Definition xrange.hh:52
T & reference
Definition xrange.hh:48
constexpr Iter & operator-=(difference_type n)
Definition xrange.hh:88
constexpr Iter operator--(int)
Definition xrange.hh:75
constexpr auto end() const
Definition xrange.hh:126
constexpr auto begin() const
Definition xrange.hh:125
constexpr void repeat(T n, Op op)
Repeat the given operation 'op' 'n' times.
Definition xrange.hh:147
constexpr auto xrange(T e)
Definition xrange.hh:132