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