OpenKalman
concat.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 
17 #ifndef OPENKALMAN_COMPATIBILITY_VIEWS_CONCAT_HPP
18 #define OPENKALMAN_COMPATIBILITY_VIEWS_CONCAT_HPP
19 
22 #include "view_interface.hpp"
23 #include "all.hpp"
24 
26 {
27 #if __cpp_lib_ranges_concat >= 202403L
28  using std::ranges::concat_view;
29  namespace views
30  {
32  }
33 #else
34 
39 #ifdef __cpp_lib_ranges
40  template<std::ranges::random_access_range...Views> requires (... and std::ranges::view<Views>) and (sizeof...(Views) > 0)
41 #else
42  template<typename...Views>
43 #endif
44  struct concat_view : view_interface<concat_view<Views...>>
45  {
46  private:
47 
48  template<typename...Rs> using concat_reference_t = common_reference_t<range_reference_t<Rs>...>;
49  template<typename...Rs> using concat_value_t = std::common_type_t<range_value_t<Rs>...>;
50  template<typename...Rs> using concat_rvalue_reference_t = common_reference_t<range_rvalue_reference_t<Rs>...>;
51 
52  template<bool Const, typename Rs>
53  using maybe_const = std::conditional_t<Const, const Rs, Rs>;
54 
55  using ViewsTup = std::tuple<Views...>;
56 
57 
58  class concat_index_table
59  {
60  template<std::size_t...cs>
61  #ifdef __cpp_lib_constexpr_vector
62  static constexpr auto
63  #else
64  static auto
65  #endif
66  make_index_table_range(const ViewsTup& tup, std::index_sequence<cs...>)
67  {
68  std::vector<std::size_t> table;
69  auto it = std::back_inserter(table);
70  (std::fill_n(it, stdex::ranges::size(std::get<cs>(tup)), cs), ...);
71  return table;
72  }
73 
74 
75  static constexpr auto
76  make_index_table(const ViewsTup& tup)
77  {
78  return make_index_table_range(tup, std::index_sequence_for<Views...>{});
79  }
80 
81  public:
82 
83  explicit constexpr concat_index_table(const ViewsTup& rs_tup) : value {make_index_table(rs_tup)} {}
84 
85  decltype(make_index_table(std::declval<const ViewsTup&>())) value;
86 
87  };
88 
89 
90  class concat_start_table
91  {
92  template<std::size_t i = 0, typename...Locs>
93  static constexpr auto
94  make_start_table(const ViewsTup& tup, std::size_t currloc = 0_uz, Locs...locs)
95  {
96  if constexpr (i < sizeof...(Views))
97  {
98  std::size_t next_loc = currloc + stdex::ranges::size(std::get<i>(tup));
99  return make_start_table<i + 1>(tup, next_loc, locs..., currloc);
100  }
101  else
102  {
103  return std::array {locs...};
104  }
105  }
106 
107  public:
108 
109  explicit constexpr concat_start_table(const ViewsTup& rs_tup) : value {make_start_table(rs_tup)} {}
110 
111  decltype(make_start_table(std::declval<const ViewsTup&>())) value;
112 
113  };
114 
115 
116  using IndexTable = decltype(concat_index_table(std::declval<ViewsTup>()).value);
117 
118  using StartTable = decltype(concat_start_table(std::declval<ViewsTup>()).value);
119 
120  public:
121 
122  template<bool Const>
123  struct iterator
124  {
125  using iterator_concept = std::random_access_iterator_tag;
126  using iterator_category = iterator_concept;
127  using value_type = concat_value_t<maybe_const<Const, Views>...>;
128  using difference_type = std::common_type_t<range_difference_t<maybe_const<Const, Views>>...>;
129  using pointer = void;
130  using reference = concat_reference_t<maybe_const<Const, Views>...>;
131 
132  private:
133 
134  using Tup = maybe_const<Const, ViewsTup>;
135 
136  template<typename = std::index_sequence_for<Views...>>
137  struct tuple_concat_iterator_call_table;
138 
139  template<std::size_t...ix>
140  struct tuple_concat_iterator_call_table<std::index_sequence<ix...>>
141  {
142  template<std::size_t i>
143  static constexpr value_type
144  call_table_get(Tup& tup, std::size_t local_i) noexcept
145  {
146  return std::get<i>(tup)[local_i];
147  }
148 
149  static constexpr std::array value {call_table_get<ix>...};
150  };
151 
152  using table = tuple_concat_iterator_call_table<>;
153 
154  public:
155 
156 #ifdef __cpp_concepts
157  constexpr iterator() = default;
158 
159  constexpr iterator(iterator<not Const> it) requires Const and
160  (... and std::convertible_to<stdex::ranges::iterator_t<Views>, stdex::ranges::iterator_t<const Views>>)
161  : parent(it.parent), current(it.current) {}
162 #else
163  constexpr iterator() : parent{nullptr} {};
164 
165  template<bool C = Const, std::enable_if_t<C and
166  (... and stdex::convertible_to<iterator_t<Views>, iterator_t<const Views>>), int> = 0>
167  constexpr iterator(iterator<not C> it) : parent(it.parent), current(it.current) {}
168 #endif
169 
170  //template<typename...Args>
171  constexpr explicit iterator(maybe_const<Const, concat_view>* parent, difference_type p)
172  //requires std::constructible_from<base_iter, Args&&...>
173  : parent(parent), current(p) {}
174 
175  constexpr iterator(const iterator& other) = default;
176  constexpr iterator(iterator&& other) noexcept = default;
177  constexpr iterator& operator=(const iterator& other) = default;
178  constexpr iterator& operator=(iterator&& other) noexcept = default;
179  explicit constexpr operator std::size_t() const noexcept { return static_cast<std::size_t>(current); }
180 
181  constexpr decltype(auto) operator*() noexcept
182  {
183  std::size_t c = (parent->index_table)[static_cast<std::size_t>(current)];
184  std::size_t local_i = current - parent->start_table[c];
185  return table::value[c](parent->views_tup, local_i);
186  }
187  constexpr decltype(auto) operator*() const noexcept
188  {
189  std::size_t c = (parent->index_table)[static_cast<std::size_t>(current)];
190  std::size_t local_i = current - parent->start_table[c];
191  return table::value[c](parent->views_tup, local_i);
192  }
193  constexpr decltype(auto) operator[](difference_type offset) noexcept
194  {
195  auto i = static_cast<std::size_t>(current + offset);
196  std::size_t c = parent->index_table[i];
197  std::size_t local_i = i - parent->start_table[c];
198  return table::value[c](parent->views_tup, local_i);
199  }
200  constexpr decltype(auto) operator[](difference_type offset) const noexcept
201  {
202  auto i = static_cast<std::size_t>(current + offset);
203  std::size_t c = parent->index_table[i];
204  std::size_t local_i = i - parent->start_table[c];
205  return table::value[c](parent->views_tup, local_i);
206  }
207  constexpr auto& operator++() noexcept { ++current; return *this; }
208  constexpr auto operator++(int) noexcept { auto temp = *this; ++*this; return temp; }
209  constexpr auto& operator--() noexcept { --current; return *this; }
210  constexpr auto operator--(int) noexcept { auto temp = *this; --*this; return temp; }
211  constexpr auto& operator+=(const difference_type diff) noexcept { current += diff; return *this; }
212  constexpr auto& operator-=(const difference_type diff) noexcept { current -= diff; return *this; }
213 
214  friend constexpr auto operator+(const iterator& it, const difference_type diff) noexcept
215  {
216  return iterator {it.parent, it.current + diff};
217  }
218  friend constexpr auto operator+(const difference_type diff, const iterator& it) noexcept
219  {
220  return iterator {it.parent, diff + it.current};
221  }
222  friend constexpr auto operator-(const iterator& it, const difference_type diff) noexcept
223  {
224  return iterator {it.parent, it.current - diff};
225  }
226  friend constexpr difference_type operator-(const iterator& it, const iterator& other) noexcept
227  {
228  return it.current - other.current;
229  }
230  friend constexpr bool operator==(const iterator& it, const iterator& other) noexcept
231  {
232  return it.current == other.current;
233  }
234 #ifdef __cpp_impl_three_way_comparison
235  constexpr auto operator<=>(const iterator& other) const noexcept { return current <=> other.current; }
236 #else
237  constexpr bool operator!=(const iterator& other) const noexcept { return current != other.current; }
238  constexpr bool operator<(const iterator& other) const noexcept { return current < other.current; }
239  constexpr bool operator>(const iterator& other) const noexcept { return current > other.current; }
240  constexpr bool operator<=(const iterator& other) const noexcept { return current <= other.current; }
241  constexpr bool operator>=(const iterator& other) const noexcept { return current >= other.current; }
242 #endif
243 
244  private:
245 
246  maybe_const<Const, concat_view>* parent;
247  difference_type current;
248 
249  };
250 
251 
252 #ifdef __cpp_concepts
253  constexpr concat_view() = default;
254 #else
255  template<bool Enable = true, std::enable_if_t<Enable and (... and stdex::default_initializable<Views>), int> = 0>
256  constexpr concat_view() {}
257 #endif
258 
259 
260  explicit constexpr concat_view(Views...vs) : views_tup {std::move(vs)...} {}
261 
262 
263  constexpr auto
264  begin() noexcept
265  {
266  return iterator<false> {this, 0};
267  }
268 
269 
270  constexpr auto
271  begin() const noexcept
272  {
273  return iterator<true> {this, 0};
274  }
275 
276 
277  constexpr auto
278  end() noexcept
279  {
280  return iterator<false> {this, static_cast<std::ptrdiff_t>(size())};
281  }
282 
283 
284  constexpr auto
285  end() const noexcept
286  {
287  return iterator<true> {this, static_cast<std::ptrdiff_t>(size())};
288  }
289 
290  private:
291 
292  template<typename F, typename Tuple>
293  static constexpr auto tuple_transform(F&& f, Tuple&& tuple)
294  {
295  return std::apply([&f](auto&&...args)
296  {
297  return std::tuple<std::invoke_result_t<F&, decltype(args)>...>(stdex::invoke(f, std::forward<decltype(args)>(args))...);
298  }, std::forward<Tuple>(tuple));
299 
300  }
301 
302  public:
303 
304 #ifdef __cpp_concepts
305  constexpr auto size() const requires (... and std::ranges::sized_range<Views>)
306 #else
307  template<bool enable = true, std::enable_if_t<enable and (... and sized_range<Views>), int> = 0>
308  constexpr auto size() const
309 #endif
310  {
311  return std::apply([](auto...sizes) { return (... + static_cast<std::size_t>(sizes)); },
312  tuple_transform(stdex::ranges::size, views_tup));
313  }
314 
315  private:
316 
317  ViewsTup views_tup;
318 
319  IndexTable index_table = concat_index_table(views_tup).value;
320 
321  StartTable start_table = concat_start_table(views_tup).value;
322 
323  };
324 
325 
326  template<typename...Rs>
328 
329 
330  namespace views
331  {
332  namespace detail
333  {
335  {
336  #ifdef __cpp_lib_ranges
337  template<std::ranges::viewable_range...Rs> requires (... and std::ranges::random_access_range<Rs>)
338  #else
339  template<typename...Rs, std::enable_if_t<(... and (viewable_range<Rs> and random_access_range<Rs>)), int> = 0>
340  #endif
341  constexpr auto
342  operator() (Rs&&...rs) const
343  {
344  if constexpr (sizeof...(Rs) == 1 and (... and input_range<Rs>))
345  return all(std::forward<Rs>(rs)...);
346  else
347  return concat_view { all(std::forward<Rs>(rs))...};
348  }
349  };
350  }
351 
352 
357  inline constexpr detail::concat_adaptor concat;
358 
359  }
360 
361 #endif
362 }
363 
364 #endif
constexpr detail::all_closure all
Equivalent to std::ranges::views::all.
Definition: all.hpp:64
constexpr bool value
T is a fixed or dynamic value that is reducible to a number.
Definition: value.hpp:45
decltype(auto) constexpr apply(F &&f, T &&t)
A generalization of std::apply.
Definition: apply.hpp:49
Definition: view_interface.hpp:32
constexpr detail::concat_adaptor concat
a std::ranges::range_adaptor_closure for a set of concatenated pattern objects.
Definition: concat.hpp:56
Definition: common.hpp:200
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:65
Definition: trait_backports.hpp:64
Definitions relating to a compatible replacement for std::invoke.