OpenKalman
to.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_TO_HPP
18 #define OPENKALMAN_COMPATIBILITY_VIEWS_TO_HPP
19 
20 #if __cpp_lib_ranges_to_container < 202202L
21 
22 #ifdef __cpp_lib_ranges
23 #include <ranges>
24 #else
26 #include "view-concepts.hpp"
28 #include "transform.hpp"
29 #endif
30 
31 namespace OpenKalman::ranges
32 {
33  namespace detail_to
34  {
35  using namespace std;
36 
37 
38 #ifdef __cpp_concepts
39  template<typename Adaptor, typename...Args>
40  concept adaptor_invocable = requires { std::declval<Adaptor>()(declval<Args>()...); };
41 #else
42  template<typename Adaptor, typename = void, typename...Args>
43  struct is_adaptor_invocable : std::false_type {};
44 
45  template<typename Adaptor, typename...Args>
46  struct is_adaptor_invocable<Adaptor, std::void_t<decltype(std::declval<Adaptor>()(declval<Args>()...))>, Args...>
47  : std::true_type {};
48 
49  template<typename Adaptor, typename...Args>
50  inline constexpr bool adaptor_invocable = is_adaptor_invocable<Adaptor, void, Args...>::value;
51 #endif
52 
53 
54  template<typename Adaptor, typename...Args>
55  struct Partial;
56 
57 
58  template<typename Adaptor, typename...Args>
59  struct Partial : ranges::range_adaptor_closure<Partial<Adaptor, Args...>>
60  {
61  template<typename...Ts>
62  constexpr explicit
63  Partial(int, Ts&&...args) : m_args(std::forward<Ts>(args)...) {}
64 
65 
66 #ifdef __cpp_concepts
67  template<typename Range> requires adaptor_invocable<Adaptor, Range&&, const Args&...>
68 #else
69  template<typename Range, std::enable_if_t<adaptor_invocable<Adaptor, Range&&, const Args&...>, int> = 0>
70 #endif
71  constexpr auto
72  operator()(Range&& r) const &
73  {
74  auto forwarder = [&r] (const auto&...args) { return Adaptor{}(std::forward<Range>(r), args...); };
75  return std::apply(forwarder, m_args);
76  }
77 
78 
79 #ifdef __cpp_concepts
80  template<typename Range> requires adaptor_invocable<Adaptor, Range, Args...>
81 #else
82  template<typename Range, std::enable_if_t<adaptor_invocable<Adaptor, Range, Args...>, int> = 0>
83 #endif
84  constexpr auto
85  operator()(Range&& r) &&
86  {
87  auto forwarder = [&r] (auto&... args) { return Adaptor{}(std::forward<Range>(r), std::move(args)...); };
88  return std::apply(forwarder, m_args);
89  }
90 
91 
92  template<typename Range>
93  constexpr auto
94  operator()(Range&& r) const && = delete;
95 
96  private:
97 
98  tuple<Args...> m_args;
99 
100  };
101 
102 
103  template<typename Adaptor, typename Arg>
105  {
106  template<typename Tp>
107  constexpr
108  Partial(int, Tp&& arg) : m_arg(std::forward<Tp>(arg)) {}
109 
110 
111 #ifdef __cpp_concepts
112  template<typename Range> requires adaptor_invocable<Adaptor, Range, const Arg&>
113 #else
114  template<typename Range, std::enable_if_t<adaptor_invocable<Adaptor, Range, const Arg&>, int> = 0>
115 #endif
116  constexpr auto
117  operator()(Range&& r) const & { return Adaptor{}(std::forward<Range>(r), m_arg); }
118 
119 
120 #ifdef __cpp_concepts
121  template<typename Range> requires adaptor_invocable<Adaptor, Range, Arg>
122 #else
123  template<typename Range, std::enable_if_t<adaptor_invocable<Adaptor, Range, Arg>, int> = 0>
124 #endif
125  constexpr auto
126  operator()(Range&& r) && { return Adaptor{}(std::forward<Range>(r), std::move(m_arg)); }
127 
128 
129  template<typename Range>
130  constexpr auto
131  operator()(Range&& r) const && = delete;
132 
133  private:
134 
135  Arg m_arg;
136  };
137 
138 
139 #ifdef __cpp_lib_ranges
140  template<typename Container>
141  inline constexpr bool reservable_container = std::ranges::sized_range<Container> and
142  requires(Container& c, std::ranges::range_size_t<Container> n)
143  {
144  c.reserve(n);
145  { c.capacity() } -> std::same_as<decltype(n)>;
146  { c.max_size() } -> std::same_as<decltype(n)>;
147  };
148 
149  template<typename Cont, typename Range>
150  inline constexpr bool toable = requires {
151  requires (not std::ranges::input_range<Cont> or
152  std::convertible_to<std::ranges::range_reference_t<Range>, std::ranges::range_value_t<Cont>>);
153  };
154 #else
155  template<typename T, typename = void, typename = void>
156  struct reservable_container_impl : std::false_type {};
157 
158  template<typename T>
159  struct reservable_container_impl<T, std::void_t<decltype(std::declval<T&>().reserve(std::declval<ranges::range_size_t<T>>()))>,
160  std::enable_if_t<
161  std::is_same_v<decltype(std::declval<T&>().capacity()), ranges::range_size_t<T>> and
162  std::is_same_v<decltype(std::declval<T&>().max_size()), ranges::range_size_t<T>>>>
163  : std::true_type {};
164 
165  template<typename Container>
166  inline constexpr bool reservable_container =
167  ranges::sized_range<Container> and reservable_container_impl<Container>::value;
168 
169  template<typename Range, typename = void>
170  struct toable1_impl : std::false_type {};
171 
172  template<typename Cont>
173  struct toable1_impl<Cont, std::enable_if_t<not ranges::input_range<Cont>>> : std::true_type {};
174 
175  template<typename Cont, typename Range, typename = void>
176  struct toable2_impl : std::false_type {};
177 
178  template<typename Cont, typename Range>
179  struct toable2_impl<Cont, Range, std::enable_if_t<
180  std::is_convertible_v<ranges::range_reference_t<Range>, ranges::range_value_t<Cont>>>> : std::true_type {};
181 
182  template<typename Cont, typename Range>
183  inline constexpr bool toable = toable1_impl<Cont>::value or toable2_impl<Cont, Range>::value;
184 #endif
185 #ifndef __cpp_concepts
186  template<typename C, typename I, typename = void>
187  struct can_emplace_back : std::false_type {};
188 
189  template<typename C, typename I>
190  struct can_emplace_back<C, I, std::void_t<decltype(std::declval<C&>().emplace_back(*std::declval<I&>()))>>
191  : std::true_type {};
192 
193 
194  template<typename C, typename I, typename = void>
195  struct can_push_back : std::false_type {};
196 
197  template<typename C, typename I>
198  struct can_push_back<C, I, std::void_t<decltype(std::declval<C&>().push_back(*std::declval<I&>()))>>
199  : std::true_type {};
200 
201 
202  template<typename C, typename I, typename = void>
203  struct can_emplace : std::false_type {};
204 
205  template<typename C, typename I>
206  struct can_emplace<C, I, std::void_t<decltype(std::declval<C&>().emplace(std::declval<C&>().end(), *std::declval<I&>()))>>
207  : std::true_type {};
208 #endif
209 
210 
211 #ifdef __cpp_lib_ranges
212  template<typename Cont, std::ranges::input_range Rg, typename...Args> requires (not std::ranges::view<Cont>)
213 #else
214  template<typename Cont, typename Rg, typename...Args, std::enable_if_t<
215  ranges::input_range<Rg> and not ranges::view<Cont>, int> = 0>
216 #endif
217  constexpr Cont
218  to [[nodiscard]] (Rg&& r, Args&&... args)
219  {
220  static_assert(not std::is_const_v<Cont> and not std::is_volatile_v<Cont>);
221  static_assert(std::is_class_v<Cont>);
222 
223  if constexpr (toable<Cont, Rg>)
224  {
225  if constexpr (std::is_constructible_v<Cont, Rg, Args...>)
226  {
227  return Cont(std::forward<Rg>(r), std::forward<Args>(args)...);
228  }
229  else if constexpr (input_iterator<Rg> and ranges::common_range<Rg> and
230  std::is_constructible_v<Cont, ranges::iterator_t<Rg>, ranges::sentinel_t<Rg>, Args...>)
231  {
232  return Cont(ranges::begin(r), ranges::end(r), std::forward<Args>(args)...);
233  }
234  else
235  {
236  static_assert(std::is_constructible_v<Cont, Args...>);
237  Cont c(std::forward<Args>(args)...);
238  if constexpr (ranges::sized_range<Rg> and reservable_container<Cont>)
239  c.reserve(static_cast<ranges::range_size_t<Cont>>(ranges::size(r)));
240  auto it = ranges::begin(r);
241  const auto sent = ranges::end(r);
242  while (it != sent)
243  {
244 #ifdef __cpp_concepts
245  if constexpr (requires { c.emplace_back(*it); }) c.emplace_back(*it);
246  else if constexpr (requires { c.push_back(*it); }) c.push_back(*it);
247  else if constexpr (requires { c.emplace(c.end(), *it); }) c.emplace(c.end(), *it);
248 #else
249  if constexpr (can_emplace_back<decltype(c), decltype(it)>::value) c.emplace_back(*it);
250  else if constexpr (can_push_back<decltype(c), decltype(it)>::value) c.push_back(*it);
251  else if constexpr (can_emplace<decltype(c), decltype(it)>::value) c.emplace(c.end(), *it);
252 #endif
253  else c.insert(c.end(), *it);
254  ++it;
255  }
256  return c;
257  }
258  }
259  else
260  {
261  static_assert(ranges::input_range<ranges::range_reference_t<Rg>>);
262  return to<Cont>(ref_view(r) | ranges::views::transform(
263  [](auto&& elem) { return to<ranges::range_value_t<Cont>>(std::forward<decltype(elem)>(elem)); }), std::forward<Args>(args)...);
264  }
265  }
266 
267 
268  template<typename Rg>
269  struct InputIter
270  {
271  using iterator_category = std::input_iterator_tag;
272  using value_type = ranges::range_value_t<Rg>;
273  using difference_type = std::ptrdiff_t;
274  using pointer = std::add_pointer_t<ranges::range_reference_t<Rg>>;
275  using reference = ranges::range_reference_t<Rg>;
276  reference operator*() const;
277  pointer operator->() const;
278  InputIter& operator++();
279  InputIter operator++(int);
280  bool operator==(const InputIter&) const;
281  };
282 
283  template<template<typename...> typename Cont, typename Rg, typename... Args>
284  using DeduceExpr1 = decltype(Cont(std::declval<Rg>(), std::declval<Args>()...));
285 
286 #ifdef __cpp_concepts
287  template<template<typename...> typename Cont, typename Rg, typename... Args>
288  concept can_DeduceExpr1 = requires requires { typename DeduceExpr1<Cont, Rg, Args...>; };
289 #else
290  template<template<typename...> typename Cont, typename Rg, typename = void, typename... Args>
291  struct can_DeduceExpr1_impl : std::false_type {};
292 
293  template<template<typename...> typename Cont, typename Rg, typename... Args>
294  struct can_DeduceExpr1_impl<Cont, Rg, std::void_t<DeduceExpr1<Cont, Rg, Args...>>, Args...> : std::true_type {};
295 
296  template<template<typename...> typename Cont, typename Rg, typename... Args>
297  inline constexpr bool can_DeduceExpr1 = can_DeduceExpr1_impl<Cont, Rg, void, Args...>::value;
298 #endif
299 
300 
301  template<template<typename...> typename Cont, typename Rg, typename... Args>
302  using DeduceExpr3 = decltype(Cont(std::declval<InputIter<Rg>>(), std::declval<InputIter<Rg>>(), std::declval<Args>()...));
303 
304 #ifdef __cpp_concepts
305  template<template<typename...> typename Cont, typename Rg, typename... Args>
306  concept can_DeduceExpr3 = requires requires { typename DeduceExpr3<Cont, Rg, Args...>; };
307 #else
308  template<template<typename...> typename Cont, typename Rg, typename = void, typename... Args>
309  struct can_DeduceExpr3_impl : std::false_type {};
310 
311  template<template<typename...> typename Cont, typename Rg, typename... Args>
312  struct can_DeduceExpr3_impl<Cont, Rg, std::void_t<DeduceExpr3<Cont, Rg, Args...>>, Args...> : std::true_type {};
313 
314  template<template<typename...> typename Cont, typename Rg, typename... Args>
315  inline constexpr bool can_DeduceExpr3 = can_DeduceExpr3_impl<Cont, Rg, void, Args...>::value;
316 #endif
317 
318 
319 #ifdef __cpp_concepts
320  template<template<typename...> typename Cont, std::ranges::input_range Rg, typename...Args>
321 #else
322  template<template<typename...> typename Cont, typename Rg, typename...Args, std::enable_if_t<ranges::input_range<Rg>, int> = 0>
323 #endif
324  constexpr auto
325  to [[nodiscard]] (Rg&& r, Args&&... args)
326  {
327  if constexpr (can_DeduceExpr1<Cont, Rg, Args...>)
328  return to<DeduceExpr1<Cont, Rg, Args...>>(std::forward<Rg>(r), std::forward<Args>(args)...);
329  else if constexpr (can_DeduceExpr3<Cont, Rg, Args...>)
330  return to<DeduceExpr3<Cont, Rg, Args...>>(std::forward<Rg>(r), std::forward<Args>(args)...);
331  else
332  static_assert(false, "Cannot deduce container specialization");
333  }
334 
335 
336  template<typename Cont>
337  struct To
338  {
339 #ifdef __cpp_concepts
340  template<typename Range, typename...Args> requires requires { to<Cont>(std::declval<Range&&>(), std::declval<Args&&>()...); }
341 #else
342  template<typename Range, typename...Args, typename = std::void_t<decltype(to<Cont>(std::declval<Range&&>(), std::declval<Args&&>()...))>>
343 #endif
344  constexpr auto
345  operator()(Range&& r, Args&&... args) const
346  {
347  return to<Cont>(std::forward<Range>(r), std::forward<Args>(args)...);
348  }
349  };
350 
351 
352 #ifdef __cpp_concepts
353  template<typename Cont, typename... Args> requires (not ranges::view<Cont>)
354 #else
355  template<typename Cont, typename...Args, std::enable_if_t<not ranges::view<Cont>, int> = 0>
356 #endif
357  constexpr auto
358  to [[nodiscard]] (Args&&... args)
359  {
360  return Partial<To<Cont>, decay_t<Args>...>{0, std::forward<Args>(args)...};
361  }
362 
363 
364  template<template<typename...> typename Cont>
365  struct To2
366  {
367 #ifdef __cpp_concepts
368  template<typename Range, typename...Args> requires requires { to<Cont>(std::declval<Range&&>(), std::declval<Args&&>()...); }
369 #else
370  template<typename Range, typename...Args, typename = std::void_t<decltype(to<Cont>(std::declval<Range&&>(), std::declval<Args&&>()...))>>
371 #endif
372  constexpr auto
373  operator()(Range&& r, Args&&...args) const
374  {
375  return to<Cont>(std::forward<Range>(r), std::forward<Args>(args)...);
376  }
377  };
378 
379 
380  template<template<typename...> typename Cont, typename...Args>
381  constexpr auto
382  to [[nodiscard]] (Args&&...args)
383  {
384  return Partial<To2<Cont>, decay_t<Args>...>{0, std::forward<Args>(args)...};
385  }
386  }
387 
388 
389  using detail_to::to;
390 
391 }
392 
393 #endif
394 
395 #endif //OPENKALMAN_COMPATIBILITY_VIEWS_TO_HPP
Definition: tuple_reverse.hpp:103
constexpr bool value
T is numerical value or is reducible to a numerical value.
Definition: value.hpp:31
Definition: to.hpp:337
Definition: range-access.hpp:25
Definition: ref_view.hpp:32
constexpr bool size
T is either an index representing a size, or void which represents that there is no size...
Definition: size.hpp:32
Definition: range_adaptor_closure.hpp:35
Definitions implementing features of the c++ ranges library for compatibility.