You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

920 lines
27KB

  1. // -*- C++ -*- operator<=> three-way comparison support.
  2. // Copyright (C) 2019-2020 Free Software Foundation, Inc.
  3. //
  4. // This file is part of GCC.
  5. //
  6. // GCC is free software; you can redistribute it and/or modify
  7. // it under the terms of the GNU General Public License as published by
  8. // the Free Software Foundation; either version 3, or (at your option)
  9. // any later version.
  10. //
  11. // GCC is distributed in the hope that it will be useful,
  12. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. // GNU General Public License for more details.
  15. //
  16. // Under Section 7 of GPL version 3, you are granted additional
  17. // permissions described in the GCC Runtime Library Exception, version
  18. // 3.1, as published by the Free Software Foundation.
  19. // You should have received a copy of the GNU General Public License and
  20. // a copy of the GCC Runtime Library Exception along with this program;
  21. // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
  22. // <http://www.gnu.org/licenses/>.
  23. /** @file compare
  24. * This is a Standard C++ Library header.
  25. */
  26. #ifndef _COMPARE
  27. #define _COMPARE
  28. #pragma GCC system_header
  29. #if __cplusplus > 201703L && __cpp_impl_three_way_comparison >= 201907L
  30. #pragma GCC visibility push(default)
  31. #include <concepts>
  32. #if __cpp_lib_concepts
  33. # define __cpp_lib_three_way_comparison 201907L
  34. #endif
  35. namespace std
  36. {
  37. // [cmp.categories], comparison category types
  38. namespace __cmp_cat
  39. {
  40. using type = signed char;
  41. enum class _Ord : type { equivalent = 0, less = -1, greater = 1 };
  42. enum class _Ncmp : type { _Unordered = 2 };
  43. struct __unspec
  44. {
  45. constexpr __unspec(__unspec*) noexcept { }
  46. };
  47. }
  48. class partial_ordering
  49. {
  50. // less=0xff, equiv=0x00, greater=0x01, unordered=0x02
  51. __cmp_cat::type _M_value;
  52. constexpr explicit
  53. partial_ordering(__cmp_cat::_Ord __v) noexcept
  54. : _M_value(__cmp_cat::type(__v))
  55. { }
  56. constexpr explicit
  57. partial_ordering(__cmp_cat::_Ncmp __v) noexcept
  58. : _M_value(__cmp_cat::type(__v))
  59. { }
  60. friend class weak_ordering;
  61. friend class strong_ordering;
  62. public:
  63. // valid values
  64. static const partial_ordering less;
  65. static const partial_ordering equivalent;
  66. static const partial_ordering greater;
  67. static const partial_ordering unordered;
  68. // comparisons
  69. friend constexpr bool
  70. operator==(partial_ordering __v, __cmp_cat::__unspec) noexcept
  71. { return __v._M_value == 0; }
  72. friend constexpr bool
  73. operator==(partial_ordering, partial_ordering) noexcept = default;
  74. friend constexpr bool
  75. operator< (partial_ordering __v, __cmp_cat::__unspec) noexcept
  76. { return __v._M_value == -1; }
  77. friend constexpr bool
  78. operator> (partial_ordering __v, __cmp_cat::__unspec) noexcept
  79. { return __v._M_value == 1; }
  80. friend constexpr bool
  81. operator<=(partial_ordering __v, __cmp_cat::__unspec) noexcept
  82. { return __v._M_value <= 0; }
  83. friend constexpr bool
  84. operator>=(partial_ordering __v, __cmp_cat::__unspec) noexcept
  85. { return __cmp_cat::type(__v._M_value & 1) == __v._M_value; }
  86. friend constexpr bool
  87. operator< (__cmp_cat::__unspec, partial_ordering __v) noexcept
  88. { return __v._M_value == 1; }
  89. friend constexpr bool
  90. operator> (__cmp_cat::__unspec, partial_ordering __v) noexcept
  91. { return __v._M_value == -1; }
  92. friend constexpr bool
  93. operator<=(__cmp_cat::__unspec, partial_ordering __v) noexcept
  94. { return __cmp_cat::type(__v._M_value & 1) == __v._M_value; }
  95. friend constexpr bool
  96. operator>=(__cmp_cat::__unspec, partial_ordering __v) noexcept
  97. { return 0 >= __v._M_value; }
  98. friend constexpr partial_ordering
  99. operator<=>(partial_ordering __v, __cmp_cat::__unspec) noexcept
  100. { return __v; }
  101. friend constexpr partial_ordering
  102. operator<=>(__cmp_cat::__unspec, partial_ordering __v) noexcept
  103. {
  104. if (__v._M_value & 1)
  105. return partial_ordering(__cmp_cat::_Ord(-__v._M_value));
  106. else
  107. return __v;
  108. }
  109. };
  110. // valid values' definitions
  111. inline constexpr partial_ordering
  112. partial_ordering::less(__cmp_cat::_Ord::less);
  113. inline constexpr partial_ordering
  114. partial_ordering::equivalent(__cmp_cat::_Ord::equivalent);
  115. inline constexpr partial_ordering
  116. partial_ordering::greater(__cmp_cat::_Ord::greater);
  117. inline constexpr partial_ordering
  118. partial_ordering::unordered(__cmp_cat::_Ncmp::_Unordered);
  119. class weak_ordering
  120. {
  121. __cmp_cat::type _M_value;
  122. constexpr explicit
  123. weak_ordering(__cmp_cat::_Ord __v) noexcept : _M_value(__cmp_cat::type(__v))
  124. { }
  125. friend class strong_ordering;
  126. public:
  127. // valid values
  128. static const weak_ordering less;
  129. static const weak_ordering equivalent;
  130. static const weak_ordering greater;
  131. constexpr operator partial_ordering() const noexcept
  132. { return partial_ordering(__cmp_cat::_Ord(_M_value)); }
  133. // comparisons
  134. friend constexpr bool
  135. operator==(weak_ordering __v, __cmp_cat::__unspec) noexcept
  136. { return __v._M_value == 0; }
  137. friend constexpr bool
  138. operator==(weak_ordering, weak_ordering) noexcept = default;
  139. friend constexpr bool
  140. operator< (weak_ordering __v, __cmp_cat::__unspec) noexcept
  141. { return __v._M_value < 0; }
  142. friend constexpr bool
  143. operator> (weak_ordering __v, __cmp_cat::__unspec) noexcept
  144. { return __v._M_value > 0; }
  145. friend constexpr bool
  146. operator<=(weak_ordering __v, __cmp_cat::__unspec) noexcept
  147. { return __v._M_value <= 0; }
  148. friend constexpr bool
  149. operator>=(weak_ordering __v, __cmp_cat::__unspec) noexcept
  150. { return __v._M_value >= 0; }
  151. friend constexpr bool
  152. operator< (__cmp_cat::__unspec, weak_ordering __v) noexcept
  153. { return 0 < __v._M_value; }
  154. friend constexpr bool
  155. operator> (__cmp_cat::__unspec, weak_ordering __v) noexcept
  156. { return 0 > __v._M_value; }
  157. friend constexpr bool
  158. operator<=(__cmp_cat::__unspec, weak_ordering __v) noexcept
  159. { return 0 <= __v._M_value; }
  160. friend constexpr bool
  161. operator>=(__cmp_cat::__unspec, weak_ordering __v) noexcept
  162. { return 0 >= __v._M_value; }
  163. friend constexpr weak_ordering
  164. operator<=>(weak_ordering __v, __cmp_cat::__unspec) noexcept
  165. { return __v; }
  166. friend constexpr weak_ordering
  167. operator<=>(__cmp_cat::__unspec, weak_ordering __v) noexcept
  168. { return weak_ordering(__cmp_cat::_Ord(-__v._M_value)); }
  169. };
  170. // valid values' definitions
  171. inline constexpr weak_ordering
  172. weak_ordering::less(__cmp_cat::_Ord::less);
  173. inline constexpr weak_ordering
  174. weak_ordering::equivalent(__cmp_cat::_Ord::equivalent);
  175. inline constexpr weak_ordering
  176. weak_ordering::greater(__cmp_cat::_Ord::greater);
  177. class strong_ordering
  178. {
  179. __cmp_cat::type _M_value;
  180. constexpr explicit
  181. strong_ordering(__cmp_cat::_Ord __v) noexcept
  182. : _M_value(__cmp_cat::type(__v))
  183. { }
  184. public:
  185. // valid values
  186. static const strong_ordering less;
  187. static const strong_ordering equal;
  188. static const strong_ordering equivalent;
  189. static const strong_ordering greater;
  190. constexpr operator partial_ordering() const noexcept
  191. { return partial_ordering(__cmp_cat::_Ord(_M_value)); }
  192. constexpr operator weak_ordering() const noexcept
  193. { return weak_ordering(__cmp_cat::_Ord(_M_value)); }
  194. // comparisons
  195. friend constexpr bool
  196. operator==(strong_ordering __v, __cmp_cat::__unspec) noexcept
  197. { return __v._M_value == 0; }
  198. friend constexpr bool
  199. operator==(strong_ordering, strong_ordering) noexcept = default;
  200. friend constexpr bool
  201. operator< (strong_ordering __v, __cmp_cat::__unspec) noexcept
  202. { return __v._M_value < 0; }
  203. friend constexpr bool
  204. operator> (strong_ordering __v, __cmp_cat::__unspec) noexcept
  205. { return __v._M_value > 0; }
  206. friend constexpr bool
  207. operator<=(strong_ordering __v, __cmp_cat::__unspec) noexcept
  208. { return __v._M_value <= 0; }
  209. friend constexpr bool
  210. operator>=(strong_ordering __v, __cmp_cat::__unspec) noexcept
  211. { return __v._M_value >= 0; }
  212. friend constexpr bool
  213. operator< (__cmp_cat::__unspec, strong_ordering __v) noexcept
  214. { return 0 < __v._M_value; }
  215. friend constexpr bool
  216. operator> (__cmp_cat::__unspec, strong_ordering __v) noexcept
  217. { return 0 > __v._M_value; }
  218. friend constexpr bool
  219. operator<=(__cmp_cat::__unspec, strong_ordering __v) noexcept
  220. { return 0 <= __v._M_value; }
  221. friend constexpr bool
  222. operator>=(__cmp_cat::__unspec, strong_ordering __v) noexcept
  223. { return 0 >= __v._M_value; }
  224. friend constexpr strong_ordering
  225. operator<=>(strong_ordering __v, __cmp_cat::__unspec) noexcept
  226. { return __v; }
  227. friend constexpr strong_ordering
  228. operator<=>(__cmp_cat::__unspec, strong_ordering __v) noexcept
  229. { return strong_ordering(__cmp_cat::_Ord(-__v._M_value)); }
  230. };
  231. // valid values' definitions
  232. inline constexpr strong_ordering
  233. strong_ordering::less(__cmp_cat::_Ord::less);
  234. inline constexpr strong_ordering
  235. strong_ordering::equal(__cmp_cat::_Ord::equivalent);
  236. inline constexpr strong_ordering
  237. strong_ordering::equivalent(__cmp_cat::_Ord::equivalent);
  238. inline constexpr strong_ordering
  239. strong_ordering::greater(__cmp_cat::_Ord::greater);
  240. // named comparison functions
  241. constexpr bool
  242. is_eq(partial_ordering __cmp) noexcept
  243. { return __cmp == 0; }
  244. constexpr bool
  245. is_neq(partial_ordering __cmp) noexcept
  246. { return __cmp != 0; }
  247. constexpr bool
  248. is_lt (partial_ordering __cmp) noexcept
  249. { return __cmp < 0; }
  250. constexpr bool
  251. is_lteq(partial_ordering __cmp) noexcept
  252. { return __cmp <= 0; }
  253. constexpr bool
  254. is_gt (partial_ordering __cmp) noexcept
  255. { return __cmp > 0; }
  256. constexpr bool
  257. is_gteq(partial_ordering __cmp) noexcept
  258. { return __cmp >= 0; }
  259. namespace __detail
  260. {
  261. template<typename _Tp>
  262. inline constexpr unsigned __cmp_cat_id = 1;
  263. template<>
  264. inline constexpr unsigned __cmp_cat_id<partial_ordering> = 2;
  265. template<>
  266. inline constexpr unsigned __cmp_cat_id<weak_ordering> = 4;
  267. template<>
  268. inline constexpr unsigned __cmp_cat_id<strong_ordering> = 8;
  269. template<typename... _Ts>
  270. constexpr auto __common_cmp_cat()
  271. {
  272. constexpr unsigned __cats = (__cmp_cat_id<_Ts> | ...);
  273. // If any Ti is not a comparison category type, U is void.
  274. if constexpr (__cats & 1)
  275. return;
  276. // Otherwise, if at least one Ti is std::partial_ordering,
  277. // U is std::partial_ordering.
  278. else if constexpr (bool(__cats & __cmp_cat_id<partial_ordering>))
  279. return partial_ordering::equivalent;
  280. // Otherwise, if at least one Ti is std::weak_ordering,
  281. // U is std::weak_ordering.
  282. else if constexpr (bool(__cats & __cmp_cat_id<weak_ordering>))
  283. return weak_ordering::equivalent;
  284. // Otherwise, U is std::strong_ordering.
  285. else
  286. return strong_ordering::equivalent;
  287. }
  288. } // namespace __detail
  289. // [cmp.common], common comparison category type
  290. template<typename... _Ts>
  291. struct common_comparison_category
  292. {
  293. using type = decltype(__detail::__common_cmp_cat<_Ts...>());
  294. };
  295. // Partial specializations for one and zero argument cases.
  296. template<typename _Tp>
  297. struct common_comparison_category<_Tp>
  298. { using type = void; };
  299. template<>
  300. struct common_comparison_category<partial_ordering>
  301. { using type = partial_ordering; };
  302. template<>
  303. struct common_comparison_category<weak_ordering>
  304. { using type = weak_ordering; };
  305. template<>
  306. struct common_comparison_category<strong_ordering>
  307. { using type = strong_ordering; };
  308. template<>
  309. struct common_comparison_category<>
  310. { using type = strong_ordering; };
  311. template<typename... _Ts>
  312. using common_comparison_category_t
  313. = typename common_comparison_category<_Ts...>::type;
  314. #if __cpp_lib_concepts
  315. namespace __detail
  316. {
  317. template<typename _Tp, typename _Cat>
  318. concept __compares_as
  319. = same_as<common_comparison_category_t<_Tp, _Cat>, _Cat>;
  320. } // namespace __detail
  321. // [cmp.concept], concept three_way_comparable
  322. template<typename _Tp, typename _Cat = partial_ordering>
  323. concept three_way_comparable
  324. = __detail::__weakly_eq_cmp_with<_Tp, _Tp>
  325. && __detail::__partially_ordered_with<_Tp, _Tp>
  326. && requires(const remove_reference_t<_Tp>& __a,
  327. const remove_reference_t<_Tp>& __b)
  328. {
  329. { __a <=> __b } -> __detail::__compares_as<_Cat>;
  330. };
  331. template<typename _Tp, typename _Up, typename _Cat = partial_ordering>
  332. concept three_way_comparable_with
  333. = three_way_comparable<_Tp, _Cat>
  334. && three_way_comparable<_Up, _Cat>
  335. && common_reference_with<const remove_reference_t<_Tp>&,
  336. const remove_reference_t<_Up>&>
  337. && three_way_comparable<
  338. common_reference_t<const remove_reference_t<_Tp>&,
  339. const remove_reference_t<_Up>&>, _Cat>
  340. && __detail::__weakly_eq_cmp_with<_Tp, _Up>
  341. && __detail::__partially_ordered_with<_Tp, _Up>
  342. && requires(const remove_reference_t<_Tp>& __t,
  343. const remove_reference_t<_Up>& __u)
  344. {
  345. { __t <=> __u } -> __detail::__compares_as<_Cat>;
  346. { __u <=> __t } -> __detail::__compares_as<_Cat>;
  347. };
  348. namespace __detail
  349. {
  350. template<typename _Tp, typename _Up>
  351. using __cmp3way_res_t
  352. = decltype(std::declval<_Tp>() <=> std::declval<_Up>());
  353. // Implementation of std::compare_three_way_result.
  354. // It is undefined for a program to add specializations of
  355. // std::compare_three_way_result, so the std::compare_three_way_result_t
  356. // alias ignores std::compare_three_way_result and uses
  357. // __detail::__cmp3way_res_impl directly instead.
  358. template<typename _Tp, typename _Up>
  359. struct __cmp3way_res_impl
  360. { };
  361. template<typename _Tp, typename _Up>
  362. requires requires { typename __cmp3way_res_t<__cref<_Tp>, __cref<_Up>>; }
  363. struct __cmp3way_res_impl<_Tp, _Up>
  364. {
  365. using type = __cmp3way_res_t<__cref<_Tp>, __cref<_Up>>;
  366. };
  367. } // namespace __detail
  368. /// [cmp.result], result of three-way comparison
  369. template<typename _Tp, typename _Up = _Tp>
  370. struct compare_three_way_result
  371. : __detail::__cmp3way_res_impl<_Tp, _Up>
  372. { };
  373. /// [cmp.result], result of three-way comparison
  374. template<typename _Tp, typename _Up = _Tp>
  375. using compare_three_way_result_t
  376. = typename __detail::__cmp3way_res_impl<_Tp, _Up>::type;
  377. namespace __detail
  378. {
  379. // BUILTIN-PTR-THREE-WAY(T, U)
  380. template<typename _Tp, typename _Up>
  381. concept __3way_builtin_ptr_cmp
  382. = requires(_Tp&& __t, _Up&& __u)
  383. { static_cast<_Tp&&>(__t) <=> static_cast<_Up&&>(__u); }
  384. && convertible_to<_Tp, const volatile void*>
  385. && convertible_to<_Up, const volatile void*>
  386. && ! requires(_Tp&& __t, _Up&& __u)
  387. { operator<=>(static_cast<_Tp&&>(__t), static_cast<_Up&&>(__u)); }
  388. && ! requires(_Tp&& __t, _Up&& __u)
  389. { static_cast<_Tp&&>(__t).operator<=>(static_cast<_Up&&>(__u)); };
  390. } // namespace __detail
  391. // [cmp.object], typename compare_three_way
  392. struct compare_three_way
  393. {
  394. template<typename _Tp, typename _Up>
  395. requires three_way_comparable_with<_Tp, _Up>
  396. || __detail::__3way_builtin_ptr_cmp<_Tp, _Up>
  397. constexpr auto
  398. operator()(_Tp&& __t, _Up&& __u) const
  399. noexcept(noexcept(std::declval<_Tp>() <=> std::declval<_Up>()))
  400. {
  401. if constexpr (__detail::__3way_builtin_ptr_cmp<_Tp, _Up>)
  402. {
  403. auto __pt = static_cast<const volatile void*>(__t);
  404. auto __pu = static_cast<const volatile void*>(__u);
  405. if (__builtin_is_constant_evaluated())
  406. return __pt <=> __pu;
  407. auto __it = reinterpret_cast<__UINTPTR_TYPE__>(__pt);
  408. auto __iu = reinterpret_cast<__UINTPTR_TYPE__>(__pu);
  409. return __it <=> __iu;
  410. }
  411. else
  412. return static_cast<_Tp&&>(__t) <=> static_cast<_Up&&>(__u);
  413. }
  414. using is_transparent = void;
  415. };
  416. namespace __cmp_cust
  417. {
  418. template<floating_point _Tp>
  419. constexpr weak_ordering
  420. __fp_weak_ordering(_Tp __e, _Tp __f)
  421. {
  422. // Returns an integer with the same sign as the argument, and magnitude
  423. // indicating the classification: zero=1 subnorm=2 norm=3 inf=4 nan=5
  424. auto __cat = [](_Tp __fp) -> int {
  425. const int __sign = __builtin_signbit(__fp) ? -1 : 1;
  426. if (__builtin_isnormal(__fp))
  427. return (__fp == 0 ? 1 : 3) * __sign;
  428. if (__builtin_isnan(__fp))
  429. return 5 * __sign;
  430. if (int __inf = __builtin_isinf_sign(__fp))
  431. return 4 * __inf;
  432. return 2 * __sign;
  433. };
  434. auto __po = __e <=> __f;
  435. if (is_lt(__po))
  436. return weak_ordering::less;
  437. else if (is_gt(__po))
  438. return weak_ordering::greater;
  439. else if (__po == partial_ordering::equivalent)
  440. return weak_ordering::equivalent;
  441. else // unordered, at least one argument is NaN
  442. {
  443. // return -1 for negative nan, +1 for positive nan, 0 otherwise.
  444. auto __isnan_sign = [](_Tp __fp) -> int {
  445. return __builtin_isnan(__fp)
  446. ? __builtin_signbit(__fp) ? -1 : 1
  447. : 0;
  448. };
  449. auto __ord = __isnan_sign(__e) <=> __isnan_sign(__f);
  450. if (is_eq(__ord))
  451. return weak_ordering::equivalent;
  452. else if (is_lt(__ord))
  453. return weak_ordering::less;
  454. else
  455. return weak_ordering::greater;
  456. }
  457. }
  458. template<typename _Tp, typename _Up>
  459. concept __adl_strong = requires(_Tp&& __t, _Up&& __u)
  460. {
  461. strong_ordering(strong_order(static_cast<_Tp&&>(__t),
  462. static_cast<_Up&&>(__u)));
  463. };
  464. template<typename _Tp, typename _Up>
  465. concept __adl_weak = requires(_Tp&& __t, _Up&& __u)
  466. {
  467. weak_ordering(weak_order(static_cast<_Tp&&>(__t),
  468. static_cast<_Up&&>(__u)));
  469. };
  470. template<typename _Tp, typename _Up>
  471. concept __adl_partial = requires(_Tp&& __t, _Up&& __u)
  472. {
  473. partial_ordering(partial_order(static_cast<_Tp&&>(__t),
  474. static_cast<_Up&&>(__u)));
  475. };
  476. template<typename _Ord, typename _Tp, typename _Up>
  477. concept __cmp3way = requires(_Tp&& __t, _Up&& __u, compare_three_way __c)
  478. {
  479. _Ord(__c(static_cast<_Tp&&>(__t), static_cast<_Up&&>(__u)));
  480. };
  481. template<typename _Tp, typename _Up>
  482. concept __strongly_ordered
  483. = __adl_strong<_Tp, _Up>
  484. // FIXME: || floating_point<remove_reference_t<_Tp>>
  485. || __cmp3way<strong_ordering, _Tp, _Up>;
  486. class _Strong_order
  487. {
  488. template<typename _Tp, typename _Up>
  489. static constexpr bool
  490. _S_noexcept()
  491. {
  492. if constexpr (floating_point<decay_t<_Tp>>)
  493. return true;
  494. else if constexpr (__adl_strong<_Tp, _Up>)
  495. return noexcept(strong_ordering(strong_order(std::declval<_Tp>(),
  496. std::declval<_Up>())));
  497. else if constexpr (__cmp3way<strong_ordering, _Tp, _Up>)
  498. return noexcept(compare_three_way()(std::declval<_Tp>(),
  499. std::declval<_Up>()));
  500. }
  501. friend class _Weak_order;
  502. friend class _Strong_fallback;
  503. public:
  504. template<typename _Tp, typename _Up>
  505. requires __strongly_ordered<_Tp, _Up>
  506. constexpr strong_ordering
  507. operator()(_Tp&& __e, _Up&& __f) const
  508. noexcept(_S_noexcept<_Tp, _Up>())
  509. {
  510. static_assert(same_as<decay_t<_Tp>, decay_t<_Up>>);
  511. /* FIXME:
  512. if constexpr (floating_point<decay_t<_Tp>>)
  513. return __cmp_cust::__fp_strong_order(__e, __f);
  514. else */ if constexpr (__adl_strong<_Tp, _Up>)
  515. return strong_ordering(strong_order(static_cast<_Tp&&>(__e),
  516. static_cast<_Up&&>(__f)));
  517. else if constexpr (__cmp3way<strong_ordering, _Tp, _Up>)
  518. return compare_three_way()(static_cast<_Tp&&>(__e),
  519. static_cast<_Up&&>(__f));
  520. }
  521. };
  522. template<typename _Tp, typename _Up>
  523. concept __weakly_ordered
  524. = floating_point<remove_reference_t<_Tp>>
  525. || __adl_weak<_Tp, _Up>
  526. || __cmp3way<weak_ordering, _Tp, _Up>
  527. || __strongly_ordered<_Tp, _Up>;
  528. class _Weak_order
  529. {
  530. template<typename _Tp, typename _Up>
  531. static constexpr bool
  532. _S_noexcept()
  533. {
  534. if constexpr (floating_point<decay_t<_Tp>>)
  535. return true;
  536. else if constexpr (__adl_weak<_Tp, _Up>)
  537. return noexcept(weak_ordering(weak_order(std::declval<_Tp>(),
  538. std::declval<_Up>())));
  539. else if constexpr (__cmp3way<weak_ordering, _Tp, _Up>)
  540. return noexcept(compare_three_way()(std::declval<_Tp>(),
  541. std::declval<_Up>()));
  542. else if constexpr (__strongly_ordered<_Tp, _Up>)
  543. return _Strong_order::_S_noexcept<_Tp, _Up>();
  544. }
  545. friend class _Partial_order;
  546. friend class _Weak_fallback;
  547. public:
  548. template<typename _Tp, typename _Up>
  549. requires __weakly_ordered<_Tp, _Up>
  550. constexpr weak_ordering
  551. operator()(_Tp&& __e, _Up&& __f) const
  552. noexcept(_S_noexcept<_Tp, _Up>())
  553. {
  554. static_assert(same_as<decay_t<_Tp>, decay_t<_Up>>);
  555. if constexpr (floating_point<decay_t<_Tp>>)
  556. return __cmp_cust::__fp_weak_ordering(__e, __f);
  557. else if constexpr (__adl_weak<_Tp, _Up>)
  558. return weak_ordering(weak_order(static_cast<_Tp&&>(__e),
  559. static_cast<_Up&&>(__f)));
  560. else if constexpr (__cmp3way<weak_ordering, _Tp, _Up>)
  561. return compare_three_way()(static_cast<_Tp&&>(__e),
  562. static_cast<_Up&&>(__f));
  563. else if constexpr (__strongly_ordered<_Tp, _Up>)
  564. return _Strong_order{}(static_cast<_Tp&&>(__e),
  565. static_cast<_Up&&>(__f));
  566. }
  567. };
  568. template<typename _Tp, typename _Up>
  569. concept __partially_ordered
  570. = __adl_partial<_Tp, _Up>
  571. || __cmp3way<partial_ordering, _Tp, _Up>
  572. || __weakly_ordered<_Tp, _Up>;
  573. class _Partial_order
  574. {
  575. template<typename _Tp, typename _Up>
  576. static constexpr bool
  577. _S_noexcept()
  578. {
  579. if constexpr (__adl_partial<_Tp, _Up>)
  580. return noexcept(partial_ordering(partial_order(std::declval<_Tp>(),
  581. std::declval<_Up>())));
  582. else if constexpr (__cmp3way<partial_ordering, _Tp, _Up>)
  583. return noexcept(compare_three_way()(std::declval<_Tp>(),
  584. std::declval<_Up>()));
  585. else if constexpr (__weakly_ordered<_Tp, _Up>)
  586. return _Weak_order::_S_noexcept<_Tp, _Up>();
  587. }
  588. friend class _Partial_fallback;
  589. public:
  590. template<typename _Tp, typename _Up>
  591. requires __partially_ordered<_Tp, _Up>
  592. constexpr partial_ordering
  593. operator()(_Tp&& __e, _Up&& __f) const
  594. noexcept(_S_noexcept<_Tp, _Up>())
  595. {
  596. static_assert(same_as<decay_t<_Tp>, decay_t<_Up>>);
  597. if constexpr (__adl_partial<_Tp, _Up>)
  598. return partial_ordering(partial_order(static_cast<_Tp&&>(__e),
  599. static_cast<_Up&&>(__f)));
  600. else if constexpr (__cmp3way<partial_ordering, _Tp, _Up>)
  601. return compare_three_way()(static_cast<_Tp&&>(__e),
  602. static_cast<_Up&&>(__f));
  603. else if constexpr (__weakly_ordered<_Tp, _Up>)
  604. return _Weak_order{}(static_cast<_Tp&&>(__e),
  605. static_cast<_Up&&>(__f));
  606. }
  607. };
  608. template<typename _Tp, typename _Up>
  609. concept __op_eq_lt = requires(_Tp&& __t, _Up&& __u)
  610. {
  611. { static_cast<_Tp&&>(__t) == static_cast<_Up&&>(__u) }
  612. -> convertible_to<bool>;
  613. { static_cast<_Tp&&>(__t) < static_cast<_Up&&>(__u) }
  614. -> convertible_to<bool>;
  615. };
  616. class _Strong_fallback
  617. {
  618. template<typename _Tp, typename _Up>
  619. static constexpr bool
  620. _S_noexcept()
  621. {
  622. if constexpr (__strongly_ordered<_Tp, _Up>)
  623. return _Strong_order::_S_noexcept<_Tp, _Up>();
  624. else
  625. return noexcept(bool(std::declval<_Tp>() == std::declval<_Up>()))
  626. && noexcept(bool(std::declval<_Tp>() < std::declval<_Up>()));
  627. }
  628. public:
  629. template<typename _Tp, typename _Up>
  630. requires __strongly_ordered<_Tp, _Up> || __op_eq_lt<_Tp, _Up>
  631. constexpr decltype(auto)
  632. operator()(_Tp&& __e, _Up&& __f) const
  633. noexcept(_S_noexcept<_Tp, _Up>())
  634. {
  635. static_assert(same_as<decay_t<_Tp>, decay_t<_Up>>);
  636. if constexpr (__strongly_ordered<_Tp, _Up>)
  637. return _Strong_order{}(static_cast<_Tp&&>(__e),
  638. static_cast<_Up&&>(__f));
  639. else if constexpr (__op_eq_lt<_Tp, _Up>)
  640. return static_cast<_Tp&&>(__e) == static_cast<_Up&&>(__f)
  641. ? strong_ordering::equal
  642. : static_cast<_Tp&&>(__e) < static_cast<_Up&&>(__f)
  643. ? strong_ordering::less
  644. : strong_ordering::greater;
  645. }
  646. };
  647. class _Weak_fallback
  648. {
  649. template<typename _Tp, typename _Up>
  650. static constexpr bool
  651. _S_noexcept()
  652. {
  653. if constexpr (__weakly_ordered<_Tp, _Up>)
  654. return _Weak_order::_S_noexcept<_Tp, _Up>();
  655. else
  656. return noexcept(bool(std::declval<_Tp>() == std::declval<_Up>()))
  657. && noexcept(bool(std::declval<_Tp>() < std::declval<_Up>()));
  658. }
  659. public:
  660. template<typename _Tp, typename _Up>
  661. requires __weakly_ordered<_Tp, _Up> || __op_eq_lt<_Tp, _Up>
  662. constexpr decltype(auto)
  663. operator()(_Tp&& __e, _Up&& __f) const
  664. noexcept(_S_noexcept<_Tp, _Up>())
  665. {
  666. static_assert(same_as<decay_t<_Tp>, decay_t<_Up>>);
  667. if constexpr (__weakly_ordered<_Tp, _Up>)
  668. return _Weak_order{}(static_cast<_Tp&&>(__e),
  669. static_cast<_Up&&>(__f));
  670. else if constexpr (__op_eq_lt<_Tp, _Up>)
  671. return static_cast<_Tp&&>(__e) == static_cast<_Up&&>(__f)
  672. ? weak_ordering::equivalent
  673. : static_cast<_Tp&&>(__e) < static_cast<_Up&&>(__f)
  674. ? weak_ordering::less
  675. : weak_ordering::greater;
  676. }
  677. };
  678. class _Partial_fallback
  679. {
  680. template<typename _Tp, typename _Up>
  681. static constexpr bool
  682. _S_noexcept()
  683. {
  684. if constexpr (__partially_ordered<_Tp, _Up>)
  685. return _Partial_order::_S_noexcept<_Tp, _Up>();
  686. else
  687. return noexcept(bool(std::declval<_Tp>() == std::declval<_Up>()))
  688. && noexcept(bool(std::declval<_Tp>() < std::declval<_Up>()));
  689. }
  690. public:
  691. template<typename _Tp, typename _Up>
  692. requires __partially_ordered<_Tp, _Up> || __op_eq_lt<_Tp, _Up>
  693. constexpr decltype(auto)
  694. operator()(_Tp&& __e, _Up&& __f) const
  695. noexcept(_S_noexcept<_Tp, _Up>())
  696. {
  697. static_assert(same_as<decay_t<_Tp>, decay_t<_Up>>);
  698. if constexpr (__partially_ordered<_Tp, _Up>)
  699. return _Partial_order{}(static_cast<_Tp&&>(__e),
  700. static_cast<_Up&&>(__f));
  701. else if constexpr (__op_eq_lt<_Tp, _Up>)
  702. return static_cast<_Tp&&>(__e) == static_cast<_Up&&>(__f)
  703. ? partial_ordering::equivalent
  704. : static_cast<_Tp&&>(__e) < static_cast<_Up&&>(__f)
  705. ? partial_ordering::less
  706. : static_cast<_Up&&>(__f) < static_cast<_Tp&&>(__e)
  707. ? partial_ordering::greater
  708. : partial_ordering::unordered;
  709. }
  710. };
  711. } // namespace __cmp_cust
  712. // [cmp.alg], comparison algorithms
  713. inline namespace __cmp_alg
  714. {
  715. inline constexpr __cmp_cust::_Strong_order strong_order{};
  716. inline constexpr __cmp_cust::_Weak_order weak_order{};
  717. inline constexpr __cmp_cust::_Partial_order partial_order{};
  718. inline constexpr __cmp_cust::_Strong_fallback
  719. compare_strong_order_fallback{};
  720. inline constexpr __cmp_cust::_Weak_fallback
  721. compare_weak_order_fallback{};
  722. inline constexpr __cmp_cust::_Partial_fallback
  723. compare_partial_order_fallback{};
  724. }
  725. namespace __detail
  726. {
  727. // [expos.only.func] synth-three-way
  728. inline constexpr struct _Synth3way
  729. {
  730. template<typename _Tp, typename _Up>
  731. static constexpr bool
  732. _S_noexcept(const _Tp* __t = nullptr, const _Up* __u = nullptr)
  733. {
  734. if constexpr (three_way_comparable_with<_Tp, _Up>)
  735. return noexcept(*__t <=> *__u);
  736. else
  737. return noexcept(*__t < *__u) && noexcept(*__u < *__t);
  738. }
  739. template<typename _Tp, typename _Up>
  740. constexpr auto
  741. operator()(const _Tp& __t, const _Up& __u) const
  742. noexcept(_S_noexcept<_Tp, _Up>())
  743. requires requires
  744. {
  745. { __t < __u } -> __boolean_testable;
  746. { __u < __t } -> __boolean_testable;
  747. }
  748. {
  749. if constexpr (three_way_comparable_with<_Tp, _Up>)
  750. return __t <=> __u;
  751. else
  752. {
  753. if (__t < __u)
  754. return weak_ordering::less;
  755. else if (__u < __t)
  756. return weak_ordering::greater;
  757. else
  758. return weak_ordering::equivalent;
  759. }
  760. }
  761. } __synth3way = {};
  762. // [expos.only.func] synth-three-way-result
  763. template<typename _Tp, typename _Up = _Tp>
  764. using __synth3way_t
  765. = decltype(__detail::__synth3way(std::declval<_Tp&>(),
  766. std::declval<_Up&>()));
  767. } // namespace __detail
  768. #endif // concepts
  769. } // namespace std
  770. #pragma GCC visibility pop
  771. #endif // C++20
  772. #endif // _COMPARE