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 
22 #include "view-concepts.hpp"
23 #include "view_interface.hpp"
24 
26 {
27 #ifdef __cpp_lib_ranges
29  namespace views
30  {
32  }
33 #else
34 
37  template<typename W, typename Bound = unreachable_sentinel_t>
38  struct iota_view : view_interface<iota_view<W, Bound>>
39  {
40  private:
41 
42  static_assert(weakly_incrementable<W> and stdex::semiregular<Bound>);
43 
44  template<typename I>
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>;
47 
48  template<typename I, typename = void>
49  struct is_decrementable : std::false_type {};
50 
51  template<typename I>
52  struct is_decrementable<I, std::enable_if_t<
53  incrementable<I> and
54  std::is_same<decltype(--std::declval<I&>()), I&>::value and
55  std::is_same<decltype(std::declval<I&>()--), I>::value>> : std::true_type {};
56 
57  template<typename I>
58  static constexpr bool decrementable = is_decrementable<I>::value;
59 
60 
61  template<typename I, typename = void>
62  struct is_advanceable : std::false_type {};
63 
64  template<typename I>
65  struct is_advanceable<I, std::enable_if_t<
66  decrementable<I> and
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 {};
79 
80  template<typename I>
81  static constexpr bool advanceable = is_advanceable<I>::value;
82 
83  public:
84 
85  struct sentinel;
86 
87 
88  struct iterator
89  {
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>>>;
93 
94  using iterator_category = std::input_iterator_tag;
95 
96  using value_type = W;
97  using difference_type = iota_diff_t<W>;
98  using reference = W;
99  using pointer = void;
100 
101  template<bool Enable = true, std::enable_if_t<Enable and stdex::default_initializable<W>, int> = 0>
102  constexpr iterator() {};
103 
104  constexpr explicit iterator(W value) : value_ {value} {}
105 
106  constexpr W operator*() const noexcept(std::is_nothrow_copy_constructible_v<W>) { return value_; }
107 
108  constexpr iterator& operator++() { ++value_; return *this; }
109 
110  template<bool Enable = true, std::enable_if_t<Enable and not incrementable<W>, int> = 0>
111  constexpr void operator++(int) { ++value_; }
112 
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; }
115 
116  constexpr iterator& operator--() { --value_; return *this; }
117 
118  constexpr iterator operator--(int) { auto tmp = *this; --value_; return tmp; }
119 
120  template<bool Enable = true, std::enable_if_t<Enable and advanceable<W>, int> = 0>
121  constexpr iterator& operator+=(const difference_type& n)
122  {
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); }
125  else
126  { value_ += n; }
127  return *this;
128  }
129 
130  template<bool Enable = true, std::enable_if_t<Enable and advanceable<W>, int> = 0>
131  constexpr iterator& operator-=(const difference_type& n)
132  {
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); }
135  else
136  { value_ -= n; }
137  return *this;
138  }
139 
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); }
142 
143  friend constexpr bool operator==(const iterator& x, const iterator& y) { return x.value_ == y.value_; }
144 
145  friend constexpr bool operator!=(const iterator& x, const iterator& y) { return not (x.value_ == y.value_); }
146 
147  friend constexpr bool operator<(const iterator& x, const iterator& y) { return x.value_ < y.value_; }
148 
149  friend constexpr bool operator>(const iterator& x, const iterator& y) { return y < x; }
150 
151  friend constexpr bool operator<=(const iterator& x, const iterator& y) { return not (y < x); }
152 
153  friend constexpr bool operator>=(const iterator& x, const iterator& y) { return not (x < y); }
154 
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; }
157 
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; }
160 
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; }
163 
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)
166  {
167  using D = difference_type;
168  if constexpr (OpenKalman::internal::is_integer_like<W>)
169  {
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_);
172  }
173  else return x.value_ - y.value_;
174  }
175 
176  private:
177 
178  friend struct iota_view::sentinel;
179  W value_;
180 
181  };
182 
183 
184  struct sentinel
185  {
186  sentinel() = default;
187 
188  constexpr explicit sentinel(Bound bound) : bound_ {bound} {};
189 
190  friend constexpr bool operator==( const iterator& x, const sentinel& y ) { return x.value_ == y.bound_; }
191 
192  friend constexpr bool operator==( const sentinel& y, const iterator& x ) { return y.bound_ == x.value_; }
193 
194  friend constexpr bool operator!=( const iterator& x, const sentinel& y ) { return not (x.value_ == y.bound_); }
195 
196  friend constexpr bool operator!=( const sentinel& y, const iterator& x ) { return not (y.bound_ == x.value_); }
197 
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_; }
200 
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_); }
203 
204  private:
205 
206  Bound bound_;
207  };
208 
209 
210  template<bool Enable = true, std::enable_if_t<Enable and stdex::default_initializable<W>, int> = 0>
211  constexpr
212  iota_view() {};
213 
214  constexpr explicit
215  iota_view(W value) : value_ {std::move(value)} {}
216 
217  constexpr explicit
218  iota_view(stdex::type_identity_t<W> value, stdex::type_identity_t<Bound> bound) : value_ {value}, bound_ {bound} {}
219 
220  template<bool Enable = true, std::enable_if_t<Enable and std::is_same_v<Bound, W>, int> = 0>
221  constexpr explicit
222  iota_view(iterator first, iterator last) : value_ {first.value_}, bound_ {last.value_} {}
223 
224  template<bool Enable = true, std::enable_if_t<Enable and std::is_same_v<Bound, unreachable_sentinel_t>, int> = 0>
225  constexpr explicit
226  iota_view(iterator first, Bound last) : value_ {first.value_}, bound_ {last} {}
227 
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>
230  constexpr explicit
231  iota_view(iterator first, sentinel last) : value_ {first.value_}, bound_ {last.bound_} {}
232 
233 
234  constexpr iterator
235  begin() const { return iterator {value_}; }
236 
237 
238  constexpr auto
239  end() const
240  {
241  if constexpr (std::is_same_v<Bound, unreachable_sentinel_t>) return unreachable_sentinel;
242  else return sentinel {bound_};
243  }
244 
245  template<bool Enable = true, std::enable_if_t<Enable and std::is_same_v<W, Bound>, int> = 0>
246  constexpr iterator
247  end() const { return sentinel {bound_}; }
248 
249 
250  constexpr auto
251  empty() const { return value_ == bound_; }
252 
253  private:
254 
255  template<typename A, typename B, typename = void>
256  struct subtractable : std::false_type {};
257 
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 {};
261 
262  public:
263 
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>
269  constexpr auto
270  size() const
271  {
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_);
274  else
275  return value_ < 0 ?
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_);
279  }
280 
281  private:
282 
283  W value_;
284 
285  Bound bound_;
286 
287  }; // struct iota_view
288 
289 
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>
293  iota_view(W, Bound) -> iota_view<W, Bound>;
294 
295 
296  template<typename W, typename Bound>
297  constexpr bool enable_borrowed_range<stdex::ranges::iota_view<W, Bound>> = true;
298 
299 
300  namespace views
301  {
302  namespace detail
303  {
305  {
306  template<typename W, typename Bound = unreachable_sentinel_t, std::enable_if_t<weakly_incrementable<W> and stdex::semiregular<Bound>, int> = 0>
307  constexpr auto
308  operator() [[nodiscard]] (W&& value, Bound&& bound = {}) const
309  {
310  return iota_view {std::forward<W>(value), std::forward<Bound>(bound)};
311  }
312  };
313  }
314 
315 
320  inline constexpr detail::iota_adapter iota;
321  }
322 
323 #endif
324 }
325 
326 #endif
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