• 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::partial_ordering`, `absl::weak_ordering`,
20 // and `absl::strong_ordering` types for storing the results of three way
21 // 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::partial_ordering`, 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 "absl/base/config.h"
34 
35 #ifdef ABSL_USES_STD_ORDERING
36 
37 #include <compare>  // IWYU pragma: export
38 #include <type_traits>
39 
40 #include "absl/meta/type_traits.h"
41 
42 #else
43 
44 #include <cstddef>
45 #include <cstdint>
46 #include <cstdlib>
47 #include <type_traits>
48 
49 #include "absl/base/attributes.h"
50 #include "absl/base/macros.h"
51 #include "absl/meta/type_traits.h"
52 
53 #endif
54 
55 namespace absl {
56 ABSL_NAMESPACE_BEGIN
57 
58 #ifdef ABSL_USES_STD_ORDERING
59 
60 using std::partial_ordering;
61 using std::strong_ordering;
62 using std::weak_ordering;
63 
64 #else
65 
66 namespace compare_internal {
67 
68 using value_type = int8_t;
69 
70 class OnlyLiteralZero {
71  public:
72 #if ABSL_HAVE_ATTRIBUTE(enable_if)
73   // On clang, we can avoid triggering modernize-use-nullptr by only enabling
74   // this overload when the value is a compile time integer constant equal to 0.
75   //
76   // In c++20, this could be a static_assert in a consteval function.
77   constexpr OnlyLiteralZero(int n)  // NOLINT
78       __attribute__((enable_if(n == 0, "Only literal `0` is allowed."))) {}
79 #else  // ABSL_HAVE_ATTRIBUTE(enable_if)
80   // Accept only literal zero since it can be implicitly converted to a pointer
81   // to member type. nullptr constants will be caught by the other constructor
82   // which accepts a nullptr_t.
83   //
84   // This constructor is not used for clang since it triggers
85   // modernize-use-nullptr.
86   constexpr OnlyLiteralZero(int OnlyLiteralZero::*) noexcept {}  // NOLINT
87 #endif
88 
89   // Fails compilation when `nullptr` or integral type arguments other than
90   // `int` are passed. This constructor doesn't accept `int` because literal `0`
91   // has type `int`. Literal `0` arguments will be implicitly converted to
92   // `std::nullptr_t` and accepted by the above constructor, while other `int`
93   // arguments will fail to be converted and cause compilation failure.
94   template <typename T, typename = typename std::enable_if<
95                             std::is_same<T, std::nullptr_t>::value ||
96                             (std::is_integral<T>::value &&
97                              !std::is_same<T, int>::value)>::type>
98   OnlyLiteralZero(T) {  // NOLINT
99     static_assert(sizeof(T) < 0, "Only literal `0` is allowed.");
100   }
101 };
102 
103 enum class eq : value_type {
104   equal = 0,
105   equivalent = equal,
106   nonequal = 1,
107   nonequivalent = nonequal,
108 };
109 
110 enum class ord : value_type { less = -1, greater = 1 };
111 
112 enum class ncmp : value_type { unordered = -127 };
113 
114 // Define macros to allow for creation or emulation of C++17 inline variables
115 // based on whether the feature is supported. Note: we can't use
116 // ABSL_INTERNAL_INLINE_CONSTEXPR here because the variables here are of
117 // incomplete types so they need to be defined after the types are complete.
118 #ifdef __cpp_inline_variables
119 
120 // A no-op expansion that can be followed by a semicolon at class level.
121 #define ABSL_COMPARE_INLINE_BASECLASS_DECL(name) static_assert(true, "")
122 
123 #define ABSL_COMPARE_INLINE_SUBCLASS_DECL(type, name) \
124   static const type name
125 
126 #define ABSL_COMPARE_INLINE_INIT(type, name, init) \
127   inline constexpr type type::name(init)
128 
129 #else  // __cpp_inline_variables
130 
131 #define ABSL_COMPARE_INLINE_BASECLASS_DECL(name) \
132   ABSL_CONST_INIT static const T name
133 
134 // A no-op expansion that can be followed by a semicolon at class level.
135 #define ABSL_COMPARE_INLINE_SUBCLASS_DECL(type, name) static_assert(true, "")
136 
137 #define ABSL_COMPARE_INLINE_INIT(type, name, init) \
138   template <typename T>                            \
139   const T compare_internal::type##_base<T>::name(init)
140 
141 #endif  // __cpp_inline_variables
142 
143 // These template base classes allow for defining the values of the constants
144 // in the header file (for performance) without using inline variables (which
145 // aren't available in C++11).
146 template <typename T>
147 struct partial_ordering_base {
148   ABSL_COMPARE_INLINE_BASECLASS_DECL(less);
149   ABSL_COMPARE_INLINE_BASECLASS_DECL(equivalent);
150   ABSL_COMPARE_INLINE_BASECLASS_DECL(greater);
151   ABSL_COMPARE_INLINE_BASECLASS_DECL(unordered);
152 };
153 
154 template <typename T>
155 struct weak_ordering_base {
156   ABSL_COMPARE_INLINE_BASECLASS_DECL(less);
157   ABSL_COMPARE_INLINE_BASECLASS_DECL(equivalent);
158   ABSL_COMPARE_INLINE_BASECLASS_DECL(greater);
159 };
160 
161 template <typename T>
162 struct strong_ordering_base {
163   ABSL_COMPARE_INLINE_BASECLASS_DECL(less);
164   ABSL_COMPARE_INLINE_BASECLASS_DECL(equal);
165   ABSL_COMPARE_INLINE_BASECLASS_DECL(equivalent);
166   ABSL_COMPARE_INLINE_BASECLASS_DECL(greater);
167 };
168 
169 }  // namespace compare_internal
170 
171 class partial_ordering
172     : public compare_internal::partial_ordering_base<partial_ordering> {
173   explicit constexpr partial_ordering(compare_internal::eq v) noexcept
174       : value_(static_cast<compare_internal::value_type>(v)) {}
175   explicit constexpr partial_ordering(compare_internal::ord v) noexcept
176       : value_(static_cast<compare_internal::value_type>(v)) {}
177   explicit constexpr partial_ordering(compare_internal::ncmp v) noexcept
178       : value_(static_cast<compare_internal::value_type>(v)) {}
179   friend struct compare_internal::partial_ordering_base<partial_ordering>;
180 
181   constexpr bool is_ordered() const noexcept {
182     return value_ !=
183            compare_internal::value_type(compare_internal::ncmp::unordered);
184   }
185 
186  public:
187   ABSL_COMPARE_INLINE_SUBCLASS_DECL(partial_ordering, less);
188   ABSL_COMPARE_INLINE_SUBCLASS_DECL(partial_ordering, equivalent);
189   ABSL_COMPARE_INLINE_SUBCLASS_DECL(partial_ordering, greater);
190   ABSL_COMPARE_INLINE_SUBCLASS_DECL(partial_ordering, unordered);
191 
192   // Comparisons
193   friend constexpr bool operator==(
194       partial_ordering v, compare_internal::OnlyLiteralZero) noexcept {
195     return v.is_ordered() && v.value_ == 0;
196   }
197   friend constexpr bool operator!=(
198       partial_ordering v, compare_internal::OnlyLiteralZero) noexcept {
199     return !v.is_ordered() || v.value_ != 0;
200   }
201   friend constexpr bool operator<(
202       partial_ordering v, compare_internal::OnlyLiteralZero) noexcept {
203     return v.is_ordered() && v.value_ < 0;
204   }
205   friend constexpr bool operator<=(
206       partial_ordering v, compare_internal::OnlyLiteralZero) noexcept {
207     return v.is_ordered() && v.value_ <= 0;
208   }
209   friend constexpr bool operator>(
210       partial_ordering v, compare_internal::OnlyLiteralZero) noexcept {
211     return v.is_ordered() && v.value_ > 0;
212   }
213   friend constexpr bool operator>=(
214       partial_ordering v, compare_internal::OnlyLiteralZero) noexcept {
215     return v.is_ordered() && v.value_ >= 0;
216   }
217   friend constexpr bool operator==(compare_internal::OnlyLiteralZero,
218                                    partial_ordering v) noexcept {
219     return v.is_ordered() && 0 == v.value_;
220   }
221   friend constexpr bool operator!=(compare_internal::OnlyLiteralZero,
222                                    partial_ordering v) noexcept {
223     return !v.is_ordered() || 0 != v.value_;
224   }
225   friend constexpr bool operator<(compare_internal::OnlyLiteralZero,
226                                   partial_ordering v) noexcept {
227     return v.is_ordered() && 0 < v.value_;
228   }
229   friend constexpr bool operator<=(compare_internal::OnlyLiteralZero,
230                                    partial_ordering v) noexcept {
231     return v.is_ordered() && 0 <= v.value_;
232   }
233   friend constexpr bool operator>(compare_internal::OnlyLiteralZero,
234                                   partial_ordering v) noexcept {
235     return v.is_ordered() && 0 > v.value_;
236   }
237   friend constexpr bool operator>=(compare_internal::OnlyLiteralZero,
238                                    partial_ordering v) noexcept {
239     return v.is_ordered() && 0 >= v.value_;
240   }
241   friend constexpr bool operator==(partial_ordering v1,
242                                    partial_ordering v2) noexcept {
243     return v1.value_ == v2.value_;
244   }
245   friend constexpr bool operator!=(partial_ordering v1,
246                                    partial_ordering v2) noexcept {
247     return v1.value_ != v2.value_;
248   }
249 
250  private:
251   compare_internal::value_type value_;
252 };
253 ABSL_COMPARE_INLINE_INIT(partial_ordering, less, compare_internal::ord::less);
254 ABSL_COMPARE_INLINE_INIT(partial_ordering, equivalent,
255                          compare_internal::eq::equivalent);
256 ABSL_COMPARE_INLINE_INIT(partial_ordering, greater,
257                          compare_internal::ord::greater);
258 ABSL_COMPARE_INLINE_INIT(partial_ordering, unordered,
259                          compare_internal::ncmp::unordered);
260 
261 class weak_ordering
262     : public compare_internal::weak_ordering_base<weak_ordering> {
263   explicit constexpr weak_ordering(compare_internal::eq v) noexcept
264       : value_(static_cast<compare_internal::value_type>(v)) {}
265   explicit constexpr weak_ordering(compare_internal::ord v) noexcept
266       : value_(static_cast<compare_internal::value_type>(v)) {}
267   friend struct compare_internal::weak_ordering_base<weak_ordering>;
268 
269  public:
270   ABSL_COMPARE_INLINE_SUBCLASS_DECL(weak_ordering, less);
271   ABSL_COMPARE_INLINE_SUBCLASS_DECL(weak_ordering, equivalent);
272   ABSL_COMPARE_INLINE_SUBCLASS_DECL(weak_ordering, greater);
273 
274   // Conversions
275   constexpr operator partial_ordering() const noexcept {  // NOLINT
276     return value_ == 0 ? partial_ordering::equivalent
277                        : (value_ < 0 ? partial_ordering::less
278                                      : partial_ordering::greater);
279   }
280   // Comparisons
281   friend constexpr bool operator==(
282       weak_ordering v, compare_internal::OnlyLiteralZero) noexcept {
283     return v.value_ == 0;
284   }
285   friend constexpr bool operator!=(
286       weak_ordering v, compare_internal::OnlyLiteralZero) noexcept {
287     return v.value_ != 0;
288   }
289   friend constexpr bool operator<(
290       weak_ordering v, compare_internal::OnlyLiteralZero) noexcept {
291     return v.value_ < 0;
292   }
293   friend constexpr bool operator<=(
294       weak_ordering v, compare_internal::OnlyLiteralZero) noexcept {
295     return v.value_ <= 0;
296   }
297   friend constexpr bool operator>(
298       weak_ordering v, compare_internal::OnlyLiteralZero) noexcept {
299     return v.value_ > 0;
300   }
301   friend constexpr bool operator>=(
302       weak_ordering v, compare_internal::OnlyLiteralZero) noexcept {
303     return v.value_ >= 0;
304   }
305   friend constexpr bool operator==(compare_internal::OnlyLiteralZero,
306                                    weak_ordering v) noexcept {
307     return 0 == v.value_;
308   }
309   friend constexpr bool operator!=(compare_internal::OnlyLiteralZero,
310                                    weak_ordering v) noexcept {
311     return 0 != v.value_;
312   }
313   friend constexpr bool operator<(compare_internal::OnlyLiteralZero,
314                                   weak_ordering v) noexcept {
315     return 0 < v.value_;
316   }
317   friend constexpr bool operator<=(compare_internal::OnlyLiteralZero,
318                                    weak_ordering v) noexcept {
319     return 0 <= v.value_;
320   }
321   friend constexpr bool operator>(compare_internal::OnlyLiteralZero,
322                                   weak_ordering v) noexcept {
323     return 0 > v.value_;
324   }
325   friend constexpr bool operator>=(compare_internal::OnlyLiteralZero,
326                                    weak_ordering v) noexcept {
327     return 0 >= v.value_;
328   }
329   friend constexpr bool operator==(weak_ordering v1,
330                                    weak_ordering v2) noexcept {
331     return v1.value_ == v2.value_;
332   }
333   friend constexpr bool operator!=(weak_ordering v1,
334                                    weak_ordering v2) noexcept {
335     return v1.value_ != v2.value_;
336   }
337 
338  private:
339   compare_internal::value_type value_;
340 };
341 ABSL_COMPARE_INLINE_INIT(weak_ordering, less, compare_internal::ord::less);
342 ABSL_COMPARE_INLINE_INIT(weak_ordering, equivalent,
343                          compare_internal::eq::equivalent);
344 ABSL_COMPARE_INLINE_INIT(weak_ordering, greater,
345                          compare_internal::ord::greater);
346 
347 class strong_ordering
348     : public compare_internal::strong_ordering_base<strong_ordering> {
349   explicit constexpr strong_ordering(compare_internal::eq v) noexcept
350       : value_(static_cast<compare_internal::value_type>(v)) {}
351   explicit constexpr strong_ordering(compare_internal::ord v) noexcept
352       : value_(static_cast<compare_internal::value_type>(v)) {}
353   friend struct compare_internal::strong_ordering_base<strong_ordering>;
354 
355  public:
356   ABSL_COMPARE_INLINE_SUBCLASS_DECL(strong_ordering, less);
357   ABSL_COMPARE_INLINE_SUBCLASS_DECL(strong_ordering, equal);
358   ABSL_COMPARE_INLINE_SUBCLASS_DECL(strong_ordering, equivalent);
359   ABSL_COMPARE_INLINE_SUBCLASS_DECL(strong_ordering, greater);
360 
361   // Conversions
362   constexpr operator partial_ordering() const noexcept {  // NOLINT
363     return value_ == 0 ? partial_ordering::equivalent
364                        : (value_ < 0 ? partial_ordering::less
365                                      : partial_ordering::greater);
366   }
367   constexpr operator weak_ordering() const noexcept {  // NOLINT
368     return value_ == 0
369                ? weak_ordering::equivalent
370                : (value_ < 0 ? weak_ordering::less : weak_ordering::greater);
371   }
372   // Comparisons
373   friend constexpr bool operator==(
374       strong_ordering v, compare_internal::OnlyLiteralZero) noexcept {
375     return v.value_ == 0;
376   }
377   friend constexpr bool operator!=(
378       strong_ordering v, compare_internal::OnlyLiteralZero) noexcept {
379     return v.value_ != 0;
380   }
381   friend constexpr bool operator<(
382       strong_ordering v, compare_internal::OnlyLiteralZero) noexcept {
383     return v.value_ < 0;
384   }
385   friend constexpr bool operator<=(
386       strong_ordering v, compare_internal::OnlyLiteralZero) noexcept {
387     return v.value_ <= 0;
388   }
389   friend constexpr bool operator>(
390       strong_ordering v, compare_internal::OnlyLiteralZero) noexcept {
391     return v.value_ > 0;
392   }
393   friend constexpr bool operator>=(
394       strong_ordering v, compare_internal::OnlyLiteralZero) noexcept {
395     return v.value_ >= 0;
396   }
397   friend constexpr bool operator==(compare_internal::OnlyLiteralZero,
398                                    strong_ordering v) noexcept {
399     return 0 == v.value_;
400   }
401   friend constexpr bool operator!=(compare_internal::OnlyLiteralZero,
402                                    strong_ordering v) noexcept {
403     return 0 != v.value_;
404   }
405   friend constexpr bool operator<(compare_internal::OnlyLiteralZero,
406                                   strong_ordering v) noexcept {
407     return 0 < v.value_;
408   }
409   friend constexpr bool operator<=(compare_internal::OnlyLiteralZero,
410                                    strong_ordering v) noexcept {
411     return 0 <= v.value_;
412   }
413   friend constexpr bool operator>(compare_internal::OnlyLiteralZero,
414                                   strong_ordering v) noexcept {
415     return 0 > v.value_;
416   }
417   friend constexpr bool operator>=(compare_internal::OnlyLiteralZero,
418                                    strong_ordering v) noexcept {
419     return 0 >= v.value_;
420   }
421   friend constexpr bool operator==(strong_ordering v1,
422                                    strong_ordering v2) noexcept {
423     return v1.value_ == v2.value_;
424   }
425   friend constexpr bool operator!=(strong_ordering v1,
426                                    strong_ordering v2) noexcept {
427     return v1.value_ != v2.value_;
428   }
429 
430  private:
431   compare_internal::value_type value_;
432 };
433 ABSL_COMPARE_INLINE_INIT(strong_ordering, less, compare_internal::ord::less);
434 ABSL_COMPARE_INLINE_INIT(strong_ordering, equal, compare_internal::eq::equal);
435 ABSL_COMPARE_INLINE_INIT(strong_ordering, equivalent,
436                          compare_internal::eq::equivalent);
437 ABSL_COMPARE_INLINE_INIT(strong_ordering, greater,
438                          compare_internal::ord::greater);
439 
440 #undef ABSL_COMPARE_INLINE_BASECLASS_DECL
441 #undef ABSL_COMPARE_INLINE_SUBCLASS_DECL
442 #undef ABSL_COMPARE_INLINE_INIT
443 
444 #endif  // ABSL_USES_STD_ORDERING
445 
446 namespace compare_internal {
447 // We also provide these comparator adapter functions for internal absl use.
448 
449 // Helper functions to do a boolean comparison of two keys given a boolean
450 // or three-way comparator.
451 // SFINAE prevents implicit conversions to bool (such as from int).
452 template <typename BoolT,
453           absl::enable_if_t<std::is_same<bool, BoolT>::value, int> = 0>
compare_result_as_less_than(const BoolT r)454 constexpr bool compare_result_as_less_than(const BoolT r) { return r; }
compare_result_as_less_than(const absl::weak_ordering r)455 constexpr bool compare_result_as_less_than(const absl::weak_ordering r) {
456   return r < 0;
457 }
458 
459 template <typename Compare, typename K, typename LK>
do_less_than_comparison(const Compare & compare,const K & x,const LK & y)460 constexpr bool do_less_than_comparison(const Compare &compare, const K &x,
461                                        const LK &y) {
462   return compare_result_as_less_than(compare(x, y));
463 }
464 
465 // Helper functions to do a three-way comparison of two keys given a boolean or
466 // three-way comparator.
467 // SFINAE prevents implicit conversions to int (such as from bool).
468 template <typename Int,
469           absl::enable_if_t<std::is_same<int, Int>::value, int> = 0>
compare_result_as_ordering(const Int c)470 constexpr absl::weak_ordering compare_result_as_ordering(const Int c) {
471   return c < 0 ? absl::weak_ordering::less
472                : c == 0 ? absl::weak_ordering::equivalent
473                         : absl::weak_ordering::greater;
474 }
compare_result_as_ordering(const absl::weak_ordering c)475 constexpr absl::weak_ordering compare_result_as_ordering(
476     const absl::weak_ordering c) {
477   return c;
478 }
479 
480 template <
481     typename Compare, typename K, typename LK,
482     absl::enable_if_t<!std::is_same<bool, absl::result_of_t<Compare(
483                                               const K &, const LK &)>>::value,
484                       int> = 0>
do_three_way_comparison(const Compare & compare,const K & x,const LK & y)485 constexpr absl::weak_ordering do_three_way_comparison(const Compare &compare,
486                                                       const K &x, const LK &y) {
487   return compare_result_as_ordering(compare(x, y));
488 }
489 template <
490     typename Compare, typename K, typename LK,
491     absl::enable_if_t<std::is_same<bool, absl::result_of_t<Compare(
492                                              const K &, const LK &)>>::value,
493                       int> = 0>
do_three_way_comparison(const Compare & compare,const K & x,const LK & y)494 constexpr absl::weak_ordering do_three_way_comparison(const Compare &compare,
495                                                       const K &x, const LK &y) {
496   return compare(x, y) ? absl::weak_ordering::less
497                        : compare(y, x) ? absl::weak_ordering::greater
498                                        : absl::weak_ordering::equivalent;
499 }
500 
501 }  // namespace compare_internal
502 ABSL_NAMESPACE_END
503 }  // namespace absl
504 
505 #endif  // ABSL_TYPES_COMPARE_H_
506