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