Line data Source code
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 20459008 : 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 179 : weak_ordering(__cmp_cat::_Ord __v) noexcept : _M_value(__cmp_cat::type(__v))
161 179 : { }
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 1785 : operator==(weak_ordering __v, __cmp_cat::__unspec) noexcept
177 1785 : { return __v._M_value == 0; }
178 :
179 : friend constexpr bool
180 : operator==(weak_ordering, weak_ordering) noexcept = default;
181 :
182 : friend constexpr bool
183 2151 : operator< (weak_ordering __v, __cmp_cat::__unspec) noexcept
184 2151 : { 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 179 : constexpr operator weak_ordering() const noexcept
253 179 : { return weak_ordering(__cmp_cat::_Ord(_M_value)); }
254 :
255 : // comparisons
256 : friend constexpr bool
257 558 : operator==(strong_ordering __v, __cmp_cat::__unspec) noexcept
258 558 : { return __v._M_value == 0; }
259 :
260 : friend constexpr bool
261 : operator==(strong_ordering, strong_ordering) noexcept = default;
262 :
263 : friend constexpr bool
264 20207295 : operator< (strong_ordering __v, __cmp_cat::__unspec) noexcept
265 20207295 : { return __v._M_value < 0; }
266 :
267 : friend constexpr bool
268 4425 : operator> (strong_ordering __v, __cmp_cat::__unspec) noexcept
269 4425 : { return __v._M_value > 0; }
270 :
271 : friend constexpr bool
272 9516 : operator<=(strong_ordering __v, __cmp_cat::__unspec) noexcept
273 9516 : { return __v._M_value <= 0; }
274 :
275 : friend constexpr bool
276 44130 : operator>=(strong_ordering __v, __cmp_cat::__unspec) noexcept
277 44130 : { return __v._M_value >= 0; }
278 :
279 : friend constexpr bool
280 115665 : operator< (__cmp_cat::__unspec, strong_ordering __v) noexcept
281 115665 : { 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 1783 : 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 1783 : auto __pt = static_cast<const volatile void*>(__t);
512 1783 : auto __pu = static_cast<const volatile void*>(__u);
513 : if (__builtin_is_constant_evaluated())
514 : return __pt <=> __pu;
515 1783 : auto __it = reinterpret_cast<__UINTPTR_TYPE__>(__pt);
516 1783 : auto __iu = reinterpret_cast<__UINTPTR_TYPE__>(__pu);
517 1783 : 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 6530 : 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 3784 : return __t <=> __u;
900 : else
901 : {
902 2746 : if (__t < __u)
903 828 : return weak_ordering::less;
904 1918 : else if (__u < __t)
905 832 : return weak_ordering::greater;
906 : else
907 1086 : 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
|