OpenKalman
from_tuple.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_TUPLE_HPP
17 #define OPENKALMAN_COLLECTIONS_VIEWS_FROM_TUPLE_HPP
18 
19 #include <type_traits>
20 #ifdef __cpp_lib_ranges
21 #include <ranges>
22 #else
25 #endif
32 
34 {
35  namespace detail
36  {
37  template<typename D, typename = std::make_index_sequence<std::tuple_size_v<D>>>
39 
40 
41  template<typename D>
42  struct tuple_iterator_call_table<D, std::index_sequence<>>
43  {
44  using element_type = int;
45 
46  static constexpr int
47  call_table_get(const D&) noexcept { return 0; }
48 
49  static constexpr std::array<decltype(call_table_get), 0> value {};
50  };
51 
52 
53  template<typename D, std::size_t...is>
54  struct tuple_iterator_call_table<D, std::index_sequence<is...>>
55  {
56  using element_type = common_tuple_type_t<D>;
57 
58  template<std::size_t i>
59  static constexpr element_type
60  call_table_get(const D& tup) noexcept { return OpenKalman::internal::generalized_std_get<i>(tup); }
61 
62  static constexpr std::array value {call_table_get<is>...};
63  };
64  }
65 
66 
70 #ifdef __cpp_lib_ranges
71  template<uniform_tuple_like Tup>
72  struct from_tuple : std::ranges::view_interface<from_tuple<Tup>>
73 #else
74  template<typename Tup>
75  struct from_tuple : ranges::view_interface<from_tuple<Tup>>
76 #endif
77  {
78  private:
79 
81 
82  template<bool Const, typename T>
83  using maybe_const = std::conditional_t<Const, const T, T>;
84 
85  public:
86 
91  template<bool Const>
92  struct iterator
93  {
94  private:
95 
96  using Parent = maybe_const<Const, from_tuple>;
98 
99  public:
100 
101  using iterator_concept = std::random_access_iterator_tag;
102  using iterator_category = std::random_access_iterator_tag;
103  using value_type = maybe_const<Const, typename call_table::element_type>;
104  using difference_type = std::ptrdiff_t;
105  using reference = typename call_table::element_type&;
106  using pointer = void;
107  constexpr iterator() = default;
108  constexpr iterator(Parent& p, std::size_t pos) : parent_ {std::addressof(p)}, current_{static_cast<difference_type>(pos)} {}
109  constexpr iterator(iterator<not Const> it) : parent_ {std::move(it.parent_)}, current_ {std::move(it.current_)} {}
110  constexpr decltype(auto) operator*() { return call_table::value[current_](parent_->tup_); }
111  constexpr decltype(auto) operator*() const { return call_table::value[current_](parent_->tup_); }
112  constexpr decltype(auto) operator[](difference_type offset) { return call_table::value[current_ + offset](parent_->tup_); }
113  constexpr decltype(auto) operator[](difference_type offset) const { return call_table::value[current_ + offset](parent_->tup_); }
114  constexpr auto& operator++() { ++current_; return *this; }
115  constexpr auto operator++(int) { auto temp = *this; ++*this; return temp; }
116  constexpr auto& operator--() { --current_; return *this; }
117  constexpr auto operator--(int) { auto temp = *this; --*this; return temp; }
118  constexpr auto& operator+=(const difference_type diff) { current_ += diff; return *this; }
119  constexpr auto& operator-=(const difference_type diff) { current_ -= diff; return *this; }
120  friend constexpr auto operator+(const iterator& it, const difference_type diff)
121  { return iterator {*it.parent_, static_cast<std::size_t>(it.current_ + diff)}; }
122  friend constexpr auto operator+(const difference_type diff, const iterator& it)
123  { return iterator {*it.parent_, static_cast<std::size_t>(diff + it.current_)}; }
124  friend constexpr auto operator-(const iterator& it, const difference_type diff)
125  { if (it.current_ < diff) throw std::out_of_range{"Iterator out of range"}; return iterator {*it.parent_, static_cast<std::size_t>(it.current_ - diff)}; }
126  friend constexpr difference_type operator-(const iterator& it, const iterator& other)
127  { return it.current_ - other.current_; }
128  friend constexpr bool operator==(const iterator& it, const iterator& other)
129  { return it.current_ == other.current_; }
130 #ifdef __cpp_impl_three_way_comparison
131  constexpr auto operator<=>(const iterator& other) const { return current_ <=> other.current_; }
132 #else
133  constexpr bool operator!=(const iterator& other) const { return current_ != other.current_; }
134  constexpr bool operator<(const iterator& other) const { return current_ < other.current_; }
135  constexpr bool operator>(const iterator& other) const { return current_ > other.current_; }
136  constexpr bool operator<=(const iterator& other) const { return current_ <= other.current_; }
137  constexpr bool operator>=(const iterator& other) const { return current_ >= other.current_; }
138 #endif
139 
140  private:
141 
142  Parent * parent_;
143  difference_type current_;
144 
145  }; // struct iterator
146 
147 
151 #ifdef __cpp_concepts
152  constexpr
153  from_tuple() = default;
154 #else
155  template<bool Enable = true, std::enable_if_t<Enable and std::is_default_constructible_v<TupBox>, int> = 0>
156  constexpr
158 #endif
159 
160 
164 #if defined(__cpp_concepts) and defined(__cpp_lib_remove_cvref)
165  template<typename Arg> requires std::constructible_from<TupBox, Arg&&> and (not std::same_as<std::remove_cvref_t<Arg>, from_tuple>)
166 #else
167  template<typename Arg, std::enable_if_t<
168  std::is_constructible_v<TupBox, Arg&&> and (not std::is_same_v<remove_cvref_t<Arg>, from_tuple>), int> = 0>
169 #endif
170  constexpr explicit
171  from_tuple(Arg&& arg) noexcept : tup_ {std::forward<Arg>(arg)} {}
172 
173 
177 #ifdef __cpp_explicit_this_parameter
178  constexpr decltype(auto)
179  base(this auto&& self) noexcept { return std::forward<decltype(self)>(self).tup_.get(); }
180 #else
181  constexpr decltype(auto) base() & { return this->tup_.get(); }
182  constexpr decltype(auto) base() const & { return this->tup_.get(); }
183  constexpr decltype(auto) base() && noexcept { return std::move(*this).tup_.get(); }
184  constexpr decltype(auto) base() const && noexcept { return std::move(*this).tup_.get(); }
185 #endif
186 
187 
193  constexpr auto begin()
194  {
195 #ifdef __cpp_lib_ranges
196  namespace ranges = std::ranges;
197 #endif
198  if constexpr (ranges::range<Tup>) return ranges::begin(base());
199  else return iterator<false> {*this, 0_uz};
200  }
201 
203  constexpr auto begin() const
204  {
205 #ifdef __cpp_lib_ranges
206  namespace ranges = std::ranges;
207 #endif
208  if constexpr (ranges::range<Tup>) return ranges::begin(base());
209  else return iterator<true> {*this, 0_uz};
210  }
211 
212 
218  constexpr auto end()
219  {
220 #ifdef __cpp_lib_ranges
221  namespace ranges = std::ranges;
222 #endif
223  if constexpr (ranges::range<Tup>) return ranges::end(base());
224  else return iterator<false> {*this, std::tuple_size_v<std::decay_t<Tup>>};
225  }
226 
228  constexpr auto end() const
229  {
230 #ifdef __cpp_lib_ranges
231  namespace ranges = std::ranges;
232 #endif
233  if constexpr (ranges::range<Tup>) return ranges::end(base());
234  else return iterator<true> {*this, std::tuple_size_v<std::decay_t<Tup>>};
235  }
236 
237 
241  static constexpr auto
242  size() { return std::tuple_size<std::decay_t<Tup>>{}; }
243 
244 
248  static constexpr auto
250  {
251  if constexpr (std::tuple_size_v<std::decay_t<Tup>> == 0) return std::true_type{};
252  else return std::false_type{};
253  }
254 
255 
259  constexpr decltype(auto)
260  front() { return OpenKalman::internal::generalized_std_get<0>(base()); }
261 
263  constexpr decltype(auto)
264  front() const { return OpenKalman::internal::generalized_std_get<0>(base()); }
265 
266 
270  constexpr decltype(auto)
271  back() { return OpenKalman::internal::generalized_std_get<size() - 1_uz>(base()); }
272 
274  constexpr decltype(auto)
275  back() const { return OpenKalman::internal::generalized_std_get<size() - 1_uz>(base()); }
276 
277 
281 #ifdef __cpp_explicit_this_parameter
282  template<typename Self, values::index I>
283  constexpr decltype(auto)
284  operator[](this Self&& self, I i) noexcept
285  {
286  if constexpr (values::fixed<I>) static_assert(values::fixed_number_of<I>::value < size(), "Index out of range");
287  return collections::get(std::forward<Self>(self), std::move(i));
288  }
289 #else
290  template<typename I, std::enable_if_t<values::index<I>, int> = 0>
291  constexpr decltype(auto)
292  operator[](I i) &
293  {
294  if constexpr (values::fixed<I>) static_assert(values::fixed_number_of<I>::value < size(), "Index out of range");
295  return collections::get(*this, std::move(i));
296  }
297 
298  template<typename I, std::enable_if_t<values::index<I>, int> = 0>
299  constexpr decltype(auto)
300  operator[](I i) const &
301  {
302  if constexpr (values::fixed<I>) static_assert(values::fixed_number_of<I>::value < size(), "Index out of range");
303  return collections::get(*this, std::move(i));
304  }
305 
306  template<typename I, std::enable_if_t<values::index<I>, int> = 0>
307  constexpr decltype(auto)
308  operator[](I i) && noexcept
309  {
310  if constexpr (values::fixed<I>) static_assert(values::fixed_number_of<I>::value < size(), "Index out of range");
311  return collections::get(std::move(*this), std::move(i));
312  }
313 
314  template<typename I, std::enable_if_t<values::index<I>, int> = 0>
315  constexpr decltype(auto)
316  operator[](I i) const && noexcept
317  {
318  if constexpr (values::fixed<I>) static_assert(values::fixed_number_of<I>::value < size(), "Index out of range");
319  return collections::get(std::move(*this), std::move(i));
320  }
321 #endif
322 
323 
327 #ifdef __cpp_explicit_this_parameter
328  template<std::size_t i>
329  constexpr decltype(auto)
330  get(this auto&& self) noexcept
331  {
332  static_assert(i < size(), "Index out of range");
333  return OpenKalman::internal::generalized_std_get<i>(std::forward<decltype(self)>(self).base());
334  }
335 #else
336  template<std::size_t i>
337  constexpr decltype(auto)
338  get() &
339  {
340  static_assert(i < size(), "Index out of range");
341  return OpenKalman::internal::generalized_std_get<i>(base());
342  }
343 
344  template<std::size_t i>
345  constexpr decltype(auto)
346  get() const &
347  {
348  static_assert(i < size(), "Index out of range");
349  return OpenKalman::internal::generalized_std_get<i>(base());
350  }
351 
352  template<std::size_t i>
353  constexpr decltype(auto)
354  get() && noexcept
355  {
356  static_assert(i < size(), "Index out of range");
357  return OpenKalman::internal::generalized_std_get<i>(std::move(*this).base());
358  }
359 
360  template<std::size_t i>
361  constexpr decltype(auto)
362  get() const && noexcept
363  {
364  static_assert(i < size(), "Index out of range");
365  return OpenKalman::internal::generalized_std_get<i>(std::move(*this).base());
366  }
367 #endif
368 
369  private:
370 
371  TupBox tup_;
372 
373  };
374 
375 
376  template<typename Tup>
377  from_tuple(Tup&&) -> from_tuple<Tup>;
378 
379 } // namespace OpenKalman::collections
380 
381 
382 #ifdef __cpp_lib_ranges
383 namespace std::ranges
384 #else
385 namespace OpenKalman::ranges
386 #endif
387 {
388  template<typename Tup>
389  constexpr bool enable_borrowed_range<OpenKalman::collections::from_tuple<Tup>> =
390  std::is_lvalue_reference_v<Tup> or enable_borrowed_range<remove_cvref_t<Tup>>;
391 }
392 
393 
394 namespace std
395 {
396  template<typename Tup>
397  struct tuple_size<OpenKalman::collections::from_tuple<Tup>> : tuple_size<decay_t<Tup>> {};
398 
399 
400  template<std::size_t i, typename Tup>
401  struct tuple_element<i, OpenKalman::collections::from_tuple<Tup>> : tuple_element<i, decay_t<Tup>> {};
402 }
403 
404 
405 #endif //OPENKALMAN_COLLECTIONS_VIEWS_FROM_TUPLE_HPP
Definition for values::index.
Namespace for collections.
Definition: collections.hpp:27
typename common_tuple_type< T >::type common_tuple_type_t
Helper template for common_collection_type.
Definition: common_tuple_type.hpp:59
Definition for collections::get.
decltype(auto) constexpr get(Arg &&arg, I i)
A generalization of std::get.
Definition: get.hpp:62
Definition: view_interface.hpp:32
constexpr auto begin()
An iterator to the beginning of the tuple (treated as a std::ranges::range).
Definition: from_tuple.hpp:193
constexpr auto end() const
Definition: from_tuple.hpp:228
Definition: tuple_reverse.hpp:103
constexpr auto end()
An iterator to the end of the tuple (treated as a std::ranges::range).
Definition: from_tuple.hpp:218
constexpr bool value
T is numerical value or is reducible to a numerical value.
Definition: value.hpp:31
The root namespace for OpenKalman.
Definition: basics.hpp:34
Iterator for from_tuple.
Definition: from_tuple.hpp:92
Definitions relating to the availability of c++ language features.
The fixed number associated with a values::fixed.
Definition: fixed_number_of.hpp:45
constexpr bool size
T is either an index representing a size, or void which represents that there is no size...
Definition: size.hpp:32
constexpr from_tuple()
Default constructor.
Definition: from_tuple.hpp:157
A collection_view created from a uniform_tuple_like object.
Definition: from_tuple.hpp:75
constexpr auto begin() const
Definition: from_tuple.hpp:203
Definitions implementing features of the c++ ranges library for compatibility.
Definition for ::fixed.
constexpr from_tuple(Arg &&arg) noexcept
Construct from a uniform_tuple_like object.
Definition: from_tuple.hpp:171
static constexpr auto size()
The size of the resulting object.
Definition: from_tuple.hpp:242
static constexpr auto empty()
Definition: from_tuple.hpp:249