OpenKalman
replicate.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_REPLICATE_HPP
17 #define OPENKALMAN_COLLECTIONS_VIEWS_REPLICATE_HPP
18 
19 #include <type_traits>
20 #ifdef __cpp_lib_ranges
21 #include <ranges>
22 #else
26 #endif
33 #include "all.hpp"
34 
36 {
50 #ifdef __cpp_lib_ranges
51  template<collection V, values::index Factor> requires std::same_as<std::decay_t<Factor>, Factor>
52  struct replicate_view : std::ranges::view_interface<replicate_view<V, Factor>>
53 #else
54  template<typename V, typename Factor>
55  struct replicate_view : ranges::view_interface<replicate_view<V, Factor>>
56 #endif
57  {
58  private:
59 
60  template<bool Const, typename T>
61  using maybe_const = std::conditional_t<Const, const T, T>;
62 
63  public:
64 
68  template<bool Const>
69  struct iterator
70  {
71  private:
72 
73  using Parent = maybe_const<Const, replicate_view>;
74 
75  public:
76 
77  using iterator_concept = std::random_access_iterator_tag;
78  using iterator_category = std::random_access_iterator_tag;
79 #ifdef __cpp_lib_ranges
80  using value_type = std::ranges::range_value_t<V>;
81  using reference = std::ranges::range_reference_t<V>;
82 #else
83  using value_type = ranges::range_value_t<V>;
84  using reference = ranges::range_reference_t<V>;
85 #endif
86  using difference_type = std::ptrdiff_t;
87  using pointer = void;
88 
89  constexpr iterator() = default;
90 
91  constexpr iterator(Parent& parent, difference_type p) : parent_ {std::addressof(parent)}, current_{p} {}
92 
93  constexpr iterator(iterator<not Const> i) : parent_ {std::move(i.parent_)}, current_ {std::move(i.current_)} {}
94 
95  constexpr decltype(auto) operator*() { return collections::get(parent_->v_, current_ % get_size(parent_->v_)); }
96  constexpr decltype(auto) operator*() const { return collections::get(parent_->v_, current_ % get_size(parent_->v_)); }
97  constexpr decltype(auto) operator[](difference_type offset) { return collections::get(parent_->v_, (current_ + offset) % get_size(parent_->v_)); }
98  constexpr decltype(auto) operator[](difference_type offset) const { return collections::get(parent_->v_, (current_ + offset) % get_size(parent_->v_)); }
99 
100  constexpr auto& operator++() noexcept { ++current_; return *this; }
101  constexpr auto operator++(int) noexcept { auto temp = *this; ++*this; return temp; }
102  constexpr auto& operator--() noexcept { --current_; return *this; }
103  constexpr auto operator--(int) noexcept { auto temp = *this; --*this; return temp; }
104  constexpr auto& operator+=(const difference_type diff) noexcept { current_ += diff; return *this; }
105  constexpr auto& operator-=(const difference_type diff) noexcept { current_ -= diff; return *this; }
106  friend constexpr auto operator+(const iterator& it, const difference_type diff) noexcept
107  { return iterator {*it.parent_, it.current_ + diff}; }
108  friend constexpr auto operator+(const difference_type diff, const iterator& it) noexcept
109  { return iterator {*it.parent_, diff + it.current_}; }
110  friend constexpr auto operator-(const iterator& it, const difference_type diff)
111  { return iterator {*it.parent_, it.current_ - diff}; }
112  friend constexpr difference_type operator-(const iterator& it, const iterator& other) noexcept
113  { return it.current_ - other.current_; }
114  friend constexpr bool operator==(const iterator& it, const iterator& other) noexcept
115  { return it.current_ == other.current_; }
116 #ifdef __cpp_impl_three_way_comparison
117  constexpr auto operator<=>(const iterator& other) const noexcept { return current_ <=> other.current_; }
118 #else
119  constexpr bool operator!=(const iterator& other) const noexcept { return current_ != other.current_; }
120  constexpr bool operator<(const iterator& other) const noexcept { return current_ < other.current_; }
121  constexpr bool operator>(const iterator& other) const noexcept { return current_ > other.current_; }
122  constexpr bool operator<=(const iterator& other) const noexcept { return current_ <= other.current_; }
123  constexpr bool operator>=(const iterator& other) const noexcept { return current_ >= other.current_; }
124 #endif
125 
126  private:
127 
128  Parent * parent_;
129  difference_type current_;
130 
131  };
132 
133 
137 #ifdef __cpp_concepts
138  constexpr
139  replicate_view() = default;
140 #else
141  template<bool Enable = true, std::enable_if_t<Enable and
142  std::is_default_constructible_v<V> and std::is_default_constructible_v<Factor>, int> = 0>
143  constexpr
145 #endif
146 
147 
151  constexpr
152  replicate_view(V& v, Factor f) : v_ {v}, f_ {std::move(f)} {}
153 
154 
156  constexpr
157  replicate_view(V&& v, Factor f) : v_ {std::move(v)}, f_ {std::move(f)} {}
158 
159 
163 #ifdef __cpp_explicit_this_parameter
164  constexpr decltype(auto)
165  base(this auto&& self) noexcept { return std::forward<decltype(self)>(self).v_; }
166 #else
167  constexpr V& base() & { return this->v_; }
168  constexpr const V& base() const & { return this->v_; }
169  constexpr V&& base() && noexcept { return std::move(*this).v_; }
170  constexpr const V&& base() const && noexcept { return std::move(*this).v_; }
171 #endif
172 
173 
177  constexpr auto
178  begin() { return iterator<false> {*this, 0_uz}; }
179 
180 #ifdef __cpp_lib_ranges
181  constexpr auto
182  begin() const requires std::ranges::range<const V>
183 #else
184  template<bool Enable = true, std::enable_if_t<Enable and ranges::range<const V>, int> = 0>
185  constexpr auto begin() const
186 #endif
187  { return iterator<true> {*this, 0_uz}; }
188 
189 
193  constexpr auto
194  end() { return iterator<false> {*this, static_cast<std::ptrdiff_t>(values::to_number(size()))}; }
195 
196 
198 #ifdef __cpp_lib_ranges
199  constexpr auto
200  end() const requires std::ranges::range<const V>
201 #else
202  template<bool Enable = true, std::enable_if_t<Enable and ranges::range<const V>, int> = 0>
203  constexpr auto
204  end() const noexcept
205 #endif
206  {
207  return iterator<true> {*this, static_cast<std::ptrdiff_t>(values::to_number(size()))};
208  }
209 
210 
214 #ifdef __cpp_concepts
215  constexpr values::index auto size() const
216 #else
217  constexpr auto size() const
218 #endif
219  {
220  return values::operation {std::multiplies{}, get_size(v_), f_};
221  }
222 
223 
227 #ifdef __cpp_explicit_this_parameter
228  template<std::size_t i>
229  constexpr decltype(auto)
230  get(this auto&& self) noexcept
231  {
232  if constexpr (size_of_v<V> != dynamic_size and values::fixed<Factor>)
233  static_assert(i < size_of_v<V> * values::fixed_number_of_v<Factor>, "Index out of range");
234  return collections::get(std::forward<decltype(self)>(self).v_,
235  values::operation {std::modulus{}, std::integral_constant<std::size_t, i>{}, get_size(self.v_)});
236  }
237 #else
238  template<std::size_t i>
239  constexpr decltype(auto)
240  get() &
241  {
242  if constexpr (size_of_v<V> != dynamic_size and values::fixed<Factor>)
243  static_assert(i < size_of_v<V> * values::fixed_number_of_v<Factor>, "Index out of range");
244  return collections::get(v_,
245  values::operation {std::modulus{}, std::integral_constant<std::size_t, i>{}, get_size(v_)});
246  }
247 
248  template<std::size_t i>
249  constexpr decltype(auto)
250  get() const &
251  {
252  if constexpr (size_of_v<V> != dynamic_size and values::fixed<Factor>)
253  static_assert(i < size_of_v<V> * values::fixed_number_of_v<Factor>, "Index out of range");
254  return collections::get(v_,
255  values::operation {std::modulus{}, std::integral_constant<std::size_t, i>{}, get_size(v_)});
256  }
257 
258  template<std::size_t i>
259  constexpr decltype(auto)
260  get() && noexcept
261  {
262  if constexpr (size_of_v<V> != dynamic_size and values::fixed<Factor>)
263  static_assert(i < size_of_v<V> * values::fixed_number_of_v<Factor>, "Index out of range");
264  return collections::get(std::move(*this).v_,
265  values::operation {std::modulus{}, std::integral_constant<std::size_t, i>{}, get_size(std::move(*this).v_)});
266  }
267 
268  template<std::size_t i>
269  constexpr decltype(auto)
270  get() const && noexcept
271  {
272  if constexpr (size_of_v<V> != dynamic_size and values::fixed<Factor>)
273  static_assert(i < size_of_v<V> * values::fixed_number_of_v<Factor>, "Index out of range");
274  return collections::get(std::move(*this).v_,
275  values::operation {std::modulus{}, std::integral_constant<std::size_t, i>{}, get_size(std::move(*this).v_)});
276  }
277 #endif
278 
279  private:
280 
281  V v_;
282  Factor f_;
283  };
284 
285 
289  template<typename V, typename F>
290  replicate_view(const V&, const F&) -> replicate_view<V, F>;
291 
292 
293 } // namespace OpenKalman::collections
294 
295 
296 #ifdef __cpp_lib_ranges
297 namespace std::ranges
298 #else
299 namespace OpenKalman::ranges
300 #endif
301 {
302  template<typename V, typename F>
303  constexpr bool enable_borrowed_range<OpenKalman::collections::replicate_view<V, F>> = enable_borrowed_range<V>;
304 }
305 
306 
307 #ifndef __cpp_lib_ranges
309 {
310  template<typename V, typename F, typename = void>
312 
313  template<typename V, typename F>
314  struct replicate_tuple_size<V, F, std::enable_if_t<values::fixed<F> and (size_of<V>::value != dynamic_size)>>
315  : std::integral_constant<std::size_t, size_of_v<V> * values::fixed_number_of_v<F>> {};
316 
317 
318  template<std::size_t i, typename V, typename = void>
320  {
321  using type = ranges::range_value_t<V>;
322  };
323 
324  template<std::size_t i, typename V>
325  struct replicate_tuple_element<i, V, std::enable_if_t<size_of<V>::value != dynamic_size>>
326  : std::tuple_element<i % size_of_v<V>, std::decay_t<V>> {};
327 
328 }
329 #endif
330 
331 
332 namespace std
333 {
334 #ifdef __cpp_lib_ranges
335  template<typename V, OpenKalman::values::fixed F> requires (OpenKalman::collections::size_of_v<V> != OpenKalman::dynamic_size)
336  struct tuple_size<OpenKalman::collections::replicate_view<V, F>>
337  : integral_constant<std::size_t, std::tuple_size_v<std::decay_t<V>> * OpenKalman::values::fixed_number_of_v<F>> {};
338 #else
339  template<typename V, typename F>
340  struct tuple_size<OpenKalman::collections::replicate_view<V, F>>
342 #endif
343 
344 
345 #ifdef __cpp_lib_ranges
346  template<size_t i, typename V, typename F> requires (OpenKalman::collections::size_of_v<V> != OpenKalman::dynamic_size)
347  struct tuple_element<i, OpenKalman::collections::replicate_view<V, F>>
348  : tuple_element<i % OpenKalman::collections::size_of_v<V>, decay_t<V>> {};
349 
350  template<size_t i, typename V, typename F> requires (OpenKalman::collections::size_of_v<V> == OpenKalman::dynamic_size)
351  struct tuple_element<i, OpenKalman::collections::replicate_view<V, F>>
352  {
353  using type = ranges::range_value_t<V>;
354  };
355 #else
356  template<size_t i, typename V, typename F>
357  struct tuple_element<i, OpenKalman::collections::replicate_view<V, F>>
359 #endif
360 
361 } // namespace std
362 
363 
365 {
366  namespace detail
367  {
368  template<typename Factor>
370 #if __cpp_lib_ranges >= 202202L
371  : std::ranges::range_adaptor_closure<replicate_closure<Factor>>
372 #else
374 #endif
375  {
376  constexpr replicate_closure(Factor f) : factor_ {std::move(f)} {};
377 
378 #ifdef __cpp_concepts
379  template<viewable_collection R>
380 #else
381  template<typename R, std::enable_if_t<viewable_collection<R>, int> = 0>
382 #endif
383  constexpr auto
384  operator() (R&& r) const
385  {
386  return replicate_view {all(std::forward<R>(r)), factor_};
387  }
388 
389  private:
390  Factor factor_;
391  };
392 
393 
395  {
396 #ifdef __cpp_concepts
397  template<values::index Factor>
398 #else
399  template<typename Factor, std::enable_if_t<values::index<Factor>, int> = 0>
400 #endif
401  constexpr auto
402  operator() (Factor factor) const
403  {
404  return replicate_closure<Factor> {std::move(factor)};
405  }
406 
407 
408 #ifdef __cpp_concepts
409  template<viewable_collection R, values::index Factor>
410 #else
411  template<typename R, typename Factor, std::enable_if_t<viewable_collection<R> and values::index<Factor>, int> = 0>
412 #endif
413  constexpr auto
414  operator() (R&& r, Factor factor) const
415  {
416  return replicate_view {all(std::forward<R>(r)), std::move(factor)};
417  }
418 
419  };
420 
421  }
422 
423 
431 
432 }
433 
434 
435 #endif //OPENKALMAN_COLLECTIONS_VIEWS_REPLICATE_HPP
constexpr auto end() const noexcept
Definition: replicate.hpp:204
Definition for values::index.
Namespace for collections.
Definition: collections.hpp:27
Definition for collections::get.
Definition for collections::collection.
constexpr replicate_view()
Default constructor.
Definition: replicate.hpp:144
constexpr replicate_view(V &v, Factor f)
Construct from a collection.
Definition: replicate.hpp:152
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
Iterator for replicate_view.
Definition: replicate.hpp:69
Definition: tuple_reverse.hpp:103
constexpr V & base() &
The base view.
Definition: replicate.hpp:167
constexpr replicate_view(V &&v, Factor f)
Definition: replicate.hpp:157
constexpr auto end()
Definition: replicate.hpp:194
constexpr auto to_number(Arg arg)
Convert any values::value to a values::number.
Definition: to_number.hpp:34
constexpr detail::replicate_adaptor replicate
a std::ranges::range_adaptor_closure associated with replicate_view.
Definition: replicate.hpp:430
Definition for collections::get_size.
The root namespace for OpenKalman.
Definition: basics.hpp:34
Definitions relating to the availability of c++ language features.
A view that replicates a collection some number of times.
Definition: replicate.hpp:55
decltype(auto) constexpr get() &
Get element i.
Definition: replicate.hpp:240
constexpr auto size() const
Definition: replicate.hpp:217
Definition: range_adaptor_closure.hpp:35
Namespace for generalized views.
Definition: collections.hpp:33
Definitions implementing features of the c++ ranges library for compatibility.
constexpr bool index
T is an index value.
Definition: index.hpp:56
Definition for ::fixed.
Definition: gettable.hpp:27
constexpr std::size_t dynamic_size
A constant indicating that a size or index is dynamic.
Definition: global-definitions.hpp:33
constexpr auto begin()
Definition: replicate.hpp:178
constexpr auto get_size(Arg &&arg)
Get the size of a sized object (e.g, a collection)
Definition: get_size.hpp:191
replicate_view(const V &, const F &) -> replicate_view< V, F >
Deduction guide.