17 #ifndef OPENKALMAN_COMPATIBILITY_VIEWS_IOTA_HPP 18 #define OPENKALMAN_COMPATIBILITY_VIEWS_IOTA_HPP 27 #ifdef __cpp_lib_ranges 37 template<
typename W,
typename Bound = unreachable_sentinel_t>
42 static_assert(weakly_incrementable<W> and stdex::semiregular<Bound>);
45 using iota_diff_t = std::conditional_t<
46 not std::is_integral_v<I> or (
sizeof(iter_difference_t<I>) >
sizeof(I)), iter_difference_t<I>, std::ptrdiff_t>;
48 template<
typename I,
typename =
void>
49 struct is_decrementable : std::false_type {};
52 struct is_decrementable<I, std::enable_if_t<
54 std::is_same<decltype(--std::declval<I&>()), I&>::value and
55 std::is_same<decltype(std::declval<I&>()--), I>::value>> : std::true_type {};
61 template<
typename I,
typename =
void>
62 struct is_advanceable : std::false_type {};
65 struct is_advanceable<I, std::enable_if_t<
67 stdex::convertible_to<decltype(std::declval<I>() == std::declval<I>()), bool> and
68 stdex::convertible_to<decltype(std::declval<I>() != std::declval<I>()), bool> and
69 stdex::convertible_to<decltype(std::declval<I>() < std::declval<I>()), bool> and
70 stdex::convertible_to<decltype(std::declval<I>() > std::declval<I>()), bool> and
71 stdex::convertible_to<decltype(std::declval<I>() <= std::declval<I>()), bool> and
72 stdex::convertible_to<decltype(std::declval<I>() >= std::declval<I>()), bool> and
73 std::is_same<decltype(std::declval<I&>() += std::declval<const iota_diff_t<I>>()), I&>::value and
74 std::is_same<decltype(std::declval<I&>() -= std::declval<const iota_diff_t<I>>()), I&>::value and
75 stdex::constructible_from<I, decltype(std::declval<const I&>() + std::declval<const iota_diff_t<I>>())> and
76 stdex::constructible_from<I, decltype(std::declval<const iota_diff_t<I>>() + std::declval<const I&>())> and
77 stdex::constructible_from<I, decltype(std::declval<const I&>() - std::declval<const iota_diff_t<I>>())> and
78 std::is_convertible<decltype(std::declval<const I&>() - std::declval<const I&>()), iota_diff_t<I>>::value>> : std::true_type {};
90 using iterator_concept = std::conditional_t<advanceable<W>, std::random_access_iterator_tag,
91 std::conditional_t<decrementable<W>, std::bidirectional_iterator_tag,
92 std::conditional_t<incrementable<W>, std::forward_iterator_tag, std::input_iterator_tag>>>;
94 using iterator_category = std::input_iterator_tag;
97 using difference_type = iota_diff_t<W>;
101 template<
bool Enable = true, std::enable_if_t<Enable and stdex::default_initializable<W>,
int> = 0>
106 constexpr W operator*()
const noexcept(std::is_nothrow_copy_constructible_v<W>) {
return value_; }
108 constexpr iterator& operator++() { ++value_;
return *
this; }
110 template<
bool Enable = true, std::enable_if_t<Enable and not incrementable<W>,
int> = 0>
111 constexpr
void operator++(
int) { ++value_; }
113 template<
bool Enable = true, std::enable_if_t<Enable and incrementable<W>,
int> = 0>
114 constexpr iterator operator++(
int) {
auto tmp = *
this; ++value_;
return tmp; }
116 constexpr iterator& operator--() { --value_;
return *
this; }
118 constexpr iterator operator--(
int) {
auto tmp = *
this; --value_;
return tmp; }
120 template<
bool Enable = true, std::enable_if_t<Enable and advanceable<W>,
int> = 0>
121 constexpr iterator& operator+=(
const difference_type& n)
123 if constexpr (OpenKalman::internal::is_unsigned_integer_like<W>)
124 {
if (n >= 0) value_ +=
static_cast<W
>(n);
else value_ -=
static_cast<W
>(-n); }
130 template<
bool Enable = true, std::enable_if_t<Enable and advanceable<W>,
int> = 0>
131 constexpr iterator& operator-=(
const difference_type& n)
133 if constexpr (OpenKalman::internal::is_unsigned_integer_like<W>)
134 {
if (n >= 0) value_ -=
static_cast<W
>(n);
else value_ +=
static_cast<W
>(-n); }
140 template<
bool Enable = true, std::enable_if_t<Enable and advanceable<W>,
int> = 0>
141 constexpr value_type operator[](difference_type n)
const noexcept {
return W(value_ + n); }
143 friend constexpr
bool operator==(
const iterator& x,
const iterator& y) {
return x.value_ == y.value_; }
145 friend constexpr
bool operator!=(
const iterator& x,
const iterator& y) {
return not (x.value_ == y.value_); }
147 friend constexpr
bool operator<(
const iterator& x,
const iterator& y) {
return x.value_ < y.value_; }
149 friend constexpr
bool operator>(
const iterator& x,
const iterator& y) {
return y < x; }
151 friend constexpr
bool operator<=(
const iterator& x,
const iterator& y) {
return not (y < x); }
153 friend constexpr
bool operator>=(
const iterator& x,
const iterator& y) {
return not (x < y); }
155 template<
bool Enable = true, std::enable_if_t<Enable and advanceable<W>,
int> = 0>
156 friend constexpr iterator operator+(iterator i,
const difference_type& n) { i += n;
return i; }
158 template<
bool Enable = true, std::enable_if_t<Enable and advanceable<W>,
int> = 0>
159 friend constexpr iterator operator+(
const difference_type& n, iterator i) { i += n;
return i; }
161 template<
bool Enable = true, std::enable_if_t<Enable and advanceable<W>,
int> = 0>
162 friend constexpr iterator operator-(iterator i,
const difference_type& n) { i -= n;
return i; }
164 template<
bool Enable = true, std::enable_if_t<Enable and advanceable<W>,
int> = 0>
165 friend constexpr difference_type operator-(
const iterator& x,
const iterator& y)
167 using D = difference_type;
168 if constexpr (OpenKalman::internal::is_integer_like<W>)
170 if constexpr (OpenKalman::internal::is_signed_integer_like<W>)
return D(D(x.value_) - D(y.value_));
171 else return y.value_ > x.value_ ? D(-D(y.value_ - x.value_)) : D(x.value_ - y.value_);
173 else return x.value_ - y.value_;
188 constexpr
explicit sentinel(Bound bound) : bound_ {bound} {};
190 friend constexpr
bool operator==(
const iterator& x,
const sentinel& y ) {
return x.value_ == y.bound_; }
192 friend constexpr
bool operator==(
const sentinel& y,
const iterator& x ) {
return y.bound_ == x.value_; }
194 friend constexpr
bool operator!=(
const iterator& x,
const sentinel& y ) {
return not (x.value_ == y.bound_); }
196 friend constexpr
bool operator!=(
const sentinel& y,
const iterator& x ) {
return not (y.bound_ == x.value_); }
198 template<
bool Enable = true, std::enable_if_t<Enable and stdex::convertible_to<decltype(std::declval<W>() - std::declval<Bound>()), iter_difference_t<W>>,
int> = 0>
199 friend constexpr iter_difference_t<W> operator-(
const iterator& x,
const sentinel& y) {
return x.value_ - y.bound_; }
201 template<
bool Enable =
true, std::enable_if_t<Enable and stdex::convertible_to<decltype(-(std::declval<W>() - std::declval<Bound>())), iter_difference_t<W>>,
int> = 0>
202 friend constexpr iter_difference_t<W> operator-(
const sentinel& x,
const iterator& y) {
return -(y.value_ - x.bound_); }
210 template<
bool Enable = true, std::enable_if_t<Enable and stdex::default_initializable<W>,
int> = 0>
218 iota_view(stdex::type_identity_t<W> value, stdex::type_identity_t<Bound> bound) : value_ {value}, bound_ {bound} {}
220 template<
bool Enable = true, std::enable_if_t<Enable and std::is_same_v<Bound, W>,
int> = 0>
224 template<
bool Enable = true, std::enable_if_t<Enable and std::is_same_v<Bound, unreachable_sentinel_t>,
int> = 0>
228 template<
bool Enable =
true, std::enable_if_t<Enable and
229 not std::is_same_v<Bound, W> and not std::is_same_v<Bound, unreachable_sentinel_t>,
int> = 0>
235 begin()
const {
return iterator {value_}; }
241 if constexpr (std::is_same_v<Bound, unreachable_sentinel_t>)
return unreachable_sentinel;
245 template<
bool Enable = true, std::enable_if_t<Enable and std::is_same_v<W, Bound>,
int> = 0>
247 end()
const {
return sentinel {bound_}; }
251 empty()
const {
return value_ == bound_; }
255 template<
typename A,
typename B,
typename =
void>
256 struct subtractable : std::false_type {};
258 template<
typename A,
typename B>
259 struct subtractable<A, B, std::enable_if_t<
260 stdex::convertible_to<decltype(std::declval<A>() - std::declval<B>()), std::size_t>>> : std::false_type {};
264 template<
bool Enable =
true, std::enable_if_t<Enable and
265 not std::is_same_v<Bound, unreachable_sentinel_t> and
266 ((std::is_same_v<W, Bound> and advanceable<W>) or
267 (OpenKalman::internal::is_integer_like<W> and OpenKalman::internal::is_integer_like<Bound>) or
268 sized_sentinel_for<Bound, W>),
int> = 0>
272 if constexpr (not OpenKalman::internal::is_integer_like<W> or not OpenKalman::internal::is_integer_like<Bound>)
273 return static_cast<std::size_t
>(bound_ - value_);
276 (bound_ < 0 ? static_cast<std::size_t>(-value_) - static_cast<std::size_t>(-bound_) :
277 static_cast<std::size_t
>(bound_) + static_cast<std::size_t>(-value_)) :
278 static_cast<std::size_t>(bound_) -
static_cast<std::size_t
>(value_);
290 template<
typename W,
typename Bound, std::enable_if_t<
291 not OpenKalman::internal::is_integer_like<W> or not OpenKalman::internal::is_integer_like<Bound> or
292 OpenKalman::internal::is_signed_integer_like<W> == OpenKalman::internal::is_signed_integer_like<Bound>,
int> = 0>
296 template<
typename W,
typename Bound>
297 constexpr
bool enable_borrowed_range<stdex::ranges::iota_view<W, Bound>> =
true;
306 template<
typename W,
typename Bound = unreachable_sentinel_t, std::enable_if_t<weakly_incrementable<W> and stdex::semiregular<Bound>,
int> = 0>
308 operator() [[nodiscard]] (W&&
value, Bound&& bound = {})
const 310 return iota_view {std::forward<W>(
value), std::forward<Bound>(bound)};
constexpr detail::iota_adapter iota
a RangeAdapterObject associated with iota_view.
Definition: iota.hpp:225
iota_view(const Start &) -> iota_view< Start >
Deduction guide for an unsized iota.
constexpr bool value
T is a fixed or dynamic value that is reducible to a number.
Definition: value.hpp:45
Definition: view_interface.hpp:32
Definitions relating to the availability of c++ language features.
Definition: common.hpp:200
constexpr bool size
T is either an index representing a size, or unbounded_size_t, which indicates that the size is unbou...
Definition: size.hpp:65
Equivalent to std::ranges::iota_view.
Definition: iota.hpp:38