source: Daodan/MSYS2/mingw32/include/c++/11.2.0/compare@ 1194

Last change on this file since 1194 was 1166, checked in by rossy, 3 years ago

Daodan: Replace MinGW build env with an up-to-date MSYS2 env

File size: 27.5 KB
Line 
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 class _Strong_order
604 {
605 template<typename _Tp, typename _Up>
606 static constexpr bool
607 _S_noexcept()
608 {
609 if constexpr (floating_point<decay_t<_Tp>>)
610 return true;
611 else if constexpr (__adl_strong<_Tp, _Up>)
612 return noexcept(strong_ordering(strong_order(std::declval<_Tp>(),
613 std::declval<_Up>())));
614 else if constexpr (__cmp3way<strong_ordering, _Tp, _Up>)
615 return noexcept(compare_three_way()(std::declval<_Tp>(),
616 std::declval<_Up>()));
617 }
618
619 friend class _Weak_order;
620 friend class _Strong_fallback;
621
622 public:
623 template<typename _Tp, typename _Up>
624 requires __strongly_ordered<_Tp, _Up>
625 constexpr strong_ordering
626 operator()(_Tp&& __e, _Up&& __f) const
627 noexcept(_S_noexcept<_Tp, _Up>())
628 {
629 static_assert(same_as<decay_t<_Tp>, decay_t<_Up>>);
630
631 /* FIXME:
632 if constexpr (floating_point<decay_t<_Tp>>)
633 return __cmp_cust::__fp_strong_order(__e, __f);
634 else */ if constexpr (__adl_strong<_Tp, _Up>)
635 return strong_ordering(strong_order(static_cast<_Tp&&>(__e),
636 static_cast<_Up&&>(__f)));
637 else if constexpr (__cmp3way<strong_ordering, _Tp, _Up>)
638 return compare_three_way()(static_cast<_Tp&&>(__e),
639 static_cast<_Up&&>(__f));
640 }
641 };
642
643 template<typename _Tp, typename _Up>
644 concept __weakly_ordered
645 = floating_point<remove_reference_t<_Tp>>
646 || __adl_weak<_Tp, _Up>
647 || __cmp3way<weak_ordering, _Tp, _Up>
648 || __strongly_ordered<_Tp, _Up>;
649
650 class _Weak_order
651 {
652 template<typename _Tp, typename _Up>
653 static constexpr bool
654 _S_noexcept()
655 {
656 if constexpr (floating_point<decay_t<_Tp>>)
657 return true;
658 else if constexpr (__adl_weak<_Tp, _Up>)
659 return noexcept(weak_ordering(weak_order(std::declval<_Tp>(),
660 std::declval<_Up>())));
661 else if constexpr (__cmp3way<weak_ordering, _Tp, _Up>)
662 return noexcept(compare_three_way()(std::declval<_Tp>(),
663 std::declval<_Up>()));
664 else if constexpr (__strongly_ordered<_Tp, _Up>)
665 return _Strong_order::_S_noexcept<_Tp, _Up>();
666 }
667
668 friend class _Partial_order;
669 friend class _Weak_fallback;
670
671 public:
672 template<typename _Tp, typename _Up>
673 requires __weakly_ordered<_Tp, _Up>
674 constexpr weak_ordering
675 operator()(_Tp&& __e, _Up&& __f) const
676 noexcept(_S_noexcept<_Tp, _Up>())
677 {
678 static_assert(same_as<decay_t<_Tp>, decay_t<_Up>>);
679
680 if constexpr (floating_point<decay_t<_Tp>>)
681 return __cmp_cust::__fp_weak_ordering(__e, __f);
682 else if constexpr (__adl_weak<_Tp, _Up>)
683 return weak_ordering(weak_order(static_cast<_Tp&&>(__e),
684 static_cast<_Up&&>(__f)));
685 else if constexpr (__cmp3way<weak_ordering, _Tp, _Up>)
686 return compare_three_way()(static_cast<_Tp&&>(__e),
687 static_cast<_Up&&>(__f));
688 else if constexpr (__strongly_ordered<_Tp, _Up>)
689 return _Strong_order{}(static_cast<_Tp&&>(__e),
690 static_cast<_Up&&>(__f));
691 }
692 };
693
694 template<typename _Tp, typename _Up>
695 concept __partially_ordered
696 = __adl_partial<_Tp, _Up>
697 || __cmp3way<partial_ordering, _Tp, _Up>
698 || __weakly_ordered<_Tp, _Up>;
699
700 class _Partial_order
701 {
702 template<typename _Tp, typename _Up>
703 static constexpr bool
704 _S_noexcept()
705 {
706 if constexpr (__adl_partial<_Tp, _Up>)
707 return noexcept(partial_ordering(partial_order(std::declval<_Tp>(),
708 std::declval<_Up>())));
709 else if constexpr (__cmp3way<partial_ordering, _Tp, _Up>)
710 return noexcept(compare_three_way()(std::declval<_Tp>(),
711 std::declval<_Up>()));
712 else if constexpr (__weakly_ordered<_Tp, _Up>)
713 return _Weak_order::_S_noexcept<_Tp, _Up>();
714 }
715
716 friend class _Partial_fallback;
717
718 public:
719 template<typename _Tp, typename _Up>
720 requires __partially_ordered<_Tp, _Up>
721 constexpr partial_ordering
722 operator()(_Tp&& __e, _Up&& __f) const
723 noexcept(_S_noexcept<_Tp, _Up>())
724 {
725 static_assert(same_as<decay_t<_Tp>, decay_t<_Up>>);
726
727 if constexpr (__adl_partial<_Tp, _Up>)
728 return partial_ordering(partial_order(static_cast<_Tp&&>(__e),
729 static_cast<_Up&&>(__f)));
730 else if constexpr (__cmp3way<partial_ordering, _Tp, _Up>)
731 return compare_three_way()(static_cast<_Tp&&>(__e),
732 static_cast<_Up&&>(__f));
733 else if constexpr (__weakly_ordered<_Tp, _Up>)
734 return _Weak_order{}(static_cast<_Tp&&>(__e),
735 static_cast<_Up&&>(__f));
736 }
737 };
738
739 template<typename _Tp, typename _Up>
740 concept __op_eq_lt = requires(_Tp&& __t, _Up&& __u)
741 {
742 { static_cast<_Tp&&>(__t) == static_cast<_Up&&>(__u) }
743 -> convertible_to<bool>;
744 { static_cast<_Tp&&>(__t) < static_cast<_Up&&>(__u) }
745 -> convertible_to<bool>;
746 };
747
748 class _Strong_fallback
749 {
750 template<typename _Tp, typename _Up>
751 static constexpr bool
752 _S_noexcept()
753 {
754 if constexpr (__strongly_ordered<_Tp, _Up>)
755 return _Strong_order::_S_noexcept<_Tp, _Up>();
756 else
757 return noexcept(bool(std::declval<_Tp>() == std::declval<_Up>()))
758 && noexcept(bool(std::declval<_Tp>() < std::declval<_Up>()));
759 }
760
761 public:
762 template<typename _Tp, typename _Up>
763 requires __strongly_ordered<_Tp, _Up> || __op_eq_lt<_Tp, _Up>
764 constexpr decltype(auto)
765 operator()(_Tp&& __e, _Up&& __f) const
766 noexcept(_S_noexcept<_Tp, _Up>())
767 {
768 static_assert(same_as<decay_t<_Tp>, decay_t<_Up>>);
769
770 if constexpr (__strongly_ordered<_Tp, _Up>)
771 return _Strong_order{}(static_cast<_Tp&&>(__e),
772 static_cast<_Up&&>(__f));
773 else if constexpr (__op_eq_lt<_Tp, _Up>)
774 return static_cast<_Tp&&>(__e) == static_cast<_Up&&>(__f)
775 ? strong_ordering::equal
776 : static_cast<_Tp&&>(__e) < static_cast<_Up&&>(__f)
777 ? strong_ordering::less
778 : strong_ordering::greater;
779 }
780 };
781
782 class _Weak_fallback
783 {
784 template<typename _Tp, typename _Up>
785 static constexpr bool
786 _S_noexcept()
787 {
788 if constexpr (__weakly_ordered<_Tp, _Up>)
789 return _Weak_order::_S_noexcept<_Tp, _Up>();
790 else
791 return noexcept(bool(std::declval<_Tp>() == std::declval<_Up>()))
792 && noexcept(bool(std::declval<_Tp>() < std::declval<_Up>()));
793 }
794
795 public:
796 template<typename _Tp, typename _Up>
797 requires __weakly_ordered<_Tp, _Up> || __op_eq_lt<_Tp, _Up>
798 constexpr decltype(auto)
799 operator()(_Tp&& __e, _Up&& __f) const
800 noexcept(_S_noexcept<_Tp, _Up>())
801 {
802 static_assert(same_as<decay_t<_Tp>, decay_t<_Up>>);
803
804 if constexpr (__weakly_ordered<_Tp, _Up>)
805 return _Weak_order{}(static_cast<_Tp&&>(__e),
806 static_cast<_Up&&>(__f));
807 else if constexpr (__op_eq_lt<_Tp, _Up>)
808 return static_cast<_Tp&&>(__e) == static_cast<_Up&&>(__f)
809 ? weak_ordering::equivalent
810 : static_cast<_Tp&&>(__e) < static_cast<_Up&&>(__f)
811 ? weak_ordering::less
812 : weak_ordering::greater;
813 }
814 };
815
816 class _Partial_fallback
817 {
818 template<typename _Tp, typename _Up>
819 static constexpr bool
820 _S_noexcept()
821 {
822 if constexpr (__partially_ordered<_Tp, _Up>)
823 return _Partial_order::_S_noexcept<_Tp, _Up>();
824 else
825 return noexcept(bool(std::declval<_Tp>() == std::declval<_Up>()))
826 && noexcept(bool(std::declval<_Tp>() < std::declval<_Up>()));
827 }
828
829 public:
830 template<typename _Tp, typename _Up>
831 requires __partially_ordered<_Tp, _Up> || __op_eq_lt<_Tp, _Up>
832 constexpr decltype(auto)
833 operator()(_Tp&& __e, _Up&& __f) const
834 noexcept(_S_noexcept<_Tp, _Up>())
835 {
836 static_assert(same_as<decay_t<_Tp>, decay_t<_Up>>);
837
838 if constexpr (__partially_ordered<_Tp, _Up>)
839 return _Partial_order{}(static_cast<_Tp&&>(__e),
840 static_cast<_Up&&>(__f));
841 else if constexpr (__op_eq_lt<_Tp, _Up>)
842 return static_cast<_Tp&&>(__e) == static_cast<_Up&&>(__f)
843 ? partial_ordering::equivalent
844 : static_cast<_Tp&&>(__e) < static_cast<_Up&&>(__f)
845 ? partial_ordering::less
846 : static_cast<_Up&&>(__f) < static_cast<_Tp&&>(__e)
847 ? partial_ordering::greater
848 : partial_ordering::unordered;
849 }
850 };
851 } // namespace __cmp_cust
852
853 // [cmp.alg], comparison algorithms
854 inline namespace __cmp_alg
855 {
856 inline constexpr __cmp_cust::_Strong_order strong_order{};
857
858 inline constexpr __cmp_cust::_Weak_order weak_order{};
859
860 inline constexpr __cmp_cust::_Partial_order partial_order{};
861
862 inline constexpr __cmp_cust::_Strong_fallback
863 compare_strong_order_fallback{};
864
865 inline constexpr __cmp_cust::_Weak_fallback
866 compare_weak_order_fallback{};
867
868 inline constexpr __cmp_cust::_Partial_fallback
869 compare_partial_order_fallback{};
870 }
871
872 namespace __detail
873 {
874 // [expos.only.func] synth-three-way
875 inline constexpr struct _Synth3way
876 {
877 template<typename _Tp, typename _Up>
878 static constexpr bool
879 _S_noexcept(const _Tp* __t = nullptr, const _Up* __u = nullptr)
880 {
881 if constexpr (three_way_comparable_with<_Tp, _Up>)
882 return noexcept(*__t <=> *__u);
883 else
884 return noexcept(*__t < *__u) && noexcept(*__u < *__t);
885 }
886
887 template<typename _Tp, typename _Up>
888 constexpr auto
889 operator()(const _Tp& __t, const _Up& __u) const
890 noexcept(_S_noexcept<_Tp, _Up>())
891 requires requires
892 {
893 { __t < __u } -> __boolean_testable;
894 { __u < __t } -> __boolean_testable;
895 }
896 {
897 if constexpr (three_way_comparable_with<_Tp, _Up>)
898 return __t <=> __u;
899 else
900 {
901 if (__t < __u)
902 return weak_ordering::less;
903 else if (__u < __t)
904 return weak_ordering::greater;
905 else
906 return weak_ordering::equivalent;
907 }
908 }
909 } __synth3way = {};
910
911 // [expos.only.func] synth-three-way-result
912 template<typename _Tp, typename _Up = _Tp>
913 using __synth3way_t
914 = decltype(__detail::__synth3way(std::declval<_Tp&>(),
915 std::declval<_Up&>()));
916 } // namespace __detail
917#endif // concepts
918} // namespace std
919
920#pragma GCC visibility pop
921
922#endif // C++20
923
924#endif // _COMPARE
Note: See TracBrowser for help on using the repository browser.