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 
45namespace 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