OpenKalman
transpose.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) 2026 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_PATTERNS_VIEWS_TRANSPOSE_HPP
17 #define OPENKALMAN_PATTERNS_VIEWS_TRANSPOSE_HPP
18 
19 #include <tuple>
20 #include <variant>
24 
25 namespace OpenKalman::patterns
26 {
33 #ifdef __cpp_lib_ranges
34  template<pattern_collection P, std::size_t indexa = 0, std::size_t indexb = 1> requires (indexa < indexb)
35 #else
36  template<typename P, std::size_t indexa = 0, std::size_t indexb = 1>
37 #endif
38  struct transpose_view : stdex::ranges::view_interface<transpose_view<P, indexa, indexb>>
39  {
40  private:
41 
42  template<bool Const, typename T>
43  using maybe_const = std::conditional_t<Const, const T, T>;
44 
45  public:
46 
50  template<bool Const>
51  struct iterator
52  {
53  using iterator_concept = std::random_access_iterator_tag;
54  using iterator_category = std::random_access_iterator_tag;
55  using value_type = stdex::ranges::range_value_t<P>;
56  using reference = stdex::ranges::range_reference_t<P>;
57  using difference_type = std::ptrdiff_t;
58  using pointer = void;
59 
60  private:
61 
62  using Parent = maybe_const<Const, transpose_view>;
63 
64  public:
65 
66  constexpr iterator() = default;
67 
68  constexpr iterator(Parent& parent, difference_type p) : parent_ {std::addressof(parent)}, current_{p} {}
69 
70  constexpr iterator(iterator<not Const> i) : parent_ {std::move(i.parent_)}, current_ {std::move(i.current_)} {}
71 
72  constexpr decltype(auto) operator*()
73  {
74  return get_pattern(parent_->p_.get(), current_ == indexa ? indexb : current_ == indexb ? indexa : current_);
75  }
76 
77  constexpr decltype(auto) operator*() const
78  {
79  return get_pattern(parent_->p_.get(), current_ == indexa ? indexb : current_ == indexb ? indexa : current_);
80  }
81 
82  constexpr decltype(auto) operator[](difference_type offset)
83  {
84  return get_pattern(parent_->p_.get(), (current_ == indexa ? indexb : current_ == indexb ? indexa : current_) + offset);
85  }
86 
87  constexpr decltype(auto) operator[](difference_type offset) const
88  {
89  return get_pattern(parent_->p_.get(), (current_ == indexa ? indexb : current_ == indexb ? indexa : current_) + offset);
90  }
91 
92  constexpr auto& operator++() noexcept { ++current_; return *this; }
93  constexpr auto operator++(int) noexcept { auto temp = *this; ++*this; return temp; }
94  constexpr auto& operator--() noexcept { --current_; return *this; }
95  constexpr auto operator--(int) noexcept { auto temp = *this; --*this; return temp; }
96  constexpr auto& operator+=(const difference_type diff) noexcept { current_ += diff; return *this; }
97  constexpr auto& operator-=(const difference_type diff) noexcept { current_ -= diff; return *this; }
98  friend constexpr auto operator+(const iterator& it, const difference_type diff) noexcept
99  { return iterator {*it.parent_, it.current_ + diff}; }
100  friend constexpr auto operator+(const difference_type diff, const iterator& it) noexcept
101  { return iterator {*it.parent_, diff + it.current_}; }
102  friend constexpr auto operator-(const iterator& it, const difference_type diff)
103  { return iterator {*it.parent_, it.current_ - diff}; }
104  friend constexpr difference_type operator-(const iterator& it, const iterator& other) noexcept
105  { return it.current_ - other.current_; }
106  friend constexpr bool operator==(const iterator& it, const iterator& other) noexcept
107  { return it.current_ == other.current_; }
108 #ifdef __cpp_impl_three_way_comparison
109  constexpr auto operator<=>(const iterator& other) const noexcept { return current_ <=> other.current_; }
110 #else
111  constexpr bool operator!=(const iterator& other) const noexcept { return current_ != other.current_; }
112  constexpr bool operator<(const iterator& other) const noexcept { return current_ < other.current_; }
113  constexpr bool operator>(const iterator& other) const noexcept { return current_ > other.current_; }
114  constexpr bool operator<=(const iterator& other) const noexcept { return current_ <= other.current_; }
115  constexpr bool operator>=(const iterator& other) const noexcept { return current_ >= other.current_; }
116 #endif
117 
118  private:
119 
120  Parent * parent_;
121  difference_type current_;
122 
123  };
124 
125 
129 #ifdef __cpp_concepts
130  constexpr transpose_view() = default;
131 #else
132  template<bool Enable = true, std::enable_if_t<Enable and stdex::default_initializable<P>, int> = 0>
133  constexpr transpose_view() {}
134 #endif
135 
136 
140  constexpr
141  transpose_view(P&& p) : p_ {std::forward<P>(p)} {}
142 
143 
147 #ifdef __cpp_explicit_this_parameter
148  constexpr decltype(auto)
149  base(this auto&& self) noexcept { return std::forward<decltype(self)>(self).p_.get(); }
150 #else
151  constexpr P& base() & { return this->p_.get(); }
152  constexpr const P& base() const & { return this->p_.get(); }
153  constexpr P&& base() && noexcept { return std::move(*this).p_.get(); }
154  constexpr const P&& base() const && noexcept { return std::move(*this).p_.get(); }
155 #endif
156 
157 
161 #ifdef __cpp_concepts
162  constexpr auto
163  begin() requires stdex::ranges::random_access_range<P>
164 #else
165  template<bool Enable = true, std::enable_if_t<Enable and stdex::ranges::random_access_range<P>, int> = 0>
166  constexpr auto begin()
167 #endif
168  { return iterator<false> {*this, 0_uz}; }
169 
170 
171 #ifdef __cpp_concepts
172  constexpr auto
173  begin() const requires stdex::ranges::random_access_range<P>
174 #else
175  template<bool Enable = true, std::enable_if_t<Enable and stdex::ranges::random_access_range<P>, int> = 0>
176  constexpr auto begin() const
177 #endif
178  { return iterator<true> {*this, 0_uz}; }
179 
180 
184 #ifdef __cpp_concepts
185  constexpr auto
186  end() requires stdex::ranges::random_access_range<P>
187 #else
188  template<bool Enable = true, std::enable_if_t<Enable and stdex::ranges::random_access_range<P>, int> = 0>
189  constexpr auto
190  end()
191 #endif
192  {
193  return iterator<false> {*this, static_cast<std::ptrdiff_t>(values::to_value_type(size()))};
194  }
195 
196 
198 #ifdef __cpp_concepts
199  constexpr auto
200  end() const requires stdex::ranges::random_access_range<P>
201 #else
202  template<bool Enable = true, std::enable_if_t<Enable and stdex::ranges::random_access_range<P>, int> = 0>
203  constexpr auto
204  end() const
205 #endif
206  {
207  return iterator<true> {*this, static_cast<std::ptrdiff_t>(values::to_value_type(size()))};
208  }
209 
210 
214 #ifdef __cpp_concepts
215  constexpr values::size auto
216  size() const noexcept requires collections::sized<P>
217 #else
218  template<bool Enable = true, std::enable_if_t<collections::sized<P>, int> = 0>
219  constexpr auto
220  size() const noexcept
221 #endif
222  {
223  struct Max { constexpr auto operator()(std::size_t a) const { return std::max(a, indexb + 1_uz); } };
224  return values::operation(Max{}, get_size(p_.get()));
225  }
226 
227 
231 #ifdef __cpp_explicit_this_parameter
232  template<std::size_t i>
233  constexpr decltype(auto)
234  get(this auto&& self) noexcept
235  {
236  constexpr std::size_t ti = i == indexa ? indexb : i == indexb ? indexa : i;
237  return get_pattern<ti>(std::forward<decltype(self)>(self).p_.get());
238  }
239 #else
240  template<std::size_t i>
241  constexpr decltype(auto)
242  get() &
243  {
244  constexpr std::size_t ti = i == indexa ? indexb : i == indexb ? indexa : i;
245  return get_pattern<ti>(p_.get());
246  }
247 
248  template<std::size_t i>
249  constexpr decltype(auto)
250  get() const &
251  {
252  constexpr std::size_t ti = i == indexa ? indexb : i == indexb ? indexa : i;
253  return get_pattern<ti>(p_.get());
254  }
255 
256  template<std::size_t i>
257  constexpr decltype(auto)
258  get() && noexcept
259  {
260  constexpr std::size_t ti = i == indexa ? indexb : i == indexb ? indexa : i;
261  return get_pattern<ti>(std::move(*this).p_.get());
262  }
263 
264  template<std::size_t i>
265  constexpr decltype(auto)
266  get() const && noexcept
267  {
268  constexpr std::size_t ti = i == indexa ? indexb : i == indexb ? indexa : i;
269  return get_pattern<ti>(std::move(*this).p_.get());
270  }
271 #endif
272 
273  private:
274 
276 
277  };
278 
279 
283  template<typename P>
285 
286 }
287 
288 
289 #ifdef __cpp_lib_ranges
290 namespace std::ranges
291 #else
292 namespace OpenKalman::stdex::ranges
293 #endif
294 {
295  template<typename P, std::size_t indexa, std::size_t indexb>
296  constexpr bool enable_borrowed_range<OpenKalman::patterns::transpose_view<P, indexa, indexb>> = enable_borrowed_range<P>;
297 }
298 
299 
300 #ifndef __cpp_lib_ranges
302 {
303  template<typename S, std::size_t indexb, typename = void>
305 
306  template<typename S, std::size_t indexb>
307  struct transpose_tuple_size<S, indexb, std::enable_if_t<
308  values::fixed_value_compares_with<S, OpenKalman::stdex::dynamic_extent, &stdex::is_neq>>>
309  : std::integral_constant<std::size_t, std::max(values::fixed_value_of_v<S>, indexb + 1_uz)> {};
310 }
311 #endif
312 
313 
314 namespace std
315 {
316 #ifdef __cpp_concepts
317  template<typename P, std::size_t indexa, std::size_t indexb> requires
318  OpenKalman::values::fixed_value_compares_with<OpenKalman::collections::size_of<P>, OpenKalman::stdex::dynamic_extent, &is_neq>
319  struct tuple_size<OpenKalman::patterns::transpose_view<P, indexa, indexb>>
320  : std::integral_constant<std::size_t, max(OpenKalman::collections::size_of_v<P>, indexb + 1)> {};
321 #else
322  template<typename P, std::size_t indexa, std::size_t indexb>
323  struct tuple_size<OpenKalman::patterns::transpose_view<P, indexa, indexb>>
324  : OpenKalman::patterns::detail::transpose_tuple_size<OpenKalman::collections::size_of<P>, indexb> {};
325 #endif
326 
327 
328  template<size_t i, typename P, std::size_t indexa, std::size_t indexb>
329  struct tuple_element<i, OpenKalman::patterns::transpose_view<P, indexa, indexb>>
330  : OpenKalman::patterns::pattern_collection_element<i == indexa ? indexb : i == indexb ? indexa : i, P> {};
331 }
332 
333 
335 {
336  namespace detail
337  {
342 #ifdef __cpp_concepts
343  template<std::size_t indexa = 0, std::size_t indexb = 1> requires (indexa < indexb)
344 #else
345  template<std::size_t indexa = 0, std::size_t indexb = 1>
346 #endif
347  struct transpose_closure : stdex::ranges::range_adaptor_closure<transpose_closure<indexa, indexb>>
348  {
349  constexpr transpose_closure() = default;
350 
351 #ifdef __cpp_concepts
352  template<pattern_collection R>
353 #else
354  template<typename R, std::enable_if_t<pattern_collection<R> and (indexa < indexb), int> = 0>
355 #endif
356  constexpr auto
357  operator() (R&& r) const
358  {
359  if constexpr (values::fixed_value_compares_with<collections::size_of<R>, 0> or
360  compares_with<pattern_collection_element_t<indexa, R>, pattern_collection_element_t<indexb, R>>)
361  {
362  if constexpr (collections::viewable_collection<R>) return collections::views::all(std::forward<R>(r));
363  else return std::forward<R>(r);
364  }
365  else if constexpr (collections::viewable_collection<R>)
366  {
367  using AR = collections::views::all_t<R&&>;
368  return transpose_view<AR, indexa, indexb> {collections::views::all(std::forward<R>(r))};
369  }
370  else
371  {
372  return transpose_view<R, indexa, indexb> {std::forward<R>(r)};
373  }
374  }
375  };
376 
377 
378 #ifdef __cpp_concepts
379  template<std::size_t indexa = 0, std::size_t indexb = 1> requires (indexa < indexb)
380 #else
381  template<std::size_t indexa = 0, std::size_t indexb = 1>
382 #endif
384  {
385  constexpr auto
386  operator() () const
387  {
389  }
390 
391 
392 #ifdef __cpp_concepts
393  template<pattern_collection R>
394 #else
395  template<typename R, std::enable_if_t<pattern_collection<R>, int> = 0>
396 #endif
397  constexpr decltype(auto)
398  operator() (R&& r) const
399  {
400  return transpose_closure<indexa, indexb>{}(std::forward<R>(r));
401  }
402 
403  };
404 
405  }
406 
407 
414 #ifdef __cpp_concepts
415  template<std::size_t indexa = 0, std::size_t indexb = 1> requires (indexa < indexb)
416 #else
417  template<std::size_t indexa = 0, std::size_t indexb = 1, std::enable_if_t<indexa < indexb, int> = 0>
418 #endif
419  inline constexpr detail::transpose_adapter<indexa, indexb> transpose;
420 
421 }
422 
423 
424 #endif
constexpr transpose_view()
Default constructor.
Definition: transpose.hpp:133
Definition for pattern_collection.
constexpr transpose_view(P &&p)
Construct from a collection.
Definition: transpose.hpp:141
constexpr auto get_size(Arg &&arg)
Get the size of a sized object (e.g, a collection)
Definition: get_size.hpp:224
decltype(auto) constexpr get_pattern(P &&p, I i)
Get a pattern within a pattern_collection.
Definition: get_pattern.hpp:39
The namespace for views for patterns::pattern object.
Definition: patterns.hpp:51
decltype(auto) constexpr to_value_type(Arg &&arg)
Convert, if necessary, a fixed or dynamic value to its underlying base type.
Definition: to_value_type.hpp:28
Definition for patterns::get_pattern.
Definition: view_interface.hpp:32
The namespace for features relating to patterns::pattern object.
Definition: collection_compares_with.hpp:24
decltype(auto) constexpr get() &
Get element i.
Definition: transpose.hpp:242
constexpr auto begin()
Definition: transpose.hpp:166
A view representing a transpose of a pattern_collection.
Definition: transpose.hpp:38
Inclusion file for collections.
constexpr auto end()
Definition: transpose.hpp:190
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:71
Definition: range_adaptor_closure.hpp:34
Iterator for transpose_view.
Definition: transpose.hpp:51
Definition: collection_compares_with.hpp:26
constexpr auto end() const
Definition: transpose.hpp:204
transpose_view(P &&) -> transpose_view< P >
Deduction guides.
constexpr auto size() const noexcept
Definition: transpose.hpp:220
The type of the element at a given index, if it can be determined at compile time.
Definition: pattern_collection_element.hpp:34
constexpr P & base() &
The base view.
Definition: transpose.hpp:151
constexpr auto operation(Operation &&op, Args &&...args)
A potentially constant-evaluated operation involving some number of values.
Definition: operation.hpp:98