Arene Base
Fundamental Utilities For Safety Critical C++
Loading...
Searching...
No Matches
compare_three_way.hpp
Go to the documentation of this file.
1// Copyright 2024, Toyota Motor Corporation
2//
3// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
4
5#ifndef INCLUDE_GUARD_ARENE_BASE_ARENE_BASE_COMPARE_COMPARE_THREE_WAY_HPP_
6#define INCLUDE_GUARD_ARENE_BASE_ARENE_BASE_COMPARE_COMPARE_THREE_WAY_HPP_
7
8// IWYU pragma: private, include "arene/base/compare.hpp"
9// IWYU pragma: friend "(arene/base(?!/tests)|stdlib/include/stdlib_detail)/.*"
10
11// parasoft-begin-suppress AUTOSAR-A16_2_2-a-2 "Arene Base aggregate headers permitted by A16-2-2 Permit #1"
12#include "arene/base/compare/strong_ordering.hpp"
13#include "arene/base/compiler_support/diagnostics.hpp"
14#include "arene/base/constraints/constraints.hpp"
15#include "arene/base/stdlib_choice/declval.hpp"
16#include "arene/base/stdlib_choice/enable_if.hpp"
17#include "arene/base/stdlib_choice/equal_to.hpp"
18#include "arene/base/stdlib_choice/is_integral.hpp"
19#include "arene/base/stdlib_choice/is_pointer.hpp"
20#include "arene/base/stdlib_choice/is_same.hpp"
21#include "arene/base/stdlib_choice/less.hpp"
22#include "arene/base/type_traits/comparison_traits.hpp"
23#include "arene/base/utility/safe_comparisons.hpp"
24// parasoft-end-suppress AUTOSAR-A16_2_2-a-2
25
26// parasoft-begin-suppress AUTOSAR-A15_4_3-a-2 "False positive: This file is the only declaration of these functions"
27
28namespace arene {
29namespace base {
30
31/// @brief Type trait to check if an instance of type @c T can be compared to an instance of type @c U with a static
32/// three-way-compare member function that returns @c strong_ordering.
33/// @tparam T The type of the lhs
34/// @tparam U The type of the rhs. Defaults to @c T
35/// @return true If @c T::three_way_compare(T,U) is defined and returns @c strong_ordering .
36/// @return false Otherwise.
37template <typename T, typename U = T, typename = constraints<>>
38extern constexpr bool is_three_way_comparable_v = false;
39
40/// @brief Specialization for the case that @c T and @c U can be compared.
41template <typename T, typename U>
42extern constexpr bool is_three_way_comparable_v<
43 T,
44 U,
46 decltype(T::three_way_compare(std::declval<T const&>(), std::declval<U const&>())),
47 strong_ordering>::value>>> = true;
48
49namespace three_way_compare_detail {
50
51/// @brief Class for callable objects that performs three-way comparison between two values. It provides a transparent
52/// comparison that depends on the comparisons provided by the underlying types.
53///
54/// Provides @c operator() that takes two values and returns a @c strong_ordering with the result of the comparison.
55///
56/// The order of preference for performing the comparison is as follows:
57/// 1. If the type of @c lhs side provides a @c three_way_compare static member function which is well-formed when
58/// applied to the type of @c rhs, that is used
59/// 1. If both <c>lhs < rhs</c> and <c>lhs == rhs</c> are well-formed, they are used
60/// 1. if only <c> lhs < rhs</c> and <c> rhs < lhs</c> are well-formed, they are used
61/// If none of those overloads are valid, the comparison cannot be made.
62///
63class compare_three_way {
64 public:
65 /// @brief Member that declares this is a transparent comparator.
66 using is_transparent = void;
67
68 /// @brief Compare two pointers using @c std::less
69 /// @tparam T The type of @c lhs
70 /// @tparam U The type of @c rhs
71 /// @param lhs The left hand operand to compare against
72 /// @param rhs The right hand operand to compare against
73 /// @return @c strong_ordering::equal if the values are equal, @c
74 /// strong_ordering::less if the first operand is less than the second
75 /// operand, @c strong_ordering::greater otherwise
76 template <
77 typename T,
78 typename U,
79 constraints<std::enable_if_t<std::is_pointer<T>::value>, std::enable_if_t<std::is_pointer<U>::value>> = nullptr>
80 constexpr auto operator()(T const& lhs, U const& rhs) const noexcept -> strong_ordering {
81 if (std::less<>{}(lhs, rhs)) {
82 return strong_ordering::less;
83 }
84 if (std::less<>{}(rhs, lhs)) {
85 return strong_ordering::greater;
86 }
87 return strong_ordering::equal;
88 }
89
90 /// @brief Compare two integral objects using less-than and equality in a sign-conversion safe way.
91 /// @tparam T The type of @c lhs
92 /// @tparam U The type of @c rhs
93 /// @param lhs The left hand operand to compare against
94 /// @param rhs The right hand operand to compare against
95 /// @return @c strong_ordering::equal if the values are equal
96 /// @return @c strong_ordering::less if the first operand is less than the second operand. Negative signed values
97 /// always compare less than unsigned values.
98 /// @return @c strong_ordering::greater Otherwise.
99 template <
100 typename T,
101 typename U,
102 constraints<std::enable_if_t<std::is_integral<T>::value>, std::enable_if_t<std::is_integral<U>::value>> = nullptr>
103 constexpr auto operator()(T const& lhs, U const& rhs) const noexcept -> strong_ordering {
104 if (::arene::base::cmp_equal(lhs, rhs)) {
105 return strong_ordering::equal;
106 }
107 if (::arene::base::cmp_less(lhs, rhs)) {
108 return strong_ordering::less;
109 }
110 return strong_ordering::greater;
111 }
112
113 ARENE_IGNORE_START();
114 ARENE_IGNORE_ALL("-Wfloat-equal", "Three-way comparison requires equality check");
115
116 /// @brief Compare two objects using less-than and equality.
117 /// @tparam T The type of @c lhs
118 /// @tparam U The type of @c rhs
119 /// @param lhs The left hand operand to compare against
120 /// @param rhs The right hand operand to compare against
121 /// @return @c strong_ordering::equal if the values are equal, @c strong_ordering::less if the first operand is less
122 /// than the second operand, @c strong_ordering::greater otherwise
123 template <
124 typename T,
125 typename U,
126 constraints<
127 std::enable_if_t<!is_three_way_comparable_v<T, U>>,
128 std::enable_if_t<!is_three_way_comparable_v<U, T>>,
129 std::enable_if_t<!std::is_pointer<T>::value || !std::is_pointer<U>::value>,
130 std::enable_if_t<!std::is_integral<T>::value || !std::is_integral<U>::value>,
131 std::enable_if_t<base::is_less_than_comparable_v<T, U>>,
132 std::enable_if_t<base::is_equality_comparable_v<T, U>>> = nullptr>
133 constexpr auto operator()(T const& lhs, U const& rhs) const
134 noexcept(base::is_nothrow_less_than_comparable_v<T, U> && base::is_nothrow_equality_comparable_v<T, U>)
135 -> strong_ordering {
136 if (std::equal_to<>{}(lhs, rhs)) {
137 return strong_ordering::equal;
138 }
139 if (std::less<>{}(lhs, rhs)) {
140 return strong_ordering::less;
141 }
142 return strong_ordering::greater;
143 }
144
145 ARENE_IGNORE_END();
146
147 /// @brief Compare two objects using less-than
148 /// @tparam T The type of @c lhs
149 /// @tparam U The type of @c rhs
150 /// @param lhs The left hand operand to compare against
151 /// @param rhs The right hand operand to compare against
152 /// @return @c strong_ordering::less if the first operand is less than the second operand, @c
153 /// strong_ordering::greater if the second is less than the first, @c strong_ordering::equal otherwise.
154 template <
155 typename T,
156 typename U,
157 constraints<
158 std::enable_if_t<!is_three_way_comparable_v<T, U>>,
159 std::enable_if_t<!is_three_way_comparable_v<U, T>>,
160 std::enable_if_t<!std::is_pointer<T>::value || !std::is_pointer<U>::value>,
161 std::enable_if_t<base::is_less_than_comparable_v<T, U>>,
162 std::enable_if_t<!base::is_equality_comparable_v<T, U>>,
163 std::enable_if_t<base::is_less_than_comparable_v<U, T>>> = nullptr>
164 constexpr auto operator()(T const& lhs, U const& rhs) const
165 noexcept(base::is_nothrow_less_than_comparable_v<T, U> && base::is_nothrow_less_than_comparable_v<U, T>)
166 -> strong_ordering {
167 if (std::less<>{}(lhs, rhs)) {
168 return strong_ordering::less;
169 }
170 if (std::less<>{}(rhs, lhs)) {
171 return strong_ordering::greater;
172 }
173 return strong_ordering::equal;
174 }
175
176 /// @brief Compare two objects using a @c three_way_compare static member function.
177 /// @tparam T The type of @c lhs
178 /// @tparam U The type of @c rhs
179 /// @param lhs The left hand operand to compare against
180 /// @param rhs The right hand operand to compare against
181 /// @return The result of @c T::three_way_compare(t,u)
182 template <typename T, typename U, constraints<std::enable_if_t<is_three_way_comparable_v<T, U>>> = nullptr>
183 constexpr auto operator()(T const& lhs, U const& rhs) const
184 noexcept(noexcept(T::three_way_compare(std::declval<T const&>(), std::declval<U const&>()))) -> strong_ordering {
185 return T::three_way_compare(lhs, rhs);
186 }
187
188 /// @brief Compare two objects using a @c three_way_compare static member function.
189 /// @tparam T The type of @c lhs
190 /// @tparam U The type of @c rhs
191 /// @param lhs The left hand operand to compare against
192 /// @param rhs The right hand operand to compare against
193 /// @return strong_ordering The opposite result of @c U::three_way_compare(u,t)
194 template <
195 typename T,
196 typename U,
197 constraints<
198 std::enable_if_t<!is_three_way_comparable_v<T, U>>,
199 std::enable_if_t<is_three_way_comparable_v<U, T>>> = nullptr>
200 constexpr auto operator()(T const& lhs, U const& rhs) const
201 noexcept(noexcept(U::three_way_compare(std::declval<U const&>(), std::declval<T const&>()))) -> strong_ordering {
202 return opposite_ordering(U::three_way_compare(rhs, lhs));
203 }
204};
205
206} // namespace three_way_compare_detail
207
208// parasoft-begin-suppress AUTOSAR-A2_7_3-a-2 "False positive: @brief tag is present"
209/// @brief Function object that does a three-way comparison between operands, equivalent to @c std::compare_three_way .
210using compare_three_way = three_way_compare_detail::compare_three_way;
211// parasoft-end-suppress AUTOSAR-A2_7_3-a-2
212
213/// @brief Boolean constant indicating if instances of @c Lhs and @c Rhs can be compared using @c compare_three_way
214/// @tparam Lhs The type of the left-hand operand
215/// @tparam Rhs The type of the right-hand operand
216/// @{
217template <typename Lhs, typename Rhs = Lhs, typename = constraints<>>
218extern constexpr bool compare_three_way_supported_v = false;
219
220template <typename Lhs, typename Rhs>
221extern constexpr bool compare_three_way_supported_v<
222 Lhs,
223 Rhs,
224 constraints<decltype(compare_three_way{}(std::declval<Lhs>(), std::declval<Rhs>()))>> = true;
225/// @}
226
227} // namespace base
228} // namespace arene
229
230#endif // INCLUDE_GUARD_ARENE_BASE_ARENE_BASE_COMPARE_COMPARE_THREE_WAY_HPP_
Definition array_exceptions_disabled.cpp:11
Copyright 2026, Toyota Motor Corporation.
Definition array_exceptions_disabled.cpp:10