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>
27 #include "all.hpp"
28 
30 {
41 #ifdef __cpp_lib_ranges
42  template<collection V, values::index Offset, values::index Extent> requires
43  std::same_as<std::decay_t<Offset>, Offset> and std::same_as<std::decay_t<Extent>, Extent> and
44  (not sized<V> or size_of_v<V> == stdex::dynamic_extent or
45  ((values::dynamic<Offset> or values::fixed_value_of_v<Offset> <= size_of_v<V>) and
46  (values::dynamic<Extent> or values::fixed_value_of_v<Extent> <= size_of_v<V>) and
47  (values::dynamic<Offset> or values::dynamic<Extent> or values::fixed_value_of_v<Offset> + values::fixed_value_of_v<Extent> <= size_of_v<V>)))
48 #else
49  template<typename V, typename Offset, typename Extent>
50 #endif
51  struct slice_view : stdex::ranges::view_interface<slice_view<V, Offset, Extent>>
52  {
56 #ifdef __cpp_concepts
57  constexpr slice_view() = default;
58 #else
59  template<bool Enable = true, std::enable_if_t<Enable and stdex::default_initializable<V> and
60  stdex::default_initializable<Offset> and stdex::default_initializable<Extent>, int> = 0>
61  constexpr slice_view() {}
62 #endif
63 
64 
68  constexpr
69  slice_view(const V& v, Offset offset, Extent extent)
70  : v_ {v}, offset_ {std::move(offset)}, extent_ {std::move(extent)} {}
71 
73  constexpr
74  slice_view(V&& v, Offset offset, Extent extent)
75  : v_ {std::move(v)}, offset_ {std::move(offset)}, extent_ {std::move(extent)} {}
76 
77 
81 #ifdef __cpp_explicit_this_parameter
82  constexpr decltype(auto)
83  base(this auto&& self) noexcept { return std::forward<decltype(self)>(self).v_; }
84 #else
85  constexpr V& base() & { return this->v_; }
86  constexpr const V& base() const & { return this->v_; }
87  constexpr V&& base() && noexcept { return std::move(*this).v_; }
88  constexpr const V&& base() const && noexcept { return std::move(*this).v_; }
89 #endif
90 
91 #ifndef __cpp_explicit_this_parameter
92  private:
93 
94  template<typename Self>
95  static constexpr auto
96  begin_impl(Self&& self) noexcept
97  {
98  return stdex::ranges::begin(std::forward<Self>(self).v_);
99  }
100 
101  public:
102 #endif
103 
107 #ifdef __cpp_explicit_this_parameter
108  constexpr auto
109  begin(this auto&& self) noexcept requires stdex::ranges::range<const V>
110  {
111  return stdex::ranges::begin(std::forward<decltype(self)>(self).v_) + std::forward<decltype(self)>(self).offset_;
112  }
113 #else
114  template<bool Enable = true, std::enable_if_t<Enable and stdex::ranges::range<const V>, int> = 0>
115  constexpr auto begin() & { 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() const & { return begin_impl(*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() && noexcept { return begin_impl(std::move(*this)) + std::move(*this).offset_; }
122 
123  template<bool Enable = true, std::enable_if_t<Enable and stdex::ranges::range<const V>, int> = 0>
124  constexpr auto begin() const && noexcept { return begin_impl(std::move(*this)) + std::move(*this).offset_; }
125 #endif
126 
127 
131 #ifdef __cpp_explicit_this_parameter
132  constexpr auto
133  end(this auto&& self) noexcept requires stdex::ranges::range<const V>
134  {
135  return std::forward<decltype(self)>(self).begin() + std::forward<decltype(self)>(self).extent_;
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() & { return this->begin() + extent_; }
140 
141  template<bool Enable = true, std::enable_if_t<Enable and stdex::ranges::range<const V>, int> = 0>
142  constexpr auto end() const & { return this->begin() + extent_; }
143 
144  template<bool Enable = true, std::enable_if_t<Enable and stdex::ranges::range<const V>, int> = 0>
145  constexpr auto end() && noexcept { return std::move(*this).begin() + std::move(*this).extent_; }
146 
147  template<bool Enable = true, std::enable_if_t<Enable and stdex::ranges::range<const V>, int> = 0>
148  constexpr auto end() const && noexcept { return std::move(*this).begin() + std::move(*this).extent_; }
149 #endif
150 
151 
155 #ifdef __cpp_explicit_this_parameter
156  constexpr values::index auto
157  size(this auto&& self) noexcept { return std::forward<decltype(self)>(self).extent_; }
158 #else
159  constexpr auto
160  size() const noexcept { return extent_; }
161 #endif
162 
163 
167 #ifdef __cpp_explicit_this_parameter
168  template<std::size_t i>
169  constexpr decltype(auto)
170  get(this auto&& self) noexcept
171  {
172  if constexpr (values::fixed<Extent>) static_assert(i < values::fixed_value_of_v<Extent>, "Index exceeds range");
173  return collections::get_element(std::forward<decltype(self)>(self).v_,
174  values::operation(std::plus{}, std::forward<decltype(self)>(self).offset_, std::integral_constant<std::size_t, i>{}));
175  }
176 #else
177  template<std::size_t i>
178  constexpr decltype(auto)
179  get() &
180  {
181  if constexpr (values::fixed<Extent>) static_assert(i < values::fixed_value_of_v<Extent>, "Index exceeds range");
182  return collections::get_element(v_,
183  values::operation(std::plus{}, offset_, std::integral_constant<std::size_t, i>{}));
184  }
185 
186  template<std::size_t i>
187  constexpr decltype(auto)
188  get() const &
189  {
190  if constexpr (values::fixed<Extent>) static_assert(i < values::fixed_value_of_v<Extent>, "Index exceeds range");
191  return collections::get_element(v_,
192  values::operation(std::plus{}, offset_, std::integral_constant<std::size_t, i>{}));
193  }
194 
195  template<std::size_t i>
196  constexpr decltype(auto)
197  get() && noexcept
198  {
199  if constexpr (values::fixed<Extent>) static_assert(i < values::fixed_value_of_v<Extent>, "Index exceeds range");
200  return collections::get_element(std::move(*this).v_,
201  values::operation(std::plus{}, offset_, std::integral_constant<std::size_t, i>{}));
202  }
203 
204  template<std::size_t i>
205  constexpr decltype(auto)
206  get() const && noexcept
207  {
208  if constexpr (values::fixed<Extent>) static_assert(i < values::fixed_value_of_v<Extent>, "Index exceeds range");
209  return collections::get_element(std::move(*this).v_,
210  values::operation(std::modulus{}, std::integral_constant<std::size_t, i>{}, get_size(std::move(*this).get_t())));
211  }
212 #endif
213 
214  private:
215 
216  V v_;
217  Offset offset_;
218  Extent extent_;
219 
220  };
221 
222 
226  template<typename V, typename O, typename E>
227  slice_view(const V&, const O&, const E&) -> slice_view<V, O, E>;
228 
229 }
230 
231 
232 #ifdef __cpp_lib_ranges
233 namespace std::ranges
234 #else
235 namespace OpenKalman::stdex::ranges
236 #endif
237 {
238  template<typename V, typename O, typename E>
239  constexpr bool enable_borrowed_range<OpenKalman::collections::slice_view<V, O, E>> = enable_borrowed_range<V>;
240 }
241 
242 
243 #ifndef __cpp_lib_ranges
245 {
246  template<std::size_t i, typename V, typename O, typename = void>
248 
249  template<std::size_t i, typename V, typename O>
250  struct slice_tuple_element<i, V, O, std::enable_if_t<values::fixed<O>>>
251  : collection_element<values::fixed_value_of_v<O> + i, std::decay_t<V>> {};
252 }
253 #endif
254 
255 
256 namespace std
257 {
258  template<typename V, typename O, typename E>
259  struct tuple_size<OpenKalman::collections::slice_view<V, O, E>> : OpenKalman::values::fixed_value_of<E> {};
260 
261 
262 #ifdef __cpp_concepts
263  template<size_t i, typename V, typename O, typename E>
264  struct tuple_element<i, OpenKalman::collections::slice_view<V, O, E>> {};
265 
266  template<size_t i, typename V, OpenKalman::values::fixed O, typename E>
267  struct tuple_element<i, OpenKalman::collections::slice_view<V, O, E>>
268  : OpenKalman::collections::collection_element<OpenKalman::values::fixed_value_of_v<O> + i, std::decay_t<V>> {};
269 #else
270  template<size_t i, typename V, typename O, typename E>
271  struct tuple_element<i, OpenKalman::collections::slice_view<V, O, E>>
273 #endif
274 }
275 
276 
278 {
279  namespace detail
280  {
281 #ifdef __cpp_concepts
282  template<typename O, typename E, typename N>
283 #else
284  template<typename O, typename E, typename N, typename = void>
285 #endif
286  struct slice_is_whole : std::false_type {};
287 
288 #ifdef __cpp_concepts
289  template<values::fixed O, values::fixed E, values::fixed N>
290  struct slice_is_whole<O, E, N>
291 #else
292  template<typename O, typename E, typename N>
293  struct slice_is_whole<O, E, N, std::enable_if_t<values::fixed<O> and values::fixed<E> and values::fixed<N>>>
294 #endif
295  : std::bool_constant<(values::fixed_value_of_v<O> == 0_uz and values::fixed_value_of_v<E> == values::fixed_value_of_v<N>)> {};
296 
297 
298 
299  template<typename O, typename E>
301  {
302  constexpr slice_closure(O o, E e) : offset_ {std::move(o)}, extent_ {std::move(e)} {};
303 
304 #ifdef __cpp_concepts
305  template<viewable_collection R>
306 #else
307  template<typename R, std::enable_if_t<viewable_collection<R>, int> = 0>
308 #endif
309  constexpr auto
310  operator() (R&& r) const
311  {
312  if constexpr (slice_is_whole<O, E, size_of<R>>::value)
313  return all(std::forward<R>(r));
314  else
315  return slice_view {all(std::forward<R>(r)), offset_, extent_};
316  }
317 
318  private:
319  O offset_;
320  E extent_;
321  };
322 
323 
325  {
326 #ifdef __cpp_concepts
327  template<values::index O, values::index E>
328 #else
329  template<typename O, typename E, std::enable_if_t<values::index<O> and values::index<E>, int> = 0>
330 #endif
331  constexpr auto
332  operator() (O o, E e) const
333  {
334  return slice_closure<O, E> {std::move(o), std::move(e)};
335  }
336 
337 
338 #ifdef __cpp_concepts
339  template<viewable_collection R, values::index O, values::index E>
340 #else
341  template<typename R, typename O, typename E, std::enable_if_t<
342  viewable_collection<R> and values::index<O> and values::index<E>, int> = 0>
343 #endif
344  constexpr decltype(auto)
345  operator() (R&& r, O o, E e) const
346  {
347  if constexpr (slice_is_whole<O, E, size_of<R>>::value)
348  return all(std::forward<R>(r));
349  else
350  return slice_view {all(std::forward<R>(r)), std::move(o), std::move(e)};
351  }
352 
353  };
354 
355  }
356 
357 
364  inline constexpr detail::slice_adapter slice;
365 
366 }
367 
368 
369 #endif
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:160
Definition of lexicographical_compare_three_way for collections.
constexpr slice_view(const V &v, Offset offset, Extent extent)
Construct from a collection.
Definition: slice.hpp:69
constexpr auto begin() &
Definition: slice.hpp:115
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 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 slice_view()
Default constructor.
Definition: slice.hpp:61
slice_view(const V &, const O &, const E &) -> slice_view< V, O, E >
Deduction guide.
constexpr V & base() &
The base view.
Definition: slice.hpp:85
Namespace for generalized views.
Definition: collections.hpp:33
constexpr detail::slice_adapter slice
a RangeAdapterObject associated with slice_view.
Definition: slice.hpp:364
Definition: range_adaptor_closure.hpp:34
A view representing a slice of a collection.
Definition: slice.hpp:51
The type of the element at a given index, if it can be determined at compile time.
Definition: collection_element.hpp:48
constexpr bool index
T is an index value.
Definition: index.hpp:62
decltype(auto) constexpr get_element(Arg &&arg, I i)
A generalization of std::get and the range subscript operator.
Definition: get_element.hpp:122
Definition for ::fixed.
Definition: gettable.hpp:24
Definition for collections::viewable_collection.
constexpr auto end() &
Definition: slice.hpp:139
decltype(auto) constexpr get() &
Get element i.
Definition: slice.hpp:179
constexpr auto get_size(Arg &&arg)
Get the size of a sized object (e.g, a collection)
Definition: get_size.hpp:188
constexpr slice_view(V &&v, Offset offset, Extent extent)
Definition: slice.hpp:74
constexpr auto operation(Operation &&op, Args &&...args)
A potentially constant-evaluated operation involving some number of values.
Definition: operation.hpp:98