OpenKalman
strides.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) 2022-2023 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_STRIDES_HPP
18 #define OPENKALMAN_STRIDES_HPP
19 
20 #include<vector>
21 
22 namespace OpenKalman::internal
23 {
24  namespace detail
25  {
26  template<Layout l, std::size_t count, typename T, typename CurrStride, std::size_t I, std::size_t...Is, typename...Strides>
27  constexpr auto strides_impl(const T& t, CurrStride curr_stride, std::index_sequence<I, Is...>, Strides...strides)
28  {
29  if constexpr (sizeof...(Is) == 0)
30  {
31  if constexpr (l == Layout::right)
32  return std::tuple {curr_stride, strides...};
33  else
34  return std::tuple {strides..., curr_stride};
35  }
36  else
37  {
38  auto curr_dim = get_index_dimension_of<l == Layout::right ? count - 1 - I : I>(t);
39  auto next_stride = [](CurrStride curr_stride, auto curr_dim)
40  {
41  if constexpr (values::fixed<CurrStride> and values::fixed<decltype(curr_dim)>)
42  return std::integral_constant<std::ptrdiff_t, std::decay_t<CurrStride>::value * decltype(curr_dim)::value>{};
43  else
44  return static_cast<std::ptrdiff_t>(curr_stride) * static_cast<std::ptrdiff_t>(curr_dim);
45  }(curr_stride, curr_dim);
46 
47  if constexpr (l == Layout::right)
48  return strides_impl<l, count>(t, next_stride, std::index_sequence<Is...>{}, curr_stride, strides...);
49  else
50  return strides_impl<l, count>(t, next_stride, std::index_sequence<Is...>{}, strides..., curr_stride);
51  }
52  }
53 
54 
55  template<typename T, std::size_t...Is>
56  constexpr bool strides_tuple_impl(std::index_sequence<Is...>)
57  {
58  return (... and (std::is_convertible_v<std::tuple_element_t<Is, T>, std::ptrdiff_t> or
59  values::fixed<std::tuple_element_t<Is, T>>));
60  }
61 
62  template<typename T>
63 #ifdef __cpp_concepts
64  concept strides_tuple =
65 #else
66  constexpr bool strides_tuple =
67 #endif
68  strides_tuple_impl<T>(std::make_index_sequence<std::tuple_size_v<T>>{});
69 
70  } // namespace detail
71 
72 
80 #ifdef __cpp_concepts
81  template<interface::count_indices_defined_for T> requires interface::layout_defined_for<T> and
82  (interface::indexible_object_traits<std::decay_t<T>>::layout != Layout::stride or interface::strides_defined_for<T>) and
83  (interface::indexible_object_traits<std::decay_t<T>>::layout != Layout::none)
84  detail::strides_tuple auto
85 #else
86  template<typename T, std::enable_if_t<interface::count_indices_defined_for<T> and interface::layout_defined_for<T> and
87  (interface::indexible_object_traits<std::decay_t<T>>::layout != Layout::stride or interface::strides_defined_for<T>) and
88  (interface::indexible_object_traits<std::decay_t<T>>::layout != Layout::none), int> = 0>
89  auto
90 #endif
91  strides(const T& t)
92  {
93  constexpr Layout l = interface::indexible_object_traits<std::decay_t<T>>::layout;
94 
95  if constexpr (l == Layout::stride)
96  {
97 #ifndef __cpp_concepts
98  static_assert(detail::strides_tuple<decltype(interface::indexible_object_traits<std::decay_t<T>>::strides(t))>);
99 #endif
100  return interface::indexible_object_traits<std::decay_t<T>>::strides(t);
101  }
102  else if constexpr (values::fixed<decltype(count_indices(t))>)
103  {
104  constexpr std::size_t count = std::decay_t<decltype(count_indices(t))>::value;
105  constexpr std::integral_constant<std::ptrdiff_t, 1> N1;
106  return detail::strides_impl<l, count>(t, N1, std::make_index_sequence<count>{});
107  }
108  else
109  {
110 #ifdef __cpp_lib_ranges
111  namespace ranges = std::ranges;
112 #endif
113  std::size_t count = count_indices(t);
114  std::vector<std::ptrdiff_t> vec(count);
115  if constexpr (l == Layout::left)
116  {
117  auto v = ranges::begin(vec);
118  std::ptrdiff_t curr_stride = 1;
119  for (int i = 0; i < count; ++i)
120  {
121  *v = curr_stride;
122  curr_stride *= get_index_dimension_of(t, i);
123  ++v;
124  }
125  }
126  else
127  {
128  auto v = ranges::end(vec);
129  std::ptrdiff_t curr_stride = 1;
130  for (int i = 1; i <= count; ++i)
131  {
132  --v;
133  *v = curr_stride;
134  curr_stride *= get_index_dimension_of(t, count - i);
135  }
136  }
137  return vec;
138  }
139  }
140 
141 
142 } // namespace OpenKalman::internal
143 
144 #endif //OPENKALMAN_STRIDES_HPP
constexpr auto count_indices(const T &t)
Get the number of indices available to address the components of an indexible object.
Definition: count_indices.hpp:33
Row-major storage (C or C++ style): contiguous storage in which the right-most index has a stride of ...
No storage layout (e.g., if the elements are calculated rather than stored).
Definition: tuple_reverse.hpp:103
constexpr bool value
T is numerical value or is reducible to a numerical value.
Definition: value.hpp:31
Column-major storage (Fortran, Matlab, or Eigen style): contiguous storage in which the left-most ext...
A generalization of the above: a custom stride is specified for each index.
Layout
The layout format of a multidimensional array.
Definition: global-definitions.hpp:47
constexpr bool fixed
T is a values::value that is determinable at compile time.
Definition: fixed.hpp:60
Definition: basics.hpp:48
constexpr auto get_index_dimension_of(const T &t, N n=N{})
Get the runtime dimensions of index N of indexible T.
Definition: get_index_dimension_of.hpp:34