]>
Commit | Line | Data |
---|---|---|
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 |
45 | namespace 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 |