• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2018 The Abseil Authors.
2 //
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
6 //
7 //      https://www.apache.org/licenses/LICENSE-2.0
8 //
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.
14 //
15 // -----------------------------------------------------------------------------
16 // compare.h
17 // -----------------------------------------------------------------------------
18 //
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.
22 //
23 // Example:
24 //   absl::weak_ordering compare(const std::string& a, const std::string& b);
25 //
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.
29 
30 #ifndef ABSL_TYPES_COMPARE_H_
31 #define ABSL_TYPES_COMPARE_H_
32 
33 #include <cstddef>
34 #include <cstdint>
35 #include <cstdlib>
36 #include <type_traits>
37 
38 #include "absl/base/attributes.h"
39 #include "absl/meta/type_traits.h"
40 
41 namespace absl {
42 ABSL_NAMESPACE_BEGIN
43 namespace compare_internal {
44 
45 using value_type = int8_t;
46 
47 template <typename T>
48 struct Fail {
49   static_assert(sizeof(T) < 0, "Only literal `0` is allowed.");
50 };
51 
52 // We need the NullPtrT template to avoid triggering the modernize-use-nullptr
53 // ClangTidy warning in user code.
54 template <typename NullPtrT = std::nullptr_t>
55 struct OnlyLiteralZero {
OnlyLiteralZeroOnlyLiteralZero56   constexpr OnlyLiteralZero(NullPtrT) noexcept {}  // NOLINT
57 
58   // Fails compilation when `nullptr` or integral type arguments other than
59   // `int` are passed. This constructor doesn't accept `int` because literal `0`
60   // has type `int`. Literal `0` arguments will be implicitly converted to
61   // `std::nullptr_t` and accepted by the above constructor, while other `int`
62   // arguments will fail to be converted and cause compilation failure.
63   template <
64       typename T,
65       typename = typename std::enable_if<
66           std::is_same<T, std::nullptr_t>::value ||
67           (std::is_integral<T>::value && !std::is_same<T, int>::value)>::type,
68       typename = typename Fail<T>::type>
69   OnlyLiteralZero(T);  // NOLINT
70 };
71 
72 enum class eq : value_type {
73   equal = 0,
74   equivalent = equal,
75   nonequal = 1,
76   nonequivalent = nonequal,
77 };
78 
79 enum class ord : value_type { less = -1, greater = 1 };
80 
81 enum class ncmp : value_type { unordered = -127 };
82 
83 // Define macros to allow for creation or emulation of C++17 inline variables
84 // based on whether the feature is supported. Note: we can't use
85 // ABSL_INTERNAL_INLINE_CONSTEXPR here because the variables here are of
86 // incomplete types so they need to be defined after the types are complete.
87 #ifdef __cpp_inline_variables
88 
89 #define ABSL_COMPARE_INLINE_BASECLASS_DECL(name)
90 
91 #define ABSL_COMPARE_INLINE_SUBCLASS_DECL(type, name) \
92   static const type name
93 
94 #define ABSL_COMPARE_INLINE_INIT(type, name, init) \
95   inline constexpr type type::name(init)
96 
97 #else  // __cpp_inline_variables
98 
99 #define ABSL_COMPARE_INLINE_BASECLASS_DECL(name) \
100   ABSL_CONST_INIT static const T name
101 
102 #define ABSL_COMPARE_INLINE_SUBCLASS_DECL(type, name)
103 
104 #define ABSL_COMPARE_INLINE_INIT(type, name, init) \
105   template <typename T>                            \
106   const T compare_internal::type##_base<T>::name(init)
107 
108 #endif  // __cpp_inline_variables
109 
110 // These template base classes allow for defining the values of the constants
111 // in the header file (for performance) without using inline variables (which
112 // aren't available in C++11).
113 template <typename T>
114 struct weak_equality_base {
115   ABSL_COMPARE_INLINE_BASECLASS_DECL(equivalent);
116   ABSL_COMPARE_INLINE_BASECLASS_DECL(nonequivalent);
117 };
118 
119 template <typename T>
120 struct strong_equality_base {
121   ABSL_COMPARE_INLINE_BASECLASS_DECL(equal);
122   ABSL_COMPARE_INLINE_BASECLASS_DECL(nonequal);
123   ABSL_COMPARE_INLINE_BASECLASS_DECL(equivalent);
124   ABSL_COMPARE_INLINE_BASECLASS_DECL(nonequivalent);
125 };
126 
127 template <typename T>
128 struct partial_ordering_base {
129   ABSL_COMPARE_INLINE_BASECLASS_DECL(less);
130   ABSL_COMPARE_INLINE_BASECLASS_DECL(equivalent);
131   ABSL_COMPARE_INLINE_BASECLASS_DECL(greater);
132   ABSL_COMPARE_INLINE_BASECLASS_DECL(unordered);
133 };
134 
135 template <typename T>
136 struct weak_ordering_base {
137   ABSL_COMPARE_INLINE_BASECLASS_DECL(less);
138   ABSL_COMPARE_INLINE_BASECLASS_DECL(equivalent);
139   ABSL_COMPARE_INLINE_BASECLASS_DECL(greater);
140 };
141 
142 template <typename T>
143 struct strong_ordering_base {
144   ABSL_COMPARE_INLINE_BASECLASS_DECL(less);
145   ABSL_COMPARE_INLINE_BASECLASS_DECL(equal);
146   ABSL_COMPARE_INLINE_BASECLASS_DECL(equivalent);
147   ABSL_COMPARE_INLINE_BASECLASS_DECL(greater);
148 };
149 
150 }  // namespace compare_internal
151 
152 class weak_equality
153     : public compare_internal::weak_equality_base<weak_equality> {
weak_equality(compare_internal::eq v)154   explicit constexpr weak_equality(compare_internal::eq v) noexcept
155       : value_(static_cast<compare_internal::value_type>(v)) {}
156   friend struct compare_internal::weak_equality_base<weak_equality>;
157 
158  public:
159   ABSL_COMPARE_INLINE_SUBCLASS_DECL(weak_equality, equivalent);
160   ABSL_COMPARE_INLINE_SUBCLASS_DECL(weak_equality, nonequivalent);
161 
162   // Comparisons
163   friend constexpr bool operator==(
164       weak_equality v, compare_internal::OnlyLiteralZero<>) noexcept {
165     return v.value_ == 0;
166   }
167   friend constexpr bool operator!=(
168       weak_equality v, compare_internal::OnlyLiteralZero<>) noexcept {
169     return v.value_ != 0;
170   }
171   friend constexpr bool operator==(compare_internal::OnlyLiteralZero<>,
172                                    weak_equality v) noexcept {
173     return 0 == v.value_;
174   }
175   friend constexpr bool operator!=(compare_internal::OnlyLiteralZero<>,
176                                    weak_equality v) noexcept {
177     return 0 != v.value_;
178   }
179   friend constexpr bool operator==(weak_equality v1,
180                                    weak_equality v2) noexcept {
181     return v1.value_ == v2.value_;
182   }
183   friend constexpr bool operator!=(weak_equality v1,
184                                    weak_equality v2) noexcept {
185     return v1.value_ != v2.value_;
186   }
187 
188  private:
189   compare_internal::value_type value_;
190 };
191 ABSL_COMPARE_INLINE_INIT(weak_equality, equivalent,
192                          compare_internal::eq::equivalent);
193 ABSL_COMPARE_INLINE_INIT(weak_equality, nonequivalent,
194                          compare_internal::eq::nonequivalent);
195 
196 class strong_equality
197     : public compare_internal::strong_equality_base<strong_equality> {
198   explicit constexpr strong_equality(compare_internal::eq v) noexcept
199       : value_(static_cast<compare_internal::value_type>(v)) {}
200   friend struct compare_internal::strong_equality_base<strong_equality>;
201 
202  public:
203   ABSL_COMPARE_INLINE_SUBCLASS_DECL(strong_equality, equal);
204   ABSL_COMPARE_INLINE_SUBCLASS_DECL(strong_equality, nonequal);
205   ABSL_COMPARE_INLINE_SUBCLASS_DECL(strong_equality, equivalent);
206   ABSL_COMPARE_INLINE_SUBCLASS_DECL(strong_equality, nonequivalent);
207 
208   // Conversion
209   constexpr operator weak_equality() const noexcept {  // NOLINT
210     return value_ == 0 ? weak_equality::equivalent
211                        : weak_equality::nonequivalent;
212   }
213   // Comparisons
214   friend constexpr bool operator==(
215       strong_equality v, compare_internal::OnlyLiteralZero<>) noexcept {
216     return v.value_ == 0;
217   }
218   friend constexpr bool operator!=(
219       strong_equality v, compare_internal::OnlyLiteralZero<>) noexcept {
220     return v.value_ != 0;
221   }
222   friend constexpr bool operator==(compare_internal::OnlyLiteralZero<>,
223                                    strong_equality v) noexcept {
224     return 0 == v.value_;
225   }
226   friend constexpr bool operator!=(compare_internal::OnlyLiteralZero<>,
227                                    strong_equality v) noexcept {
228     return 0 != v.value_;
229   }
230   friend constexpr bool operator==(strong_equality v1,
231                                    strong_equality v2) noexcept {
232     return v1.value_ == v2.value_;
233   }
234   friend constexpr bool operator!=(strong_equality v1,
235                                    strong_equality v2) noexcept {
236     return v1.value_ != v2.value_;
237   }
238 
239  private:
240   compare_internal::value_type value_;
241 };
242 ABSL_COMPARE_INLINE_INIT(strong_equality, equal, compare_internal::eq::equal);
243 ABSL_COMPARE_INLINE_INIT(strong_equality, nonequal,
244                          compare_internal::eq::nonequal);
245 ABSL_COMPARE_INLINE_INIT(strong_equality, equivalent,
246                          compare_internal::eq::equivalent);
247 ABSL_COMPARE_INLINE_INIT(strong_equality, nonequivalent,
248                          compare_internal::eq::nonequivalent);
249 
250 class partial_ordering
251     : public compare_internal::partial_ordering_base<partial_ordering> {
252   explicit constexpr partial_ordering(compare_internal::eq v) noexcept
253       : value_(static_cast<compare_internal::value_type>(v)) {}
254   explicit constexpr partial_ordering(compare_internal::ord v) noexcept
255       : value_(static_cast<compare_internal::value_type>(v)) {}
256   explicit constexpr partial_ordering(compare_internal::ncmp v) noexcept
257       : value_(static_cast<compare_internal::value_type>(v)) {}
258   friend struct compare_internal::partial_ordering_base<partial_ordering>;
259 
260   constexpr bool is_ordered() const noexcept {
261     return value_ !=
262            compare_internal::value_type(compare_internal::ncmp::unordered);
263   }
264 
265  public:
266   ABSL_COMPARE_INLINE_SUBCLASS_DECL(partial_ordering, less);
267   ABSL_COMPARE_INLINE_SUBCLASS_DECL(partial_ordering, equivalent);
268   ABSL_COMPARE_INLINE_SUBCLASS_DECL(partial_ordering, greater);
269   ABSL_COMPARE_INLINE_SUBCLASS_DECL(partial_ordering, unordered);
270 
271   // Conversion
272   constexpr operator weak_equality() const noexcept {  // NOLINT
273     return value_ == 0 ? weak_equality::equivalent
274                        : weak_equality::nonequivalent;
275   }
276   // Comparisons
277   friend constexpr bool operator==(
278       partial_ordering v, compare_internal::OnlyLiteralZero<>) noexcept {
279     return v.is_ordered() && v.value_ == 0;
280   }
281   friend constexpr bool operator!=(
282       partial_ordering v, compare_internal::OnlyLiteralZero<>) noexcept {
283     return !v.is_ordered() || v.value_ != 0;
284   }
285   friend constexpr bool operator<(
286       partial_ordering v, compare_internal::OnlyLiteralZero<>) noexcept {
287     return v.is_ordered() && v.value_ < 0;
288   }
289   friend constexpr bool operator<=(
290       partial_ordering v, compare_internal::OnlyLiteralZero<>) noexcept {
291     return v.is_ordered() && v.value_ <= 0;
292   }
293   friend constexpr bool operator>(
294       partial_ordering v, compare_internal::OnlyLiteralZero<>) noexcept {
295     return v.is_ordered() && v.value_ > 0;
296   }
297   friend constexpr bool operator>=(
298       partial_ordering v, compare_internal::OnlyLiteralZero<>) noexcept {
299     return v.is_ordered() && v.value_ >= 0;
300   }
301   friend constexpr bool operator==(compare_internal::OnlyLiteralZero<>,
302                                    partial_ordering v) noexcept {
303     return v.is_ordered() && 0 == v.value_;
304   }
305   friend constexpr bool operator!=(compare_internal::OnlyLiteralZero<>,
306                                    partial_ordering v) noexcept {
307     return !v.is_ordered() || 0 != v.value_;
308   }
309   friend constexpr bool operator<(compare_internal::OnlyLiteralZero<>,
310                                   partial_ordering v) noexcept {
311     return v.is_ordered() && 0 < v.value_;
312   }
313   friend constexpr bool operator<=(compare_internal::OnlyLiteralZero<>,
314                                    partial_ordering v) noexcept {
315     return v.is_ordered() && 0 <= v.value_;
316   }
317   friend constexpr bool operator>(compare_internal::OnlyLiteralZero<>,
318                                   partial_ordering v) noexcept {
319     return v.is_ordered() && 0 > v.value_;
320   }
321   friend constexpr bool operator>=(compare_internal::OnlyLiteralZero<>,
322                                    partial_ordering v) noexcept {
323     return v.is_ordered() && 0 >= v.value_;
324   }
325   friend constexpr bool operator==(partial_ordering v1,
326                                    partial_ordering v2) noexcept {
327     return v1.value_ == v2.value_;
328   }
329   friend constexpr bool operator!=(partial_ordering v1,
330                                    partial_ordering v2) noexcept {
331     return v1.value_ != v2.value_;
332   }
333 
334  private:
335   compare_internal::value_type value_;
336 };
337 ABSL_COMPARE_INLINE_INIT(partial_ordering, less, compare_internal::ord::less);
338 ABSL_COMPARE_INLINE_INIT(partial_ordering, equivalent,
339                          compare_internal::eq::equivalent);
340 ABSL_COMPARE_INLINE_INIT(partial_ordering, greater,
341                          compare_internal::ord::greater);
342 ABSL_COMPARE_INLINE_INIT(partial_ordering, unordered,
343                          compare_internal::ncmp::unordered);
344 
345 class weak_ordering
346     : public compare_internal::weak_ordering_base<weak_ordering> {
347   explicit constexpr weak_ordering(compare_internal::eq v) noexcept
348       : value_(static_cast<compare_internal::value_type>(v)) {}
349   explicit constexpr weak_ordering(compare_internal::ord v) noexcept
350       : value_(static_cast<compare_internal::value_type>(v)) {}
351   friend struct compare_internal::weak_ordering_base<weak_ordering>;
352 
353  public:
354   ABSL_COMPARE_INLINE_SUBCLASS_DECL(weak_ordering, less);
355   ABSL_COMPARE_INLINE_SUBCLASS_DECL(weak_ordering, equivalent);
356   ABSL_COMPARE_INLINE_SUBCLASS_DECL(weak_ordering, greater);
357 
358   // Conversions
359   constexpr operator weak_equality() const noexcept {  // NOLINT
360     return value_ == 0 ? weak_equality::equivalent
361                        : weak_equality::nonequivalent;
362   }
363   constexpr operator partial_ordering() const noexcept {  // NOLINT
364     return value_ == 0 ? partial_ordering::equivalent
365                        : (value_ < 0 ? partial_ordering::less
366                                      : partial_ordering::greater);
367   }
368   // Comparisons
369   friend constexpr bool operator==(
370       weak_ordering v, compare_internal::OnlyLiteralZero<>) noexcept {
371     return v.value_ == 0;
372   }
373   friend constexpr bool operator!=(
374       weak_ordering v, compare_internal::OnlyLiteralZero<>) noexcept {
375     return v.value_ != 0;
376   }
377   friend constexpr bool operator<(
378       weak_ordering v, compare_internal::OnlyLiteralZero<>) noexcept {
379     return v.value_ < 0;
380   }
381   friend constexpr bool operator<=(
382       weak_ordering v, compare_internal::OnlyLiteralZero<>) noexcept {
383     return v.value_ <= 0;
384   }
385   friend constexpr bool operator>(
386       weak_ordering v, compare_internal::OnlyLiteralZero<>) noexcept {
387     return v.value_ > 0;
388   }
389   friend constexpr bool operator>=(
390       weak_ordering v, compare_internal::OnlyLiteralZero<>) noexcept {
391     return v.value_ >= 0;
392   }
393   friend constexpr bool operator==(compare_internal::OnlyLiteralZero<>,
394                                    weak_ordering v) noexcept {
395     return 0 == v.value_;
396   }
397   friend constexpr bool operator!=(compare_internal::OnlyLiteralZero<>,
398                                    weak_ordering v) noexcept {
399     return 0 != v.value_;
400   }
401   friend constexpr bool operator<(compare_internal::OnlyLiteralZero<>,
402                                   weak_ordering v) noexcept {
403     return 0 < v.value_;
404   }
405   friend constexpr bool operator<=(compare_internal::OnlyLiteralZero<>,
406                                    weak_ordering v) noexcept {
407     return 0 <= v.value_;
408   }
409   friend constexpr bool operator>(compare_internal::OnlyLiteralZero<>,
410                                   weak_ordering v) noexcept {
411     return 0 > v.value_;
412   }
413   friend constexpr bool operator>=(compare_internal::OnlyLiteralZero<>,
414                                    weak_ordering v) noexcept {
415     return 0 >= v.value_;
416   }
417   friend constexpr bool operator==(weak_ordering v1,
418                                    weak_ordering v2) noexcept {
419     return v1.value_ == v2.value_;
420   }
421   friend constexpr bool operator!=(weak_ordering v1,
422                                    weak_ordering v2) noexcept {
423     return v1.value_ != v2.value_;
424   }
425 
426  private:
427   compare_internal::value_type value_;
428 };
429 ABSL_COMPARE_INLINE_INIT(weak_ordering, less, compare_internal::ord::less);
430 ABSL_COMPARE_INLINE_INIT(weak_ordering, equivalent,
431                          compare_internal::eq::equivalent);
432 ABSL_COMPARE_INLINE_INIT(weak_ordering, greater,
433                          compare_internal::ord::greater);
434 
435 class strong_ordering
436     : public compare_internal::strong_ordering_base<strong_ordering> {
437   explicit constexpr strong_ordering(compare_internal::eq v) noexcept
438       : value_(static_cast<compare_internal::value_type>(v)) {}
439   explicit constexpr strong_ordering(compare_internal::ord v) noexcept
440       : value_(static_cast<compare_internal::value_type>(v)) {}
441   friend struct compare_internal::strong_ordering_base<strong_ordering>;
442 
443  public:
444   ABSL_COMPARE_INLINE_SUBCLASS_DECL(strong_ordering, less);
445   ABSL_COMPARE_INLINE_SUBCLASS_DECL(strong_ordering, equal);
446   ABSL_COMPARE_INLINE_SUBCLASS_DECL(strong_ordering, equivalent);
447   ABSL_COMPARE_INLINE_SUBCLASS_DECL(strong_ordering, greater);
448 
449   // Conversions
450   constexpr operator weak_equality() const noexcept {  // NOLINT
451     return value_ == 0 ? weak_equality::equivalent
452                        : weak_equality::nonequivalent;
453   }
454   constexpr operator strong_equality() const noexcept {  // NOLINT
455     return value_ == 0 ? strong_equality::equal : strong_equality::nonequal;
456   }
457   constexpr operator partial_ordering() const noexcept {  // NOLINT
458     return value_ == 0 ? partial_ordering::equivalent
459                        : (value_ < 0 ? partial_ordering::less
460                                      : partial_ordering::greater);
461   }
462   constexpr operator weak_ordering() const noexcept {  // NOLINT
463     return value_ == 0
464                ? weak_ordering::equivalent
465                : (value_ < 0 ? weak_ordering::less : weak_ordering::greater);
466   }
467   // Comparisons
468   friend constexpr bool operator==(
469       strong_ordering v, compare_internal::OnlyLiteralZero<>) noexcept {
470     return v.value_ == 0;
471   }
472   friend constexpr bool operator!=(
473       strong_ordering v, compare_internal::OnlyLiteralZero<>) noexcept {
474     return v.value_ != 0;
475   }
476   friend constexpr bool operator<(
477       strong_ordering v, compare_internal::OnlyLiteralZero<>) noexcept {
478     return v.value_ < 0;
479   }
480   friend constexpr bool operator<=(
481       strong_ordering v, compare_internal::OnlyLiteralZero<>) noexcept {
482     return v.value_ <= 0;
483   }
484   friend constexpr bool operator>(
485       strong_ordering v, compare_internal::OnlyLiteralZero<>) noexcept {
486     return v.value_ > 0;
487   }
488   friend constexpr bool operator>=(
489       strong_ordering v, compare_internal::OnlyLiteralZero<>) noexcept {
490     return v.value_ >= 0;
491   }
492   friend constexpr bool operator==(compare_internal::OnlyLiteralZero<>,
493                                    strong_ordering v) noexcept {
494     return 0 == v.value_;
495   }
496   friend constexpr bool operator!=(compare_internal::OnlyLiteralZero<>,
497                                    strong_ordering v) noexcept {
498     return 0 != v.value_;
499   }
500   friend constexpr bool operator<(compare_internal::OnlyLiteralZero<>,
501                                   strong_ordering v) noexcept {
502     return 0 < v.value_;
503   }
504   friend constexpr bool operator<=(compare_internal::OnlyLiteralZero<>,
505                                    strong_ordering v) noexcept {
506     return 0 <= v.value_;
507   }
508   friend constexpr bool operator>(compare_internal::OnlyLiteralZero<>,
509                                   strong_ordering v) noexcept {
510     return 0 > v.value_;
511   }
512   friend constexpr bool operator>=(compare_internal::OnlyLiteralZero<>,
513                                    strong_ordering v) noexcept {
514     return 0 >= v.value_;
515   }
516   friend constexpr bool operator==(strong_ordering v1,
517                                    strong_ordering v2) noexcept {
518     return v1.value_ == v2.value_;
519   }
520   friend constexpr bool operator!=(strong_ordering v1,
521                                    strong_ordering v2) noexcept {
522     return v1.value_ != v2.value_;
523   }
524 
525  private:
526   compare_internal::value_type value_;
527 };
528 ABSL_COMPARE_INLINE_INIT(strong_ordering, less, compare_internal::ord::less);
529 ABSL_COMPARE_INLINE_INIT(strong_ordering, equal, compare_internal::eq::equal);
530 ABSL_COMPARE_INLINE_INIT(strong_ordering, equivalent,
531                          compare_internal::eq::equivalent);
532 ABSL_COMPARE_INLINE_INIT(strong_ordering, greater,
533                          compare_internal::ord::greater);
534 
535 #undef ABSL_COMPARE_INLINE_BASECLASS_DECL
536 #undef ABSL_COMPARE_INLINE_SUBCLASS_DECL
537 #undef ABSL_COMPARE_INLINE_INIT
538 
539 namespace compare_internal {
540 // We also provide these comparator adapter functions for internal absl use.
541 
542 // Helper functions to do a boolean comparison of two keys given a boolean
543 // or three-way comparator.
544 // SFINAE prevents implicit conversions to bool (such as from int).
545 template <typename Bool,
546           absl::enable_if_t<std::is_same<bool, Bool>::value, int> = 0>
547 constexpr bool compare_result_as_less_than(const Bool r) { return r; }
548 constexpr bool compare_result_as_less_than(const absl::weak_ordering r) {
549   return r < 0;
550 }
551 
552 template <typename Compare, typename K, typename LK>
553 constexpr bool do_less_than_comparison(const Compare &compare, const K &x,
554                                        const LK &y) {
555   return compare_result_as_less_than(compare(x, y));
556 }
557 
558 // Helper functions to do a three-way comparison of two keys given a boolean or
559 // three-way comparator.
560 // SFINAE prevents implicit conversions to int (such as from bool).
561 template <typename Int,
562           absl::enable_if_t<std::is_same<int, Int>::value, int> = 0>
563 constexpr absl::weak_ordering compare_result_as_ordering(const Int c) {
564   return c < 0 ? absl::weak_ordering::less
565                : c == 0 ? absl::weak_ordering::equivalent
566                         : absl::weak_ordering::greater;
567 }
568 constexpr absl::weak_ordering compare_result_as_ordering(
569     const absl::weak_ordering c) {
570   return c;
571 }
572 
573 template <
574     typename Compare, typename K, typename LK,
575     absl::enable_if_t<!std::is_same<bool, absl::result_of_t<Compare(
576                                               const K &, const LK &)>>::value,
577                       int> = 0>
578 constexpr absl::weak_ordering do_three_way_comparison(const Compare &compare,
579                                                       const K &x, const LK &y) {
580   return compare_result_as_ordering(compare(x, y));
581 }
582 template <
583     typename Compare, typename K, typename LK,
584     absl::enable_if_t<std::is_same<bool, absl::result_of_t<Compare(
585                                              const K &, const LK &)>>::value,
586                       int> = 0>
587 constexpr absl::weak_ordering do_three_way_comparison(const Compare &compare,
588                                                       const K &x, const LK &y) {
589   return compare(x, y) ? absl::weak_ordering::less
590                        : compare(y, x) ? absl::weak_ordering::greater
591                                        : absl::weak_ordering::equivalent;
592 }
593 
594 }  // namespace compare_internal
595 ABSL_NAMESPACE_END
596 }  // namespace absl
597 
598 #endif  // ABSL_TYPES_COMPARE_H_
599