• 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 // A no-op expansion that can be followed by a semicolon at class level.
90 #define ABSL_COMPARE_INLINE_BASECLASS_DECL(name) static_assert(true, "")
91 
92 #define ABSL_COMPARE_INLINE_SUBCLASS_DECL(type, name) \
93   static const type name
94 
95 #define ABSL_COMPARE_INLINE_INIT(type, name, init) \
96   inline constexpr type type::name(init)
97 
98 #else  // __cpp_inline_variables
99 
100 #define ABSL_COMPARE_INLINE_BASECLASS_DECL(name) \
101   ABSL_CONST_INIT static const T name
102 
103 // A no-op expansion that can be followed by a semicolon at class level.
104 #define ABSL_COMPARE_INLINE_SUBCLASS_DECL(type, name) static_assert(true, "")
105 
106 #define ABSL_COMPARE_INLINE_INIT(type, name, init) \
107   template <typename T>                            \
108   const T compare_internal::type##_base<T>::name(init)
109 
110 #endif  // __cpp_inline_variables
111 
112 // These template base classes allow for defining the values of the constants
113 // in the header file (for performance) without using inline variables (which
114 // aren't available in C++11).
115 template <typename T>
116 struct weak_equality_base {
117   ABSL_COMPARE_INLINE_BASECLASS_DECL(equivalent);
118   ABSL_COMPARE_INLINE_BASECLASS_DECL(nonequivalent);
119 };
120 
121 template <typename T>
122 struct strong_equality_base {
123   ABSL_COMPARE_INLINE_BASECLASS_DECL(equal);
124   ABSL_COMPARE_INLINE_BASECLASS_DECL(nonequal);
125   ABSL_COMPARE_INLINE_BASECLASS_DECL(equivalent);
126   ABSL_COMPARE_INLINE_BASECLASS_DECL(nonequivalent);
127 };
128 
129 template <typename T>
130 struct partial_ordering_base {
131   ABSL_COMPARE_INLINE_BASECLASS_DECL(less);
132   ABSL_COMPARE_INLINE_BASECLASS_DECL(equivalent);
133   ABSL_COMPARE_INLINE_BASECLASS_DECL(greater);
134   ABSL_COMPARE_INLINE_BASECLASS_DECL(unordered);
135 };
136 
137 template <typename T>
138 struct weak_ordering_base {
139   ABSL_COMPARE_INLINE_BASECLASS_DECL(less);
140   ABSL_COMPARE_INLINE_BASECLASS_DECL(equivalent);
141   ABSL_COMPARE_INLINE_BASECLASS_DECL(greater);
142 };
143 
144 template <typename T>
145 struct strong_ordering_base {
146   ABSL_COMPARE_INLINE_BASECLASS_DECL(less);
147   ABSL_COMPARE_INLINE_BASECLASS_DECL(equal);
148   ABSL_COMPARE_INLINE_BASECLASS_DECL(equivalent);
149   ABSL_COMPARE_INLINE_BASECLASS_DECL(greater);
150 };
151 
152 }  // namespace compare_internal
153 
154 class weak_equality
155     : public compare_internal::weak_equality_base<weak_equality> {
weak_equality(compare_internal::eq v)156   explicit constexpr weak_equality(compare_internal::eq v) noexcept
157       : value_(static_cast<compare_internal::value_type>(v)) {}
158   friend struct compare_internal::weak_equality_base<weak_equality>;
159 
160  public:
161   ABSL_COMPARE_INLINE_SUBCLASS_DECL(weak_equality, equivalent);
162   ABSL_COMPARE_INLINE_SUBCLASS_DECL(weak_equality, nonequivalent);
163 
164   // Comparisons
165   friend constexpr bool operator==(
166       weak_equality v, compare_internal::OnlyLiteralZero<>) noexcept {
167     return v.value_ == 0;
168   }
169   friend constexpr bool operator!=(
170       weak_equality v, compare_internal::OnlyLiteralZero<>) noexcept {
171     return v.value_ != 0;
172   }
173   friend constexpr bool operator==(compare_internal::OnlyLiteralZero<>,
174                                    weak_equality v) noexcept {
175     return 0 == v.value_;
176   }
177   friend constexpr bool operator!=(compare_internal::OnlyLiteralZero<>,
178                                    weak_equality v) noexcept {
179     return 0 != v.value_;
180   }
181   friend constexpr bool operator==(weak_equality v1,
182                                    weak_equality v2) noexcept {
183     return v1.value_ == v2.value_;
184   }
185   friend constexpr bool operator!=(weak_equality v1,
186                                    weak_equality v2) noexcept {
187     return v1.value_ != v2.value_;
188   }
189 
190  private:
191   compare_internal::value_type value_;
192 };
193 ABSL_COMPARE_INLINE_INIT(weak_equality, equivalent,
194                          compare_internal::eq::equivalent);
195 ABSL_COMPARE_INLINE_INIT(weak_equality, nonequivalent,
196                          compare_internal::eq::nonequivalent);
197 
198 class strong_equality
199     : public compare_internal::strong_equality_base<strong_equality> {
200   explicit constexpr strong_equality(compare_internal::eq v) noexcept
201       : value_(static_cast<compare_internal::value_type>(v)) {}
202   friend struct compare_internal::strong_equality_base<strong_equality>;
203 
204  public:
205   ABSL_COMPARE_INLINE_SUBCLASS_DECL(strong_equality, equal);
206   ABSL_COMPARE_INLINE_SUBCLASS_DECL(strong_equality, nonequal);
207   ABSL_COMPARE_INLINE_SUBCLASS_DECL(strong_equality, equivalent);
208   ABSL_COMPARE_INLINE_SUBCLASS_DECL(strong_equality, nonequivalent);
209 
210   // Conversion
211   constexpr operator weak_equality() const noexcept {  // NOLINT
212     return value_ == 0 ? weak_equality::equivalent
213                        : weak_equality::nonequivalent;
214   }
215   // Comparisons
216   friend constexpr bool operator==(
217       strong_equality v, compare_internal::OnlyLiteralZero<>) noexcept {
218     return v.value_ == 0;
219   }
220   friend constexpr bool operator!=(
221       strong_equality v, compare_internal::OnlyLiteralZero<>) noexcept {
222     return v.value_ != 0;
223   }
224   friend constexpr bool operator==(compare_internal::OnlyLiteralZero<>,
225                                    strong_equality v) noexcept {
226     return 0 == v.value_;
227   }
228   friend constexpr bool operator!=(compare_internal::OnlyLiteralZero<>,
229                                    strong_equality v) noexcept {
230     return 0 != v.value_;
231   }
232   friend constexpr bool operator==(strong_equality v1,
233                                    strong_equality v2) noexcept {
234     return v1.value_ == v2.value_;
235   }
236   friend constexpr bool operator!=(strong_equality v1,
237                                    strong_equality v2) noexcept {
238     return v1.value_ != v2.value_;
239   }
240 
241  private:
242   compare_internal::value_type value_;
243 };
244 ABSL_COMPARE_INLINE_INIT(strong_equality, equal, compare_internal::eq::equal);
245 ABSL_COMPARE_INLINE_INIT(strong_equality, nonequal,
246                          compare_internal::eq::nonequal);
247 ABSL_COMPARE_INLINE_INIT(strong_equality, equivalent,
248                          compare_internal::eq::equivalent);
249 ABSL_COMPARE_INLINE_INIT(strong_equality, nonequivalent,
250                          compare_internal::eq::nonequivalent);
251 
252 class partial_ordering
253     : public compare_internal::partial_ordering_base<partial_ordering> {
254   explicit constexpr partial_ordering(compare_internal::eq v) noexcept
255       : value_(static_cast<compare_internal::value_type>(v)) {}
256   explicit constexpr partial_ordering(compare_internal::ord v) noexcept
257       : value_(static_cast<compare_internal::value_type>(v)) {}
258   explicit constexpr partial_ordering(compare_internal::ncmp v) noexcept
259       : value_(static_cast<compare_internal::value_type>(v)) {}
260   friend struct compare_internal::partial_ordering_base<partial_ordering>;
261 
262   constexpr bool is_ordered() const noexcept {
263     return value_ !=
264            compare_internal::value_type(compare_internal::ncmp::unordered);
265   }
266 
267  public:
268   ABSL_COMPARE_INLINE_SUBCLASS_DECL(partial_ordering, less);
269   ABSL_COMPARE_INLINE_SUBCLASS_DECL(partial_ordering, equivalent);
270   ABSL_COMPARE_INLINE_SUBCLASS_DECL(partial_ordering, greater);
271   ABSL_COMPARE_INLINE_SUBCLASS_DECL(partial_ordering, unordered);
272 
273   // Conversion
274   constexpr operator weak_equality() const noexcept {  // NOLINT
275     return value_ == 0 ? weak_equality::equivalent
276                        : weak_equality::nonequivalent;
277   }
278   // Comparisons
279   friend constexpr bool operator==(
280       partial_ordering v, compare_internal::OnlyLiteralZero<>) noexcept {
281     return v.is_ordered() && v.value_ == 0;
282   }
283   friend constexpr bool operator!=(
284       partial_ordering v, compare_internal::OnlyLiteralZero<>) noexcept {
285     return !v.is_ordered() || v.value_ != 0;
286   }
287   friend constexpr bool operator<(
288       partial_ordering v, compare_internal::OnlyLiteralZero<>) noexcept {
289     return v.is_ordered() && v.value_ < 0;
290   }
291   friend constexpr bool operator<=(
292       partial_ordering v, compare_internal::OnlyLiteralZero<>) noexcept {
293     return v.is_ordered() && v.value_ <= 0;
294   }
295   friend constexpr bool operator>(
296       partial_ordering v, compare_internal::OnlyLiteralZero<>) noexcept {
297     return v.is_ordered() && v.value_ > 0;
298   }
299   friend constexpr bool operator>=(
300       partial_ordering v, compare_internal::OnlyLiteralZero<>) noexcept {
301     return v.is_ordered() && v.value_ >= 0;
302   }
303   friend constexpr bool operator==(compare_internal::OnlyLiteralZero<>,
304                                    partial_ordering v) noexcept {
305     return v.is_ordered() && 0 == v.value_;
306   }
307   friend constexpr bool operator!=(compare_internal::OnlyLiteralZero<>,
308                                    partial_ordering v) noexcept {
309     return !v.is_ordered() || 0 != v.value_;
310   }
311   friend constexpr bool operator<(compare_internal::OnlyLiteralZero<>,
312                                   partial_ordering v) noexcept {
313     return v.is_ordered() && 0 < v.value_;
314   }
315   friend constexpr bool operator<=(compare_internal::OnlyLiteralZero<>,
316                                    partial_ordering v) noexcept {
317     return v.is_ordered() && 0 <= v.value_;
318   }
319   friend constexpr bool operator>(compare_internal::OnlyLiteralZero<>,
320                                   partial_ordering v) noexcept {
321     return v.is_ordered() && 0 > v.value_;
322   }
323   friend constexpr bool operator>=(compare_internal::OnlyLiteralZero<>,
324                                    partial_ordering v) noexcept {
325     return v.is_ordered() && 0 >= v.value_;
326   }
327   friend constexpr bool operator==(partial_ordering v1,
328                                    partial_ordering v2) noexcept {
329     return v1.value_ == v2.value_;
330   }
331   friend constexpr bool operator!=(partial_ordering v1,
332                                    partial_ordering v2) noexcept {
333     return v1.value_ != v2.value_;
334   }
335 
336  private:
337   compare_internal::value_type value_;
338 };
339 ABSL_COMPARE_INLINE_INIT(partial_ordering, less, compare_internal::ord::less);
340 ABSL_COMPARE_INLINE_INIT(partial_ordering, equivalent,
341                          compare_internal::eq::equivalent);
342 ABSL_COMPARE_INLINE_INIT(partial_ordering, greater,
343                          compare_internal::ord::greater);
344 ABSL_COMPARE_INLINE_INIT(partial_ordering, unordered,
345                          compare_internal::ncmp::unordered);
346 
347 class weak_ordering
348     : public compare_internal::weak_ordering_base<weak_ordering> {
349   explicit constexpr weak_ordering(compare_internal::eq v) noexcept
350       : value_(static_cast<compare_internal::value_type>(v)) {}
351   explicit constexpr weak_ordering(compare_internal::ord v) noexcept
352       : value_(static_cast<compare_internal::value_type>(v)) {}
353   friend struct compare_internal::weak_ordering_base<weak_ordering>;
354 
355  public:
356   ABSL_COMPARE_INLINE_SUBCLASS_DECL(weak_ordering, less);
357   ABSL_COMPARE_INLINE_SUBCLASS_DECL(weak_ordering, equivalent);
358   ABSL_COMPARE_INLINE_SUBCLASS_DECL(weak_ordering, greater);
359 
360   // Conversions
361   constexpr operator weak_equality() const noexcept {  // NOLINT
362     return value_ == 0 ? weak_equality::equivalent
363                        : weak_equality::nonequivalent;
364   }
365   constexpr operator partial_ordering() const noexcept {  // NOLINT
366     return value_ == 0 ? partial_ordering::equivalent
367                        : (value_ < 0 ? partial_ordering::less
368                                      : partial_ordering::greater);
369   }
370   // Comparisons
371   friend constexpr bool operator==(
372       weak_ordering v, compare_internal::OnlyLiteralZero<>) noexcept {
373     return v.value_ == 0;
374   }
375   friend constexpr bool operator!=(
376       weak_ordering v, compare_internal::OnlyLiteralZero<>) noexcept {
377     return v.value_ != 0;
378   }
379   friend constexpr bool operator<(
380       weak_ordering v, compare_internal::OnlyLiteralZero<>) noexcept {
381     return v.value_ < 0;
382   }
383   friend constexpr bool operator<=(
384       weak_ordering v, compare_internal::OnlyLiteralZero<>) noexcept {
385     return v.value_ <= 0;
386   }
387   friend constexpr bool operator>(
388       weak_ordering v, compare_internal::OnlyLiteralZero<>) noexcept {
389     return v.value_ > 0;
390   }
391   friend constexpr bool operator>=(
392       weak_ordering v, compare_internal::OnlyLiteralZero<>) noexcept {
393     return v.value_ >= 0;
394   }
395   friend constexpr bool operator==(compare_internal::OnlyLiteralZero<>,
396                                    weak_ordering v) noexcept {
397     return 0 == v.value_;
398   }
399   friend constexpr bool operator!=(compare_internal::OnlyLiteralZero<>,
400                                    weak_ordering v) noexcept {
401     return 0 != v.value_;
402   }
403   friend constexpr bool operator<(compare_internal::OnlyLiteralZero<>,
404                                   weak_ordering v) noexcept {
405     return 0 < v.value_;
406   }
407   friend constexpr bool operator<=(compare_internal::OnlyLiteralZero<>,
408                                    weak_ordering v) noexcept {
409     return 0 <= v.value_;
410   }
411   friend constexpr bool operator>(compare_internal::OnlyLiteralZero<>,
412                                   weak_ordering v) noexcept {
413     return 0 > v.value_;
414   }
415   friend constexpr bool operator>=(compare_internal::OnlyLiteralZero<>,
416                                    weak_ordering v) noexcept {
417     return 0 >= v.value_;
418   }
419   friend constexpr bool operator==(weak_ordering v1,
420                                    weak_ordering v2) noexcept {
421     return v1.value_ == v2.value_;
422   }
423   friend constexpr bool operator!=(weak_ordering v1,
424                                    weak_ordering v2) noexcept {
425     return v1.value_ != v2.value_;
426   }
427 
428  private:
429   compare_internal::value_type value_;
430 };
431 ABSL_COMPARE_INLINE_INIT(weak_ordering, less, compare_internal::ord::less);
432 ABSL_COMPARE_INLINE_INIT(weak_ordering, equivalent,
433                          compare_internal::eq::equivalent);
434 ABSL_COMPARE_INLINE_INIT(weak_ordering, greater,
435                          compare_internal::ord::greater);
436 
437 class strong_ordering
438     : public compare_internal::strong_ordering_base<strong_ordering> {
439   explicit constexpr strong_ordering(compare_internal::eq v) noexcept
440       : value_(static_cast<compare_internal::value_type>(v)) {}
441   explicit constexpr strong_ordering(compare_internal::ord v) noexcept
442       : value_(static_cast<compare_internal::value_type>(v)) {}
443   friend struct compare_internal::strong_ordering_base<strong_ordering>;
444 
445  public:
446   ABSL_COMPARE_INLINE_SUBCLASS_DECL(strong_ordering, less);
447   ABSL_COMPARE_INLINE_SUBCLASS_DECL(strong_ordering, equal);
448   ABSL_COMPARE_INLINE_SUBCLASS_DECL(strong_ordering, equivalent);
449   ABSL_COMPARE_INLINE_SUBCLASS_DECL(strong_ordering, greater);
450 
451   // Conversions
452   constexpr operator weak_equality() const noexcept {  // NOLINT
453     return value_ == 0 ? weak_equality::equivalent
454                        : weak_equality::nonequivalent;
455   }
456   constexpr operator strong_equality() const noexcept {  // NOLINT
457     return value_ == 0 ? strong_equality::equal : strong_equality::nonequal;
458   }
459   constexpr operator partial_ordering() const noexcept {  // NOLINT
460     return value_ == 0 ? partial_ordering::equivalent
461                        : (value_ < 0 ? partial_ordering::less
462                                      : partial_ordering::greater);
463   }
464   constexpr operator weak_ordering() const noexcept {  // NOLINT
465     return value_ == 0
466                ? weak_ordering::equivalent
467                : (value_ < 0 ? weak_ordering::less : weak_ordering::greater);
468   }
469   // Comparisons
470   friend constexpr bool operator==(
471       strong_ordering v, compare_internal::OnlyLiteralZero<>) noexcept {
472     return v.value_ == 0;
473   }
474   friend constexpr bool operator!=(
475       strong_ordering v, compare_internal::OnlyLiteralZero<>) noexcept {
476     return v.value_ != 0;
477   }
478   friend constexpr bool operator<(
479       strong_ordering v, compare_internal::OnlyLiteralZero<>) noexcept {
480     return v.value_ < 0;
481   }
482   friend constexpr bool operator<=(
483       strong_ordering v, compare_internal::OnlyLiteralZero<>) noexcept {
484     return v.value_ <= 0;
485   }
486   friend constexpr bool operator>(
487       strong_ordering v, compare_internal::OnlyLiteralZero<>) noexcept {
488     return v.value_ > 0;
489   }
490   friend constexpr bool operator>=(
491       strong_ordering v, compare_internal::OnlyLiteralZero<>) noexcept {
492     return v.value_ >= 0;
493   }
494   friend constexpr bool operator==(compare_internal::OnlyLiteralZero<>,
495                                    strong_ordering v) noexcept {
496     return 0 == v.value_;
497   }
498   friend constexpr bool operator!=(compare_internal::OnlyLiteralZero<>,
499                                    strong_ordering v) noexcept {
500     return 0 != v.value_;
501   }
502   friend constexpr bool operator<(compare_internal::OnlyLiteralZero<>,
503                                   strong_ordering v) noexcept {
504     return 0 < v.value_;
505   }
506   friend constexpr bool operator<=(compare_internal::OnlyLiteralZero<>,
507                                    strong_ordering v) noexcept {
508     return 0 <= v.value_;
509   }
510   friend constexpr bool operator>(compare_internal::OnlyLiteralZero<>,
511                                   strong_ordering v) noexcept {
512     return 0 > v.value_;
513   }
514   friend constexpr bool operator>=(compare_internal::OnlyLiteralZero<>,
515                                    strong_ordering v) noexcept {
516     return 0 >= v.value_;
517   }
518   friend constexpr bool operator==(strong_ordering v1,
519                                    strong_ordering v2) noexcept {
520     return v1.value_ == v2.value_;
521   }
522   friend constexpr bool operator!=(strong_ordering v1,
523                                    strong_ordering v2) noexcept {
524     return v1.value_ != v2.value_;
525   }
526 
527  private:
528   compare_internal::value_type value_;
529 };
530 ABSL_COMPARE_INLINE_INIT(strong_ordering, less, compare_internal::ord::less);
531 ABSL_COMPARE_INLINE_INIT(strong_ordering, equal, compare_internal::eq::equal);
532 ABSL_COMPARE_INLINE_INIT(strong_ordering, equivalent,
533                          compare_internal::eq::equivalent);
534 ABSL_COMPARE_INLINE_INIT(strong_ordering, greater,
535                          compare_internal::ord::greater);
536 
537 #undef ABSL_COMPARE_INLINE_BASECLASS_DECL
538 #undef ABSL_COMPARE_INLINE_SUBCLASS_DECL
539 #undef ABSL_COMPARE_INLINE_INIT
540 
541 namespace compare_internal {
542 // We also provide these comparator adapter functions for internal absl use.
543 
544 // Helper functions to do a boolean comparison of two keys given a boolean
545 // or three-way comparator.
546 // SFINAE prevents implicit conversions to bool (such as from int).
547 template <typename Bool,
548           absl::enable_if_t<std::is_same<bool, Bool>::value, int> = 0>
549 constexpr bool compare_result_as_less_than(const Bool r) { return r; }
550 constexpr bool compare_result_as_less_than(const absl::weak_ordering r) {
551   return r < 0;
552 }
553 
554 template <typename Compare, typename K, typename LK>
555 constexpr bool do_less_than_comparison(const Compare &compare, const K &x,
556                                        const LK &y) {
557   return compare_result_as_less_than(compare(x, y));
558 }
559 
560 // Helper functions to do a three-way comparison of two keys given a boolean or
561 // three-way comparator.
562 // SFINAE prevents implicit conversions to int (such as from bool).
563 template <typename Int,
564           absl::enable_if_t<std::is_same<int, Int>::value, int> = 0>
565 constexpr absl::weak_ordering compare_result_as_ordering(const Int c) {
566   return c < 0 ? absl::weak_ordering::less
567                : c == 0 ? absl::weak_ordering::equivalent
568                         : absl::weak_ordering::greater;
569 }
570 constexpr absl::weak_ordering compare_result_as_ordering(
571     const absl::weak_ordering c) {
572   return c;
573 }
574 
575 template <
576     typename Compare, typename K, typename LK,
577     absl::enable_if_t<!std::is_same<bool, absl::result_of_t<Compare(
578                                               const K &, const LK &)>>::value,
579                       int> = 0>
580 constexpr absl::weak_ordering do_three_way_comparison(const Compare &compare,
581                                                       const K &x, const LK &y) {
582   return compare_result_as_ordering(compare(x, y));
583 }
584 template <
585     typename Compare, typename K, typename LK,
586     absl::enable_if_t<std::is_same<bool, absl::result_of_t<Compare(
587                                              const K &, const LK &)>>::value,
588                       int> = 0>
589 constexpr absl::weak_ordering do_three_way_comparison(const Compare &compare,
590                                                       const K &x, const LK &y) {
591   return compare(x, y) ? absl::weak_ordering::less
592                        : compare(y, x) ? absl::weak_ordering::greater
593                                        : absl::weak_ordering::equivalent;
594 }
595 
596 }  // namespace compare_internal
597 ABSL_NAMESPACE_END
598 }  // namespace absl
599 
600 #endif  // ABSL_TYPES_COMPARE_H_
601