1 | // -*- C++ -*- operator<=> three-way comparison support. |
2 | |
3 | // Copyright (C) 2019-2021 Free Software Foundation, Inc. |
4 | // |
5 | // This file is part of GCC. |
6 | // |
7 | // GCC is free software; you can redistribute it and/or modify |
8 | // it under the terms of the GNU General Public License as published by |
9 | // the Free Software Foundation; either version 3, or (at your option) |
10 | // any later version. |
11 | // |
12 | // GCC is distributed in the hope that it will be useful, |
13 | // but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
15 | // GNU General Public License for more details. |
16 | // |
17 | // Under Section 7 of GPL version 3, you are granted additional |
18 | // permissions described in the GCC Runtime Library Exception, version |
19 | // 3.1, as published by the Free Software Foundation. |
20 | |
21 | // You should have received a copy of the GNU General Public License and |
22 | // a copy of the GCC Runtime Library Exception along with this program; |
23 | // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see |
24 | // <http://www.gnu.org/licenses/>. |
25 | |
26 | /** @file compare |
27 | * This is a Standard C++ Library header. |
28 | */ |
29 | |
30 | #ifndef _COMPARE |
31 | #define _COMPARE |
32 | |
33 | #pragma GCC system_header |
34 | |
35 | #if __cplusplus > 201703L && __cpp_impl_three_way_comparison >= 201907L |
36 | |
37 | #pragma GCC visibility push(default) |
38 | |
39 | #include <concepts> |
40 | |
41 | #if __cpp_lib_concepts |
42 | # define __cpp_lib_three_way_comparison 201907L |
43 | #endif |
44 | |
45 | namespace std |
46 | { |
47 | // [cmp.categories], comparison category types |
48 | |
49 | namespace __cmp_cat |
50 | { |
51 | using type = signed char; |
52 | |
53 | enum class _Ord : type { equivalent = 0, less = -1, greater = 1 }; |
54 | |
55 | enum class _Ncmp : type { _Unordered = 2 }; |
56 | |
57 | struct __unspec |
58 | { |
59 | constexpr __unspec(__unspec*) noexcept { } |
60 | }; |
61 | } |
62 | |
63 | class partial_ordering |
64 | { |
65 | // less=0xff, equiv=0x00, greater=0x01, unordered=0x02 |
66 | __cmp_cat::type _M_value; |
67 | |
68 | constexpr explicit |
69 | partial_ordering(__cmp_cat::_Ord __v) noexcept |
70 | : _M_value(__cmp_cat::type(__v)) |
71 | { } |
72 | |
73 | constexpr explicit |
74 | partial_ordering(__cmp_cat::_Ncmp __v) noexcept |
75 | : _M_value(__cmp_cat::type(__v)) |
76 | { } |
77 | |
78 | friend class weak_ordering; |
79 | friend class strong_ordering; |
80 | |
81 | public: |
82 | // valid values |
83 | static const partial_ordering less; |
84 | static const partial_ordering equivalent; |
85 | static const partial_ordering greater; |
86 | static const partial_ordering unordered; |
87 | |
88 | // comparisons |
89 | friend constexpr bool |
90 | operator==(partial_ordering __v, __cmp_cat::__unspec) noexcept |
91 | { return __v._M_value == 0; } |
92 | |
93 | friend constexpr bool |
94 | operator==(partial_ordering, partial_ordering) noexcept = default; |
95 | |
96 | friend constexpr bool |
97 | operator< (partial_ordering __v, __cmp_cat::__unspec) noexcept |
98 | { return __v._M_value == -1; } |
99 | |
100 | friend constexpr bool |
101 | operator> (partial_ordering __v, __cmp_cat::__unspec) noexcept |
102 | { return __v._M_value == 1; } |
103 | |
104 | friend constexpr bool |
105 | operator<=(partial_ordering __v, __cmp_cat::__unspec) noexcept |
106 | { return __v._M_value <= 0; } |
107 | |
108 | friend constexpr bool |
109 | operator>=(partial_ordering __v, __cmp_cat::__unspec) noexcept |
110 | { return __cmp_cat::type(__v._M_value & 1) == __v._M_value; } |
111 | |
112 | friend constexpr bool |
113 | operator< (__cmp_cat::__unspec, partial_ordering __v) noexcept |
114 | { return __v._M_value == 1; } |
115 | |
116 | friend constexpr bool |
117 | operator> (__cmp_cat::__unspec, partial_ordering __v) noexcept |
118 | { return __v._M_value == -1; } |
119 | |
120 | friend constexpr bool |
121 | operator<=(__cmp_cat::__unspec, partial_ordering __v) noexcept |
122 | { return __cmp_cat::type(__v._M_value & 1) == __v._M_value; } |
123 | |
124 | friend constexpr bool |
125 | operator>=(__cmp_cat::__unspec, partial_ordering __v) noexcept |
126 | { return 0 >= __v._M_value; } |
127 | |
128 | friend constexpr partial_ordering |
129 | operator<=>(partial_ordering __v, __cmp_cat::__unspec) noexcept |
130 | { return __v; } |
131 | |
132 | friend constexpr partial_ordering |
133 | operator<=>(__cmp_cat::__unspec, partial_ordering __v) noexcept |
134 | { |
135 | if (__v._M_value & 1) |
136 | return partial_ordering(__cmp_cat::_Ord(-__v._M_value)); |
137 | else |
138 | return __v; |
139 | } |
140 | }; |
141 | |
142 | // valid values' definitions |
143 | inline constexpr partial_ordering |
144 | partial_ordering::less(__cmp_cat::_Ord::less); |
145 | |
146 | inline constexpr partial_ordering |
147 | partial_ordering::equivalent(__cmp_cat::_Ord::equivalent); |
148 | |
149 | inline constexpr partial_ordering |
150 | partial_ordering::greater(__cmp_cat::_Ord::greater); |
151 | |
152 | inline constexpr partial_ordering |
153 | partial_ordering::unordered(__cmp_cat::_Ncmp::_Unordered); |
154 | |
155 | class weak_ordering |
156 | { |
157 | __cmp_cat::type _M_value; |
158 | |
159 | constexpr explicit |
160 | weak_ordering(__cmp_cat::_Ord __v) noexcept : _M_value(__cmp_cat::type(__v)) |
161 | { } |
162 | |
163 | friend class strong_ordering; |
164 | |
165 | public: |
166 | // valid values |
167 | static const weak_ordering less; |
168 | static const weak_ordering equivalent; |
169 | static const weak_ordering greater; |
170 | |
171 | constexpr operator partial_ordering() const noexcept |
172 | { return partial_ordering(__cmp_cat::_Ord(_M_value)); } |
173 | |
174 | // comparisons |
175 | friend constexpr bool |
176 | operator==(weak_ordering __v, __cmp_cat::__unspec) noexcept |
177 | { return __v._M_value == 0; } |
178 | |
179 | friend constexpr bool |
180 | operator==(weak_ordering, weak_ordering) noexcept = default; |
181 | |
182 | friend constexpr bool |
183 | operator< (weak_ordering __v, __cmp_cat::__unspec) noexcept |
184 | { return __v._M_value < 0; } |
185 | |
186 | friend constexpr bool |
187 | operator> (weak_ordering __v, __cmp_cat::__unspec) noexcept |
188 | { return __v._M_value > 0; } |
189 | |
190 | friend constexpr bool |
191 | operator<=(weak_ordering __v, __cmp_cat::__unspec) noexcept |
192 | { return __v._M_value <= 0; } |
193 | |
194 | friend constexpr bool |
195 | operator>=(weak_ordering __v, __cmp_cat::__unspec) noexcept |
196 | { return __v._M_value >= 0; } |
197 | |
198 | friend constexpr bool |
199 | operator< (__cmp_cat::__unspec, weak_ordering __v) noexcept |
200 | { return 0 < __v._M_value; } |
201 | |
202 | friend constexpr bool |
203 | operator> (__cmp_cat::__unspec, weak_ordering __v) noexcept |
204 | { return 0 > __v._M_value; } |
205 | |
206 | friend constexpr bool |
207 | operator<=(__cmp_cat::__unspec, weak_ordering __v) noexcept |
208 | { return 0 <= __v._M_value; } |
209 | |
210 | friend constexpr bool |
211 | operator>=(__cmp_cat::__unspec, weak_ordering __v) noexcept |
212 | { return 0 >= __v._M_value; } |
213 | |
214 | friend constexpr weak_ordering |
215 | operator<=>(weak_ordering __v, __cmp_cat::__unspec) noexcept |
216 | { return __v; } |
217 | |
218 | friend constexpr weak_ordering |
219 | operator<=>(__cmp_cat::__unspec, weak_ordering __v) noexcept |
220 | { return weak_ordering(__cmp_cat::_Ord(-__v._M_value)); } |
221 | }; |
222 | |
223 | // valid values' definitions |
224 | inline constexpr weak_ordering |
225 | weak_ordering::less(__cmp_cat::_Ord::less); |
226 | |
227 | inline constexpr weak_ordering |
228 | weak_ordering::equivalent(__cmp_cat::_Ord::equivalent); |
229 | |
230 | inline constexpr weak_ordering |
231 | weak_ordering::greater(__cmp_cat::_Ord::greater); |
232 | |
233 | class strong_ordering |
234 | { |
235 | __cmp_cat::type _M_value; |
236 | |
237 | constexpr explicit |
238 | strong_ordering(__cmp_cat::_Ord __v) noexcept |
239 | : _M_value(__cmp_cat::type(__v)) |
240 | { } |
241 | |
242 | public: |
243 | // valid values |
244 | static const strong_ordering less; |
245 | static const strong_ordering equal; |
246 | static const strong_ordering equivalent; |
247 | static const strong_ordering greater; |
248 | |
249 | constexpr operator partial_ordering() const noexcept |
250 | { return partial_ordering(__cmp_cat::_Ord(_M_value)); } |
251 | |
252 | constexpr operator weak_ordering() const noexcept |
253 | { return weak_ordering(__cmp_cat::_Ord(_M_value)); } |
254 | |
255 | // comparisons |
256 | friend constexpr bool |
257 | operator==(strong_ordering __v, __cmp_cat::__unspec) noexcept |
258 | { return __v._M_value == 0; } |
259 | |
260 | friend constexpr bool |
261 | operator==(strong_ordering, strong_ordering) noexcept = default; |
262 | |
263 | friend constexpr bool |
264 | operator< (strong_ordering __v, __cmp_cat::__unspec) noexcept |
265 | { return __v._M_value < 0; } |
266 | |
267 | friend constexpr bool |
268 | operator> (strong_ordering __v, __cmp_cat::__unspec) noexcept |
269 | { return __v._M_value > 0; } |
270 | |
271 | friend constexpr bool |
272 | operator<=(strong_ordering __v, __cmp_cat::__unspec) noexcept |
273 | { return __v._M_value <= 0; } |
274 | |
275 | friend constexpr bool |
276 | operator>=(strong_ordering __v, __cmp_cat::__unspec) noexcept |
277 | { return __v._M_value >= 0; } |
278 | |
279 | friend constexpr bool |
280 | operator< (__cmp_cat::__unspec, strong_ordering __v) noexcept |
281 | { return 0 < __v._M_value; } |
282 | |
283 | friend constexpr bool |
284 | operator> (__cmp_cat::__unspec, strong_ordering __v) noexcept |
285 | { return 0 > __v._M_value; } |
286 | |
287 | friend constexpr bool |
288 | operator<=(__cmp_cat::__unspec, strong_ordering __v) noexcept |
289 | { return 0 <= __v._M_value; } |
290 | |
291 | friend constexpr bool |
292 | operator>=(__cmp_cat::__unspec, strong_ordering __v) noexcept |
293 | { return 0 >= __v._M_value; } |
294 | |
295 | friend constexpr strong_ordering |
296 | operator<=>(strong_ordering __v, __cmp_cat::__unspec) noexcept |
297 | { return __v; } |
298 | |
299 | friend constexpr strong_ordering |
300 | operator<=>(__cmp_cat::__unspec, strong_ordering __v) noexcept |
301 | { return strong_ordering(__cmp_cat::_Ord(-__v._M_value)); } |
302 | }; |
303 | |
304 | // valid values' definitions |
305 | inline constexpr strong_ordering |
306 | strong_ordering::less(__cmp_cat::_Ord::less); |
307 | |
308 | inline constexpr strong_ordering |
309 | strong_ordering::equal(__cmp_cat::_Ord::equivalent); |
310 | |
311 | inline constexpr strong_ordering |
312 | strong_ordering::equivalent(__cmp_cat::_Ord::equivalent); |
313 | |
314 | inline constexpr strong_ordering |
315 | strong_ordering::greater(__cmp_cat::_Ord::greater); |
316 | |
317 | |
318 | // named comparison functions |
319 | constexpr bool |
320 | is_eq(partial_ordering __cmp) noexcept |
321 | { return __cmp == 0; } |
322 | |
323 | constexpr bool |
324 | is_neq(partial_ordering __cmp) noexcept |
325 | { return __cmp != 0; } |
326 | |
327 | constexpr bool |
328 | is_lt (partial_ordering __cmp) noexcept |
329 | { return __cmp < 0; } |
330 | |
331 | constexpr bool |
332 | is_lteq(partial_ordering __cmp) noexcept |
333 | { return __cmp <= 0; } |
334 | |
335 | constexpr bool |
336 | is_gt (partial_ordering __cmp) noexcept |
337 | { return __cmp > 0; } |
338 | |
339 | constexpr bool |
340 | is_gteq(partial_ordering __cmp) noexcept |
341 | { return __cmp >= 0; } |
342 | |
343 | namespace __detail |
344 | { |
345 | template<typename _Tp> |
346 | inline constexpr unsigned __cmp_cat_id = 1; |
347 | template<> |
348 | inline constexpr unsigned __cmp_cat_id<partial_ordering> = 2; |
349 | template<> |
350 | inline constexpr unsigned __cmp_cat_id<weak_ordering> = 4; |
351 | template<> |
352 | inline constexpr unsigned __cmp_cat_id<strong_ordering> = 8; |
353 | |
354 | template<typename... _Ts> |
355 | constexpr auto __common_cmp_cat() |
356 | { |
357 | constexpr unsigned __cats = (__cmp_cat_id<_Ts> | ...); |
358 | // If any Ti is not a comparison category type, U is void. |
359 | if constexpr (__cats & 1) |
360 | return; |
361 | // Otherwise, if at least one Ti is std::partial_ordering, |
362 | // U is std::partial_ordering. |
363 | else if constexpr (bool(__cats & __cmp_cat_id<partial_ordering>)) |
364 | return partial_ordering::equivalent; |
365 | // Otherwise, if at least one Ti is std::weak_ordering, |
366 | // U is std::weak_ordering. |
367 | else if constexpr (bool(__cats & __cmp_cat_id<weak_ordering>)) |
368 | return weak_ordering::equivalent; |
369 | // Otherwise, U is std::strong_ordering. |
370 | else |
371 | return strong_ordering::equivalent; |
372 | } |
373 | } // namespace __detail |
374 | |
375 | // [cmp.common], common comparison category type |
376 | template<typename... _Ts> |
377 | struct common_comparison_category |
378 | { |
379 | using type = decltype(__detail::__common_cmp_cat<_Ts...>()); |
380 | }; |
381 | |
382 | // Partial specializations for one and zero argument cases. |
383 | |
384 | template<typename _Tp> |
385 | struct common_comparison_category<_Tp> |
386 | { using type = void; }; |
387 | |
388 | template<> |
389 | struct common_comparison_category<partial_ordering> |
390 | { using type = partial_ordering; }; |
391 | |
392 | template<> |
393 | struct common_comparison_category<weak_ordering> |
394 | { using type = weak_ordering; }; |
395 | |
396 | template<> |
397 | struct common_comparison_category<strong_ordering> |
398 | { using type = strong_ordering; }; |
399 | |
400 | template<> |
401 | struct common_comparison_category<> |
402 | { using type = strong_ordering; }; |
403 | |
404 | template<typename... _Ts> |
405 | using common_comparison_category_t |
406 | = typename common_comparison_category<_Ts...>::type; |
407 | |
408 | #if __cpp_lib_concepts |
409 | namespace __detail |
410 | { |
411 | template<typename _Tp, typename _Cat> |
412 | concept __compares_as |
413 | = same_as<common_comparison_category_t<_Tp, _Cat>, _Cat>; |
414 | } // namespace __detail |
415 | |
416 | // [cmp.concept], concept three_way_comparable |
417 | template<typename _Tp, typename _Cat = partial_ordering> |
418 | concept three_way_comparable |
419 | = __detail::__weakly_eq_cmp_with<_Tp, _Tp> |
420 | && __detail::__partially_ordered_with<_Tp, _Tp> |
421 | && requires(const remove_reference_t<_Tp>& __a, |
422 | const remove_reference_t<_Tp>& __b) |
423 | { |
424 | { __a <=> __b } -> __detail::__compares_as<_Cat>; |
425 | }; |
426 | |
427 | template<typename _Tp, typename _Up, typename _Cat = partial_ordering> |
428 | concept three_way_comparable_with |
429 | = three_way_comparable<_Tp, _Cat> |
430 | && three_way_comparable<_Up, _Cat> |
431 | && common_reference_with<const remove_reference_t<_Tp>&, |
432 | const remove_reference_t<_Up>&> |
433 | && three_way_comparable< |
434 | common_reference_t<const remove_reference_t<_Tp>&, |
435 | const remove_reference_t<_Up>&>, _Cat> |
436 | && __detail::__weakly_eq_cmp_with<_Tp, _Up> |
437 | && __detail::__partially_ordered_with<_Tp, _Up> |
438 | && requires(const remove_reference_t<_Tp>& __t, |
439 | const remove_reference_t<_Up>& __u) |
440 | { |
441 | { __t <=> __u } -> __detail::__compares_as<_Cat>; |
442 | { __u <=> __t } -> __detail::__compares_as<_Cat>; |
443 | }; |
444 | |
445 | namespace __detail |
446 | { |
447 | template<typename _Tp, typename _Up> |
448 | using __cmp3way_res_t |
449 | = decltype(std::declval<_Tp>() <=> std::declval<_Up>()); |
450 | |
451 | // Implementation of std::compare_three_way_result. |
452 | // It is undefined for a program to add specializations of |
453 | // std::compare_three_way_result, so the std::compare_three_way_result_t |
454 | // alias ignores std::compare_three_way_result and uses |
455 | // __detail::__cmp3way_res_impl directly instead. |
456 | template<typename _Tp, typename _Up> |
457 | struct __cmp3way_res_impl |
458 | { }; |
459 | |
460 | template<typename _Tp, typename _Up> |
461 | requires requires { typename __cmp3way_res_t<__cref<_Tp>, __cref<_Up>>; } |
462 | struct __cmp3way_res_impl<_Tp, _Up> |
463 | { |
464 | using type = __cmp3way_res_t<__cref<_Tp>, __cref<_Up>>; |
465 | }; |
466 | } // namespace __detail |
467 | |
468 | /// [cmp.result], result of three-way comparison |
469 | template<typename _Tp, typename _Up = _Tp> |
470 | struct compare_three_way_result |
471 | : __detail::__cmp3way_res_impl<_Tp, _Up> |
472 | { }; |
473 | |
474 | /// [cmp.result], result of three-way comparison |
475 | template<typename _Tp, typename _Up = _Tp> |
476 | using compare_three_way_result_t |
477 | = typename __detail::__cmp3way_res_impl<_Tp, _Up>::type; |
478 | |
479 | namespace __detail |
480 | { |
481 | // BUILTIN-PTR-THREE-WAY(T, U) |
482 | // This determines whether t <=> u results in a call to a built-in |
483 | // operator<=> comparing pointers. It doesn't work for function pointers |
484 | // (PR 93628). |
485 | template<typename _Tp, typename _Up> |
486 | concept __3way_builtin_ptr_cmp |
487 | = requires(_Tp&& __t, _Up&& __u) |
488 | { static_cast<_Tp&&>(__t) <=> static_cast<_Up&&>(__u); } |
489 | && convertible_to<_Tp, const volatile void*> |
490 | && convertible_to<_Up, const volatile void*> |
491 | && ! requires(_Tp&& __t, _Up&& __u) |
492 | { operator<=>(static_cast<_Tp&&>(__t), static_cast<_Up&&>(__u)); } |
493 | && ! requires(_Tp&& __t, _Up&& __u) |
494 | { static_cast<_Tp&&>(__t).operator<=>(static_cast<_Up&&>(__u)); }; |
495 | } // namespace __detail |
496 | |
497 | // _GLIBCXX_RESOLVE_LIB_DEFECTS |
498 | // 3530 BUILTIN-PTR-MEOW should not opt the type out of syntactic checks |
499 | |
500 | // [cmp.object], typename compare_three_way |
501 | struct compare_three_way |
502 | { |
503 | template<typename _Tp, typename _Up> |
504 | requires three_way_comparable_with<_Tp, _Up> |
505 | constexpr auto |
506 | operator()(_Tp&& __t, _Up&& __u) const |
507 | noexcept(noexcept(std::declval<_Tp>() <=> std::declval<_Up>())) |
508 | { |
509 | if constexpr (__detail::__3way_builtin_ptr_cmp<_Tp, _Up>) |
510 | { |
511 | auto __pt = static_cast<const volatile void*>(__t); |
512 | auto __pu = static_cast<const volatile void*>(__u); |
513 | if (__builtin_is_constant_evaluated()) |
514 | return __pt <=> __pu; |
515 | auto __it = reinterpret_cast<__UINTPTR_TYPE__>(__pt); |
516 | auto __iu = reinterpret_cast<__UINTPTR_TYPE__>(__pu); |
517 | return __it <=> __iu; |
518 | } |
519 | else |
520 | return static_cast<_Tp&&>(__t) <=> static_cast<_Up&&>(__u); |
521 | } |
522 | |
523 | using is_transparent = void; |
524 | }; |
525 | |
526 | namespace __cmp_cust |
527 | { |
528 | template<floating_point _Tp> |
529 | constexpr weak_ordering |
530 | __fp_weak_ordering(_Tp __e, _Tp __f) |
531 | { |
532 | // Returns an integer with the same sign as the argument, and magnitude |
533 | // indicating the classification: zero=1 subnorm=2 norm=3 inf=4 nan=5 |
534 | auto __cat = [](_Tp __fp) -> int { |
535 | const int __sign = __builtin_signbit(__fp) ? -1 : 1; |
536 | if (__builtin_isnormal(__fp)) |
537 | return (__fp == 0 ? 1 : 3) * __sign; |
538 | if (__builtin_isnan(__fp)) |
539 | return 5 * __sign; |
540 | if (int __inf = __builtin_isinf_sign(__fp)) |
541 | return 4 * __inf; |
542 | return 2 * __sign; |
543 | }; |
544 | |
545 | auto __po = __e <=> __f; |
546 | if (is_lt(__po)) |
547 | return weak_ordering::less; |
548 | else if (is_gt(__po)) |
549 | return weak_ordering::greater; |
550 | else if (__po == partial_ordering::equivalent) |
551 | return weak_ordering::equivalent; |
552 | else // unordered, at least one argument is NaN |
553 | { |
554 | // return -1 for negative nan, +1 for positive nan, 0 otherwise. |
555 | auto __isnan_sign = [](_Tp __fp) -> int { |
556 | return __builtin_isnan(__fp) |
557 | ? __builtin_signbit(__fp) ? -1 : 1 |
558 | : 0; |
559 | }; |
560 | auto __ord = __isnan_sign(__e) <=> __isnan_sign(__f); |
561 | if (is_eq(__ord)) |
562 | return weak_ordering::equivalent; |
563 | else if (is_lt(__ord)) |
564 | return weak_ordering::less; |
565 | else |
566 | return weak_ordering::greater; |
567 | } |
568 | } |
569 | |
570 | template<typename _Tp, typename _Up> |
571 | concept __adl_strong = requires(_Tp&& __t, _Up&& __u) |
572 | { |
573 | strong_ordering(strong_order(static_cast<_Tp&&>(__t), |
574 | static_cast<_Up&&>(__u))); |
575 | }; |
576 | |
577 | template<typename _Tp, typename _Up> |
578 | concept __adl_weak = requires(_Tp&& __t, _Up&& __u) |
579 | { |
580 | weak_ordering(weak_order(static_cast<_Tp&&>(__t), |
581 | static_cast<_Up&&>(__u))); |
582 | }; |
583 | |
584 | template<typename _Tp, typename _Up> |
585 | concept __adl_partial = requires(_Tp&& __t, _Up&& __u) |
586 | { |
587 | partial_ordering(partial_order(static_cast<_Tp&&>(__t), |
588 | static_cast<_Up&&>(__u))); |
589 | }; |
590 | |
591 | template<typename _Ord, typename _Tp, typename _Up> |
592 | concept __cmp3way = requires(_Tp&& __t, _Up&& __u, compare_three_way __c) |
593 | { |
594 | _Ord(__c(static_cast<_Tp&&>(__t), static_cast<_Up&&>(__u))); |
595 | }; |
596 | |
597 | template<typename _Tp, typename _Up> |
598 | concept __strongly_ordered |
599 | = __adl_strong<_Tp, _Up> |
600 | // FIXME: || floating_point<remove_reference_t<_Tp>> |
601 | || __cmp3way<strong_ordering, _Tp, _Up>; |
602 | |
603 | template<typename _Tp, typename _Up> |
604 | concept __decayed_same_as = same_as<decay_t<_Tp>, decay_t<_Up>>; |
605 | |
606 | class _Strong_order |
607 | { |
608 | template<typename _Tp, typename _Up> |
609 | static constexpr bool |
610 | _S_noexcept() |
611 | { |
612 | if constexpr (floating_point<decay_t<_Tp>>) |
613 | return true; |
614 | else if constexpr (__adl_strong<_Tp, _Up>) |
615 | return noexcept(strong_ordering(strong_order(std::declval<_Tp>(), |
616 | std::declval<_Up>()))); |
617 | else if constexpr (__cmp3way<strong_ordering, _Tp, _Up>) |
618 | return noexcept(compare_three_way()(std::declval<_Tp>(), |
619 | std::declval<_Up>())); |
620 | } |
621 | |
622 | friend class _Weak_order; |
623 | friend class _Strong_fallback; |
624 | |
625 | public: |
626 | template<typename _Tp, __decayed_same_as<_Tp> _Up> |
627 | requires __strongly_ordered<_Tp, _Up> |
628 | constexpr strong_ordering |
629 | operator()(_Tp&& __e, _Up&& __f) const |
630 | noexcept(_S_noexcept<_Tp, _Up>()) |
631 | { |
632 | /* FIXME: |
633 | if constexpr (floating_point<decay_t<_Tp>>) |
634 | return __cmp_cust::__fp_strong_order(__e, __f); |
635 | else */ if constexpr (__adl_strong<_Tp, _Up>) |
636 | return strong_ordering(strong_order(static_cast<_Tp&&>(__e), |
637 | static_cast<_Up&&>(__f))); |
638 | else if constexpr (__cmp3way<strong_ordering, _Tp, _Up>) |
639 | return compare_three_way()(static_cast<_Tp&&>(__e), |
640 | static_cast<_Up&&>(__f)); |
641 | } |
642 | }; |
643 | |
644 | template<typename _Tp, typename _Up> |
645 | concept __weakly_ordered |
646 | = floating_point<remove_reference_t<_Tp>> |
647 | || __adl_weak<_Tp, _Up> |
648 | || __cmp3way<weak_ordering, _Tp, _Up> |
649 | || __strongly_ordered<_Tp, _Up>; |
650 | |
651 | class _Weak_order |
652 | { |
653 | template<typename _Tp, typename _Up> |
654 | static constexpr bool |
655 | _S_noexcept() |
656 | { |
657 | if constexpr (floating_point<decay_t<_Tp>>) |
658 | return true; |
659 | else if constexpr (__adl_weak<_Tp, _Up>) |
660 | return noexcept(weak_ordering(weak_order(std::declval<_Tp>(), |
661 | std::declval<_Up>()))); |
662 | else if constexpr (__cmp3way<weak_ordering, _Tp, _Up>) |
663 | return noexcept(compare_three_way()(std::declval<_Tp>(), |
664 | std::declval<_Up>())); |
665 | else if constexpr (__strongly_ordered<_Tp, _Up>) |
666 | return _Strong_order::_S_noexcept<_Tp, _Up>(); |
667 | } |
668 | |
669 | friend class _Partial_order; |
670 | friend class _Weak_fallback; |
671 | |
672 | public: |
673 | template<typename _Tp, __decayed_same_as<_Tp> _Up> |
674 | requires __weakly_ordered<_Tp, _Up> |
675 | constexpr weak_ordering |
676 | operator()(_Tp&& __e, _Up&& __f) const |
677 | noexcept(_S_noexcept<_Tp, _Up>()) |
678 | { |
679 | if constexpr (floating_point<decay_t<_Tp>>) |
680 | return __cmp_cust::__fp_weak_ordering(__e, __f); |
681 | else if constexpr (__adl_weak<_Tp, _Up>) |
682 | return weak_ordering(weak_order(static_cast<_Tp&&>(__e), |
683 | static_cast<_Up&&>(__f))); |
684 | else if constexpr (__cmp3way<weak_ordering, _Tp, _Up>) |
685 | return compare_three_way()(static_cast<_Tp&&>(__e), |
686 | static_cast<_Up&&>(__f)); |
687 | else if constexpr (__strongly_ordered<_Tp, _Up>) |
688 | return _Strong_order{}(static_cast<_Tp&&>(__e), |
689 | static_cast<_Up&&>(__f)); |
690 | } |
691 | }; |
692 | |
693 | template<typename _Tp, typename _Up> |
694 | concept __partially_ordered |
695 | = __adl_partial<_Tp, _Up> |
696 | || __cmp3way<partial_ordering, _Tp, _Up> |
697 | || __weakly_ordered<_Tp, _Up>; |
698 | |
699 | class _Partial_order |
700 | { |
701 | template<typename _Tp, typename _Up> |
702 | static constexpr bool |
703 | _S_noexcept() |
704 | { |
705 | if constexpr (__adl_partial<_Tp, _Up>) |
706 | return noexcept(partial_ordering(partial_order(std::declval<_Tp>(), |
707 | std::declval<_Up>()))); |
708 | else if constexpr (__cmp3way<partial_ordering, _Tp, _Up>) |
709 | return noexcept(compare_three_way()(std::declval<_Tp>(), |
710 | std::declval<_Up>())); |
711 | else if constexpr (__weakly_ordered<_Tp, _Up>) |
712 | return _Weak_order::_S_noexcept<_Tp, _Up>(); |
713 | } |
714 | |
715 | friend class _Partial_fallback; |
716 | |
717 | public: |
718 | template<typename _Tp, __decayed_same_as<_Tp> _Up> |
719 | requires __partially_ordered<_Tp, _Up> |
720 | constexpr partial_ordering |
721 | operator()(_Tp&& __e, _Up&& __f) const |
722 | noexcept(_S_noexcept<_Tp, _Up>()) |
723 | { |
724 | if constexpr (__adl_partial<_Tp, _Up>) |
725 | return partial_ordering(partial_order(static_cast<_Tp&&>(__e), |
726 | static_cast<_Up&&>(__f))); |
727 | else if constexpr (__cmp3way<partial_ordering, _Tp, _Up>) |
728 | return compare_three_way()(static_cast<_Tp&&>(__e), |
729 | static_cast<_Up&&>(__f)); |
730 | else if constexpr (__weakly_ordered<_Tp, _Up>) |
731 | return _Weak_order{}(static_cast<_Tp&&>(__e), |
732 | static_cast<_Up&&>(__f)); |
733 | } |
734 | }; |
735 | |
736 | template<typename _Tp, typename _Up> |
737 | concept __op_eq_lt = requires(_Tp&& __t, _Up&& __u) |
738 | { |
739 | { static_cast<_Tp&&>(__t) == static_cast<_Up&&>(__u) } |
740 | -> convertible_to<bool>; |
741 | { static_cast<_Tp&&>(__t) < static_cast<_Up&&>(__u) } |
742 | -> convertible_to<bool>; |
743 | }; |
744 | |
745 | class _Strong_fallback |
746 | { |
747 | template<typename _Tp, typename _Up> |
748 | static constexpr bool |
749 | _S_noexcept() |
750 | { |
751 | if constexpr (__strongly_ordered<_Tp, _Up>) |
752 | return _Strong_order::_S_noexcept<_Tp, _Up>(); |
753 | else |
754 | return noexcept(bool(std::declval<_Tp>() == std::declval<_Up>())) |
755 | && noexcept(bool(std::declval<_Tp>() < std::declval<_Up>())); |
756 | } |
757 | |
758 | public: |
759 | template<typename _Tp, __decayed_same_as<_Tp> _Up> |
760 | requires __strongly_ordered<_Tp, _Up> || __op_eq_lt<_Tp, _Up> |
761 | constexpr strong_ordering |
762 | operator()(_Tp&& __e, _Up&& __f) const |
763 | noexcept(_S_noexcept<_Tp, _Up>()) |
764 | { |
765 | if constexpr (__strongly_ordered<_Tp, _Up>) |
766 | return _Strong_order{}(static_cast<_Tp&&>(__e), |
767 | static_cast<_Up&&>(__f)); |
768 | else // __op_eq_lt<_Tp, _Up> |
769 | return static_cast<_Tp&&>(__e) == static_cast<_Up&&>(__f) |
770 | ? strong_ordering::equal |
771 | : static_cast<_Tp&&>(__e) < static_cast<_Up&&>(__f) |
772 | ? strong_ordering::less |
773 | : strong_ordering::greater; |
774 | } |
775 | }; |
776 | |
777 | class _Weak_fallback |
778 | { |
779 | template<typename _Tp, typename _Up> |
780 | static constexpr bool |
781 | _S_noexcept() |
782 | { |
783 | if constexpr (__weakly_ordered<_Tp, _Up>) |
784 | return _Weak_order::_S_noexcept<_Tp, _Up>(); |
785 | else |
786 | return noexcept(bool(std::declval<_Tp>() == std::declval<_Up>())) |
787 | && noexcept(bool(std::declval<_Tp>() < std::declval<_Up>())); |
788 | } |
789 | |
790 | public: |
791 | template<typename _Tp, __decayed_same_as<_Tp> _Up> |
792 | requires __weakly_ordered<_Tp, _Up> || __op_eq_lt<_Tp, _Up> |
793 | constexpr weak_ordering |
794 | operator()(_Tp&& __e, _Up&& __f) const |
795 | noexcept(_S_noexcept<_Tp, _Up>()) |
796 | { |
797 | if constexpr (__weakly_ordered<_Tp, _Up>) |
798 | return _Weak_order{}(static_cast<_Tp&&>(__e), |
799 | static_cast<_Up&&>(__f)); |
800 | else // __op_eq_lt<_Tp, _Up> |
801 | return static_cast<_Tp&&>(__e) == static_cast<_Up&&>(__f) |
802 | ? weak_ordering::equivalent |
803 | : static_cast<_Tp&&>(__e) < static_cast<_Up&&>(__f) |
804 | ? weak_ordering::less |
805 | : weak_ordering::greater; |
806 | } |
807 | }; |
808 | |
809 | // _GLIBCXX_RESOLVE_LIB_DEFECTS |
810 | // 3465. compare_partial_order_fallback requires F < E |
811 | template<typename _Tp, typename _Up> |
812 | concept __op_eq_lt_lt = __op_eq_lt<_Tp, _Up> |
813 | && requires(_Tp&& __t, _Up&& __u) |
814 | { |
815 | { static_cast<_Up&&>(__u) < static_cast<_Tp&&>(__t) } |
816 | -> convertible_to<bool>; |
817 | }; |
818 | |
819 | class _Partial_fallback |
820 | { |
821 | template<typename _Tp, typename _Up> |
822 | static constexpr bool |
823 | _S_noexcept() |
824 | { |
825 | if constexpr (__partially_ordered<_Tp, _Up>) |
826 | return _Partial_order::_S_noexcept<_Tp, _Up>(); |
827 | else |
828 | return noexcept(bool(std::declval<_Tp>() == std::declval<_Up>())) |
829 | && noexcept(bool(std::declval<_Tp>() < std::declval<_Up>())); |
830 | } |
831 | |
832 | public: |
833 | template<typename _Tp, __decayed_same_as<_Tp> _Up> |
834 | requires __partially_ordered<_Tp, _Up> || __op_eq_lt_lt<_Tp, _Up> |
835 | constexpr partial_ordering |
836 | operator()(_Tp&& __e, _Up&& __f) const |
837 | noexcept(_S_noexcept<_Tp, _Up>()) |
838 | { |
839 | if constexpr (__partially_ordered<_Tp, _Up>) |
840 | return _Partial_order{}(static_cast<_Tp&&>(__e), |
841 | static_cast<_Up&&>(__f)); |
842 | else // __op_eq_lt_lt<_Tp, _Up> |
843 | return static_cast<_Tp&&>(__e) == static_cast<_Up&&>(__f) |
844 | ? partial_ordering::equivalent |
845 | : static_cast<_Tp&&>(__e) < static_cast<_Up&&>(__f) |
846 | ? partial_ordering::less |
847 | : static_cast<_Up&&>(__f) < static_cast<_Tp&&>(__e) |
848 | ? partial_ordering::greater |
849 | : partial_ordering::unordered; |
850 | } |
851 | }; |
852 | } // namespace __cmp_cust |
853 | |
854 | // [cmp.alg], comparison algorithms |
855 | inline namespace __cmp_alg |
856 | { |
857 | inline constexpr __cmp_cust::_Strong_order strong_order{}; |
858 | |
859 | inline constexpr __cmp_cust::_Weak_order weak_order{}; |
860 | |
861 | inline constexpr __cmp_cust::_Partial_order partial_order{}; |
862 | |
863 | inline constexpr __cmp_cust::_Strong_fallback |
864 | compare_strong_order_fallback{}; |
865 | |
866 | inline constexpr __cmp_cust::_Weak_fallback |
867 | compare_weak_order_fallback{}; |
868 | |
869 | inline constexpr __cmp_cust::_Partial_fallback |
870 | compare_partial_order_fallback{}; |
871 | } |
872 | |
873 | namespace __detail |
874 | { |
875 | // [expos.only.func] synth-three-way |
876 | inline constexpr struct _Synth3way |
877 | { |
878 | template<typename _Tp, typename _Up> |
879 | static constexpr bool |
880 | _S_noexcept(const _Tp* __t = nullptr, const _Up* __u = nullptr) |
881 | { |
882 | if constexpr (three_way_comparable_with<_Tp, _Up>) |
883 | return noexcept(*__t <=> *__u); |
884 | else |
885 | return noexcept(*__t < *__u) && noexcept(*__u < *__t); |
886 | } |
887 | |
888 | template<typename _Tp, typename _Up> |
889 | constexpr auto |
890 | operator()(const _Tp& __t, const _Up& __u) const |
891 | noexcept(_S_noexcept<_Tp, _Up>()) |
892 | requires requires |
893 | { |
894 | { __t < __u } -> __boolean_testable; |
895 | { __u < __t } -> __boolean_testable; |
896 | } |
897 | { |
898 | if constexpr (three_way_comparable_with<_Tp, _Up>) |
899 | return __t <=> __u; |
900 | else |
901 | { |
902 | if (__t < __u) |
903 | return weak_ordering::less; |
904 | else if (__u < __t) |
905 | return weak_ordering::greater; |
906 | else |
907 | return weak_ordering::equivalent; |
908 | } |
909 | } |
910 | } __synth3way = {}; |
911 | |
912 | // [expos.only.func] synth-three-way-result |
913 | template<typename _Tp, typename _Up = _Tp> |
914 | using __synth3way_t |
915 | = decltype(__detail::__synth3way(std::declval<_Tp&>(), |
916 | std::declval<_Up&>())); |
917 | } // namespace __detail |
918 | #endif // concepts |
919 | } // namespace std |
920 | |
921 | #pragma GCC visibility pop |
922 | |
923 | #endif // C++20 |
924 | |
925 | #endif // _COMPARE |
926 | |