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 <cstddef>
37#include <iterator>
38#include <type_traits>
39
40template<typename T> struct XRange
41{
42 struct Iter
43 {
44 using difference_type = ptrdiff_t;
45 using value_type = T;
46 using pointer = T*;
47 using reference = T&;
48 using iterator_category = std::random_access_iterator_tag;
49
50 // ForwardIterator
51 [[nodiscard]] constexpr T operator*() const
52 {
53 return x;
54 }
55
56 constexpr Iter& operator++()
57 {
58 ++x;
59 return *this;
60 }
61 constexpr Iter operator++(int)
62 {
63 auto copy = *this;
64 ++x;
65 return copy;
66 }
67
68 [[nodiscard]] /*constexpr*/ bool operator==(const Iter&) const = default;
69
70 // BidirectionalIterator
71 constexpr Iter& operator--()
72 {
73 --x;
74 return *this;
75 }
76 constexpr Iter operator--(int)
77 {
78 auto copy = *this;
79 --x;
80 return copy;
81 }
82
83 // RandomAccessIterator
85 {
86 x += n;
87 return *this;
88 }
90 {
91 x -= n;
92 return *this;
93 }
94
95 [[nodiscard]] constexpr friend Iter operator+(Iter i, difference_type n)
96 {
97 i += n;
98 return i;
99 }
100 [[nodiscard]] constexpr friend Iter operator+(difference_type n, Iter i)
101 {
102 i += n;
103 return i;
104 }
105 [[nodiscard]] constexpr friend Iter operator-(Iter i, difference_type n)
106 {
107 i -= n;
108 return i;
109 }
110
111 [[nodiscard]] constexpr friend difference_type operator-(const Iter& i, const Iter& j)
112 {
113 return i.x - j.x;
114 }
115
116 [[nodiscard]] constexpr T operator[](difference_type n)
117 {
118 return *(*this + n);
119 }
120
121 [[nodiscard]] /*constexpr*/ auto operator<=>(const Iter&) const = default;
122
123 T x;
124 };
125
126 [[nodiscard]] constexpr auto begin() const { return Iter{b}; }
127 [[nodiscard]] constexpr auto end() const { return Iter{e}; }
128
129 /*const*/ T b; // non-const to workaround msvc bug(?)
130 /*const*/ T e;
131};
132
133template<typename T> [[nodiscard]] constexpr auto xrange(T e)
134{
135 return XRange<T>{T(0), e < T(0) ? T(0) : e};
136}
137template<typename T1, typename T2> [[nodiscard]] constexpr auto xrange(T1 b, T2 e)
138{
139 static_assert(std::is_signed_v<T1> == std::is_signed_v<T2>);
140 using T = std::common_type_t<T1, T2>;
141 return XRange<T>{b, e < b ? b : e};
142}
143
144
147template<typename T, typename Op>
148constexpr void repeat(T n, Op op)
149{
150 for (auto i : xrange(n)) {
151 (void)i;
152 op();
153 }
154}
155
156#endif
constexpr double e
Definition: Math.hh:18
auto copy(InputRange &&range, OutputIter out)
Definition: ranges.hh:208
constexpr friend Iter operator+(Iter i, difference_type n)
Definition: xrange.hh:95
constexpr Iter & operator+=(difference_type n)
Definition: xrange.hh:84
ptrdiff_t difference_type
Definition: xrange.hh:44
auto operator<=>(const Iter &) const =default
constexpr Iter & operator--()
Definition: xrange.hh:71
constexpr T operator[](difference_type n)
Definition: xrange.hh:116
std::random_access_iterator_tag iterator_category
Definition: xrange.hh:48
constexpr friend difference_type operator-(const Iter &i, const Iter &j)
Definition: xrange.hh:111
constexpr friend Iter operator+(difference_type n, Iter i)
Definition: xrange.hh:100
T * pointer
Definition: xrange.hh:46
constexpr friend Iter operator-(Iter i, difference_type n)
Definition: xrange.hh:105
constexpr Iter & operator++()
Definition: xrange.hh:56
bool operator==(const Iter &) const =default
constexpr Iter operator++(int)
Definition: xrange.hh:61
constexpr T operator*() const
Definition: xrange.hh:51
T & reference
Definition: xrange.hh:47
constexpr Iter & operator-=(difference_type n)
Definition: xrange.hh:89
T value_type
Definition: xrange.hh:45
constexpr Iter operator--(int)
Definition: xrange.hh:76
Definition: xrange.hh:41
T e
Definition: xrange.hh:130
constexpr auto end() const
Definition: xrange.hh:127
constexpr auto begin() const
Definition: xrange.hh:126
T b
Definition: xrange.hh:129
constexpr void repeat(T n, Op op)
Repeat the given operation 'op' 'n' times.
Definition: xrange.hh:148
constexpr auto xrange(T e)
Definition: xrange.hh:133