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