17 #ifndef OPENKALMAN_COMPATIBILITY_VIEWS_IOTA_HPP 18 #define OPENKALMAN_COMPATIBILITY_VIEWS_IOTA_HPP 20 #ifndef __cpp_lib_ranges 32 template<
typename W,
typename Bound = unreachable_sentinel_t>
37 static_assert(weakly_incrementable<W> and semiregular<Bound>);
40 using iota_diff_t = std::conditional_t<
41 not std::is_integral_v<I> or (
sizeof(iter_difference_t<I>) >
sizeof(I)), iter_difference_t<I>, std::ptrdiff_t>;
43 template<
typename I,
typename =
void>
44 struct is_decrementable : std::false_type {};
47 struct is_decrementable<I, std::enable_if_t<
49 std::is_same<decltype(--std::declval<I&>()), I&>::value and
50 std::is_same<decltype(std::declval<I&>()--), I>::value>> : std::true_type {};
56 template<
typename I,
typename =
void>
57 struct is_advanceable : std::false_type {};
60 struct is_advanceable<I, std::enable_if_t<
62 std::is_convertible_v<decltype(std::declval<I>() == std::declval<I>()), bool> and
63 std::is_convertible_v<decltype(std::declval<I>() != std::declval<I>()), bool> and
64 std::is_convertible_v<decltype(std::declval<I>() < std::declval<I>()), bool> and
65 std::is_convertible_v<decltype(std::declval<I>() > std::declval<I>()), bool> and
66 std::is_convertible_v<decltype(std::declval<I>() <= std::declval<I>()), bool> and
67 std::is_convertible_v<decltype(std::declval<I>() >= std::declval<I>()), bool> and
68 std::is_same<decltype(std::declval<I&>() += std::declval<const iota_diff_t<I>>()), I&>::value and
69 std::is_same<decltype(std::declval<I&>() -= std::declval<const iota_diff_t<I>>()), I&>::value and
70 std::is_constructible_v<I, decltype(std::declval<const I&>() + std::declval<const iota_diff_t<I>>())> and
71 std::is_constructible_v<I, decltype(std::declval<const iota_diff_t<I>>() + std::declval<const I&>())> and
72 std::is_constructible_v<I, decltype(std::declval<const I&>() - std::declval<const iota_diff_t<I>>())> and
73 std::is_convertible<decltype(std::declval<const I&>() - std::declval<const I&>()), iota_diff_t<I>>::value>> : std::true_type {};
85 using iterator_concept = std::conditional_t<advanceable<W>, std::random_access_iterator_tag,
86 std::conditional_t<decrementable<W>, std::bidirectional_iterator_tag,
87 std::conditional_t<incrementable<W>, std::forward_iterator_tag, std::input_iterator_tag>>>;
89 using iterator_category = std::input_iterator_tag;
92 using difference_type = iota_diff_t<W>;
96 template<
bool Enable = true, std::enable_if_t<Enable and std::is_default_constructible_v<W>,
int> = 0>
101 constexpr W operator*()
const noexcept(std::is_nothrow_copy_constructible_v<W>) {
return value_; }
103 constexpr iterator& operator++() { ++value_;
return *
this; }
105 template<
bool Enable = true, std::enable_if_t<Enable and not incrementable<W>,
int> = 0>
106 constexpr
void operator++(
int) { ++value_; }
108 template<
bool Enable = true, std::enable_if_t<Enable and incrementable<W>,
int> = 0>
109 constexpr iterator operator++(
int) {
auto tmp = *
this; ++value_;
return tmp; }
111 constexpr iterator& operator--() { --value_;
return *
this; }
113 constexpr iterator operator--(
int) {
auto tmp = *
this; --value_;
return tmp; }
115 template<
bool Enable = true, std::enable_if_t<Enable and advanceable<W>,
int> = 0>
116 constexpr iterator& operator+=(
const difference_type& n)
118 if constexpr (OpenKalman::internal::is_unsigned_integer_like<W>)
119 {
if (n >= 0) value_ +=
static_cast<W
>(n);
else value_ -=
static_cast<W
>(-n); }
125 template<
bool Enable = true, std::enable_if_t<Enable and advanceable<W>,
int> = 0>
126 constexpr iterator& operator-=(
const difference_type& n)
128 if constexpr (OpenKalman::internal::is_unsigned_integer_like<W>)
129 {
if (n >= 0) value_ -=
static_cast<W
>(n);
else value_ +=
static_cast<W
>(-n); }
135 template<
bool Enable = true, std::enable_if_t<Enable and advanceable<W>,
int> = 0>
136 constexpr value_type operator[](difference_type n)
const noexcept {
return W(value_ + n); }
138 friend constexpr
bool operator==(
const iterator& x,
const iterator& y) {
return x.value_ == y.value_; }
140 friend constexpr
bool operator!=(
const iterator& x,
const iterator& y) {
return not (x.value_ == y.value_); }
142 friend constexpr
bool operator<(
const iterator& x,
const iterator& y) {
return x.value_ < y.value_; }
144 friend constexpr
bool operator>(
const iterator& x,
const iterator& y) {
return y < x; }
146 friend constexpr
bool operator<=(
const iterator& x,
const iterator& y) {
return not (y < x); }
148 friend constexpr
bool operator>=(
const iterator& x,
const iterator& y) {
return not (x < y); }
150 template<
bool Enable = true, std::enable_if_t<Enable and advanceable<W>,
int> = 0>
151 friend constexpr iterator operator+(iterator i,
const difference_type& n) { i += n;
return i; }
153 template<
bool Enable = true, std::enable_if_t<Enable and advanceable<W>,
int> = 0>
154 friend constexpr iterator operator+(
const difference_type& n, iterator i) { i += n;
return i; }
156 template<
bool Enable = true, std::enable_if_t<Enable and advanceable<W>,
int> = 0>
157 friend constexpr iterator operator-(iterator i,
const difference_type& n) { i -= n;
return i; }
159 template<
bool Enable = true, std::enable_if_t<Enable and advanceable<W>,
int> = 0>
160 friend constexpr difference_type operator-(
const iterator& x,
const iterator& y)
162 using D = difference_type;
163 if constexpr (OpenKalman::internal::is_integer_like<W>)
165 if constexpr (OpenKalman::internal::is_signed_integer_like<W>)
return D(D(x.value_) - D(y.value_));
166 else return y.value_ > x.value_ ? D(-D(y.value_ - x.value_)) : D(x.value_ - y.value_);
168 else return x.value_ - y.value_;
183 constexpr
explicit sentinel(Bound bound) : bound_ {bound} {};
185 friend constexpr
bool operator==(
const iterator& x,
const sentinel& y ) {
return x.value_ == y.bound_; }
187 friend constexpr
bool operator==(
const sentinel& y,
const iterator& x ) {
return y.bound_ == x.value_; }
189 friend constexpr
bool operator!=(
const iterator& x,
const sentinel& y ) {
return not (x.value_ == y.bound_); }
191 friend constexpr
bool operator!=(
const sentinel& y,
const iterator& x ) {
return not (y.bound_ == x.value_); }
193 template<
bool Enable = true, std::enable_if_t<Enable and std::is_convertible_v<decltype(std::declval<W>() - std::declval<Bound>()), iter_difference_t<W>>,
int> = 0>
194 friend constexpr iter_difference_t<W> operator-(
const iterator& x,
const sentinel& y) {
return x.value_ - y.bound_; }
196 template<
bool Enable =
true, std::enable_if_t<Enable and std::is_convertible_v<decltype(-(std::declval<W>() - std::declval<Bound>())), iter_difference_t<W>>,
int> = 0>
197 friend constexpr iter_difference_t<W> operator-(
const sentinel& x,
const iterator& y) {
return -(y.value_ - x.bound_); }
205 template<
bool Enable = true, std::enable_if_t<Enable and std::is_default_constructible_v<W>,
int> = 0>
213 iota_view(type_identity_t<W> value, type_identity_t<Bound> bound) : value_ {value}, bound_ {bound} {}
215 template<
bool Enable = true, std::enable_if_t<Enable and std::is_same_v<Bound, W>,
int> = 0>
217 iota_view(
iterator first,
iterator last) : value_ {first.value_}, bound_ {last.value_} {}
219 template<
bool Enable = true, std::enable_if_t<Enable and std::is_same_v<Bound, unreachable_sentinel_t>,
int> = 0>
221 iota_view(
iterator first, Bound last) : value_ {first.value_}, bound_ {last} {}
223 template<
bool Enable =
true, std::enable_if_t<Enable and
224 not std::is_same_v<Bound, W> and not std::is_same_v<Bound, unreachable_sentinel_t>,
int> = 0>
226 iota_view(
iterator first,
sentinel last) : value_ {first.value_}, bound_ {last.bound_} {}
230 begin()
const {
return iterator {value_}; }
236 if constexpr (std::is_same_v<Bound, unreachable_sentinel_t>)
return unreachable_sentinel;
240 template<
bool Enable = true, std::enable_if_t<Enable and std::is_same_v<W, Bound>,
int> = 0>
242 end()
const {
return sentinel {bound_}; }
246 empty()
const {
return value_ == bound_; }
250 template<
typename A,
typename B,
typename =
void>
251 struct subtractable : std::false_type {};
253 template<
typename A,
typename B>
254 struct subtractable<A, B, std::enable_if_t<
255 std::is_convertible_v<decltype(std::declval<A>() - std::declval<B>()), std::size_t>>> : std::false_type {};
259 template<
bool Enable =
true, std::enable_if_t<Enable and
260 not std::is_same_v<Bound, unreachable_sentinel_t> and
261 ((std::is_same_v<W, Bound> and advanceable<W>) or
262 (OpenKalman::internal::is_integer_like<W> and OpenKalman::internal::is_integer_like<Bound>) or
263 sized_sentinel_for<Bound, W>),
int> = 0>
267 if constexpr (not OpenKalman::internal::is_integer_like<W> or not OpenKalman::internal::is_integer_like<Bound>)
268 return static_cast<std::size_t
>(bound_ - value_);
271 (bound_ < 0 ? static_cast<std::size_t>(-value_) - static_cast<std::size_t>(-bound_) :
272 static_cast<std::size_t
>(bound_) + static_cast<std::size_t>(-value_)) :
273 static_cast<std::size_t>(bound_) -
static_cast<std::size_t
>(value_);
285 template<
typename W,
typename Bound, std::enable_if_t<
286 not OpenKalman::internal::is_integer_like<W> or not OpenKalman::internal::is_integer_like<Bound> or
287 OpenKalman::internal::is_signed_integer_like<W> == OpenKalman::internal::is_signed_integer_like<Bound>,
int> = 0>
291 template<
typename W,
typename Bound>
292 constexpr
bool enable_borrowed_range<ranges::iota_view<W, Bound>> =
true;
303 template<
typename W,
typename Bound = unreachable_sentinel_t, std::enable_if_t<weakly_incrementable<W> and semiregular<Bound>,
int> = 0>
305 operator() [[nodiscard]] (W&&
value, Bound&& bound = {})
const 307 return iota_view {std::forward<W>(
value), std::forward<Bound>(bound)};
324 #endif //OPENKALMAN_COMPATIBILITY_VIEWS_IOTA_HPP constexpr detail::iota_adapter iota
a RangeAdapterObject associated with iota_view.
Definition: iota.hpp:237
Definition: view_interface.hpp:32
constexpr bool value
T is numerical value or is reducible to a numerical value.
Definition: value.hpp:31
Definition: range-access.hpp:25
Definitions relating to the availability of c++ language features.
Equivalent to std::ranges::iota_view.
Definition: iota.hpp:33