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