sandbox
Loading...
Searching...
No Matches
range.hpp
1// SPDX-License-Identifier: MIT
2#ifndef LIBSBX_RANGE_HPP_
3#define LIBSBX_RANGE_HPP_
4
5#include <cmath>
6#include <iterator>
7#include <type_traits>
8#include <concepts>
9
10#include <libsbx/utility/iterator.hpp>
11
12namespace sbx::ecs {
13
14namespace detail {
15
16template<std::integral Type>
17struct range_iterator_base : utility::iterator<std::input_iterator_tag, Type> {
18
19 range_iterator_base(Type current) : _current(current) { }
20
21 auto operator*() const -> Type {
22 return _current;
23 }
24
25 auto operator->() const -> const Type* {
26 return &_current;
27 }
28
29 auto operator++() -> range_iterator_base& {
30 ++_current;
31 return *this;
32 }
33
34 auto operator++(int) -> range_iterator_base {
35 auto copy = *this;
36 ++(*this);
37 return copy;
38 }
39
40 auto operator==(const range_iterator_base& other) const -> bool {
41 return _current == other._current;
42 }
43
44protected:
45
46 Type _current;
47
48}; // struct range_iterator_base
49
50} // namespace detail
51
52template<std::integral Type>
55 iterator(Type current, Type step)
57 _step{step} { }
58
59 using detail::range_iterator_base<Type>::_current;
60
61 auto operator++() -> iterator& {
62 _current += _step;
63 return *this;
64 }
65
66 auto operator ++(int) -> iterator {
67 auto copy = *this;
68 ++(*this);
69 return copy;
70 }
71
72 auto operator ==(iterator const& other) const -> bool {
73 return _step > 0 ? _current >= other._current : _current < other._current;
74 }
75
76 Type _step;
77 }; // struct iterator
78
79 step_range_proxy(Type begin, Type end, Type step)
80 : _begin{begin, step},
81 _end{end, step} { }
82
83 auto begin() const -> iterator {
84 return _begin;
85 }
86
87 auto end() const -> iterator {
88 return _end;
89 }
90
91 auto size() const -> std::size_t {
92 if (*_end >= *_begin) {
93 // Increasing and empty range
94 if (_begin._step < Type{0}) {
95 return 0;
96 }
97 } else {
98 // Decreasing range
99 if (_begin._step > Type{0}) {
100 return 0;
101 }
102 }
103 return std::ceil(std::abs(static_cast<std::float_t>(*_end - *_begin) / _begin._step));
104 }
105
106private:
107
108 iterator _begin;
109 iterator _end;
110
111}; // struct step_range_proxy
112
113template<std::integral Type>
116 iterator(Type current)
118 }; // iterator
119
120 range_proxy(Type begin, Type end)
121 : _begin{begin},
122 _end{end} { }
123
124 auto step(Type step) -> step_range_proxy<Type> {
125 return {*_begin, *_end, step};
126 }
127
128 auto begin() const -> iterator {
129 return _begin;
130 }
131
132 auto end() const -> iterator {
133 return _end;
134 }
135
136 auto size() const -> std::size_t {
137 return *_end - *_begin;
138 }
139
140private:
141
142 iterator _begin;
143 iterator _end;
144
145}; // struct range_proxy
146
147template<std::integral Type>
150 iterator(Type current = Type{}, Type step = Type{})
152 _step{step} { }
153
154 using detail::range_iterator_base<Type>::_current;
155
156 auto operator++() -> iterator& {
157 _current += _step;
158 return *this;
159 }
160
161 auto operator++(int) -> iterator {
162 auto copy = *this;
163 ++(*this);
164 return copy;
165 }
166
167 auto operator==(const iterator&) const -> bool {
168 return false;
169 }
170
171 private:
172
173 Type _step;
174
175 }; // iterator
176
177 step_infinite_range_proxy(Type begin, Type step)
178 : _begin{begin, step} { }
179
180 auto begin() const -> iterator {
181 return _begin;
182 }
183
184 auto end() const -> iterator {
185 return iterator{};
186 }
187
188private:
189
190 iterator _begin;
191
192}; // step_infinite_range_proxy
193
194template<std::integral Type>
197 iterator(Type current = Type{})
199
200 bool operator==(const iterator&) const {
201 return false;
202 }
203
204 }; // struct iterator
205
206 infinite_range_proxy(Type begin)
207 : _begin{begin} { }
208
209 auto step(Type step) -> step_infinite_range_proxy<Type> {
210 return {*_begin, step};
211 }
212
213 auto begin() const -> iterator {
214 return _begin;
215 }
216
217 auto end() const -> iterator {
218 return iterator{};
219 }
220
221private:
222
223 iterator _begin;
224
225}; // struct infinite_range_proxy
226
227template<std::integral T, std::integral U>
228auto range(T begin, U end) -> range_proxy<std::common_type_t<T, U>> {
229 using common_type = std::common_type_t<T, U>;
230 return range_proxy{static_cast<common_type>(begin), static_cast<common_type>(end)};
231}
232
233template <typename Type>
234auto range(Type begin) -> infinite_range_proxy<Type> {
235 return infinite_range_proxy{begin};
236}
237
238template<typename Container>
239requires (requires(const Container& container){ { container.size() } -> std::integral; })
240auto indices(const Container& container) -> range_proxy<decltype(container.size())> {
241 return range_proxy{0, container.size()};
242}
243
244template<typename Type, std::size_t Size>
245auto indices(Type(&)[Size]) -> range_proxy<std::size_t> {
246 return range_proxy{std::size_t{0}, Size};
247}
248
249template<typename Type>
250auto indices(std::initializer_list<Type>&& container) -> range_proxy<typename std::initializer_list<Type>::size_type> {
251 return range_proxy{std::size_t{0}, container.size()};
252}
253
254} // namespace sbx::ecs
255
256#endif // LIBSBX_RANGE_HPP_
Definition: range.hpp:195
Definition: range.hpp:115
Definition: range.hpp:114
Definition: range.hpp:148
Definition: range.hpp:54
Definition: range.hpp:53
Definition: iterator.hpp:17