OpenKalman
slice.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_SLICE_HPP
17 #define OPENKALMAN_COLLECTIONS_VIEWS_SLICE_HPP
18 
19 #include <tuple>
28 #include "all.hpp"
29 
31 {
42 #ifdef __cpp_lib_ranges
43  template<collection V, values::index Offset, values::index Extent> requires
44  std::same_as<std::decay_t<Offset>, Offset> and std::same_as<std::decay_t<Extent>, Extent> and
45  (size_of_v<V> == dynamic_size or
46  ((values::dynamic<Offset> or values::fixed_number_of_v<Offset> <= std::tuple_size_v<std::decay_t<V>>) and
47  (values::dynamic<Extent> or values::fixed_number_of_v<Extent> <= std::tuple_size_v<std::decay_t<V>>) and
48  (values::dynamic<Offset> or values::dynamic<Extent> or values::fixed_number_of_v<Offset> + values::fixed_number_of_v<Extent> <= std::tuple_size_v<std::decay_t<V>>)))
49  struct slice_view : std::ranges::view_interface<slice_view<V, Offset, Extent>>
50 #else
51  template<typename V, typename Offset, typename Extent>
52  struct slice_view : ranges::view_interface<slice_view<V, Offset, Extent>>
53 #endif
54  {
58 #ifdef __cpp_concepts
59  constexpr slice_view() = default;
60 #else
61  template<bool Enable = true, std::enable_if_t<Enable and std::is_default_constructible_v<V> and
62  std::is_default_constructible_v<Offset> and std::is_default_constructible_v<Extent>, int> = 0>
63  constexpr slice_view() {}
64 #endif
65 
66 
70  constexpr
71  slice_view(const V& v, Offset offset, Extent extent)
72  : v_ {v}, offset_ {std::move(offset)}, extent_ {std::move(extent)} {}
73 
75  constexpr
76  slice_view(V&& v, Offset offset, Extent extent)
77  : v_ {std::move(v)}, offset_ {std::move(offset)}, extent_ {std::move(extent)} {}
78 
79 
83 #ifdef __cpp_explicit_this_parameter
84  constexpr decltype(auto)
85  base(this auto&& self) noexcept { return std::forward<decltype(self)>(self).v_; }
86 #else
87  constexpr V& base() & { return this->v_; }
88  constexpr const V& base() const & { return this->v_; }
89  constexpr V&& base() && noexcept { return std::move(*this).v_; }
90  constexpr const V&& base() const && noexcept { return std::move(*this).v_; }
91 #endif
92 
93  private:
94 
95  template<typename Self>
96  static constexpr auto
97  begin_impl(Self&& self) noexcept
98  {
99 #ifdef __cpp_lib_ranges
100  namespace ranges = std::ranges;
101 #else
102  namespace ranges = OpenKalman::ranges;
103 #endif
104  return ranges::begin(std::forward<Self>(self).v_);
105  }
106 
107  public:
108 
112 #ifdef __cpp_explicit_this_parameter
113  constexpr auto
114  begin(this auto&& self) noexcept
115  {
116  return begin_impl(std::forward<decltype(self)>(self)) + std::forward<decltype(self)>(self).offset_;
117  }
118 #else
119  constexpr auto begin() & { return begin_impl(*this) + offset_; }
120  constexpr auto begin() const & { return begin_impl(*this) + offset_; }
121  constexpr auto begin() && noexcept { return begin_impl(std::move(*this)) + std::move(*this).offset_; }
122  constexpr auto begin() const && noexcept { return begin_impl(std::move(*this)) + std::move(*this).offset_; }
123 #endif
124 
125 
129 #ifdef __cpp_explicit_this_parameter
130  constexpr auto
131  end(this auto&& self) noexcept
132  {
133  return begin_impl(std::forward<decltype(self)>(self)) +
134  std::forward<decltype(self)>(self).offset_ + std::forward<decltype(self)>(self).extent_;
135  }
136 #else
137  constexpr auto end() & { return begin_impl(*this) + offset_ + extent_; }
138  constexpr auto end() const & { return begin_impl(*this) + offset_ + extent_; }
139  constexpr auto end() && noexcept { return begin_impl(std::move(*this)) + std::move(*this).offset_ + std::move(*this).extent_; }
140  constexpr auto end() const && noexcept { return begin_impl(std::move(*this)) + std::move(*this).offset_ + std::move(*this).extent_; }
141 #endif
142 
143 
147 #ifdef __cpp_explicit_this_parameter
148  constexpr values::index auto
149  size(this auto&& self) noexcept { return std::forward<decltype(self)>(self).extent_; }
150 #else
151  constexpr auto
152  size() const noexcept { return extent_; }
153 #endif
154 
155 
159 #ifdef __cpp_explicit_this_parameter
160  template<std::size_t i>
161  constexpr decltype(auto)
162  get(this auto&& self) noexcept
163  {
164  if constexpr (values::fixed<Extent>) static_assert(i < values::fixed_number_of_v<Extent>, "Index exceeds range");
165  return collections::get(std::forward<decltype(self)>(self).v_,
166  values::operation {std::plus{}, std::forward<decltype(self)>(self).offset_, std::integral_constant<std::size_t, i>{}});
167  }
168 #else
169  template<std::size_t i>
170  constexpr decltype(auto)
171  get() &
172  {
173  if constexpr (values::fixed<Extent>) static_assert(i < values::fixed_number_of_v<Extent>, "Index exceeds range");
174  return collections::get(v_,
175  values::operation {std::plus{}, offset_, std::integral_constant<std::size_t, i>{}});
176  }
177 
178  template<std::size_t i>
179  constexpr decltype(auto)
180  get() const &
181  {
182  if constexpr (values::fixed<Extent>) static_assert(i < values::fixed_number_of_v<Extent>, "Index exceeds range");
183  return collections::get(v_,
184  values::operation {std::plus{}, offset_, std::integral_constant<std::size_t, i>{}});
185  }
186 
187  template<std::size_t i>
188  constexpr decltype(auto)
189  get() && noexcept
190  {
191  if constexpr (values::fixed<Extent>) static_assert(i < values::fixed_number_of_v<Extent>, "Index exceeds range");
192  return collections::get(std::move(*this).v_,
193  values::operation {std::plus{}, offset_, std::integral_constant<std::size_t, i>{}});
194  }
195 
196  template<std::size_t i>
197  constexpr decltype(auto)
198  get() const && noexcept
199  {
200  if constexpr (values::fixed<Extent>) static_assert(i < values::fixed_number_of_v<Extent>, "Index exceeds range");
201  return collections::get(std::move(*this).v_,
202  values::operation {std::modulus{}, std::integral_constant<std::size_t, i>{}, get_size(std::move(*this).get_t())});
203  }
204 #endif
205 
206  private:
207 
208  V v_;
209  Offset offset_;
210  Extent extent_;
211 
212  };
213 
214 
218  template<typename V, typename O, typename E>
219  slice_view(const V&, const O&, const E&) -> slice_view<V, O, E>;
220 
221 } // namespace OpenKalman
222 
223 
224 #ifdef __cpp_lib_ranges
225 namespace std::ranges
226 #else
227 namespace OpenKalman::ranges
228 #endif
229 {
230  template<typename V, typename O, typename E>
231  constexpr bool enable_borrowed_range<OpenKalman::collections::slice_view<V, O, E>> = enable_borrowed_range<V>;
232 }
233 
234 
235 #ifndef __cpp_lib_ranges
237 {
238  template<std::size_t i, typename V, typename O, typename = void>
240  {
241  using type = ranges::range_value_t<V>;
242  };
243 
244  template<std::size_t i, typename V, typename O>
245  struct slice_tuple_element<i, V, O, std::enable_if_t<values::fixed<O>>>
246  : std::tuple_element<values::fixed_number_of_v<O> + i, std::decay_t<V>> {};
247 }
248 #endif
249 
250 
251 namespace std
252 {
253  template<typename V, typename O, typename E>
254  struct tuple_size<OpenKalman::collections::slice_view<V, O, E>> : OpenKalman::values::fixed_number_of<E> {};
255 
256 
257 #ifdef __cpp_lib_ranges
258  template<size_t i, typename V, OpenKalman::values::fixed O, typename E>
259  struct tuple_element<i, OpenKalman::collections::slice_view<V, O, E>>
260  : tuple_element<OpenKalman::values::fixed_number_of_v<O> + i, std::decay_t<V>> {};
261 
262  template<size_t i, typename V, typename O, typename E> requires (not OpenKalman::values::fixed<O>)
263  struct tuple_element<i, OpenKalman::collections::slice_view<V, O, E>>
264  {
265  using type = ranges::range_value_t<V>;
266  };
267 #else
268  template<size_t i, typename V, typename O, typename E>
269  struct tuple_element<i, OpenKalman::collections::slice_view<V, O, E>>
271 #endif
272 } // namespace std
273 
274 
276 {
277  namespace detail
278  {
279  template<typename O, typename E>
281 #if __cpp_lib_ranges >= 202202L
282  : std::ranges::range_adaptor_closure<slice_closure<O, E>>
283 #else
285 #endif
286  {
287  constexpr slice_closure(O o, E e) : offset_ {std::move(o)}, extent_ {std::move(e)} {};
288 
289 #ifdef __cpp_concepts
290  template<viewable_collection R>
291 #else
292  template<typename R, std::enable_if_t<viewable_collection<R>, int> = 0>
293 #endif
294  constexpr auto
295  operator() (R&& r) const
296  {
297  return slice_view {all(std::forward<R>(r)), offset_, extent_};
298  }
299 
300  private:
301  O offset_;
302  E extent_;
303  };
304 
305 
307  {
308 #ifdef __cpp_concepts
309  template<values::index O, values::index E>
310 #else
311  template<typename O, typename E, std::enable_if_t<values::index<O> and values::index<E>, int> = 0>
312 #endif
313  constexpr auto
314  operator() (O o, E e) const
315  {
316  return slice_closure<O, E> {std::move(o), std::move(e)};
317  }
318 
319 
320 #ifdef __cpp_concepts
321  template<collection V, values::index O, values::index E>
322 #else
323  template<typename V, typename O, typename E, std::enable_if_t<collection<V> and values::index<O> and values::index<E>, int> = 0>
324 #endif
325  constexpr auto
326  operator() (V&& t, O o, E e) const
327  {
328  return slice_view {all(std::forward<V>(t)), std::move(o), std::move(e)};
329  }
330 
331  };
332 
333  }
334 
335 
342  inline constexpr detail::slice_adapter slice;
343 
344 }
345 
346 
347 #endif //OPENKALMAN_COLLECTIONS_VIEWS_SLICE_HPP
Definition for values::index.
Namespace for collections.
Definition: collections.hpp:27
Definition for collections::get.
Definition for collections::collection.
constexpr auto size() const noexcept
Definition: slice.hpp:152
constexpr slice_view(const V &v, Offset offset, Extent extent)
Construct from a collection.
Definition: slice.hpp:71
decltype(auto) constexpr get(Arg &&arg, I i)
A generalization of std::get.
Definition: get.hpp:62
An operation involving some number of values.
Definition: operation.hpp:69
Definition: view_interface.hpp:32
Definition for collections::sized_random_access_range.
Definition: tuple_reverse.hpp:103
constexpr slice_view()
Default constructor.
Definition: slice.hpp:63
Definition: range-access.hpp:25
slice_view(const V &, const O &, const E &) -> slice_view< V, O, E >
Deduction guide.
The fixed number associated with a values::fixed.
Definition: fixed_number_of.hpp:45
constexpr V & base() &
The base view.
Definition: slice.hpp:87
constexpr auto end() &
Definition: slice.hpp:137
Definition: range_adaptor_closure.hpp:35
Namespace for generalized views.
Definition: collections.hpp:33
constexpr detail::slice_adapter slice
a RangeAdapterObject associated with slice_view.
Definition: slice.hpp:342
A view representing a slice of a collection.
Definition: slice.hpp:52
constexpr bool index
T is an index value.
Definition: index.hpp:56
Definition for ::fixed.
constexpr auto begin() &
Definition: slice.hpp:119
Definition: gettable.hpp:27
Definition for collections::viewable_collection.
constexpr std::size_t dynamic_size
A constant indicating that a size or index is dynamic.
Definition: global-definitions.hpp:33
decltype(auto) constexpr get() &
Get element i.
Definition: slice.hpp:171
constexpr auto get_size(Arg &&arg)
Get the size of a sized object (e.g, a collection)
Definition: get_size.hpp:191
constexpr slice_view(V &&v, Offset offset, Extent extent)
Definition: slice.hpp:76