OpenKalman
from_tuple_like.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 "values/values.hpp"
26 
28 {
29  namespace detail
30  {
31  template<typename D, typename = std::make_index_sequence<size_of_v<D>>>
33 
34 
35  template<typename D>
36  struct tuple_iterator_call_table<D, std::index_sequence<>>
37  {
38  using element_type = std::size_t;
39 
40  static constexpr element_type
41  call_table_get(const internal::tuple_wrapper<D>&) noexcept { return 0; }
42 
43  static constexpr std::array<decltype(call_table_get), 0>
44  value {};
45  };
46 
47 
48  template<typename D, std::size_t...is>
49  struct tuple_iterator_call_table<D, std::index_sequence<is...>>
50  {
51  using element_type = std::decay_t<common_collection_type_t<D>>;
52 
53  template<std::size_t i>
54  static constexpr auto
55  call_table_get(const internal::tuple_wrapper<D>& box) noexcept
56  {
57  return static_cast<element_type>(get<i>(box));
58  }
59 
60  static constexpr std::array
61  value {call_table_get<is>...};
62  };
63  }
64 
65 
69 #ifdef __cpp_lib_ranges
70  template<viewable_tuple_like Tup>
71 #else
72  template<typename Tup>
73 #endif
74  struct from_tuple_like : stdex::ranges::view_interface<from_tuple_like<Tup>>
75  {
76  private:
77 
79 
80  template<bool Const, typename T>
81  using maybe_const = std::conditional_t<Const, const T, T>;
82 
83  public:
84 
89  template<bool Const>
90  struct iterator
91  {
92  private:
93 
94  using Parent = maybe_const<Const, from_tuple_like>;
96 
97  public:
98 
99  using iterator_concept = std::random_access_iterator_tag;
100  using iterator_category = std::random_access_iterator_tag;
101  using value_type = maybe_const<Const, typename call_table::element_type>;
102  using difference_type = std::ptrdiff_t;
103  using reference = typename call_table::element_type;
104  using pointer = void;
105  constexpr iterator() = default;
106  constexpr iterator(Parent& p, std::size_t pos) : parent_ {std::addressof(p)}, current_{static_cast<difference_type>(pos)} {}
107  constexpr iterator(iterator<not Const> it) : parent_ {std::move(it.parent_)}, current_ {std::move(it.current_)} {}
108  constexpr decltype(auto) operator*() { return call_table::value[current_](parent_->tup_); }
109  constexpr decltype(auto) operator*() const { return call_table::value[current_](parent_->tup_); }
110  constexpr decltype(auto) operator[](difference_type offset) { return call_table::value[current_ + offset](parent_->tup_); }
111  constexpr decltype(auto) operator[](difference_type offset) const { return call_table::value[current_ + offset](parent_->tup_); }
112  constexpr auto& operator++() { ++current_; return *this; }
113  constexpr auto operator++(int) { auto temp = *this; ++*this; return temp; }
114  constexpr auto& operator--() { --current_; return *this; }
115  constexpr auto operator--(int) { auto temp = *this; --*this; return temp; }
116  constexpr auto& operator+=(const difference_type diff) { current_ += diff; return *this; }
117  constexpr auto& operator-=(const difference_type diff) { current_ -= diff; return *this; }
118  friend constexpr auto operator+(const iterator& it, const difference_type diff)
119  { return iterator {*it.parent_, static_cast<std::size_t>(it.current_ + diff)}; }
120  friend constexpr auto operator+(const difference_type diff, const iterator& it)
121  { return iterator {*it.parent_, static_cast<std::size_t>(diff + it.current_)}; }
122  friend constexpr auto operator-(const iterator& it, const difference_type diff)
123  { 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)}; }
124  friend constexpr difference_type operator-(const iterator& it, const iterator& other)
125  { return it.current_ - other.current_; }
126  friend constexpr bool operator==(const iterator& it, const iterator& other)
127  { return it.current_ == other.current_; }
128 #ifdef __cpp_impl_three_way_comparison
129  constexpr auto operator<=>(const iterator& other) const { return current_ <=> other.current_; }
130 #else
131  constexpr bool operator!=(const iterator& other) const { return current_ != other.current_; }
132  constexpr bool operator<(const iterator& other) const { return current_ < other.current_; }
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 #endif
137 
138  private:
139 
140  Parent * parent_;
141  difference_type current_;
142 
143  }; // struct iterator
144 
145 
149 #ifdef __cpp_concepts
150  constexpr
151  from_tuple_like() = default;
152 #else
153  template<bool Enable = true, std::enable_if_t<Enable and stdex::default_initializable<TupBox>, int> = 0>
154  constexpr
156 #endif
157 
158 
162 #ifdef __cpp_concepts
163  template<typename Arg> requires (not std::same_as<stdex::remove_cvref_t<Arg>, from_tuple_like>)
164 #else
165  template<typename Arg, std::enable_if_t<(not std::is_same_v<stdex::remove_cvref_t<Arg>, from_tuple_like>), int> = 0>
166 #endif
167  constexpr explicit
168  from_tuple_like(Arg&& arg) noexcept : tup_ {std::forward<Arg>(arg)} {}
169 
170 
176  constexpr auto begin()
177  {
178  return iterator<false> {*this, 0_uz};
179  }
180 
182  constexpr auto begin() const
183  {
184  return iterator<true> {*this, 0_uz};
185  }
186 
187 
193  constexpr auto end()
194  {
195  return iterator<false> {*this, size_of_v<Tup>};
196  }
197 
199  constexpr auto end() const
200  {
201  return iterator<true> {*this, size_of_v<Tup>};
202  }
203 
204 
208  static constexpr auto
209  size() { return size_of<Tup>{}; }
210 
211 
215  static constexpr auto
217  {
218  if constexpr (size_of_v<Tup> == 0) return std::true_type{};
219  else return std::false_type{};
220  }
221 
222 
226  constexpr decltype(auto)
227  front() { return collections::get<0>(tup_); }
228 
230  constexpr decltype(auto)
231  front() const { return collections::get<0>(tup_); }
232 
233 
237  constexpr decltype(auto)
238  back() { return collections::get<size() - 1_uz>(tup_); }
239 
241  constexpr decltype(auto)
242  back() const { return collections::get<size() - 1_uz>(tup_); }
243 
244 
249 #ifdef __cpp_explicit_this_parameter
250  template<typename Self, values::index I>
251  constexpr decltype(auto)
252  operator[](this Self&& self, I i) noexcept
253  {
254  if constexpr (values::fixed<I>) static_assert(values::fixed_value_of<I>::value < size(), "Index out of range");
255  return collections::get_element(std::forward<Self>(self), std::move(i));
256  }
257 #else
258  template<typename I, std::enable_if_t<values::index<I>, int> = 0>
259  constexpr decltype(auto)
260  operator[](I i) &
261  {
262  if constexpr (values::fixed<I>) static_assert(values::fixed_value_of<I>::value < size(), "Index out of range");
263  return collections::get_element(*this, std::move(i));
264  }
265 
266  template<typename I, std::enable_if_t<values::index<I>, int> = 0>
267  constexpr decltype(auto)
268  operator[](I i) const &
269  {
270  if constexpr (values::fixed<I>) static_assert(values::fixed_value_of<I>::value < size(), "Index out of range");
271  return collections::get_element(*this, std::move(i));
272  }
273 
274  template<typename I, std::enable_if_t<values::index<I>, int> = 0>
275  constexpr decltype(auto)
276  operator[](I i) && noexcept
277  {
278  if constexpr (values::fixed<I>) static_assert(values::fixed_value_of<I>::value < size(), "Index out of range");
279  return collections::get_element(std::move(*this), std::move(i));
280  }
281 
282  template<typename I, std::enable_if_t<values::index<I>, int> = 0>
283  constexpr decltype(auto)
284  operator[](I i) const && noexcept
285  {
286  if constexpr (values::fixed<I>) static_assert(values::fixed_value_of<I>::value < size(), "Index out of range");
287  return collections::get_element(std::move(*this), std::move(i));
288  }
289 #endif
290 
291 
296 #ifdef __cpp_explicit_this_parameter
297  template<std::size_t i>
298  constexpr decltype(auto)
299  get(this auto&& self) noexcept
300  {
301  static_assert(i < size_of_v<Tup>, "Index out of range");
302  return collections::get<i>(std::forward<decltype(self)>(self).tup_);
303  }
304 #else
305  template<std::size_t i>
306  constexpr decltype(auto)
307  get() &
308  {
309  static_assert(i < size_of_v<Tup>, "Index out of range");
310  return collections::get<i>(tup_);
311  }
312 
313  template<std::size_t i>
314  constexpr decltype(auto)
315  get() const &
316  {
317  static_assert(i < size_of_v<Tup>, "Index out of range");
318  return collections::get<i>(tup_);
319  }
320 
321  template<std::size_t i>
322  constexpr decltype(auto)
323  get() && noexcept
324  {
325  static_assert(i < size_of_v<Tup>, "Index out of range");
326  return collections::get<i>(std::move(*this).tup_);
327  }
328 
329  template<std::size_t i>
330  constexpr decltype(auto)
331  get() const && noexcept
332  {
333  static_assert(i < size_of_v<Tup>, "Index out of range");
334  return collections::get<i>(std::move(*this).tup_);
335  }
336 #endif
337 
338  private:
339 
340  TupBox tup_;
341 
342  };
343 
344 
345  template<typename Tup>
347 
348 }
349 
350 
351 #ifdef __cpp_lib_ranges
352 namespace std::ranges
353 #else
354 namespace OpenKalman::stdex::ranges
355 #endif
356 {
357  template<typename Tup>
358  constexpr bool enable_borrowed_range<OpenKalman::collections::from_tuple_like<Tup>> =
359  std::is_lvalue_reference_v<Tup> or enable_borrowed_range<OpenKalman::stdex::remove_cvref_t<Tup>>;
360 }
361 
362 
363 namespace std
364 {
365  template<typename Tup>
366  struct tuple_size<OpenKalman::collections::from_tuple_like<Tup>>
368 
369 
370  template<std::size_t i, typename Tup>
371  struct tuple_element<i, OpenKalman::collections::from_tuple_like<Tup>>
373 }
374 
375 
376 #endif
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
Definition of lexicographical_compare_three_way for collections.
constexpr from_tuple_like()
Default constructor.
Definition: from_tuple_like.hpp:155
Definition: tuple_wrapper.hpp:39
constexpr auto end() const
Definition: from_tuple_like.hpp:199
Header file for code relating to values (e.g., scalars and indices)
constexpr auto begin()
An iterator to the beginning of the tuple (treated as a std::ranges::range).
Definition: from_tuple_like.hpp:176
Definition for collections::size_of.
Iterator for from_tuple_like.
Definition: from_tuple_like.hpp:90
The fixed value associated with a fixed.
Definition: fixed_value_of.hpp:44
constexpr bool value
T is a fixed or dynamic value that is reducible to a number.
Definition: value.hpp:45
Definition: view_interface.hpp:32
constexpr auto end()
An iterator to the end of the tuple (treated as a std::ranges::range).
Definition: from_tuple_like.hpp:193
The root namespace for OpenKalman.
Definition: basics.hpp:34
A collection_view created from a viewable_tuple_like object.
Definition: from_tuple_like.hpp:74
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 auto begin() const
Definition: from_tuple_like.hpp:182
The type of the element at a given index, if it can be determined at compile time.
Definition: collection_element.hpp:48
constexpr from_tuple_like(Arg &&arg) noexcept
Construct from a viewable_tuple_like object.
Definition: from_tuple_like.hpp:168
decltype(auto) constexpr get_element(Arg &&arg, I i)
A generalization of std::get and the range subscript operator.
Definition: get_element.hpp:122
static constexpr auto size()
The size of the resulting object.
Definition: from_tuple_like.hpp:209
Definition for collections::collection_element.
Definition for collections::common_collection_type.
static constexpr auto empty()
Definition: from_tuple_like.hpp:216