OpenKalman
compare.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_COLLECTION_COMPARE_HPP
18 #define OPENKALMAN_COLLECTION_COMPARE_HPP
19 
20 #include <type_traits>
21 #include <tuple>
23 #ifdef __cpp_lib_ranges
24 #include <ranges>
25 #else
27 #endif
31 
33 {
34  namespace detail
35  {
36 #ifdef __cpp_lib_ranges
37  template<typename T>
38  concept comparable = collection_view<T> and (size_of_v<T> != dynamic_size) or std::ranges::input_range<T>;
39 #else
40  template<typename T>
41  inline constexpr bool comparable = collection_view<T> and (size_of_v<T> != dynamic_size) or ranges::input_range<T>;
42 #endif
43 
44 
45  template<std::size_t i = 0, typename T1, typename T2>
46  constexpr auto
47  fixed_compare(const T1& lhs, const T2& rhs)
48  {
49  using namespace std;
50  constexpr auto ix = std::integral_constant<std::size_t, i>{};
51  if constexpr (i == size_of_v<T1> and i == size_of_v<T2>) { return partial_ordering::equivalent; }
52  else if constexpr (i == size_of_v<T1>) { return partial_ordering::less; }
53  else if constexpr (i == size_of_v<T2>) { return partial_ordering::greater; }
54  else if (get(lhs, ix) == get(rhs, ix)) { return fixed_compare<i + 1>(lhs, rhs); }
55  else
56  {
57  auto cmp = compare_three_way{}(get(lhs, ix), get(rhs, ix));
58  if (cmp == 0) return partial_ordering::equivalent;
59  if (cmp < 0) return partial_ordering::less;
60  if (cmp > 0) return partial_ordering::greater;
61  return partial_ordering::unordered;
62  }
63  }
64  }
65 
66 
70 #ifdef __cpp_impl_three_way_comparison
71  template<detail::comparable Lhs, detail::comparable Rhs>
72  constexpr std::partial_ordering
73  compare(const Lhs& lhs, const Rhs& rhs)
74  {
75 #ifdef __cpp_lib_ranges
76  namespace ranges = std::ranges;
77 #endif
78  if constexpr (size_of_v<Lhs> != dynamic_size and size_of_v<Rhs> != dynamic_size) { return detail::fixed_compare(lhs, rhs); }
79  else { return std::lexicographical_compare_three_way(ranges::begin(lhs), ranges::end(lhs), ranges::begin(rhs), ranges::end(rhs)); }
80  }
81 
82 
86  template<detail::comparable Lhs, detail::comparable Rhs>
87  constexpr std::partial_ordering
88  operator<=>(const Lhs& lhs, const Rhs& rhs) noexcept
89  {
90  return compare(lhs, rhs);
91  }
92 
93 
97  template<detail::comparable Lhs, detail::comparable Rhs>
98  constexpr bool
99  operator==(const Lhs& lhs, const Rhs& rhs) noexcept
100  {
101  return std::is_eq(operator<=>(lhs, rhs));
102  }
103 #else
104  template<typename Lhs, typename Rhs, std::enable_if_t<detail::comparable<Lhs> and detail::comparable<Rhs>, int> = 0>
105  constexpr partial_ordering
106  compare(const Lhs& lhs, const Rhs& rhs)
107  {
108  if constexpr (size_of_v<Lhs> != dynamic_size and size_of_v<Rhs> != dynamic_size) return detail::fixed_compare(lhs, rhs);
109  else
110  {
111 #ifdef __cpp_lib_ranges
112  namespace ranges = std::ranges;
113 #endif
114  auto l = ranges::begin(lhs);
115  auto r = ranges::begin(rhs);
116  auto le = ranges::end(lhs);
117  auto re = ranges::end(rhs);
118  for (; l != le and r != re; ++l, ++r)
119  {
120  if (*l == *r) { continue; }
121  if (*l < *r) { return partial_ordering::less; }
122  if (*l > *r) { return partial_ordering::greater; }
123  return partial_ordering::unordered;
124  }
125  if (l == le and r == re) { return partial_ordering::equivalent; }
126  if (l == le) { return partial_ordering::less; }
127  if (r == re) { return partial_ordering::greater; }
128  return partial_ordering::unordered;
129  }
130  }
131 
132 
133  template<typename Lhs, typename Rhs, std::enable_if_t<detail::comparable<Lhs> and detail::comparable<Rhs>, int> = 0>
134  constexpr bool operator==(const Lhs& lhs, const Rhs& rhs) { return compare(lhs, rhs) == 0; }
135 
136  template<typename Lhs, typename Rhs, std::enable_if_t<detail::comparable<Lhs> and detail::comparable<Rhs>, int> = 0>
137  constexpr bool operator!=(const Lhs& lhs, const Rhs& rhs) { return not (compare(lhs, rhs) == 0); }
138 
139  template<typename Lhs, typename Rhs, std::enable_if_t<detail::comparable<Lhs> and detail::comparable<Rhs>, int> = 0>
140  constexpr bool operator<(const Lhs& lhs, const Rhs& rhs) { return compare(lhs, rhs) < 0; }
141 
142  template<typename Lhs, typename Rhs, std::enable_if_t<detail::comparable<Lhs> and detail::comparable<Rhs>, int> = 0>
143  constexpr bool operator>(const Lhs& lhs, const Rhs& rhs) { return compare(lhs, rhs) > 0; }
144 
145  template<typename Lhs, typename Rhs, std::enable_if_t<detail::comparable<Lhs> and detail::comparable<Rhs>, int> = 0>
146  constexpr bool operator<=(const Lhs& lhs, const Rhs& rhs) { return compare(lhs, rhs) <= 0; }
147 
148  template<typename Lhs, typename Rhs, std::enable_if_t<detail::comparable<Lhs> and detail::comparable<Rhs>, int> = 0>
149  constexpr bool operator>=(const Lhs& lhs, const Rhs& rhs) { return compare(lhs, rhs) >= 0; }
150 #endif
151 
152 }
153 
154 #endif //OPENKALMAN_COLLECTION_COMPARE_HPP
Namespace for collections.
Definition: collections.hpp:27
Definition for collections::get.
constexpr partial_ordering compare(const Lhs &lhs, const Rhs &rhs)
Compare two collections.
Definition: compare.hpp:106
Definition: tuple_reverse.hpp:103
Definition for collections::size_of.
Definition for collections::collection_view.
Definitions relating to the availability of c++ language features.
Definitions implementing features of the c++ ranges library for compatibility.
constexpr std::size_t dynamic_size
A constant indicating that a size or index is dynamic.
Definition: global-definitions.hpp:33