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-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_COLLECTIONS_VIEWS_SLICE_HPP
17 #define OPENKALMAN_COLLECTIONS_VIEWS_SLICE_HPP
18 
19 #include <tuple>
20 #include "values/values.hpp"
25 #include "all.hpp"
26 
28 {
36 #ifdef __cpp_lib_ranges
37  template<collection V, values::index Offset, values::size Extent = values::unbounded_size_t> requires
38  std::same_as<std::decay_t<Offset>, Offset> and std::same_as<std::decay_t<Extent>, Extent> and
39  (not values::size_compares_with<Offset, size_of_t<V>, &stdex::is_gt>) and
40  (not values::index<Extent> or not values::size_compares_with<Extent, size_of_t<V>, &stdex::is_gt>) and
41  (not sized<V> or not values::index<Extent> or
42  not values::size_compares_with<values::operation_t<std::plus<>, Offset, Extent>, size_of_t<V>, &std::is_gt>)
43 #else
44  template<typename V, typename Offset, typename Extent = values::unbounded_size_t>
45 #endif
46  struct slice_view : stdex::ranges::view_interface<slice_view<V, Offset, Extent>>
47  {
51 #ifdef __cpp_concepts
52  constexpr slice_view() = default;
53 #else
54  template<bool Enable = true, std::enable_if_t<Enable and stdex::default_initializable<V> and
55  stdex::default_initializable<Offset> and stdex::default_initializable<Extent>, int> = 0>
56  constexpr slice_view() {}
57 #endif
58 
59 
63  constexpr
64  slice_view(V&& v, Offset offset = {}, Extent extent = {})
65  : v_ {std::forward<V>(v)}, offset_ {std::move(offset)}, extent_ {std::move(extent)} {}
66 
67 
71 #ifdef __cpp_explicit_this_parameter
72  constexpr decltype(auto)
73  base(this auto&& self) noexcept { return std::forward<decltype(self)>(self).v_.get(); }
74 #else
75  constexpr V& base() & { return this->v_.get(); }
76  constexpr const V& base() const & { return this->v_.get(); }
77  constexpr V&& base() && noexcept { return std::move(*this).v_.get(); }
78  constexpr const V&& base() const && noexcept { return std::move(*this).v_.get(); }
79 #endif
80 
81 #ifndef __cpp_explicit_this_parameter
82  private:
83 
84  template<typename Self>
85  static constexpr auto
86  begin_impl(Self&& self) noexcept
87  {
88  return stdex::ranges::begin(std::forward<Self>(self).v_.get());
89  }
90 
91  template<typename Self>
92  static constexpr auto
93  end_impl(Self&& self) noexcept
94  {
95  return stdex::ranges::end(std::forward<Self>(self).v_.get());
96  }
97 
98  public:
99 #endif
100 
104 #ifdef __cpp_explicit_this_parameter
105  constexpr auto
106  begin(this auto&& self) noexcept requires stdex::ranges::range<const V>
107  {
108  return stdex::ranges::begin(std::forward<decltype(self)>(self).v_.get()) + std::forward<decltype(self)>(self).offset_;
109  }
110 #else
111  template<bool Enable = true, std::enable_if_t<Enable and stdex::ranges::range<const V>, int> = 0>
112  constexpr auto begin() & { return begin_impl(*this) + offset_; }
113 
114  template<bool Enable = true, std::enable_if_t<Enable and stdex::ranges::range<const V>, int> = 0>
115  constexpr auto begin() const & { return begin_impl(*this) + offset_; }
116 
117  template<bool Enable = true, std::enable_if_t<Enable and stdex::ranges::range<const V>, int> = 0>
118  constexpr auto begin() && noexcept { return begin_impl(std::move(*this)) + std::move(*this).offset_; }
119 
120  template<bool Enable = true, std::enable_if_t<Enable and stdex::ranges::range<const V>, int> = 0>
121  constexpr auto begin() const && noexcept { return begin_impl(std::move(*this)) + std::move(*this).offset_; }
122 #endif
123 
124 
128 #ifdef __cpp_explicit_this_parameter
129  constexpr auto
130  end(this auto&& self) noexcept requires stdex::ranges::range<const V>
131  {
132  if constexpr (values::index<Extent>)
133  return std::forward<decltype(self)>(self).begin() + std::forward<decltype(self)>(self).extent_;
134  else
135  return stdex::ranges::end(std::forward<decltype(self)>(self).v_.get());
136  }
137 #else
138  template<bool Enable = true, std::enable_if_t<Enable and stdex::ranges::range<const V>, int> = 0>
139  constexpr auto end() &
140  {
141  if constexpr (values::index<Extent>) return this->begin() + extent_;
142  else return end_impl(*this);
143  }
144 
145  template<bool Enable = true, std::enable_if_t<Enable and stdex::ranges::range<const V>, int> = 0>
146  constexpr auto end() const &
147  {
148  if constexpr (values::index<Extent>) return this->begin() + extent_;
149  else return end_impl(*this);
150  }
151 
152  template<bool Enable = true, std::enable_if_t<Enable and stdex::ranges::range<const V>, int> = 0>
153  constexpr auto end() && noexcept
154  {
155  if constexpr (values::index<Extent>) return std::move(*this).begin() + std::move(*this).extent_;
156  else return end_impl(std::move(*this));
157  }
158 
159  template<bool Enable = true, std::enable_if_t<Enable and stdex::ranges::range<const V>, int> = 0>
160  constexpr auto end() const && noexcept
161  {
162  if constexpr (values::index<Extent>) return std::move(*this).begin() + std::move(*this).extent_;
163  else return end_impl(std::move(*this));
164  }
165 #endif
166 
167 
171 #ifdef __cpp_explicit_this_parameter
172  constexpr values::size auto
173  size(this auto&& self) noexcept requires values::index<Extent> or sized<V>
174  {
175  if constexpr (values::index<Extent>)
176  return std::forward<decltype(self)>(self).extent_;
177  else
178  return values::operation(
179  std::minus{},
180  get_size(std::forward<decltype(self)>(self).v_.get()),
181  std::forward<decltype(self)>(self).offset_);
182  }
183 #else
184  template<bool Enable = true, std::enable_if_t<values::index<Extent> or sized<V>, int> = 0>
185  constexpr auto
186  size() const noexcept
187  {
188  if constexpr (values::index<Extent>)
189  return extent_;
190  else
191  return values::operation(std::minus{}, get_size(v_.get()), offset_);
192  }
193 #endif
194 
195 
199 #ifdef __cpp_explicit_this_parameter
200  template<std::size_t i>
201  constexpr decltype(auto)
202  get(this auto&& self) noexcept
203  {
204  if constexpr (values::fixed<Extent>) static_assert(i < values::fixed_value_of_v<Extent>, "Index exceeds range");
205  return collections::get_element(std::forward<decltype(self)>(self).v_.get(),
206  values::operation(std::plus{}, std::forward<decltype(self)>(self).offset_, std::integral_constant<std::size_t, i>{}));
207  }
208 #else
209  template<std::size_t i>
210  constexpr decltype(auto)
211  get() &
212  {
213  if constexpr (values::fixed<Extent>) static_assert(i < values::fixed_value_of_v<Extent>, "Index exceeds range");
214  return collections::get_element(v_.get(),
215  values::operation(std::plus{}, offset_, std::integral_constant<std::size_t, i>{}));
216  }
217 
218  template<std::size_t i>
219  constexpr decltype(auto)
220  get() const &
221  {
222  if constexpr (values::fixed<Extent>) static_assert(i < values::fixed_value_of_v<Extent>, "Index exceeds range");
223  return collections::get_element(v_.get(),
224  values::operation(std::plus{}, offset_, std::integral_constant<std::size_t, i>{}));
225  }
226 
227  template<std::size_t i>
228  constexpr decltype(auto)
229  get() && noexcept
230  {
231  if constexpr (values::fixed<Extent>) static_assert(i < values::fixed_value_of_v<Extent>, "Index exceeds range");
232  return collections::get_element(std::move(*this).v_.get(),
233  values::operation(std::plus{}, offset_, std::integral_constant<std::size_t, i>{}));
234  }
235 
236  template<std::size_t i>
237  constexpr decltype(auto)
238  get() const && noexcept
239  {
240  if constexpr (values::fixed<Extent>) static_assert(i < values::fixed_value_of_v<Extent>, "Index exceeds range");
241  return collections::get_element(std::move(*this).v_.get(),
242  values::operation(std::modulus{}, std::integral_constant<std::size_t, i>{}, get_size(std::move(*this).get_t())));
243  }
244 #endif
245 
246  private:
247 
249  Offset offset_;
250  Extent extent_;
251 
252  };
253 
254 
258  template<typename V, typename O, typename E>
259  slice_view(V&&, const O&, const E&) -> slice_view<V, O, E>;
260 
261  template<typename V, typename O>
262  slice_view(V&&, const O&) -> slice_view<V, O>;
263 
264 
265 }
266 
267 
268 #ifdef __cpp_lib_ranges
269 namespace std::ranges
270 #else
271 namespace OpenKalman::stdex::ranges
272 #endif
273 {
274  template<typename V, typename O, typename E>
275  constexpr bool enable_borrowed_range<OpenKalman::collections::slice_view<V, O, E>> = enable_borrowed_range<V>;
276 }
277 
278 
279 #ifndef __cpp_lib_ranges
281 {
282  template<std::size_t i, typename V, typename O, typename = void>
284 
285  template<std::size_t i, typename V, typename O>
286  struct slice_tuple_element<i, V, O, std::enable_if_t<values::fixed<O>>>
287  : collection_element<values::fixed_value_of_v<O> + i, std::decay_t<V>> {};
288 }
289 #endif
290 
291 
292 namespace std
293 {
294  template<typename V, typename O, typename E>
295  struct tuple_size<OpenKalman::collections::slice_view<V, O, E>> : OpenKalman::values::fixed_value_of<E> {};
296 
297  template<typename V, typename O>
298  struct tuple_size<OpenKalman::collections::slice_view<V, O, OpenKalman::values::unbounded_size_t>>
299  : std::conditional_t<
300  OpenKalman::values::fixed<OpenKalman::collections::size_of<V>> and OpenKalman::values::fixed<O>,
301  OpenKalman::values::operation_t<std::minus<>, OpenKalman::collections::size_of<V>, O>,
302  std::monostate> {};
303 
304 
305 #ifdef __cpp_concepts
306  template<size_t i, typename V, typename O, typename E>
307  struct tuple_element<i, OpenKalman::collections::slice_view<V, O, E>> {};
308 
309  template<size_t i, typename V, OpenKalman::values::fixed O, typename E>
310  struct tuple_element<i, OpenKalman::collections::slice_view<V, O, E>>
311  : OpenKalman::collections::collection_element<OpenKalman::values::fixed_value_of_v<O> + i, std::decay_t<V>> {};
312 #else
313  template<size_t i, typename V, typename O, typename E>
314  struct tuple_element<i, OpenKalman::collections::slice_view<V, O, E>>
316 #endif
317 }
318 
319 
321 {
322  namespace detail
323  {
324  template<typename R, typename O, typename E>
325  constexpr auto
326  slice_impl(R&& r, O&& o, E&& e)
327  {
328  if constexpr (viewable_collection<R>)
329  {
330  if constexpr (values::fixed_value_compares_with<O, 0_uz> and values::size_compares_with<E, size_of_t<R>>)
331  return all(std::forward<R>(r));
332  else
333  return slice_view {all(std::forward<R>(r)), std::forward<O>(o), std::forward<E>(e)};
334  }
335  else return slice_view {std::forward<R>(r), std::forward<O>(o), std::forward<E>(e)};
336  };
337 
338 
343  template<typename O, typename E>
345  {
346  constexpr slice_closure(O o, E e) : offset_ {std::move(o)}, extent_ {std::move(e)} {};
347 
348 #ifdef __cpp_concepts
349  template<typename R> requires
350  (viewable_collection<R> or
351  (uniformly_gettable<R> and values::fixed<O> and (values::fixed<E> or not values::index<E>))) and
352  (not values::size_compares_with<O, size_of<R>, &std::is_gt>) and
353  (not values::index<E> or not values::size_compares_with<E, size_of<R>, &std::is_gt>) and
354  (not sized<R> or size_of_v<R> == std::dynamic_extent or
355  values::dynamic<O> or values::dynamic<E> or
356  values::fixed_value_of_v<O> + values::fixed_value_of_v<E> <= size_of_v<R>)
357 #else
358  template<typename R, std::enable_if_t<
359  ((viewable_collection<R> or (uniformly_gettable<R> and values::fixed<O> and (values::fixed<E> or not values::index<E>))) and
360  values::index<O> and values::size<E>) and
361  (not values::size_compares_with<O, size_of<R>, &stdex::is_gt>) and
362  (not values::index<E> or not values::size_compares_with<E, size_of<R>, &stdex::is_gt>), int> = 0>
363 #endif
364  constexpr auto
365  operator() (R&& r) const
366  {
367  return slice_impl(std::forward<R>(r), offset_, extent_);
368  }
369 
370  private:
371  O offset_;
372  E extent_;
373  };
374 
375 
377  {
378 #ifdef __cpp_concepts
379  template<values::index O, values::size E = values::unbounded_size_t>
380 #else
381  template<typename O, typename E = values::unbounded_size_t, std::enable_if_t<
382  values::index<O> and values::size<E>, int> = 0>
383 #endif
384  constexpr auto
385  operator() (O o, E e = values::unbounded_size) const
386  {
387  return slice_closure<O, E> {std::move(o), std::move(e)};
388  }
389 
390 
391 #ifdef __cpp_concepts
392  template<typename R, values::index O, values::size E = values::unbounded_size_t> requires
393  (viewable_collection<R> or
394  (uniformly_gettable<R> and values::fixed<O> and (values::fixed<E> or not values::index<E>))) and
395  (not values::size_compares_with<O, size_of_t<R>, &std::is_gt>) and
396  (not values::index<E> or not values::size_compares_with<E, size_of_t<R>, &std::is_gt>) and
397  (not sized<R> or not values::index<E> or
398  not values::size_compares_with<values::operation_t<std::plus<>, O, E>, size_of_t<R>, &std::is_gt>)
399 #else
400  template<typename R, typename O, typename E = values::unbounded_size_t, std::enable_if_t<
401  ((viewable_collection<R> or (uniformly_gettable<R> and values::fixed<O> and (values::fixed<E> or not values::index<E>))) and
402  values::index<O> and values::size<E>) and
403  (not values::size_compares_with<O, size_of<R>, &stdex::is_gt>) and
404  (not values::index<E> or not values::size_compares_with<E, size_of<R>, &stdex::is_gt>), int> = 0>
405 #endif
406  constexpr decltype(auto)
407  operator() (R&& r, O o, E e = values::unbounded_size) const
408  {
409  return slice_impl(std::forward<R>(r), std::move(o), std::move(e));
410  }
411 
412  };
413 
414  }
415 
416 
423  inline constexpr detail::slice_adapter slice;
424 
425 }
426 
427 
428 #endif
Namespace for collections.
Definition: collections.hpp:27
Definition for collections::collection.
constexpr slice_view(V &&v, Offset offset={}, Extent extent={})
Construct from a collection.
Definition: slice.hpp:64
constexpr auto get_size(Arg &&arg)
Get the size of a sized object (e.g, a collection)
Definition: get_size.hpp:224
Header file for code relating to values (e.g., scalars and indices)
constexpr auto begin() &
Definition: slice.hpp:112
The size of a sized object (including a collection).
Definition: size_of.hpp:33
The fixed value associated with a fixed.
Definition: fixed_value_of.hpp:44
constexpr auto size() const noexcept
Definition: slice.hpp:186
Definition: view_interface.hpp:32
Definition for collections::get_size.
constexpr slice_view()
Default constructor.
Definition: slice.hpp:56
Definition for collections::get_element.
std::conditional_t< sized< T >, size_of< T >, values::unbounded_size_t > size_of_t
The type of the argument&#39;s size, which will satisfy values::size.
Definition: size_of.hpp:69
constexpr bool sized
An object (std::ranges::sized_range, std::tuple, std::span, etc.) that has a discernible size...
Definition: sized.hpp:32
A type reflecting an unbound size.
Definition: size.hpp:27
constexpr V & base() &
The base view.
Definition: slice.hpp:75
constexpr T & get() &noexcept
Retrieve the stored value.
Definition: movable_wrapper.hpp:72
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
constexpr bool size_compares_with
T and U are sizes that compare in a particular way based on parameter comp.
Definition: size_compares_with.hpp:98
Namespace for generalized views.
Definition: collections.hpp:33
constexpr detail::slice_adapter slice
a RangeAdapterObject associated with slice_view.
Definition: slice.hpp:423
Definition: range_adaptor_closure.hpp:34
decltype(operation(std::declval< Operation && >(), std::declval< Args && >()...)) operation_t
The resulting type from an values::operation.
Definition: operation.hpp:115
A view representing a slice of a collection.
Definition: slice.hpp:46
The type of the element at a given index, if it can be determined at compile time.
Definition: collection_element.hpp:48
decltype(auto) constexpr get_element(Arg &&arg, I i)
A generalization of std::get and the range subscript operator.
Definition: get_element.hpp:124
constexpr unbounded_size_t unbounded_size
An instance of unbounded_size_t;.
Definition: size.hpp:60
Definition: gettable.hpp:24
Definition for collections::viewable_collection.
slice_view(V &&, const O &, const E &) -> slice_view< V, O, E >
Deduction guides.
constexpr auto end() &
Definition: slice.hpp:139
decltype(auto) constexpr get() &
Get element i.
Definition: slice.hpp:211
constexpr auto operation(Operation &&op, Args &&...args)
A potentially constant-evaluated operation involving some number of values.
Definition: operation.hpp:98
constexpr bool index
An object describing a collection of /ref values::index objects.
Definition: index.hpp:77