1 // Copyright 2018 The Abseil Authors.
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
7 // https://www.apache.org/licenses/LICENSE-2.0
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
15 // -----------------------------------------------------------------------------
17 // -----------------------------------------------------------------------------
19 // This header file defines the `absl::weak_equality`, `absl::strong_equality`,
20 // `absl::partial_ordering`, `absl::weak_ordering`, and `absl::strong_ordering`
21 // types for storing the results of three way comparisons.
24 // absl::weak_ordering compare(const std::string& a, const std::string& b);
26 // These are C++11 compatible versions of the C++20 corresponding types
27 // (`std::weak_equality`, etc.) and are designed to be drop-in replacements
28 // for code compliant with C++20.
30 #ifndef ABSL_TYPES_COMPARE_H_
31 #define ABSL_TYPES_COMPARE_H_
36 #include <type_traits>
38 #include "absl/base/attributes.h"
39 #include "absl/meta/type_traits.h"
42 namespace compare_internal {
44 using value_type = int8_t;
48 static_assert(sizeof(T) < 0, "Only literal `0` is allowed.");
51 // We need the NullPtrT template to avoid triggering the modernize-use-nullptr
52 // ClangTidy warning in user code.
53 template <typename NullPtrT = std::nullptr_t>
54 struct OnlyLiteralZero {
55 constexpr OnlyLiteralZero(NullPtrT) noexcept {} // NOLINT
57 // Fails compilation when `nullptr` or integral type arguments other than
58 // `int` are passed. This constructor doesn't accept `int` because literal `0`
59 // has type `int`. Literal `0` arguments will be implicitly converted to
60 // `std::nullptr_t` and accepted by the above constructor, while other `int`
61 // arguments will fail to be converted and cause compilation failure.
64 typename = typename std::enable_if<
65 std::is_same<T, std::nullptr_t>::value ||
66 (std::is_integral<T>::value && !std::is_same<T, int>::value)>::type,
67 typename = typename Fail<T>::type>
68 OnlyLiteralZero(T); // NOLINT
71 enum class eq : value_type {
75 nonequivalent = nonequal,
78 enum class ord : value_type { less = -1, greater = 1 };
80 enum class ncmp : value_type { unordered = -127 };
82 // These template base classes allow for defining the values of the constants
83 // in the header file (for performance) without using inline variables (which
84 // aren't available in C++11).
86 struct weak_equality_base {
87 ABSL_CONST_INIT static const T equivalent;
88 ABSL_CONST_INIT static const T nonequivalent;
91 const T weak_equality_base<T>::equivalent(eq::equivalent);
93 const T weak_equality_base<T>::nonequivalent(eq::nonequivalent);
96 struct strong_equality_base {
97 ABSL_CONST_INIT static const T equal;
98 ABSL_CONST_INIT static const T nonequal;
99 ABSL_CONST_INIT static const T equivalent;
100 ABSL_CONST_INIT static const T nonequivalent;
102 template <typename T>
103 const T strong_equality_base<T>::equal(eq::equal);
104 template <typename T>
105 const T strong_equality_base<T>::nonequal(eq::nonequal);
106 template <typename T>
107 const T strong_equality_base<T>::equivalent(eq::equivalent);
108 template <typename T>
109 const T strong_equality_base<T>::nonequivalent(eq::nonequivalent);
111 template <typename T>
112 struct partial_ordering_base {
113 ABSL_CONST_INIT static const T less;
114 ABSL_CONST_INIT static const T equivalent;
115 ABSL_CONST_INIT static const T greater;
116 ABSL_CONST_INIT static const T unordered;
118 template <typename T>
119 const T partial_ordering_base<T>::less(ord::less);
120 template <typename T>
121 const T partial_ordering_base<T>::equivalent(eq::equivalent);
122 template <typename T>
123 const T partial_ordering_base<T>::greater(ord::greater);
124 template <typename T>
125 const T partial_ordering_base<T>::unordered(ncmp::unordered);
127 template <typename T>
128 struct weak_ordering_base {
129 ABSL_CONST_INIT static const T less;
130 ABSL_CONST_INIT static const T equivalent;
131 ABSL_CONST_INIT static const T greater;
133 template <typename T>
134 const T weak_ordering_base<T>::less(ord::less);
135 template <typename T>
136 const T weak_ordering_base<T>::equivalent(eq::equivalent);
137 template <typename T>
138 const T weak_ordering_base<T>::greater(ord::greater);
140 template <typename T>
141 struct strong_ordering_base {
142 ABSL_CONST_INIT static const T less;
143 ABSL_CONST_INIT static const T equal;
144 ABSL_CONST_INIT static const T equivalent;
145 ABSL_CONST_INIT static const T greater;
147 template <typename T>
148 const T strong_ordering_base<T>::less(ord::less);
149 template <typename T>
150 const T strong_ordering_base<T>::equal(eq::equal);
151 template <typename T>
152 const T strong_ordering_base<T>::equivalent(eq::equivalent);
153 template <typename T>
154 const T strong_ordering_base<T>::greater(ord::greater);
156 } // namespace compare_internal
159 : public compare_internal::weak_equality_base<weak_equality> {
160 explicit constexpr weak_equality(compare_internal::eq v) noexcept
161 : value_(static_cast<compare_internal::value_type>(v)) {}
162 friend struct compare_internal::weak_equality_base<weak_equality>;
166 friend constexpr bool operator==(
167 weak_equality v, compare_internal::OnlyLiteralZero<>) noexcept {
168 return v.value_ == 0;
170 friend constexpr bool operator!=(
171 weak_equality v, compare_internal::OnlyLiteralZero<>) noexcept {
172 return v.value_ != 0;
174 friend constexpr bool operator==(compare_internal::OnlyLiteralZero<>,
175 weak_equality v) noexcept {
176 return 0 == v.value_;
178 friend constexpr bool operator!=(compare_internal::OnlyLiteralZero<>,
179 weak_equality v) noexcept {
180 return 0 != v.value_;
184 compare_internal::value_type value_;
187 class strong_equality
188 : public compare_internal::strong_equality_base<strong_equality> {
189 explicit constexpr strong_equality(compare_internal::eq v) noexcept
190 : value_(static_cast<compare_internal::value_type>(v)) {}
191 friend struct compare_internal::strong_equality_base<strong_equality>;
195 constexpr operator weak_equality() const noexcept { // NOLINT
196 return value_ == 0 ? weak_equality::equivalent
197 : weak_equality::nonequivalent;
200 friend constexpr bool operator==(
201 strong_equality v, compare_internal::OnlyLiteralZero<>) noexcept {
202 return v.value_ == 0;
204 friend constexpr bool operator!=(
205 strong_equality v, compare_internal::OnlyLiteralZero<>) noexcept {
206 return v.value_ != 0;
208 friend constexpr bool operator==(compare_internal::OnlyLiteralZero<>,
209 strong_equality v) noexcept {
210 return 0 == v.value_;
212 friend constexpr bool operator!=(compare_internal::OnlyLiteralZero<>,
213 strong_equality v) noexcept {
214 return 0 != v.value_;
218 compare_internal::value_type value_;
221 class partial_ordering
222 : public compare_internal::partial_ordering_base<partial_ordering> {
223 explicit constexpr partial_ordering(compare_internal::eq v) noexcept
224 : value_(static_cast<compare_internal::value_type>(v)) {}
225 explicit constexpr partial_ordering(compare_internal::ord v) noexcept
226 : value_(static_cast<compare_internal::value_type>(v)) {}
227 explicit constexpr partial_ordering(compare_internal::ncmp v) noexcept
228 : value_(static_cast<compare_internal::value_type>(v)) {}
229 friend struct compare_internal::partial_ordering_base<partial_ordering>;
231 constexpr bool is_ordered() const noexcept {
233 compare_internal::value_type(compare_internal::ncmp::unordered);
238 constexpr operator weak_equality() const noexcept { // NOLINT
239 return value_ == 0 ? weak_equality::equivalent
240 : weak_equality::nonequivalent;
243 friend constexpr bool operator==(
244 partial_ordering v, compare_internal::OnlyLiteralZero<>) noexcept {
245 return v.is_ordered() && v.value_ == 0;
247 friend constexpr bool operator!=(
248 partial_ordering v, compare_internal::OnlyLiteralZero<>) noexcept {
249 return !v.is_ordered() || v.value_ != 0;
251 friend constexpr bool operator<(
252 partial_ordering v, compare_internal::OnlyLiteralZero<>) noexcept {
253 return v.is_ordered() && v.value_ < 0;
255 friend constexpr bool operator<=(
256 partial_ordering v, compare_internal::OnlyLiteralZero<>) noexcept {
257 return v.is_ordered() && v.value_ <= 0;
259 friend constexpr bool operator>(
260 partial_ordering v, compare_internal::OnlyLiteralZero<>) noexcept {
261 return v.is_ordered() && v.value_ > 0;
263 friend constexpr bool operator>=(
264 partial_ordering v, compare_internal::OnlyLiteralZero<>) noexcept {
265 return v.is_ordered() && v.value_ >= 0;
267 friend constexpr bool operator==(compare_internal::OnlyLiteralZero<>,
268 partial_ordering v) noexcept {
269 return v.is_ordered() && 0 == v.value_;
271 friend constexpr bool operator!=(compare_internal::OnlyLiteralZero<>,
272 partial_ordering v) noexcept {
273 return !v.is_ordered() || 0 != v.value_;
275 friend constexpr bool operator<(compare_internal::OnlyLiteralZero<>,
276 partial_ordering v) noexcept {
277 return v.is_ordered() && 0 < v.value_;
279 friend constexpr bool operator<=(compare_internal::OnlyLiteralZero<>,
280 partial_ordering v) noexcept {
281 return v.is_ordered() && 0 <= v.value_;
283 friend constexpr bool operator>(compare_internal::OnlyLiteralZero<>,
284 partial_ordering v) noexcept {
285 return v.is_ordered() && 0 > v.value_;
287 friend constexpr bool operator>=(compare_internal::OnlyLiteralZero<>,
288 partial_ordering v) noexcept {
289 return v.is_ordered() && 0 >= v.value_;
293 compare_internal::value_type value_;
297 : public compare_internal::weak_ordering_base<weak_ordering> {
298 explicit constexpr weak_ordering(compare_internal::eq v) noexcept
299 : value_(static_cast<compare_internal::value_type>(v)) {}
300 explicit constexpr weak_ordering(compare_internal::ord v) noexcept
301 : value_(static_cast<compare_internal::value_type>(v)) {}
302 friend struct compare_internal::weak_ordering_base<weak_ordering>;
306 constexpr operator weak_equality() const noexcept { // NOLINT
307 return value_ == 0 ? weak_equality::equivalent
308 : weak_equality::nonequivalent;
310 constexpr operator partial_ordering() const noexcept { // NOLINT
311 return value_ == 0 ? partial_ordering::equivalent
312 : (value_ < 0 ? partial_ordering::less
313 : partial_ordering::greater);
316 friend constexpr bool operator==(
317 weak_ordering v, compare_internal::OnlyLiteralZero<>) noexcept {
318 return v.value_ == 0;
320 friend constexpr bool operator!=(
321 weak_ordering v, compare_internal::OnlyLiteralZero<>) noexcept {
322 return v.value_ != 0;
324 friend constexpr bool operator<(
325 weak_ordering v, compare_internal::OnlyLiteralZero<>) noexcept {
328 friend constexpr bool operator<=(
329 weak_ordering v, compare_internal::OnlyLiteralZero<>) noexcept {
330 return v.value_ <= 0;
332 friend constexpr bool operator>(
333 weak_ordering v, compare_internal::OnlyLiteralZero<>) noexcept {
336 friend constexpr bool operator>=(
337 weak_ordering v, compare_internal::OnlyLiteralZero<>) noexcept {
338 return v.value_ >= 0;
340 friend constexpr bool operator==(compare_internal::OnlyLiteralZero<>,
341 weak_ordering v) noexcept {
342 return 0 == v.value_;
344 friend constexpr bool operator!=(compare_internal::OnlyLiteralZero<>,
345 weak_ordering v) noexcept {
346 return 0 != v.value_;
348 friend constexpr bool operator<(compare_internal::OnlyLiteralZero<>,
349 weak_ordering v) noexcept {
352 friend constexpr bool operator<=(compare_internal::OnlyLiteralZero<>,
353 weak_ordering v) noexcept {
354 return 0 <= v.value_;
356 friend constexpr bool operator>(compare_internal::OnlyLiteralZero<>,
357 weak_ordering v) noexcept {
360 friend constexpr bool operator>=(compare_internal::OnlyLiteralZero<>,
361 weak_ordering v) noexcept {
362 return 0 >= v.value_;
366 compare_internal::value_type value_;
369 class strong_ordering
370 : public compare_internal::strong_ordering_base<strong_ordering> {
371 explicit constexpr strong_ordering(compare_internal::eq v) noexcept
372 : value_(static_cast<compare_internal::value_type>(v)) {}
373 explicit constexpr strong_ordering(compare_internal::ord v) noexcept
374 : value_(static_cast<compare_internal::value_type>(v)) {}
375 friend struct compare_internal::strong_ordering_base<strong_ordering>;
379 constexpr operator weak_equality() const noexcept { // NOLINT
380 return value_ == 0 ? weak_equality::equivalent
381 : weak_equality::nonequivalent;
383 constexpr operator strong_equality() const noexcept { // NOLINT
384 return value_ == 0 ? strong_equality::equal : strong_equality::nonequal;
386 constexpr operator partial_ordering() const noexcept { // NOLINT
387 return value_ == 0 ? partial_ordering::equivalent
388 : (value_ < 0 ? partial_ordering::less
389 : partial_ordering::greater);
391 constexpr operator weak_ordering() const noexcept { // NOLINT
393 ? weak_ordering::equivalent
394 : (value_ < 0 ? weak_ordering::less : weak_ordering::greater);
397 friend constexpr bool operator==(
398 strong_ordering v, compare_internal::OnlyLiteralZero<>) noexcept {
399 return v.value_ == 0;
401 friend constexpr bool operator!=(
402 strong_ordering v, compare_internal::OnlyLiteralZero<>) noexcept {
403 return v.value_ != 0;
405 friend constexpr bool operator<(
406 strong_ordering v, compare_internal::OnlyLiteralZero<>) noexcept {
409 friend constexpr bool operator<=(
410 strong_ordering v, compare_internal::OnlyLiteralZero<>) noexcept {
411 return v.value_ <= 0;
413 friend constexpr bool operator>(
414 strong_ordering v, compare_internal::OnlyLiteralZero<>) noexcept {
417 friend constexpr bool operator>=(
418 strong_ordering v, compare_internal::OnlyLiteralZero<>) noexcept {
419 return v.value_ >= 0;
421 friend constexpr bool operator==(compare_internal::OnlyLiteralZero<>,
422 strong_ordering v) noexcept {
423 return 0 == v.value_;
425 friend constexpr bool operator!=(compare_internal::OnlyLiteralZero<>,
426 strong_ordering v) noexcept {
427 return 0 != v.value_;
429 friend constexpr bool operator<(compare_internal::OnlyLiteralZero<>,
430 strong_ordering v) noexcept {
433 friend constexpr bool operator<=(compare_internal::OnlyLiteralZero<>,
434 strong_ordering v) noexcept {
435 return 0 <= v.value_;
437 friend constexpr bool operator>(compare_internal::OnlyLiteralZero<>,
438 strong_ordering v) noexcept {
441 friend constexpr bool operator>=(compare_internal::OnlyLiteralZero<>,
442 strong_ordering v) noexcept {
443 return 0 >= v.value_;
447 compare_internal::value_type value_;
450 namespace compare_internal {
451 // We also provide these comparator adapter functions for internal absl use.
453 // Helper functions to do a boolean comparison of two keys given a boolean
454 // or three-way comparator.
455 // SFINAE prevents implicit conversions to bool (such as from int).
456 template <typename Bool,
457 absl::enable_if_t<std::is_same<bool, Bool>::value, int> = 0>
458 constexpr bool compare_result_as_less_than(const Bool r) { return r; }
459 constexpr bool compare_result_as_less_than(const absl::weak_ordering r) {
463 template <typename Compare, typename K, typename LK>
464 constexpr bool do_less_than_comparison(const Compare &compare, const K &x,
466 return compare_result_as_less_than(compare(x, y));
469 // Helper functions to do a three-way comparison of two keys given a boolean or
470 // three-way comparator.
471 // SFINAE prevents implicit conversions to int (such as from bool).
472 template <typename Int,
473 absl::enable_if_t<std::is_same<int, Int>::value, int> = 0>
474 constexpr absl::weak_ordering compare_result_as_ordering(const Int c) {
475 return c < 0 ? absl::weak_ordering::less
476 : c == 0 ? absl::weak_ordering::equivalent
477 : absl::weak_ordering::greater;
479 constexpr absl::weak_ordering compare_result_as_ordering(
480 const absl::weak_ordering c) {
485 typename Compare, typename K, typename LK,
486 absl::enable_if_t<!std::is_same<bool, absl::result_of_t<Compare(
487 const K &, const LK &)>>::value,
489 constexpr absl::weak_ordering do_three_way_comparison(const Compare &compare,
490 const K &x, const LK &y) {
491 return compare_result_as_ordering(compare(x, y));
494 typename Compare, typename K, typename LK,
495 absl::enable_if_t<std::is_same<bool, absl::result_of_t<Compare(
496 const K &, const LK &)>>::value,
498 constexpr absl::weak_ordering do_three_way_comparison(const Compare &compare,
499 const K &x, const LK &y) {
500 return compare(x, y) ? absl::weak_ordering::less
501 : compare(y, x) ? absl::weak_ordering::greater
502 : absl::weak_ordering::equivalent;
505 } // namespace compare_internal
508 #endif // ABSL_TYPES_COMPARE_H_