OpenKalman
transform.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_TRANSFORM_HPP
18 #define OPENKALMAN_COMPATIBILITY_VIEWS_TRANSFORM_HPP
19 
20 #ifndef __cpp_lib_ranges
21 
23 #include "basics/compatibility/ranges/range-access.hpp"
25 #include "view-concepts.hpp"
26 #include "view_interface.hpp"
27 #include "all.hpp"
28 
29 namespace OpenKalman::ranges
30 {
34  template<typename V, typename F>
35  struct transform_view : ranges::view_interface<transform_view<V, F>>
36  {
37  private:
38 
39  static_assert(ranges::input_range<V>);
40  static_assert(std::is_move_constructible_v<F>);
41  static_assert(ranges::view<V>);
42  static_assert(std::is_object_v<F>);
43  static_assert(std::is_invocable_v<F&, ranges::range_reference_t<V>>);
44 
45  template<bool Const, typename T>
46  using maybe_const = std::conditional_t<Const, const T, T>;
47 
48  public:
49 
50  template<bool> struct sentinel;
51 
52 
53  template<bool Const>
54  struct iterator
55  {
56  private:
57 
58  using Parent = maybe_const<Const, transform_view>;
59  using Base = maybe_const<Const, V>;
60 
61  public:
62 
63  using iterator_concept = std::conditional_t<
64  ranges::random_access_range<Base>, std::random_access_iterator_tag,
65  std::conditional_t<ranges::bidirectional_range<Base>, std::bidirectional_iterator_tag,
66  std::conditional_t<ranges::forward_range<Base>, std::forward_iterator_tag, std::input_iterator_tag>>>;
67 
68  using reference = std::invoke_result_t<maybe_const<Const, F>&, ranges::range_reference_t<Base>>;
69  using value_type = remove_cvref_t<reference>;
70  using difference_type = ranges::range_difference_t<Base>;
71  using pointer = void;
72 
73  using iterator_category = std::conditional_t<
74  not std::is_reference_v<reference>,
75  std::input_iterator_tag,
76  typename std::iterator_traits<ranges::iterator_t<Base>>::iterator_category>;
77 
78  template<bool Enable = true, std::enable_if_t<Enable and std::is_default_constructible_v<ranges::iterator_t<Base>>, int> = 0>
79  constexpr iterator() {};
80 
81  constexpr iterator(Parent& parent, ranges::iterator_t<Base> current) : current_ {std::move(current)}, parent_ {std::addressof(parent)} {}
82 
83  template<bool Enable = Const, std::enable_if_t<Enable and std::is_convertible_v<ranges::iterator_t<V>, ranges::iterator_t<Base>>, int> = 0>
84  constexpr iterator(iterator<not Const> i) : current_ {std::move(i.current_)}, parent_ {std::move(i.parent_)} {}
85 
86  constexpr const ranges::iterator_t<Base>& base() const & noexcept { return current_; }
87 
88  constexpr ranges::iterator_t<Base> base() && { return std::move(current_); }
89 
90  constexpr decltype(auto) operator*() const
91  {
92 #if __cplusplus >= 202002L
93  namespace ns = std;
94 #else
95  namespace ns = OpenKalman;
96 #endif
97  return ns::invoke(std::get<0>(parent_->fun_), *current_);
98  }
99 
100  template<bool Enable = true, std::enable_if_t<Enable and ranges::random_access_range<Base>, int> = 0>
101  constexpr decltype(auto) operator[](difference_type n) const
102  {
103 #if __cplusplus >= 202002L
104  namespace ns = std;
105 #else
106  namespace ns = OpenKalman;
107 #endif
108  return ns::invoke(std::get<0>(parent_->fun_), current_[n]);
109  }
110 
111  constexpr iterator& operator++() { ++current_; return *this; }
112 
113  template<bool Enable = true, std::enable_if_t<Enable and not ranges::forward_range<Base>, int> = 0>
114  constexpr void operator++(int) { ++current_; }
115 
116  template<bool Enable = true, std::enable_if_t<Enable and ranges::forward_range<Base>, int> = 0>
117  constexpr iterator operator++(int) { auto tmp = *this; ++*this; return tmp; }
118 
119  template<bool Enable = true, std::enable_if_t<Enable and ranges::bidirectional_range<Base>, int> = 0>
120  constexpr iterator& operator--() { --current_; return *this; }
121 
122  template<bool Enable = true, std::enable_if_t<Enable and ranges::bidirectional_range<Base>, int> = 0>
123  constexpr iterator operator--(int) { auto tmp = *this; --*this; return tmp; }
124 
125  template<bool Enable = true, std::enable_if_t<Enable and ranges::random_access_range<Base>, int> = 0>
126  constexpr iterator& operator+=(const difference_type& n) { current_ += n; return *this; }
127 
128  template<bool Enable = true, std::enable_if_t<Enable and ranges::random_access_range<Base>, int> = 0>
129  constexpr iterator& operator-=(const difference_type& n) { current_ -= n; return *this; }
130 
131  friend constexpr bool operator==(const iterator& x, const iterator& y) { return x.current_ == y.current_; }
132 
133  friend constexpr bool operator!=(const iterator& x, const iterator& y) { return not (x.current_ == y.current_); }
134 
135  friend constexpr bool operator<(const iterator& x, const iterator& y) { return x.current_ < y.current_; }
136 
137  friend constexpr bool operator>(const iterator& x, const iterator& y) { return y < x; }
138 
139  friend constexpr bool operator<=(const iterator& x, const iterator& y) { return not (y < x); }
140 
141  friend constexpr bool operator>=(const iterator& x, const iterator& y) { return not (x < y); }
142 
143  template<bool Enable = true, std::enable_if_t<Enable and ranges::random_access_range<Base>, int> = 0>
144  friend constexpr iterator operator+(const iterator& i, const difference_type& n) { return iterator {*i.parent_, i.current_ + n}; }
145 
146  template<bool Enable = true, std::enable_if_t<Enable and ranges::random_access_range<Base>, int> = 0>
147  friend constexpr iterator operator+(const difference_type& n, const iterator& i) { return iterator {*i.parent_, i.current_ + n}; }
148 
149  template<bool Enable = true, std::enable_if_t<Enable and ranges::random_access_range<Base>, int> = 0>
150  friend constexpr iterator operator-(const iterator& i, const difference_type& n) { return iterator {*i.parent_, i.current_ - n}; }
151 
152  template<bool Enable = true, std::enable_if_t<Enable and ranges::random_access_range<Base>, int> = 0>
153  friend constexpr difference_type operator-(const iterator& x, const iterator& y) { return x.current_ - y.current_; }
154 
155  template<bool Enable = true, std::enable_if_t<Enable and ranges::random_access_range<Base>, int> = 0>
156  friend constexpr decltype(auto) iter_move(const iterator& i) noexcept(noexcept(std::invoke(std::get<0>(i.parent_->fun_), *i.current_)))
157  {
158  if constexpr (std::is_lvalue_reference_v<decltype(*i)>) return std::move(*i);
159  else return *i;
160  }
161 
162  private:
163 
164  template<bool> friend struct transform_view::sentinel;
165  ranges::iterator_t<Base> current_;
166  Parent* parent_;
167  };
168 
169 
170  template<bool Const>
171  struct sentinel
172  {
173  private:
174 
175  using Parent = maybe_const<Const, transform_view>;
176  using Base = maybe_const<Const, V>;
177  using difference_type = ranges::range_difference_t<Base>;
178 
179  public:
180 
181  sentinel() = default;
182 
183  constexpr explicit sentinel(ranges::sentinel_t<Base> end) : end_ {end} {};
184 
185  constexpr const ranges::sentinel_t<Base>& base() const { return end_; }
186 
187  friend constexpr bool operator==( const iterator<Const>& x, const sentinel<Const>& y ) { return x.current_ == y.end_; }
188 
189  friend constexpr bool operator==( const sentinel<Const>& y, const iterator<Const>& x ) { return y.end_ == x.current_; }
190 
191  friend constexpr bool operator!=( const iterator<Const>& x, const sentinel<Const>& y ) { return not (x.current_ == y.end_); }
192 
193  friend constexpr bool operator!=( const sentinel<Const>& y, const iterator<Const>& x ) { return not (y.end_ == x.current_); }
194 
195  template<bool Enable = true, std::enable_if_t<Enable and
196  std::is_convertible_v<decltype(std::declval<ranges::iterator_t<Base>>() - std::declval<ranges::sentinel_t<Base>>()), difference_type>, int> = 0>
197  friend constexpr difference_type operator-(const iterator<Const>& x, const sentinel& y)
198  { return x.current_ - y.end_; }
199 
200  template<bool Enable = true, std::enable_if_t<Enable and
201  std::is_convertible_v<decltype(-(std::declval<ranges::sentinel_t<Base>>() - std::declval<ranges::iterator_t<Base>>())), difference_type>, int> = 0>
202  friend constexpr difference_type operator-(const sentinel& y, const iterator<Const>& x)
203  { return y.end_ - x.current_; }
204 
205  private:
206 
207  ranges::sentinel_t<Base> end_;
208  };
209 
210 
211  template<bool Enable = true, std::enable_if_t<Enable and std::is_default_constructible_v<V> and std::is_default_constructible_v<F>, int> = 0>
212  constexpr
213  transform_view() {}
214 
215 
216  constexpr explicit
217  transform_view(V base, F fun) : base_ {std::move(base)}, fun_ {std::move(fun)} {}
218 
219 
220  template<bool Enable = true, std::enable_if_t<Enable and std::is_copy_constructible_v<V>, int> = 0>
221  constexpr V
222  base() const& { return base_; }
223 
224  constexpr V
225  base() && { return std::move(base_); }
226 
227 
228  constexpr auto
229  begin() { return iterator<false> {*this, ranges::begin(base_)}; }
230 
231  template<bool Enable = true, std::enable_if_t<Enable and
232  ranges::range<const V> and std::is_invocable_v<const F&, ranges::range_reference_t<const V>>, int> = 0>
233  constexpr auto
234  begin() const { return iterator<true> {*this, ranges::begin(base_)}; }
235 
236 
237  template<bool Enable = true, std::enable_if_t<Enable and not ranges::common_range<V>, int> = 0>
238  constexpr auto
239  end() { return sentinel<false> {ranges::end(base_)}; }
240 
241  template<bool Enable = true, std::enable_if_t<Enable and ranges::common_range<V>, int> = 0>
242  constexpr auto
243  end() { return iterator<false> {*this, ranges::end(base_)}; }
244 
245  template<bool Enable = true, std::enable_if_t<Enable and ranges::range<const V> and not ranges::common_range<const V> and
246  std::is_invocable_v<const F&, ranges::range_reference_t<const V>>, int> = 0>
247  constexpr auto
248  end() const { return sentinel<true> {ranges::end(base_)}; }
249 
250  template<bool Enable = true, std::enable_if_t<Enable and ranges::common_range<const V> and
251  std::is_invocable_v<const F&, ranges::range_reference_t<const V>>, int> = 0>
252  constexpr auto
253  end() const { return iterator<true> {*this, ranges::end(base_)}; }
254 
255 
256  template<bool Enable = true, std::enable_if_t<Enable and ranges::sized_range<V>, int> = 0>
257  constexpr auto
258  size() { return ranges::size(base_); }
259 
260  template<bool Enable = true, std::enable_if_t<Enable and ranges::sized_range<const V>, int> = 0>
261  constexpr auto
262  size() const { return ranges::size(base_); }
263 
264  private:
265 
266  V base_;
267  std::tuple<F> fun_;
268 
269  };
270 
271 
272  template<typename R, typename F>
274 
275 } // namespace OpenKalman::values
276 
277 
279 {
280  namespace detail
281  {
282  template<typename F>
284  : ranges::range_adaptor_closure<transform_closure<F>>
285  {
286  constexpr transform_closure(F&& f) : my_f {std::forward<F>(f)} {};
287 
288  template<typename R, std::enable_if_t<ranges::viewable_range<R>, int> = 0>
289  constexpr auto
290  operator() (R&& r) const { return transform_view {std::forward<R>(r), my_f}; }
291 
292  private:
293  F my_f;
294  };
295 
296 
298  {
299  template<typename F>
300  constexpr auto
301  operator() (F&& f) const
302  {
303  return transform_closure<F> {std::forward<F>(f)};
304  }
305 
306 
307  template<typename R, typename F, std::enable_if_t<ranges::viewable_range<R>, int> = 0>
308  constexpr auto
309  operator() (R&& r, F&& f) const
310  {
311  return transform_view {std::forward<R>(r), std::forward<F>(f)};
312  }
313 
314  };
315 
316  }
317 
318 
326 
327 }
328 
329 #endif
330 
331 #endif //OPENKALMAN_COMPATIBILITY_VIEWS_TRANSFORM_HPP
Definition: view_interface.hpp:32
constexpr detail::transform_adaptor transform
a std::ranges::range_adaptor_closure associated with transform_view.
Definition: transform.hpp:325
Definition: tuple_reverse.hpp:103
The root namespace for OpenKalman.
Definition: basics.hpp:34
Definition: range-access.hpp:25
Definitions relating to the availability of c++ language features.
constexpr bool size
T is either an index representing a size, or void which represents that there is no size...
Definition: size.hpp:32
Definition: range_adaptor_closure.hpp:35
Definition: all.hpp:35
Equivalent to std::ranges::transform_view.
Definition: transform.hpp:35