OpenKalman
common.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_COMMON_HPP
18 #define OPENKALMAN_COMPATIBILITY_COMMON_HPP
19 
20 #include "core-concepts.hpp"
21 
22 namespace OpenKalman::stdex
23 {
24 #if __cplusplus >= 202002L
25  using std::common_reference;
26  using std::common_reference_t;
27  using std::common_reference_with;
28  using std::common_with;
29 #else
30  namespace detail
31  {
32  template<typename From, typename To>
33  using copy_cv = std::conditional_t<
34  std::is_const_v<From>,
35  std::conditional_t<std::is_volatile_v<From>, const volatile To, const To>,
36  std::conditional_t<std::is_volatile_v<From>, volatile To, To>
37  >;
38 
39  template<typename A, typename B>
40  using cond_res = decltype(false ? std::declval<A(&)()>()() : std::declval<B(&)()>()());
41 
42  template<typename A, typename B>
43  using cond_res_cvref = cond_res<copy_cv<A, B>&, copy_cv<B, A>&>;
44 
45 
46  template<typename, typename, typename = void>
47  struct common_ref {};
48 
49  template<typename A, typename B>
50  using common_ref_t = typename common_ref<A, B>::type;
51 
52  template<typename A, typename B>
53  struct common_ref<A&, B&, std::void_t<cond_res_cvref<A, B>>> : std::enable_if<
54  std::is_reference_v<cond_res_cvref<A, B>>, cond_res_cvref<A, B>> {};
55 
56  template<typename A, typename B>
57  using common_ref_C = std::remove_reference_t<common_ref_t<A&, B&>>&&;
58 
59  template<typename A, typename B>
60  struct common_ref<A&&, B&&, std::enable_if_t<convertible_to<A&&, common_ref_C<A, B>> and convertible_to<B&&, common_ref_C<A, B>>>>
61  { using type = common_ref_C<A, B>; };
62 
63  template<typename A, typename B>
64  using common_ref_D = common_ref_t<const A&, B&>;
65 
66  template<typename A, typename B>
67  struct common_ref<A&&, B&, std::enable_if_t<convertible_to<A&&, common_ref_D<A, B>>>>
68  { using type = common_ref_D<A, B>; };
69 
70  template<typename A, typename B>
71  struct common_ref<A&, B&&> : common_ref<B&&, A&> {};
72 
73 
74  template<typename T1, typename T2, int b = 1, typename = void>
75  struct common_reference_impl : common_reference_impl<T1, T2, b + 1> {};
76 
77  template<typename T1, typename T2>
78  struct common_reference_impl<T1&, T2&, 1, std::void_t<common_ref_t<T1&, T2&>>> { using type = common_ref_t<T1&, T2&>; };
79 
80  template<typename T1, typename T2>
81  struct common_reference_impl<T1&&, T2&&, 1, std::void_t<common_ref_t<T1&&, T2&&>>> { using type = common_ref_t<T1&&, T2&&>; };
82 
83  template<typename T1, typename T2>
84  struct common_reference_impl<T1&, T2&&, 1, std::void_t<common_ref_t<T1&, T2&&>>> { using type = common_ref_t<T1&, T2&&>; };
85 
86  template<typename T1, typename T2>
87  struct common_reference_impl<T1&&, T2&, 1, std::void_t<common_ref_t<T1&&, T2&>>> { using type = common_ref_t<T1&&, T2&>; };
88 
89  template<typename T1, typename T2>
90  struct common_reference_impl<T1, T2, 3, std::void_t<cond_res<T1, T2>>> { using type = cond_res<T1, T2>; };
91 
92  template<typename T1, typename T2>
93  struct common_reference_impl<T1, T2, 4, std::void_t<std::common_type_t<T1, T2>>> { using type = std::common_type_t<T1, T2>; };
94 
95  template<typename T1, typename T2>
96  struct common_reference_impl<T1, T2, 5, void> {};
97 
98  }
99 
100 
101  template<typename...T>
103 
104  template<>
105  struct common_reference<> {};
106 
107  template<typename T>
108  struct common_reference<T> { using type = T; };
109 
110  namespace detail
111  {
112  template<typename T1, typename T2, typename = void, typename...Ts>
114 
115  template<typename T1, typename T2, typename...Ts>
116  struct combine_common_reference<T1, T2, std::void_t<typename common_reference_impl<T1, T2>::type>, Ts...>
117  : common_reference<typename common_reference_impl<T1, T2>::type, Ts...> {};
118  }
119 
120  template<typename T1, typename T2, typename...Ts>
121  struct common_reference<T1, T2, Ts...> : detail::combine_common_reference<T1, T2, void, Ts...> {};
122 
123 
124  template<typename...T>
125  using common_reference_t = typename common_reference<T...>::type;
126 
127 
128  template<typename T, typename U>
129  inline constexpr bool
130  common_reference_with =
131  same_as<common_reference_t<T, U>, common_reference_t<U, T>> and
132  stdex::convertible_to<T, common_reference_t<T, U>> and
133  stdex::convertible_to<U, common_reference_t<T, U>>;
134 
135  namespace detail
136  {
137  template<typename T, typename U, typename = void>
138  struct common_with_impl1 : std::false_type {};
139 
140  template<typename T, typename U>
141  struct common_with_impl1<T, U, std::enable_if_t<
142  (same_as<typename std::common_type<T, U>::type, typename std::common_type<U, T>::type>)>> : std::true_type {};
143 
144  template<typename T, typename U, typename = void>
145  struct common_with_impl2 : std::false_type {};
146 
147  template<typename T, typename U>
148  struct common_with_impl2<T, U, std::void_t<
149  decltype(static_cast<typename std::common_type<T, U>::type>(std::declval<T>())),
150  decltype(static_cast<typename std::common_type<T, U>::type>(std::declval<U>()))>> : std::true_type {};
151 
152  template<typename T, typename U, typename = void>
153  struct common_with_impl3 : std::false_type {};
154 
155  template<typename T, typename U>
156  struct common_with_impl3<T, U, std::enable_if_t<
157  (common_reference_with<std::add_lvalue_reference_t<typename std::common_type<T, U>::type>,
158  common_reference_t<std::add_lvalue_reference_t<const T>, std::add_lvalue_reference_t<const U>>>)>> : std::true_type {};
159  }
160 
161 
162  template<typename T, typename U>
163  inline constexpr bool
164  common_with =
167  stdex::common_reference_with<std::add_lvalue_reference_t<const T>, std::add_lvalue_reference_t<const U>> and
169 
170 #endif
171 }
172 
173 
174 namespace OpenKalman::stdex
175 {
176 #ifdef __cpp_lib_concepts
177  using std::assignable_from;
178 #else
179  namespace detail
180  {
181  template<typename LHS, typename RHS, typename = void>
182  struct assignable_from_impl : std::false_type {};
183 
184  template<typename LHS, typename RHS>
185  struct assignable_from_impl<LHS, RHS, std::enable_if_t<
186  stdex::same_as<decltype(std::declval<LHS>() = std::declval<RHS&&>()), LHS>>> : std::true_type {};
187  }
188 
189 
190  template<typename LHS, typename RHS>
191  inline constexpr bool
192  assignable_from =
193  std::is_lvalue_reference_v<LHS> and
194  stdex::common_reference_with<const std::remove_reference_t<LHS>&, const std::remove_reference_t<RHS>&> and
196 #endif
197 }
198 
199 
201 {
202 #if __cplusplus >= 202002L
203  using std::ranges::swap;
204 #else
205  namespace detail_swap
206  {
207  template<typename Tp>
208  inline constexpr bool class_or_enum = std::is_class_v<Tp> or std::is_union_v<Tp> or std::is_enum_v<Tp>;
209 
210 
211  template<typename Tp> void swap(Tp&, Tp&) noexcept = delete;
212 
213 
214  template<typename Tp, typename Up, typename = void>
215  struct adl_swap_impl : std::false_type {};
216 
217  template<typename Tp, typename Up>
218  struct adl_swap_impl<Tp, Up, std::void_t<
219  decltype(swap(static_cast<Tp&&>(std::declval<Tp&>()), static_cast<Up&&>(std::declval<Up&>())))>> : std::true_type {};
220 
221 
222  template<typename Tp, typename Up>
223  inline constexpr bool adl_swap =
224  (class_or_enum<std::remove_reference_t<Tp>> or class_or_enum<std::remove_reference_t<Up>>) and
226 
227 
228  class swap_impl
229  {
230  template<typename Tp, typename Up>
231  static constexpr bool S_noexcept()
232  {
233  if constexpr (adl_swap<Tp, Up>)
234  return noexcept(swap(std::declval<Tp>(), std::declval<Up>()));
235  else
236  return std::is_nothrow_move_constructible_v<std::remove_reference_t<Tp>> and
237  std::is_nothrow_move_assignable_v<std::remove_reference_t<Tp>>;
238  }
239 
240  public:
241 
242  template<typename Tp, typename Up, std::enable_if_t<adl_swap<Tp, Up> or
243  (stdex::same_as<Tp, Up> && std::is_lvalue_reference_v<Tp> and
244  stdex::move_constructible<std::remove_reference_t<Tp>> and
245  stdex::assignable_from<Tp, std::remove_reference_t<Tp>>), int> = 0>
246  constexpr void
247  operator()(Tp&& t, Up&& u) const noexcept(S_noexcept<Tp, Up>())
248  {
249  if constexpr (adl_swap<Tp, Up>)
250  {
251  swap(static_cast<Tp&&>(t), static_cast<Up&&>(u));
252  }
253  else
254  {
255  auto tmp = static_cast<std::remove_reference_t<Tp>&&>(t);
256  t = static_cast<std::remove_reference_t<Tp>&&>(u);
257  u = static_cast<std::remove_reference_t<Tp>&&>(tmp);
258  }
259  }
260 
261  template<typename Tp, typename Up, size_t Num, typename = std::void_t<
262  decltype(std::declval<const swap_impl&>()(std::declval<Tp&>(), std::declval<Up&>()))>>
263  constexpr void
264  operator()(Tp (&e1)[Num], Up (&e2)[Num]) const noexcept(noexcept(std::declval<const swap_impl&>()(*e1, *e2)))
265  {
266  for (size_t n = 0; n < Num; ++n) (*this)(e1[n], e2[n]);
267  }
268  };
269  }
270 
271 
272  inline constexpr detail_swap::swap_impl swap;
273 #endif
274 }
275 
276 
277 namespace OpenKalman::stdex
278 {
279 #if __cplusplus >= 202002L
280  using std::swappable;
281  using std::swappable_with;
282 #else
283  namespace detail
284  {
285  template<typename T, typename U, typename = void>
286  struct swappable_impl : std::false_type {};
287 
288  template<typename T, typename U>
289  struct swappable_impl<T, U, std::void_t<decltype(stdex::ranges::swap(std::declval<T&>(), std::declval<U&>()))>> : std::true_type {};
290 
291  template<typename T, typename U, typename = void>
292  struct swappable_with_impl : std::false_type {};
293 
294  template<typename T, typename U>
295  struct swappable_with_impl<T, U, std::void_t<decltype(stdex::ranges::swap(std::declval<T&&>(), std::declval<U&&>()))>> : std::true_type {};
296  }
297 
298 
299  template<typename T>
300  inline constexpr bool swappable = detail::swappable_impl<T, T>::value;
301 
302 
303  template<typename T, typename U>
304  inline constexpr bool swappable_with =
305  stdex::common_reference_with<T, U> and
310 
311 #endif
312 }
313 
314 
315 #endif
Definition: common.hpp:47
Definition: common.hpp:200
Definitions relating to standard c++ library concepts.
Definition: common.hpp:102
Definition: basics.hpp:55