OpenKalman
comparison.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_COMPATIBILILTY_COMPARISON_HPP
17 #define OPENKALMAN_COMPATIBILILTY_COMPARISON_HPP
18 
19 #include <utility>
20 #ifdef __cpp_impl_three_way_comparison
21 #include <compare>
22 #endif
23 #include "internal/exposition.hpp"
24 #include "common.hpp"
25 
26 namespace OpenKalman::stdex
27 {
28 #ifdef __cpp_lib_integer_comparison_functions
29  using std::cmp_equal;
30  using std::cmp_not_equal;
31  using std::cmp_less;
32  using std::cmp_greater;
33  using std::cmp_less_equal;
34  using std::cmp_greater_equal;
35 #else
36  template<typename T, typename U>
37  constexpr bool cmp_equal(T t, U u) noexcept
38  {
39  if constexpr (std::is_signed_v<T> == std::is_signed_v<U>)
40  {
41  return t == u;
42  }
43  else if constexpr (std::is_signed_v<T>)
44  {
45  return t >= 0 && std::make_unsigned_t<T>(t) == u;
46  }
47  else
48  {
49  return u >= 0 && std::make_unsigned_t<U>(u) == t;
50  }
51  }
52 
53  template<typename T, typename U>
54  constexpr bool cmp_not_equal(T t, U u) noexcept
55  {
56  return not cmp_equal(t, u);
57  }
58 
59  template<typename T, typename U>
60  constexpr bool cmp_less(T t, U u) noexcept
61  {
62  if constexpr (std::is_signed_v<T> == std::is_signed_v<U>) return t < u;
63  else if constexpr (std::is_signed_v<T>) return t < 0 or std::make_unsigned_t<T>(t) < u;
64  else return u >= 0 and t < std::make_unsigned_t<U>(u);
65  }
66 
67  template<typename T, typename U>
68  constexpr bool cmp_greater(T t, U u) noexcept
69  {
70  return cmp_less(u, t);
71  }
72 
73  template<typename T, typename U>
74  constexpr bool cmp_less_equal(T t, U u) noexcept
75  {
76  return not cmp_less(u, t);
77  }
78 
79  template<typename T, typename U>
80  constexpr bool cmp_greater_equal(T t, U u) noexcept
81  {
82  return not cmp_less(t, u);
83  }
84 #endif
85 
86 
87 #ifdef __cpp_impl_three_way_comparison
88  using std::partial_ordering;
90  using std::lexicographical_compare_three_way;
91  using std::is_eq;
92  using std::is_neq;
93  using std::is_lt;
94  using std::is_gt;
95  using std::is_lteq;
96  using std::is_gteq;
97 #else
98  namespace detail
99  {
100  enum struct Ord : signed char { equivalent = 0, less = -1, greater = 1, unordered = 2 };
101  }
102 
103 
105  {
106  struct unspecified { constexpr unspecified(unspecified*) noexcept {} };
107 
108  detail::Ord my_value;
109 
110  explicit constexpr partial_ordering(detail::Ord value) noexcept : my_value(value) {}
111 
112  public:
113 
114  static const partial_ordering less;
115  static const partial_ordering equivalent;
116  static const partial_ordering greater;
117  static const partial_ordering unordered;
118 
119  template<typename I, std::enable_if_t<stdex::constructible_from<std::ptrdiff_t, I>, int> = 0>
120  explicit constexpr partial_ordering(I i) : my_value(static_cast<detail::Ord>(i)) {}
121 
122  [[nodiscard]] friend constexpr bool
123  operator==(partial_ordering v, unspecified) noexcept { return v.my_value == detail::Ord::equivalent; }
124 
125  [[nodiscard]] friend constexpr bool
126  operator==(unspecified, partial_ordering v) noexcept { return v.my_value == detail::Ord::equivalent; }
127 
128  [[nodiscard]] friend constexpr bool
129  operator==(partial_ordering v, partial_ordering w) noexcept { return v.my_value == w.my_value; };
130 
131  [[nodiscard]] friend constexpr bool
132  operator!=(partial_ordering v, unspecified) noexcept { return v.my_value != detail::Ord::equivalent; }
133 
134  [[nodiscard]] friend constexpr bool
135  operator!=(unspecified, partial_ordering v) noexcept { return v.my_value != detail::Ord::equivalent; }
136 
137  [[nodiscard]] friend constexpr bool
138  operator!=(partial_ordering v, partial_ordering w) noexcept { return v.my_value != w.my_value; };
139 
140  [[nodiscard]] friend constexpr bool
141  operator<(partial_ordering v, unspecified) noexcept { return v.my_value == detail::Ord::less; }
142 
143  [[nodiscard]] friend constexpr bool
144  operator<(unspecified, partial_ordering v) noexcept { return v.my_value == detail::Ord::greater; }
145 
146  [[nodiscard]] friend constexpr bool
147  operator>(partial_ordering v, unspecified) noexcept { return v.my_value == detail::Ord::greater; }
148 
149  [[nodiscard]] friend constexpr bool
150  operator>(unspecified, partial_ordering v) noexcept { return v.my_value == detail::Ord::less; }
151 
152  [[nodiscard]] friend constexpr bool
153  operator<=(partial_ordering v, unspecified) noexcept { return v.my_value <= detail::Ord::equivalent; }
154 
155  [[nodiscard]] friend constexpr bool
156  operator<=(unspecified, partial_ordering v) noexcept { return v.my_value == detail::Ord::greater or v.my_value == detail::Ord::equivalent; }
157 
158  [[nodiscard]] friend constexpr bool
159  operator>=(partial_ordering v, unspecified) noexcept { return v.my_value == detail::Ord::greater or v.my_value == detail::Ord::equivalent; }
160 
161  [[nodiscard]] friend constexpr bool
162  operator>=(unspecified, partial_ordering v) noexcept { return v.my_value <= detail::Ord::equivalent; }
163  };
164 
165 
166  // valid values' definitions
167  inline constexpr partial_ordering partial_ordering::less(detail::Ord::less);
168 
169  inline constexpr partial_ordering partial_ordering::equivalent(detail::Ord::equivalent);
170 
171  inline constexpr partial_ordering partial_ordering::greater(detail::Ord::greater);
172 
173  inline constexpr partial_ordering partial_ordering::unordered(detail::Ord::unordered);
174 
175 
177  {
178  template<typename T, typename U>
179  constexpr partial_ordering
180  operator() [[nodiscard]] (T&& t, U&& u) const
181  {
182  if (stdex::cmp_equal(t, u)) return partial_ordering::equivalent;
183  if (stdex::cmp_less(t, u)) return partial_ordering::less;
184  if (stdex::cmp_greater(t, u)) return partial_ordering::greater;
185  return partial_ordering::unordered;
186  }
187 
188  using is_transparent = void;
189  };
190 
191 
192  template<typename InputIt1, typename InputIt2, typename Cmp>
193  constexpr auto
194  lexicographical_compare_three_way(InputIt1 first1, InputIt1 last1, InputIt2 first2, InputIt2 last2, Cmp comp)
195  -> decltype(comp(*first1, *first2))
196  {
197  using ret_t = decltype(comp(*first1, *first2));
198  static_assert(std::disjunction_v<
199  //std::is_same<ret_t, strong_ordering>,
200  //std::is_same<ret_t, weak_ordering>,
201  std::is_same<ret_t, partial_ordering>>,
202  "The return type must be a comparison category type.");
203 
204  bool exhaust1 = (first1 == last1);
205  bool exhaust2 = (first2 == last2);
206  for (; not exhaust1 and not exhaust2; exhaust1 = (++first1 == last1), exhaust2 = (++first2 == last2))
207  if (auto c = comp(*first1, *first2); c != partial_ordering(0)) return c;
208 
209  return not exhaust1 ? partial_ordering::greater: // strong_ordering::greater:
210  not exhaust2 ? partial_ordering::less: // strong_ordering::less:
211  partial_ordering::equivalent; // strong_ordering::equal;
212  }
213 
214 
215  template<typename InputIt1, typename InputIt2>
216  constexpr auto
217  lexicographical_compare_three_way(InputIt1 first1, InputIt1 last1, InputIt2 first2, InputIt2 last2 )
218  {
219  return lexicographical_compare_three_way(first1, last1, first2, last2, compare_three_way());
220  }
221 
222 
223  constexpr bool is_eq( partial_ordering cmp ) noexcept { return cmp == 0; };
224  constexpr bool is_neq( partial_ordering cmp ) noexcept { return cmp != 0; };
225  constexpr bool is_lt( partial_ordering cmp ) noexcept { return cmp < 0; };
226  constexpr bool is_lteq( partial_ordering cmp ) noexcept { return cmp <= 0; };
227  constexpr bool is_gt( partial_ordering cmp ) noexcept { return cmp > 0; };
228  constexpr bool is_gteq( partial_ordering cmp ) noexcept { return cmp >= 0; };
229 #endif
230 
231 
232 #ifdef __cpp_lib_concepts
233  using std::equality_comparable;
234  using std::equality_comparable_with;
235  using std::totally_ordered;
236  using std::totally_ordered_with;
237 #else
238  namespace detail
239  {
240  template<typename T, typename U, typename C = typename stdex::common_reference<const T&, const U&>::type, typename = void>
241  struct ComparisonCommonTypeWithImpl : std::false_type {};
242 
243  template<typename T, typename U, typename C>
244  struct ComparisonCommonTypeWithImpl<T, U, C, std::enable_if_t<
245  stdex::same_as<common_reference_t<const T&, const U&>, common_reference_t<const U&, const T&>> and
246  (stdex::convertible_to<const T&, const C&> or stdex::convertible_to<T&, const C&>) and
247  (stdex::convertible_to<const U&, const C&> or stdex::convertible_to<U&, const C&>)
248  >> : std::true_type {};
249 
250 
251  template<typename T, typename U>
252  inline constexpr bool
253  ComparisonCommonTypeWith = ComparisonCommonTypeWithImpl<remove_cvref_t<T>, remove_cvref_t<U>>::value;
254  }
255 
256 
257  template<typename T>
258  inline constexpr bool
259  equality_comparable = OpenKalman::internal::WeaklyEqualityComparableWith<T, T>;
260 
261 
262  template<typename T, typename U>
263  inline constexpr bool
264  equality_comparable_with =
265  equality_comparable<T> and
266  equality_comparable<U> and
267  detail::ComparisonCommonTypeWith<T, U> and
268  equality_comparable<common_reference_t<const std::remove_reference_t<T>&, const std::remove_reference_t<U>&>> and
269  OpenKalman::internal::WeaklyEqualityComparableWith<T, U>;
270 
271 
272  namespace detail
273  {
274 
275 
276  }
277 
278 
279  template<typename T>
280  inline constexpr bool
281  totally_ordered = equality_comparable<T> and OpenKalman::internal::PartiallyOrderedWith<T, T>;
282 
283 
284  namespace detail
285  {
286  template<typename T, typename U, typename = void>
287  struct totally_ordered_with_impl : std::false_type {};
288 
289  template<typename T, typename U>
290  struct totally_ordered_with_impl<T, U, std::enable_if_t<
291  totally_ordered<typename stdex::common_reference<const std::remove_reference_t<T>&, const std::remove_reference_t<U>&>::type>>> : std::true_type {};
292  }
293 
294 
295  template<typename T, typename U>
296  inline constexpr bool
297  totally_ordered_with =
298  totally_ordered<T> and
299  totally_ordered<U> and
300  equality_comparable_with<T, U> and
302  OpenKalman::internal::PartiallyOrderedWith<T, U>;
303 #endif
304 
305 }
306 
307 
308 #endif
Definition: comparison.hpp:104
Definition: comparison.hpp:176
constexpr bool value
T is a fixed or dynamic value that is reducible to a number.
Definition: value.hpp:45
Exposition-only definitions from teh c++ language standard.
constexpr auto compare_three_way(A &&a, B &&b, const Comparison &c={})
Compare two coordinates::pattern objects lexicographically.
Definition: compare_three_way.hpp:142
Definition: basics.hpp:55