OpenKalman
iota.hpp
Go to the documentation of this file.
1 /* This file is part of OpenKalman, a header-only C++ library for
2  * Kalman filters and other recursive filters.
3  *
4  * Copyright (c) 2025 Christopher Lee Ogden <ogden@gatech.edu>
5  *
6  * This Source Code Form is subject to the terms of the Mozilla Public
7  * License, v. 2.0. If a copy of the MPL was not distributed with this
8  * file, You can obtain one at https://mozilla.org/MPL/2.0/.
9  */
10 
17 #ifndef OPENKALMAN_COMPATIBILITY_VIEWS_IOTA_HPP
18 #define OPENKALMAN_COMPATIBILITY_VIEWS_IOTA_HPP
19 
20 #ifndef __cpp_lib_ranges
21 
24 #include "view-concepts.hpp"
25 #include "view_interface.hpp"
26 
27 namespace OpenKalman::ranges
28 {
32  template<typename W, typename Bound = unreachable_sentinel_t>
33  struct iota_view : view_interface<iota_view<W, Bound>>
34  {
35  private:
36 
37  static_assert(weakly_incrementable<W> and semiregular<Bound>);
38 
39  template<typename I>
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>;
42 
43  template<typename I, typename = void>
44  struct is_decrementable : std::false_type {};
45 
46  template<typename I>
47  struct is_decrementable<I, std::enable_if_t<
48  incrementable<I> and
49  std::is_same<decltype(--std::declval<I&>()), I&>::value and
50  std::is_same<decltype(std::declval<I&>()--), I>::value>> : std::true_type {};
51 
52  template<typename I>
53  static constexpr bool decrementable = is_decrementable<I>::value;
54 
55 
56  template<typename I, typename = void>
57  struct is_advanceable : std::false_type {};
58 
59  template<typename I>
60  struct is_advanceable<I, std::enable_if_t<
61  decrementable<I> and
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 {};
74 
75  template<typename I>
76  static constexpr bool advanceable = is_advanceable<I>::value;
77 
78  public:
79 
80  struct sentinel;
81 
82 
83  struct iterator
84  {
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>>>;
88 
89  using iterator_category = std::input_iterator_tag;
90 
91  using value_type = W;
92  using difference_type = iota_diff_t<W>;
93  using reference = W;
94  using pointer = void;
95 
96  template<bool Enable = true, std::enable_if_t<Enable and std::is_default_constructible_v<W>, int> = 0>
97  constexpr iterator() {};
98 
99  constexpr explicit iterator(W value) : value_ {value} {}
100 
101  constexpr W operator*() const noexcept(std::is_nothrow_copy_constructible_v<W>) { return value_; }
102 
103  constexpr iterator& operator++() { ++value_; return *this; }
104 
105  template<bool Enable = true, std::enable_if_t<Enable and not incrementable<W>, int> = 0>
106  constexpr void operator++(int) { ++value_; }
107 
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; }
110 
111  constexpr iterator& operator--() { --value_; return *this; }
112 
113  constexpr iterator operator--(int) { auto tmp = *this; --value_; return tmp; }
114 
115  template<bool Enable = true, std::enable_if_t<Enable and advanceable<W>, int> = 0>
116  constexpr iterator& operator+=(const difference_type& n)
117  {
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); }
120  else
121  { value_ += n; }
122  return *this;
123  }
124 
125  template<bool Enable = true, std::enable_if_t<Enable and advanceable<W>, int> = 0>
126  constexpr iterator& operator-=(const difference_type& n)
127  {
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); }
130  else
131  { value_ -= n; }
132  return *this;
133  }
134 
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); }
137 
138  friend constexpr bool operator==(const iterator& x, const iterator& y) { return x.value_ == y.value_; }
139 
140  friend constexpr bool operator!=(const iterator& x, const iterator& y) { return not (x.value_ == y.value_); }
141 
142  friend constexpr bool operator<(const iterator& x, const iterator& y) { return x.value_ < y.value_; }
143 
144  friend constexpr bool operator>(const iterator& x, const iterator& y) { return y < x; }
145 
146  friend constexpr bool operator<=(const iterator& x, const iterator& y) { return not (y < x); }
147 
148  friend constexpr bool operator>=(const iterator& x, const iterator& y) { return not (x < y); }
149 
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; }
152 
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; }
155 
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; }
158 
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)
161  {
162  using D = difference_type;
163  if constexpr (OpenKalman::internal::is_integer_like<W>)
164  {
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_);
167  }
168  else return x.value_ - y.value_;
169  }
170 
171  private:
172 
173  friend struct iota_view::sentinel;
174  W value_;
175 
176  };
177 
178 
179  struct sentinel
180  {
181  sentinel() = default;
182 
183  constexpr explicit sentinel(Bound bound) : bound_ {bound} {};
184 
185  friend constexpr bool operator==( const iterator& x, const sentinel& y ) { return x.value_ == y.bound_; }
186 
187  friend constexpr bool operator==( const sentinel& y, const iterator& x ) { return y.bound_ == x.value_; }
188 
189  friend constexpr bool operator!=( const iterator& x, const sentinel& y ) { return not (x.value_ == y.bound_); }
190 
191  friend constexpr bool operator!=( const sentinel& y, const iterator& x ) { return not (y.bound_ == x.value_); }
192 
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_; }
195 
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_); }
198 
199  private:
200 
201  Bound bound_;
202  };
203 
204 
205  template<bool Enable = true, std::enable_if_t<Enable and std::is_default_constructible_v<W>, int> = 0>
206  constexpr
207  iota_view() {};
208 
209  constexpr explicit
210  iota_view(W value) : value_ {std::move(value)} {}
211 
212  constexpr explicit
213  iota_view(type_identity_t<W> value, type_identity_t<Bound> bound) : value_ {value}, bound_ {bound} {}
214 
215  template<bool Enable = true, std::enable_if_t<Enable and std::is_same_v<Bound, W>, int> = 0>
216  constexpr explicit
217  iota_view(iterator first, iterator last) : value_ {first.value_}, bound_ {last.value_} {}
218 
219  template<bool Enable = true, std::enable_if_t<Enable and std::is_same_v<Bound, unreachable_sentinel_t>, int> = 0>
220  constexpr explicit
221  iota_view(iterator first, Bound last) : value_ {first.value_}, bound_ {last} {}
222 
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>
225  constexpr explicit
226  iota_view(iterator first, sentinel last) : value_ {first.value_}, bound_ {last.bound_} {}
227 
228 
229  constexpr iterator
230  begin() const { return iterator {value_}; }
231 
232 
233  constexpr auto
234  end() const
235  {
236  if constexpr (std::is_same_v<Bound, unreachable_sentinel_t>) return unreachable_sentinel;
237  else return sentinel {bound_};
238  }
239 
240  template<bool Enable = true, std::enable_if_t<Enable and std::is_same_v<W, Bound>, int> = 0>
241  constexpr iterator
242  end() const { return sentinel {bound_}; }
243 
244 
245  constexpr auto
246  empty() const { return value_ == bound_; }
247 
248  private:
249 
250  template<typename A, typename B, typename = void>
251  struct subtractable : std::false_type {};
252 
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 {};
256 
257  public:
258 
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>
264  constexpr auto
265  size() const
266  {
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_);
269  else
270  return value_ < 0 ?
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_);
274  }
275 
276  private:
277 
278  W value_;
279 
280  Bound bound_;
281 
282  }; // struct iota_view
283 
284 
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>
288  iota_view(W, Bound) -> iota_view<W, Bound>;
289 
290 
291  template<typename W, typename Bound>
292  constexpr bool enable_borrowed_range<ranges::iota_view<W, Bound>> = true;
293 
294 }
295 
296 
298 {
299  namespace detail
300  {
302  {
303  template<typename W, typename Bound = unreachable_sentinel_t, std::enable_if_t<weakly_incrementable<W> and semiregular<Bound>, int> = 0>
304  constexpr auto
305  operator() [[nodiscard]] (W&& value, Bound&& bound = {}) const
306  {
307  return iota_view {std::forward<W>(value), std::forward<Bound>(bound)};
308  }
309  };
310  }
311 
312 
317  inline constexpr detail::iota_adapter iota;
318 
319 }
320 
321 
322 #endif
323 
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
Definition: all.hpp:35