OpenKalman
update.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_UPDATE_HPP
17 #define OPENKALMAN_COLLECTIONS_VIEWS_UPDATE_HPP
18 
19 #include <type_traits>
20 #ifdef __cpp_lib_ranges
21 #include <ranges>
22 #else
24 #endif
25 #include "all.hpp"
33 
35 {
43 #ifdef __cpp_lib_ranges
44  template<collection_view V, typename F> requires
45  std::is_invocable_r_v<std::ranges::range_value_t<const V>, F&, std::remove_cvref_t<V>&, std::integral_constant<std::size_t, 0>>
46  struct update_view : std::ranges::view_interface<update_view<V, F>>
47 #else
48  template<typename V, typename F>
49  struct update_view : ranges::view_interface<update_view<V, F>>
50 #endif
51  {
52  private:
53 
54  template<bool Const, typename T>
55  using maybe_const = std::conditional_t<Const, const T, T>;
56 
58 
59  using value_type = std::invoke_result_t<F, V&, std::size_t>;
60 
61  public:
62 
66  template<bool Const, typename Index>
67  class proxy
68  {
69  using Parent = maybe_const<Const, update_view>;
70 
71  template<typename Fun, typename...Args>
72  static constexpr decltype(auto)
73  invoke_fun(Fun&& f, Args&&... args) noexcept(std::is_nothrow_invocable_v<Fun, Args...>)
74  {
75  #if __cplusplus >= 202002L
76  namespace ns = std;
77  #else
78  namespace ns = OpenKalman;
79  #endif
80  return ns::invoke(std::forward<Fun>(f), std::forward<Args>(args)...);
81  }
82 
83  public:
84 
85  constexpr proxy(Parent * parent, Index current = {}) : parent_ {parent}, current_ {std::move(current)} {}
86 
87  constexpr operator std::ranges::range_value_t<V> () const
88  {
89  return invoke_fun(parent_->f_.get(), parent_->v_, current_);
90  }
91 
92 #ifdef __cpp_lib_ranges
93  constexpr proxy& operator=(std::ranges::range_value_t<V> x) requires
94  std::invocable<S&, std::remove_cvref_t<V>&, std::integral_constant<std::size_t, 0>, std::ranges::range_value_t<V>> and
95  std::ranges::output_range<V, std::ranges::range_value_t<views::all_t<V>>>
96 #else
97  template<bool Enable = true, std::enable_if_t<Enable and
98  std::is_invocable_v<S&, remove_cvref_t<V>&, std::integral_constant<std::size_t, 0>, ranges::range_value_t<V>> and
99  ranges::output_range<V, ranges::range_value_t<views::all_t<V>>>, int> = 0>
100  constexpr proxy& operator=(std::ranges::range_value_t<V> x) requires
101 #endif
102  {
103  invoke_fun(parent_->s_.get(), parent_->v_, current_, std::move(x));
104  return *this;
105  }
106 
107  private:
108 
109  Parent * parent_;
110  Index current_;
111  };
112 
113 
118  template<bool Const>
119  class iterator
120  {
121  using Parent = maybe_const<Const, update_view>;
122  using Base = maybe_const<Const, V>;
123 
124  public:
125 
126  using iterator_concept = std::random_access_iterator_tag;
127  using iterator_category = std::random_access_iterator_tag;
128  using difference_type = std::ptrdiff_t;
129  using pointer = void;
131  using reference = value_type;
132 
133  constexpr iterator() = default;
134 
135  constexpr iterator(maybe_const<Const, Parent>* parent, std::size_t pos)
136  : current_ {static_cast<difference_type>(pos)}, parent_ {parent} {}
137 
138  explicit constexpr iterator(iterator<not Const> i) : current_ {std::move(i.current_)}, parent_ {std::move(i.parent_)} {}
139 
140  constexpr auto operator*() const { return value_type {parent_, static_cast<std::size_t>(current_)}; }
141 
142  constexpr auto operator[](difference_type n) const { return value_type {parent_, static_cast<std::size_t>(current_ + n)}; }
143 
144  constexpr iterator& operator++() { ++current_; return *this; }
145 
146  constexpr iterator operator++(int) { auto tmp = *this; ++*this; return tmp; }
147 
148  constexpr iterator& operator--() { --current_; return *this; }
149 
150  constexpr iterator operator--(int) { auto tmp = *this; --*this; return tmp; }
151 
152  constexpr iterator& operator+=(const difference_type& n) { current_ += n; return *this; }
153 
154  constexpr iterator& operator-=(const difference_type& n) { current_ -= n; return *this; }
155 
156  friend constexpr bool operator==(const iterator& x, const iterator& y) { return x.current_ == y.current_; }
157 
158  friend constexpr bool operator!=(const iterator& x, const iterator& y) { return not (x.current_ == y.current_); }
159 
160  friend constexpr bool operator<(const iterator& x, const iterator& y) { return x.current_ < y.current_; }
161 
162  friend constexpr bool operator>(const iterator& x, const iterator& y) { return y < x; }
163 
164  friend constexpr bool operator<=(const iterator& x, const iterator& y) { return not (y < x); }
165 
166  friend constexpr bool operator>=(const iterator& x, const iterator& y) { return not (x < y); }
167 
168  friend constexpr iterator operator+(const iterator& i, const difference_type& n) { return iterator {*i.parent_, i.current_ + n}; }
169 
170  friend constexpr iterator operator+(const difference_type& n, const iterator& i) { return iterator {*i.parent_, i.current_ + n}; }
171 
172  friend constexpr iterator operator-(const iterator& i, const difference_type& n) { return iterator {*i.parent_, i.current_ - n}; }
173 
174  friend constexpr difference_type operator-(const iterator& x, const iterator& y) { return x.current_ - y.current_; }
175 
176  private:
177 
178  difference_type current_;
179  Parent * parent_;
180  };
181 
182 
186 #ifdef __cpp_concepts
187  constexpr
188  update_view() requires std::default_initializable<V> = default;
189 #else
190  template<bool Enable = true, std::enable_if_t<Enable and std::is_default_constructible_v<V> and
191  std::is_default_constructible_v<F_box> and std::is_default_constructible_v<S_box>, int> = 0>
192  constexpr
194 #endif
195 
196 
200  template<typename G_, typename S_>
201  constexpr
202  update_view(V& v, G_&& g, S_&& s) : v_ {v}, f_ {std::forward<G_>(g)}, s_ {std::forward<S_>(s)} {}
203 
205  template<typename G_, typename S_>
206  constexpr
207  update_view(V&& v, G_&& g, S_&& s) : v_ {std::move(v)}, f_ {std::forward<G_>(g)}, s_ {std::forward<S_>(s)} {}
208 
209 
213  constexpr auto begin() { return iterator<false> {this, 0}; }
214 
216  constexpr auto begin() const { return iterator<true> {this, 0}; }
217 
218 
222  constexpr auto end()
223  {
224  using namespace std;
225  if constexpr (sized<V>) return iterator<false> {this, get_size(v_)};
226  else return unreachable_sentinel;
227  }
228 
230  constexpr auto end() const
231  {
232  using namespace std;
233  if constexpr (sized<V>) return iterator<true> {this, get_size(v_)};
234  else return unreachable_sentinel;
235  }
236 
237 
241 #ifdef __cpp_concepts
242  constexpr values::index auto
243  size() const requires sized<V>
244 #else
245  template<bool Enable = true, std::enable_if_t<Enable and sized<V>, int> = 0>
246  constexpr auto size() const
247 #endif
248  {
249  return get_size(v_);
250  }
251 
252 
256  template<std::size_t i>
257  constexpr decltype(auto)
258  get()
259  {
260  if constexpr (sized<V>) if constexpr (size_of_v<V> != dynamic_size) static_assert(i < size_of_v<V>, "Index out of range");
262  }
263 
265  template<std::size_t i>
266  constexpr decltype(auto)
267  get() const
268  {
269  if constexpr (sized<V>) if constexpr (size_of_v<V> != dynamic_size) static_assert(i < size_of_v<V>, "Index out of range");
271  }
272 
273  private:
274 
275  V v_;
276  F_box f_;
277 
278  };
279 
280 
281  template<typename V, typename F>
282  update_view(const V&, F&&) -> update_view<V, F>;
283 
284 
285 #ifndef __cpp_concepts
286  namespace detail
287  {
288  template<std::size_t i, typename C, typename Fun, typename = void>
290 
291  template<std::size_t i, typename C, typename Fun>
292  struct update_view_tuple_element_impl<i, C, Fun, std::enable_if_t<tuple_like<C>>>
293  {
294  using type = std::invoke_result_t<Fun, std::tuple_element_t<i, C>>;
295  };
296  } // namespace detail
297 #endif
298 
299 
300 
301 #ifndef __cpp_concepts
302  namespace detail_update
303  {
304  template<typename V, typename = void>
305  struct tuple_size {};
306 
307  template<typename V>
308  struct tuple_size<V, std::enable_if_t<sized<V> and size_of<V>::value != dynamic_size>> : size_of<V> {};
309  }
310 #endif
311 
312 }
313 
314 
315 namespace std
316 {
317 #ifdef __cpp_concepts
318  template<OpenKalman::collections::sized V, typename F> requires
319  (OpenKalman::collections::size_of_v<V> != OpenKalman::dynamic_size)
320  struct tuple_size<OpenKalman::collections::update_view<V, F>> : OpenKalman::collections::size_of<V> {};
321 #else
322  template<typename V, typename F>
323  struct tuple_size<OpenKalman::collections::update_view<V, F>> : OpenKalman::collections::detail_update::tuple_size<V> {};
324 #endif
325 
326 
327  template<std::size_t i, typename V, typename F>
328  struct tuple_element<i, OpenKalman::collections::update_view<V, F>>
329  {
330 #ifdef __cpp_lib_ranges
331  using type = std::invoke_result_t<F, V&, std::integral_constant<std::size_t, i>>;
332 #else
333  using type = std::invoke_result_t<F, V&, std::integral_constant<std::size_t, i>>;
334 #endif
335  };
336 
337 } // namespace std
338 
339 
341 {
342  namespace detail
343  {
344  template<typename F>
346 #if __cpp_lib_ranges >= 202202L
347  : std::ranges::range_adaptor_closure<update_closure<F>>
348 #else
350 #endif
351  {
352  constexpr update_closure(F&& f) : f_ {std::forward<F>(f)} {};
353 
354 
355 #ifdef __cpp_concepts
356  template<viewable_collection R> requires
357  std::is_invocable_r_v<std::ranges::range_value_t<R>, F, all_t<R&&>, std::integral_constant<std::size_t, 0>>
358 #else
359  template<typename R>
360 #endif
361  constexpr auto
362  operator() (R&& r) const { return update_view {all(std::forward<R>(r)), f_}; }
363 
364  private:
365 
366  F f_;
367  };
368 
369 
371  {
372  template<typename F>
373  constexpr auto
374  operator() (F&& f) const
375  {
376  return update_closure<std::decay_t<F>> {std::forward<F>(f)};
377  }
378 
379 
380 #ifdef __cpp_concepts
381  template<viewable_collection R, typename F> requires
382  std::is_invocable_r_v<std::ranges::range_value_t<R>, F, all_t<R&&>, std::integral_constant<std::size_t, 0>>
383 #else
384  template<typename R, typename F>
385 #endif
386  constexpr auto
387  operator() (R&& r, F&& g) const
388  {
389  return update_view {std::forward<R>(r) | all, std::forward<F>(g)};
390  }
391 
392  };
393 
394  }
395 
396 
403  inline constexpr detail::update_adaptor update;
404 
405 }
406 
407 #endif //OPENKALMAN_COLLECTIONS_VIEWS_UPDATE_HPP
Definition for values::index.
Namespace for collections.
Definition: collections.hpp:27
constexpr auto end() const
Definition: update.hpp:230
A collection_view that updates an underlying collection_view on an element-by-element basis...
Definition: update.hpp:49
Definition: view_interface.hpp:32
Definition for collections::sized_random_access_range.
Definition: tuple_reverse.hpp:103
The size of a sized object (including a collection).
Definition: size_of.hpp:36
Definition for collections::get_size.
The root namespace for OpenKalman.
Definition: basics.hpp:34
Definition for collections::collection_view.
Iterator for update_view.
Definition: update.hpp:119
constexpr auto end()
Definition: update.hpp:222
Definition: range_adaptor_closure.hpp:35
constexpr auto begin()
Definition: update.hpp:213
Namespace for generalized views.
Definition: collections.hpp:33
constexpr update_view(V &v, G_ &&g, S_ &&s)
Construct from a collection, a getter function, and a setter function.
Definition: update.hpp:202
decltype(auto) constexpr get()
Get element i.
Definition: update.hpp:258
constexpr auto begin() const
Definition: update.hpp:216
Definitions implementing features of the c++ ranges library for compatibility.
constexpr bool index
T is an index value.
Definition: index.hpp:56
Definition for ::fixed.
Definition for collections::viewable_collection.
constexpr std::size_t dynamic_size
A constant indicating that a size or index is dynamic.
Definition: global-definitions.hpp:33
decltype(all(std::declval< R >())) all_t
Calculates the suitable collection_view type of a viewable_collection type.
Definition: all.hpp:97
constexpr auto get_size(Arg &&arg)
Get the size of a sized object (e.g, a collection)
Definition: get_size.hpp:191
constexpr update_view(V &&v, G_ &&g, S_ &&s)
Definition: update.hpp:207
constexpr auto size() const
The size of the resulting object.
Definition: update.hpp:246
constexpr update_view()
Default constructor.
Definition: update.hpp:193
A proxy object for accessing the base view.
Definition: update.hpp:67
constexpr detail::update_adaptor update
a std::ranges::range_adaptor_closure associated with update_view.
Definition: update.hpp:403