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