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