1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
|
#pragma once
#include <type_traits>
namespace ksys::util {
template <typename IntType>
class IntRange {
public:
static_assert(std::is_integral_v<IntType>, "T is not a integer type");
class Iterator {
public:
constexpr explicit Iterator(IntType value) : mValue(value) {}
constexpr bool operator==(Iterator rhs) const { return mValue == rhs.mValue; }
constexpr bool operator!=(Iterator rhs) const { return !operator==(rhs); }
constexpr IntType operator*() const { return mValue; }
constexpr Iterator& operator++() {
++mValue;
return *this;
}
constexpr Iterator operator++(int) const { return Iterator(mValue + 1); }
private:
IntType mValue;
};
constexpr IntRange(IntType begin, IntType end) : mBegin(begin), mEnd(end) {}
constexpr Iterator begin() const { return mBegin; }
constexpr Iterator end() const { return mEnd; }
constexpr Iterator cbegin() const { return mBegin; }
constexpr Iterator cend() const { return mEnd; }
private:
Iterator mBegin;
Iterator mEnd;
};
/// Range [begin, end) with a step of 1.
template <typename IntType>
constexpr IntRange<IntType> range(IntType begin, IntType end) {
return {begin, end};
}
/// Range [0, end) with a step of 1.
template <typename IntType>
constexpr auto range(IntType end) {
return IntRange<IntType>{0, end};
}
/// Use this as a replacement for `for (int i = 0, n = c.size(); i < n; ++i)` loops.
///
/// @warning The even better option is to use the container's own iterators,
/// as index-based loops can result in useless bounds checks at every iteration.
template <typename Container>
class IndexRange {
public:
class ElementProxy {
public:
constexpr ElementProxy(Container& container, int index)
: mIndex(index), mContainer(container) {}
constexpr int getIndex() const { return mIndex; }
constexpr decltype(auto) get() const { return mContainer[mIndex]; }
constexpr decltype(auto) operator*() const { return get(); }
constexpr auto* operator->() const { return &get(); }
private:
int mIndex;
Container& mContainer;
};
class Iterator {
public:
constexpr Iterator(Container& container, int index)
: mIndex(index), mContainer(container) {}
constexpr bool operator==(Iterator rhs) const { return mIndex == rhs.mIndex; }
constexpr bool operator!=(Iterator rhs) const { return !operator==(rhs); }
constexpr int getIndex() const { return mIndex; }
constexpr ElementProxy operator*() const { return ElementProxy(mContainer, mIndex); }
constexpr Iterator& operator++() {
++mIndex;
return *this;
}
constexpr Iterator operator++(int) const {
auto copy = *this;
++copy;
return copy;
}
private:
int mIndex;
Container& mContainer;
};
class EndIterator {
public:
constexpr explicit EndIterator(int index) : mIndex(index) {}
constexpr bool notEnd(Iterator it) const { return it.getIndex() < mIndex; }
friend constexpr bool operator!=(EndIterator end, Iterator it) { return end.notEnd(it); }
friend constexpr bool operator!=(Iterator it, EndIterator end) { return end.notEnd(it); }
private:
int mIndex;
};
constexpr explicit IndexRange(Container& container) : mContainer(container) {}
constexpr Iterator begin() const { return Iterator(mContainer, 0); }
constexpr EndIterator end() const { return EndIterator(mContainer.size()); }
private:
Container& mContainer;
};
template <typename Container>
constexpr auto indexIter(Container& container) {
return IndexRange<Container>{container};
}
} // namespace ksys::util
|