OpenKalman
generate.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 
16 #ifndef OPENKALMAN_COLLECTIONS_VIEWS_GENERATE_HPP
17 #define OPENKALMAN_COLLECTIONS_VIEWS_GENERATE_HPP
18 
19 #include <variant> // for std::monostate
20 #include "values/values.hpp"
23 
25 {
33 #ifdef __cpp_concepts
34  template<typename F, values::size Size = values::unbounded_size_t> requires
35  std::same_as<Size, std::remove_reference_t<Size>> and std::is_object_v<F> and std::invocable<F&, std::size_t>
36 #else
37  template<typename F, typename Size = values::unbounded_size_t>
38 #endif
39  struct generate_view : stdex::ranges::view_interface<generate_view<F, Size>>
40  {
41  private:
42 
43  static_assert(not values::fixed_value_compares_with<Size, stdex::dynamic_extent>,
44  "Size parameter for generate_view cannot be std::dynamic_extent");
45 
47 
48  template<bool Const, typename T>
49  using maybe_const = std::conditional_t<Const, const T, T>;
50 
51  public:
52 
56  template<bool Const>
57  struct iterator
58  {
59  using iterator_concept = std::random_access_iterator_tag;
60  using iterator_category = std::random_access_iterator_tag;
61  using value_type = std::invoke_result_t<F_box&, std::size_t>;
62  using difference_type = std::ptrdiff_t;
63  using reference = value_type;
64  using pointer = void;
65 
66  constexpr iterator() = default;
67 
68  constexpr iterator(maybe_const<Const, F_box>& f, std::size_t pos)
69  : f_ {std::addressof(f)}, current_ {static_cast<difference_type>(pos)} {};
70 
71  constexpr iterator(iterator<not Const> i) : f_ {std::move(i.f_)}, current_ {std::move(i.current_)} {}
72 
73  constexpr value_type operator*() const
74  {
75  return stdex::invoke(*f_, static_cast<std::size_t>(current_));
76  }
77 
78  constexpr value_type operator[](difference_type offset) const
79  {
80  return stdex::invoke(*f_, static_cast<std::size_t>(current_ + offset));
81  }
82 
83  constexpr auto& operator++() noexcept { ++current_; return *this; }
84  constexpr auto operator++(int) noexcept { auto temp = *this; ++*this; return temp; }
85  constexpr auto& operator--() noexcept { --current_; return *this; }
86  constexpr auto operator--(int) noexcept { auto temp = *this; --*this; return temp; }
87  constexpr auto& operator+=(const difference_type diff) noexcept { current_ += diff; return *this; }
88  constexpr auto& operator-=(const difference_type diff) noexcept { current_ -= diff; return *this; }
89 
90  friend constexpr auto operator+(const iterator& it, const difference_type diff)
91  { return iterator {*it.f_, static_cast<std::size_t>(it.current_ + diff)}; }
92  friend constexpr auto operator+(const difference_type diff, const iterator& it)
93  { return iterator {*it.f_, static_cast<std::size_t>(diff + it.current_)}; }
94  friend constexpr auto operator-(const iterator& it, const difference_type diff)
95  { if (it.current_ < diff) throw std::out_of_range{"Iterator out of range"}; return iterator {*it.f_, static_cast<std::size_t>(it.current_ - diff)}; }
96  friend constexpr difference_type operator-(const iterator& it, const iterator& other)
97  { return it.current_ - other.current_; }
98  friend constexpr bool operator==(const iterator& it, const iterator& other)
99  { return it.current_ == other.current_; }
100 #ifdef __cpp_impl_three_way_comparison
101  constexpr auto operator<=>(const iterator& other) const noexcept { return current_ <=> other.current_; }
102 #else
103  constexpr bool operator!=(const iterator& other) const noexcept { return current_ != other.current_; }
104  constexpr bool operator<(const iterator& other) const noexcept { return current_ < other.current_; }
105  constexpr bool operator>(const iterator& other) const noexcept { return current_ > other.current_; }
106  constexpr bool operator<=(const iterator& other) const noexcept { return current_ <= other.current_; }
107  constexpr bool operator>=(const iterator& other) const noexcept { return current_ >= other.current_; }
108 #endif
109 
110  private:
111 
112  maybe_const<Const, F_box> * f_;
113  difference_type current_;
114 
115  }; // struct Iterator
116 
117 
121  constexpr
122  generate_view(F f, Size size)
123  : f_box {std::move(f)}, size_ {std::move(size)} {}
124 
125 
129 #ifdef __cpp_concepts
130  constexpr
131  generate_view(F f) noexcept requires (not values::index<Size>)
132 #else
133  template<bool Enable = true, std::enable_if_t<Enable and (not values::index<Size>), int> = 0>
134  constexpr
135  generate_view(F f) noexcept
136 #endif
137  : f_box {std::move(f)} {}
138 
139 
143  constexpr
144  generate_view() = default;
145 
146 
150  constexpr auto begin() { return iterator<false> {f_box, 0}; }
151 
153  constexpr auto begin() const { return iterator<true> {f_box, 0}; }
154 
155 
159  constexpr auto end()
160  {
161  if constexpr (values::index<Size>)
162  return iterator<false> {f_box, static_cast<std::size_t>(size_)};
163  else
164  return stdex::unreachable_sentinel;
165  }
166 
168  constexpr auto end() const
169  {
170  if constexpr (values::index<Size>)
171  return iterator<true> {f_box, static_cast<std::size_t>(size_)};
172  else
173  return stdex::unreachable_sentinel;
174  }
175 
176 
180 #ifdef __cpp_concepts
181  constexpr auto
182  size() const noexcept requires values::index<Size>
183 #else
184  template<bool Enable = true, std::enable_if_t<Enable and (values::index<Size>), int> = 0>
185  constexpr auto size() const noexcept
186 #endif
187  {
188  return size_;
189  }
190 
191 
195 #ifdef __cpp_explicit_this_parameter
196  template<std::size_t i>
197  constexpr decltype(auto)
198  get(this auto&& self) noexcept
199  {
200  static_assert (not values::fixed_value_compares_with<Size, i, &std::is_lteq>, "Index out of range");
201  return std::forward<decltype(self)>(self).f_box(std::integral_constant<std::size_t, i>{});
202  }
203 #else
204  template<std::size_t i>
205  constexpr decltype(auto)
206  get() &
207  {
208  static_assert (not values::fixed_value_compares_with<Size, i, &stdex::is_lteq>, "Index out of range");
209  return f_box(std::integral_constant<std::size_t, i>{});
210  }
211 
212  template<std::size_t i>
213  constexpr decltype(auto)
214  get() const &
215  {
216  static_assert (not values::fixed_value_compares_with<Size, i, &stdex::is_lteq>, "Index out of range");
217  return f_box(std::integral_constant<std::size_t, i>{});
218  }
219 
220  template<std::size_t i>
221  constexpr decltype(auto)
222  get() && noexcept
223  {
224  static_assert (not values::fixed_value_compares_with<Size, i, &stdex::is_lteq>, "Index out of range");
225  return std::move(*this).f_box(std::integral_constant<std::size_t, i>{});
226  }
227 
228  template<std::size_t i>
229  constexpr decltype(auto)
230  get() const && noexcept
231  {
232  static_assert (not values::fixed_value_compares_with<Size, i, &stdex::is_lteq>, "Index out of range");
233  return std::move(*this).f_box(std::integral_constant<std::size_t, i>{});
234  }
235 #endif
236 
237  private:
238 
239  F_box f_box;
240  Size size_;
241 
242  };
243 
244 
248  template<typename F, typename S>
250 
252  template<typename F>
254 
255 
256 }
257 
258 
259 #ifdef __cpp_lib_ranges
260 namespace std::ranges
261 #else
262 namespace OpenKalman::stdex::ranges
263 #endif
264 {
265  template<typename F, typename S>
266  constexpr bool enable_borrowed_range<OpenKalman::collections::generate_view<F, S>> = std::is_lvalue_reference_v<F> or
267  OpenKalman::stdex::semiregular<OpenKalman::collections::internal::movable_wrapper<F>>;
268 }
269 
270 
271 namespace std
272 {
273  template<typename F, typename S>
275 
276 
277  template<std::size_t i, typename F, typename S>
278  struct tuple_element<i, OpenKalman::collections::generate_view<F, S>>
279  {
280  using type = std::invoke_result_t<F, std::integral_constant<std::size_t, i>>;
281  };
282 
283 }
284 
285 
287 {
288  namespace detail
289  {
291  {
295 #ifdef __cpp_concepts
296  template<typename F, values::index Size> requires
297  std::invocable<F, std::size_t> and std::invocable<F, std::integral_constant<std::size_t, 0>>
298 #else
299  template<typename F, typename Size, std::enable_if_t<values::index<Size> and
300  std::is_invocable_v<F, std::size_t> and std::is_invocable_v<F, std::integral_constant<std::size_t, 0>>, int> = 0>
301 #endif
302  constexpr auto
303  operator() (F&& f, Size s) const
304  {
305  return generate_view {std::forward<F>(f), std::move(s)};
306  }
307 
308 
312 #ifdef __cpp_concepts
313  template<typename F> requires
314  std::invocable<F, std::size_t> and std::invocable<F, std::integral_constant<std::size_t, 0>>
315 #else
316  template<typename F, std::enable_if_t<std::is_invocable_v<F, std::size_t> and
317  std::is_invocable_v<F, std::integral_constant<std::size_t, 0>>, int> = 0>
318 #endif
319  constexpr auto
320  operator() (F&& f) const
321  {
322  return generate_view {std::forward<F>(f)};
323  }
324 
325  };
326 
327  }
328 
329 
336 
337 }
338 
339 #endif
Namespace for collections.
Definition: collections.hpp:27
constexpr auto size() const noexcept
The size of the resulting object.
Definition: generate.hpp:185
Definition of lexicographical_compare_three_way for collections.
Iterator for generate_view.
Definition: generate.hpp:57
Header file for code relating to values (e.g., scalars and indices)
generate_view(F, S) -> generate_view< F, S >
Deduction guide.
The fixed value associated with a fixed.
Definition: fixed_value_of.hpp:44
constexpr auto begin() const
Definition: generate.hpp:153
constexpr auto begin()
Definition: generate.hpp:150
Definition: view_interface.hpp:32
constexpr generate_view(F f, Size size)
Construct from a callable object and a size.
Definition: generate.hpp:122
A collection_view created by lazily generating elements based on an index.
Definition: generate.hpp:39
The root namespace for OpenKalman.
Definition: basics.hpp:34
decltype(auto) constexpr get() &
Get element i.
Definition: generate.hpp:206
Namespace for generalized views.
Definition: collections.hpp:33
constexpr detail::generate_adaptor generate
a collection_view generator associated with generate_view.
Definition: generate.hpp:335
constexpr generate_view()=default
Default constructor.
constexpr generate_view(F f) noexcept
Construct from a callable object, if the view is unsized.
Definition: generate.hpp:135
constexpr auto end()
Definition: generate.hpp:159
constexpr auto end() const
Definition: generate.hpp:168