OpenKalman
from_range.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_FROM_RANGE_HPP
17 #define OPENKALMAN_COLLECTIONS_VIEWS_FROM_RANGE_HPP
18 
19 #include <variant>
20 #include "values/values.hpp"
25 
27 {
28  namespace detail_from_range
29  {
30 #ifdef __cpp_concepts
31  template<std::size_t i, typename T>
32 #else
33  template<std::size_t i, typename T, typename = void>
34 #endif
36  {
37  using type = stdex::ranges::range_value_t<T>;
38 
39  template<typename R> constexpr decltype(auto) operator() (R&& r) const
40  { return get<i>(std::forward<R>(r)); }
41  };
42 
43 
44 #ifdef __cpp_concepts
45  template<std::size_t i, typename T> requires gettable<i, T>
46  struct tuple_element_impl<i, T>
47 #else
48  template<std::size_t i, typename T>
49  struct tuple_element_impl<i, T, std::enable_if_t<gettable<i, T>>>
50 #endif
51  : collection_element<i, T>
52  {
53  template<typename R> constexpr decltype(auto) operator() (R&& r) const
54  { return get<i>(std::forward<R>(r)); }
55  };
56 
57 
58 #ifdef __cpp_concepts
59  template<std::size_t i, typename T>
60 #else
61  template<std::size_t i, typename T, typename = void>
62 #endif
63  struct get_elem : tuple_element_impl<i, T> {};
64 
65 
66  template<std::size_t i, typename R>
67  inline constexpr decltype(auto)
68  get_from_base(R&& r) { return get_elem<i, stdex::remove_cvref_t<R>>{}(std::forward<R>(r)); }
69 
70 
71  template<typename T>
72  struct get_elem<0, stdex::ranges::single_view<T>>
73  {
74  using type = T;
75  template<typename U> constexpr decltype(auto) operator() (U&& u) const { return *std::forward<U>(u).data(); }
76  };
77 
78 
79  template<std::size_t i, typename R>
80  struct get_elem<i, stdex::ranges::ref_view<R>> : get_elem<i, stdex::remove_cvref_t<R>>
81  {
82  template<typename T> constexpr decltype(auto) operator() (T&& t) const { return get_from_base<i>(std::forward<T>(t).base()); }
83  };
84 
85 
86  template<std::size_t i, typename R>
87  struct get_elem<i, stdex::ranges::owning_view<R>> : get_elem<i, stdex::remove_cvref_t<R>>
88  {
89  template<typename T> constexpr decltype(auto) operator() (T&& t) const { return get_from_base<i>(std::forward<T>(t).base()); }
90  };
91 
92 
93 #ifdef __cpp_concepts
94  template<std::size_t i, typename V> requires (size_of_v<V> != stdex::dynamic_extent)
95  struct get_elem<i, stdex::ranges::reverse_view<V>>
96 #else
97  template<std::size_t i, typename V>
98  struct get_elem<i, stdex::ranges::reverse_view<V>, std::enable_if_t<size_of_v<V> != stdex::dynamic_extent>>
99 #endif
100  : get_elem<size_of_v<V> - i - 1_uz, stdex::remove_cvref_t<V>>
101  {
102  template<typename T> constexpr decltype(auto) operator() (T&& t) const
103  {
104  if constexpr (not std::is_lvalue_reference_v<T> or stdex::copy_constructible<V>)
105  return get_from_base<size_of_v<V> - i - 1_uz>(std::forward<T>(t).base());
106  else
107  return get<i>(std::forward<T>(t));
108  }
109  };
110 
111  }
112 
113 
117 #ifdef __cpp_concepts
118  template<stdex::ranges::random_access_range V> requires stdex::ranges::viewable_range<V>
119 #else
120  template<typename V>
121 #endif
123  {
124  private:
125 
127 
128  public:
129 
133 #ifdef __cpp_concepts
134  constexpr
135  from_range() = default;
136 #else
137  template<bool Enable = true, std::enable_if_t<Enable and stdex::default_initializable<RangeBox>, int> = 0>
138  constexpr
140 #endif
141 
142 
146 #ifdef __cpp_concepts
147  template<typename Arg> requires (not std::same_as<stdex::remove_cvref_t<Arg>, from_range>)
148 #else
149  template<typename Arg, std::enable_if_t<(not std::is_same_v<stdex::remove_cvref_t<Arg>, from_range>), int> = 0>
150 #endif
151  constexpr explicit
152  from_range(Arg&& arg) noexcept : r_ {std::forward<Arg>(arg)} {}
153 
154 
158 #ifdef __cpp_explicit_this_parameter
159  constexpr decltype(auto)
160  base(this auto&& self) noexcept { return std::forward<decltype(self)>(self).r_.get(); }
161 #else
162  constexpr V& base() & { return this->r_.get(); }
163  constexpr const V& base() const & { return this->r_.get(); }
164  constexpr V&& base() && noexcept { return std::move(*this).r_.get(); }
165  constexpr const V&& base() const && noexcept { return std::move(*this).r_.get(); }
166 #endif
167 
168 
172  constexpr auto begin() { return stdex::ranges::begin(base()); }
173 
175  constexpr auto begin() const { return stdex::ranges::begin(base()); }
176 
177 
181  constexpr auto end() { return stdex::ranges::end(base()); }
182 
184  constexpr auto end() const { return stdex::ranges::end(base()); }
185 
186 
190 #ifdef __cpp_concepts
191  constexpr auto
192  size() const requires sized<V>
193 #else
194  template<bool Enable = true, std::enable_if_t<Enable and sized<V>, int> = 0>
195  constexpr auto
196  size() const
197 #endif
198  {
199  if constexpr (values::fixed_value_compares_with<size_of<V>, stdex::dynamic_extent>)
200  return get_size(base());
201  else
202  return size_of<V>{};
203  }
204 
205 
209 #ifdef __cpp_concepts
210  constexpr auto
211  empty() const requires sized<V> or stdex::ranges::forward_range<V>
212 #else
213  template<bool Enable = true, std::enable_if_t<Enable and (sized<V> or stdex::ranges::forward_range<V>), int> = 0>
214  constexpr auto
215  empty() const
216 #endif
217  {
218  if constexpr (sized<V>)
219  {
220  if constexpr (size_of_v<V> == stdex::dynamic_extent) return get_size(base()) == 0_uz;
221  else if constexpr (size_of_v<V> == 0) return std::true_type{};
222  else return std::false_type{};
223  }
224  else
225  {
226  return stdex::ranges::begin(base()) == stdex::ranges::end(base());
227  }
228  }
229 
230 
234  constexpr decltype(auto)
235  front() { return collections::get<0>(base()); }
236 
238  constexpr decltype(auto)
239  front() const { return collections::get<0>(base()); }
240 
241  private:
242 
243 #ifdef __cpp_lib_ranges
244  template<typename T>
245 #else
246  template<typename T, typename = void>
247 #endif
248  struct back_gettable : std::false_type {};
249 
250  template<typename T>
251 #ifdef __cpp_lib_ranges
252  requires values::fixed_value_compares_with<size_of<T>, stdex::dynamic_extent, &stdex::is_neq>
253  struct back_gettable<T>
254 #else
255  struct back_gettable<T, std::enable_if_t<
256  values::fixed_value_compares_with<size_of<T>, stdex::dynamic_extent, &stdex::is_neq>>>
257 #endif
258  : std::bool_constant<gettable<size_of_v<T> - 1_uz, T>> {};
259 
260  public:
261 
265 #ifdef __cpp_concepts
266  constexpr decltype(auto)
267  back() requires (stdex::ranges::bidirectional_range<V> and stdex::ranges::common_range<V>) or back_gettable<V>::value
268 #else
269  template<bool Enable = true, std::enable_if_t<Enable and
270  (stdex::ranges::bidirectional_range<V> and stdex::ranges::common_range<V>) or back_gettable<V>::value, int> = 0>
271  constexpr decltype(auto)
272  back()
273 #endif
274  {
275  if constexpr (back_gettable<V>::value)
276  return collections::get<size_of_v<V> - 1_uz>(base());
277  else
279  }
280 
282 #ifdef __cpp_concepts
283  constexpr decltype(auto)
284  back() const requires (stdex::ranges::bidirectional_range<V> and stdex::ranges::common_range<V>) or back_gettable<V>::value
285 #else
286  template<bool Enable = true, std::enable_if_t<Enable and
287  (stdex::ranges::bidirectional_range<V> and stdex::ranges::common_range<V>) or back_gettable<V>::value, int> = 0>
288  constexpr decltype(auto)
289  back() const
290 #endif
291  {
292  if constexpr (back_gettable<V>::value)
293  return collections::get<size_of_v<V> - 1_uz>(base());
294  else
296  }
297 
298 
303 #ifdef __cpp_explicit_this_parameter
304  template<typename Self, values::index I>
305  constexpr decltype(auto)
306  operator[](this Self&& self, I i)
307  {
308  static_assert(not values::size_compares_with<I, size_of<V>, &stdex::is_gteq>, "Index out of range");
309  return collections::get_element(std::forward<Self>(self), std::move(i));
310  }
311 #else
312  template<typename I, std::enable_if_t<values::index<I>, int> = 0>
313  constexpr decltype(auto)
314  operator[](I i) &
315  {
316  static_assert(not values::size_compares_with<I, size_of<V>, &stdex::is_gteq>, "Index out of range");
317  return collections::get_element(*this, std::move(i));
318  }
319 
320  template<typename I, std::enable_if_t<values::index<I>, int> = 0>
321  constexpr decltype(auto)
322  operator[](I i) const &
323  {
324  static_assert(not values::size_compares_with<I, size_of<V>, &stdex::is_gteq>, "Index out of range");
325  return collections::get_element(*this, std::move(i));
326  }
327 
328  template<typename I, std::enable_if_t<values::index<I>, int> = 0>
329  constexpr decltype(auto)
330  operator[](I i) && noexcept
331  {
332  static_assert(not values::size_compares_with<I, size_of<V>, &stdex::is_gteq>, "Index out of range");
333  return collections::get_element(std::move(*this), std::move(i));
334  }
335 
336  template<typename I, std::enable_if_t<values::index<I>, int> = 0>
337  constexpr decltype(auto)
338  operator[](I i) const && noexcept
339  {
340  static_assert(not values::size_compares_with<I, size_of<V>, &stdex::is_gteq>, "Index out of range");
341  return collections::get_element(std::move(*this), std::move(i));
342  }
343 #endif
344 
345 
350 #ifdef __cpp_explicit_this_parameter
351  template<std::size_t i>
352  constexpr decltype(auto)
353  get(this auto&& self) noexcept
354  {
355  using Ni = std::integral_constant<std::size_t, i>;
356  static_assert(not values::size_compares_with<Ni, size_of<V>, &stdex::is_gteq>, "Index out of range");
357  return detail_from_range::get_from_base<i>(std::forward<decltype(self)>(self).base());
358  }
359 #else
360  template<std::size_t i>
361  constexpr decltype(auto)
362  get() &
363  {
364  using Ni = std::integral_constant<std::size_t, i>;
365  static_assert(not values::size_compares_with<Ni, size_of<V>, &stdex::is_gteq>, "Index out of range");
366  return detail_from_range::get_from_base<i>(base());
367  }
368 
369  template<std::size_t i>
370  constexpr decltype(auto)
371  get() const &
372  {
373  using Ni = std::integral_constant<std::size_t, i>;
374  static_assert(not values::size_compares_with<Ni, size_of<V>, &stdex::is_gteq>, "Index out of range");
375  return detail_from_range::get_from_base<i>(base());
376  }
377 
378  template<std::size_t i>
379  constexpr decltype(auto)
380  get() && noexcept
381  {
382  using Ni = std::integral_constant<std::size_t, i>;
383  static_assert(not values::size_compares_with<Ni, size_of<V>, &stdex::is_gteq>, "Index out of range");
384  return detail_from_range::get_from_base<i>(std::move(*this).base());
385  }
386 
387  template<std::size_t i>
388  constexpr decltype(auto)
389  get() const && noexcept
390  {
391  using Ni = std::integral_constant<std::size_t, i>;
392  static_assert(not values::size_compares_with<Ni, size_of<V>, &stdex::is_gteq>, "Index out of range");
393  return detail_from_range::get_from_base<i>(std::move(*this).base());
394  }
395 #endif
396 
397  private:
398 
399  RangeBox r_;
400 
401  };
402 
403 
405  template<typename V>
406  from_range(V&&) -> from_range<V>;
407 
408 
409 }
410 
411 
412 #ifdef __cpp_lib_ranges
413 namespace std::ranges
414 #else
415 namespace OpenKalman::stdex::ranges
416 #endif
417 {
418  template<typename V>
419  constexpr bool enable_borrowed_range<OpenKalman::collections::from_range<V>> =
420  std::is_lvalue_reference_v<V> or enable_borrowed_range<OpenKalman::stdex::remove_cvref_t<V>>;
421 }
422 
423 
424 namespace std
425 {
426  template<typename V>
427  struct tuple_size<OpenKalman::collections::from_range<V>>
428  : std::conditional_t<
429  OpenKalman::values::fixed_value_compares_with<
430  OpenKalman::collections::size_of<V>, OpenKalman::stdex::dynamic_extent, &OpenKalman::stdex::is_neq>,
431  OpenKalman::collections::size_of<V>,
432  monostate> {};
433 
434 
435  template<std::size_t i, typename V>
436  struct tuple_element<i, OpenKalman::collections::from_range<V>>
437  : OpenKalman::collections::detail_from_range::get_elem<i, OpenKalman::stdex::remove_cvref_t<V>> {};
438 }
439 
440 
441 #endif
constexpr from_range()
Default constructor.
Definition: from_range.hpp:139
constexpr auto size() const
The size of the resulting object.
Definition: from_range.hpp:196
Namespace for collections.
Definition: collections.hpp:27
Definition for collections::get.
constexpr detail_get::get_impl< i > get
A generalization of std::get, where the index is known at compile time.
Definition: get.hpp:50
from_range(V &&) -> from_range< V >
Deduction guide.
Header file for code relating to values (e.g., scalars and indices)
constexpr V & base() &
The base tuple.
Definition: from_range.hpp:162
A collection_view created from a std::ranges::random_access_range that is a std::ranges::viewable_ran...
Definition: from_range.hpp:122
constexpr auto end()
An iterator to the end of the range.
Definition: from_range.hpp:181
constexpr from_range(Arg &&arg) noexcept
Construct from a std::ranges::random_access_range.
Definition: from_range.hpp:152
Definition for collections::size_of.
The size of a sized object (including a collection).
Definition: size_of.hpp:33
constexpr bool value
T is a fixed or dynamic value that is reducible to a number.
Definition: value.hpp:45
constexpr auto begin()
An iterator to the beginning of the range.
Definition: from_range.hpp:172
Definition: view_interface.hpp:32
Definition for collections::get_size.
The root namespace for OpenKalman.
Definition: basics.hpp:34
constexpr auto empty() const
Definition: from_range.hpp:215
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
constexpr bool size_compares_with
T and U are sizes that compare in a particular way based on parameter comp.
Definition: size_compares_with.hpp:98
The type of the element at a given index, if it can be determined at compile time.
Definition: collection_element.hpp:48
constexpr bool fixed_value_compares_with
T has a fixed value that compares with N in a particular way based on parameter comp.
Definition: fixed_value_compares_with.hpp:74
decltype(auto) constexpr get_element(Arg &&arg, I i)
A generalization of std::get and the range subscript operator.
Definition: get_element.hpp:122
constexpr auto begin() const
Definition: from_range.hpp:175
constexpr auto get_size(Arg &&arg)
Get the size of a sized object (e.g, a collection)
Definition: get_size.hpp:188
constexpr auto end() const
Definition: from_range.hpp:184