// compare standard header (core) // Copyright (c) Microsoft Corporation. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception #pragma once #ifndef _COMPARE_ #define _COMPARE_ #include #if _STL_COMPILER_PREPROCESSOR #if !_HAS_CXX20 #pragma message("The contents of are available only with C++20 or later.") #else // ^^^ !_HAS_CXX20 / _HAS_CXX20 vvv #ifdef __cpp_lib_concepts #include #else // ^^^ __cpp_lib_concepts / !__cpp_lib_concepts vvv #include #endif // !__cpp_lib_concepts #pragma pack(push, _CRT_PACKING) #pragma warning(push, _STL_WARNING_LEVEL) #pragma warning(disable : _STL_DISABLED_WARNINGS) _STL_DISABLE_CLANG_WARNINGS #pragma push_macro("new") #undef new _STD_BEGIN using _Literal_zero = decltype(nullptr); using _Compare_t = signed char; // These "pretty" enumerator names are safe since they reuse names of user-facing entities. enum class _Compare_eq : _Compare_t { equal = 0, equivalent = equal }; enum class _Compare_ord : _Compare_t { less = -1, greater = 1 }; enum class _Compare_ncmp : _Compare_t { unordered = -127 }; // CLASS partial_ordering class partial_ordering { public: _NODISCARD constexpr explicit partial_ordering(const _Compare_eq _Value_) noexcept : _Value(static_cast<_Compare_t>(_Value_)) {} _NODISCARD constexpr explicit partial_ordering(const _Compare_ord _Value_) noexcept : _Value(static_cast<_Compare_t>(_Value_)) {} _NODISCARD constexpr explicit partial_ordering(const _Compare_ncmp _Value_) noexcept : _Value(static_cast<_Compare_t>(_Value_)) {} static const partial_ordering less; static const partial_ordering equivalent; static const partial_ordering greater; static const partial_ordering unordered; _NODISCARD friend constexpr bool operator==(const partial_ordering _Val, _Literal_zero) noexcept { return _Val._Value == 0; } #if defined(__cpp_impl_three_way_comparison) && __cpp_impl_three_way_comparison >= 201902L _NODISCARD friend constexpr bool operator==(const partial_ordering&, const partial_ordering&) noexcept = default; #else // ^^^ supports <=> and P1185 / supports neither vvv _NODISCARD friend constexpr bool operator!=(const partial_ordering _Val, _Literal_zero) noexcept { return _Val._Value != 0; } _NODISCARD friend constexpr bool operator==(_Literal_zero, const partial_ordering _Val) noexcept { return 0 == _Val._Value; } _NODISCARD friend constexpr bool operator!=(_Literal_zero, const partial_ordering _Val) noexcept { return 0 != _Val._Value; } #endif // defined(__cpp_impl_three_way_comparison) && __cpp_impl_three_way_comparison >= 201902L _NODISCARD friend constexpr bool operator<(const partial_ordering _Val, _Literal_zero) noexcept { return _Val._Value == static_cast<_Compare_t>(_Compare_ord::less); } _NODISCARD friend constexpr bool operator>(const partial_ordering _Val, _Literal_zero) noexcept { return _Val._Value > 0; } _NODISCARD friend constexpr bool operator<=(const partial_ordering _Val, _Literal_zero) noexcept { return _Val._Value <= 0 && _Val._Is_ordered(); } _NODISCARD friend constexpr bool operator>=(const partial_ordering _Val, _Literal_zero) noexcept { return _Val._Value >= 0; } _NODISCARD friend constexpr bool operator<(_Literal_zero, const partial_ordering _Val) noexcept { return 0 < _Val._Value; } _NODISCARD friend constexpr bool operator>(_Literal_zero, const partial_ordering _Val) noexcept { return 0 > _Val._Value && _Val._Is_ordered(); } _NODISCARD friend constexpr bool operator<=(_Literal_zero, const partial_ordering _Val) noexcept { return 0 <= _Val._Value; } _NODISCARD friend constexpr bool operator>=(_Literal_zero, const partial_ordering _Val) noexcept { return 0 >= _Val._Value && _Val._Is_ordered(); } #ifdef __cpp_impl_three_way_comparison _NODISCARD friend constexpr partial_ordering operator<=>(const partial_ordering _Val, _Literal_zero) noexcept { return _Val; } _NODISCARD friend constexpr partial_ordering operator<=>(_Literal_zero, const partial_ordering _Val) noexcept { return partial_ordering{static_cast<_Compare_ord>(-_Val._Value)}; } #endif // __cpp_impl_three_way_comparison private: _NODISCARD constexpr bool _Is_ordered() const noexcept { return _Value != static_cast<_Compare_t>(_Compare_ncmp::unordered); } _Compare_t _Value; }; inline constexpr partial_ordering partial_ordering::less(_Compare_ord::less); inline constexpr partial_ordering partial_ordering::equivalent(_Compare_eq::equivalent); inline constexpr partial_ordering partial_ordering::greater(_Compare_ord::greater); inline constexpr partial_ordering partial_ordering::unordered(_Compare_ncmp::unordered); // CLASS weak_ordering class weak_ordering { public: _NODISCARD constexpr explicit weak_ordering(const _Compare_eq _Value_) noexcept : _Value(static_cast<_Compare_t>(_Value_)) {} _NODISCARD constexpr explicit weak_ordering(const _Compare_ord _Value_) noexcept : _Value(static_cast<_Compare_t>(_Value_)) {} static const weak_ordering less; static const weak_ordering equivalent; static const weak_ordering greater; constexpr operator partial_ordering() const noexcept { return partial_ordering{static_cast<_Compare_ord>(_Value)}; } _NODISCARD friend constexpr bool operator==(const weak_ordering _Val, _Literal_zero) noexcept { return _Val._Value == 0; } #if defined(__cpp_impl_three_way_comparison) && __cpp_impl_three_way_comparison >= 201902L _NODISCARD friend constexpr bool operator==(const weak_ordering&, const weak_ordering&) noexcept = default; #else // ^^^ supports <=> and P1185 / supports neither vvv _NODISCARD friend constexpr bool operator!=(const weak_ordering _Val, _Literal_zero) noexcept { return _Val._Value != 0; } _NODISCARD friend constexpr bool operator==(_Literal_zero, const weak_ordering _Val) noexcept { return 0 == _Val._Value; } _NODISCARD friend constexpr bool operator!=(_Literal_zero, const weak_ordering _Val) noexcept { return 0 != _Val._Value; } #endif // defined(__cpp_impl_three_way_comparison) && __cpp_impl_three_way_comparison >= 201902L _NODISCARD friend constexpr bool operator<(const weak_ordering _Val, _Literal_zero) noexcept { return _Val._Value < 0; } _NODISCARD friend constexpr bool operator>(const weak_ordering _Val, _Literal_zero) noexcept { return _Val._Value > 0; } _NODISCARD friend constexpr bool operator<=(const weak_ordering _Val, _Literal_zero) noexcept { return _Val._Value <= 0; } _NODISCARD friend constexpr bool operator>=(const weak_ordering _Val, _Literal_zero) noexcept { return _Val._Value >= 0; } _NODISCARD friend constexpr bool operator<(_Literal_zero, const weak_ordering _Val) noexcept { return 0 < _Val._Value; } _NODISCARD friend constexpr bool operator>(_Literal_zero, const weak_ordering _Val) noexcept { return 0 > _Val._Value; } _NODISCARD friend constexpr bool operator<=(_Literal_zero, const weak_ordering _Val) noexcept { return 0 <= _Val._Value; } _NODISCARD friend constexpr bool operator>=(_Literal_zero, const weak_ordering _Val) noexcept { return 0 >= _Val._Value; } #ifdef __cpp_impl_three_way_comparison _NODISCARD friend constexpr weak_ordering operator<=>(const weak_ordering _Val, _Literal_zero) noexcept { return _Val; } _NODISCARD friend constexpr weak_ordering operator<=>(_Literal_zero, const weak_ordering _Val) noexcept { return weak_ordering{static_cast<_Compare_ord>(-_Val._Value)}; } #endif // __cpp_impl_three_way_comparison private: _Compare_t _Value; }; inline constexpr weak_ordering weak_ordering::less(_Compare_ord::less); inline constexpr weak_ordering weak_ordering::equivalent(_Compare_eq::equivalent); inline constexpr weak_ordering weak_ordering::greater(_Compare_ord::greater); // CLASS strong_ordering class strong_ordering { public: _NODISCARD constexpr explicit strong_ordering(const _Compare_eq _Value_) noexcept : _Value(static_cast<_Compare_t>(_Value_)) {} _NODISCARD constexpr explicit strong_ordering(const _Compare_ord _Value_) noexcept : _Value(static_cast<_Compare_t>(_Value_)) {} static const strong_ordering less; static const strong_ordering equal; static const strong_ordering equivalent; static const strong_ordering greater; constexpr operator partial_ordering() const noexcept { return partial_ordering{static_cast<_Compare_ord>(_Value)}; } constexpr operator weak_ordering() const noexcept { return weak_ordering{static_cast<_Compare_ord>(_Value)}; } _NODISCARD friend constexpr bool operator==(const strong_ordering _Val, _Literal_zero) noexcept { return _Val._Value == 0; } #if defined(__cpp_impl_three_way_comparison) && __cpp_impl_three_way_comparison >= 201902L _NODISCARD friend constexpr bool operator==(const strong_ordering&, const strong_ordering&) noexcept = default; #else // ^^^ supports <=> and P1185 / supports neither vvv _NODISCARD friend constexpr bool operator!=(const strong_ordering _Val, _Literal_zero) noexcept { return _Val._Value != 0; } _NODISCARD friend constexpr bool operator==(_Literal_zero, const strong_ordering _Val) noexcept { return 0 == _Val._Value; } _NODISCARD friend constexpr bool operator!=(_Literal_zero, const strong_ordering _Val) noexcept { return 0 != _Val._Value; } #endif // defined(__cpp_impl_three_way_comparison) && __cpp_impl_three_way_comparison >= 201902L _NODISCARD friend constexpr bool operator<(const strong_ordering _Val, _Literal_zero) noexcept { return _Val._Value < 0; } _NODISCARD friend constexpr bool operator>(const strong_ordering _Val, _Literal_zero) noexcept { return _Val._Value > 0; } _NODISCARD friend constexpr bool operator<=(const strong_ordering _Val, _Literal_zero) noexcept { return _Val._Value <= 0; } _NODISCARD friend constexpr bool operator>=(const strong_ordering _Val, _Literal_zero) noexcept { return _Val._Value >= 0; } _NODISCARD friend constexpr bool operator<(_Literal_zero, const strong_ordering _Val) noexcept { return 0 < _Val._Value; } _NODISCARD friend constexpr bool operator>(_Literal_zero, const strong_ordering _Val) noexcept { return 0 > _Val._Value; } _NODISCARD friend constexpr bool operator<=(_Literal_zero, const strong_ordering _Val) noexcept { return 0 <= _Val._Value; } _NODISCARD friend constexpr bool operator>=(_Literal_zero, const strong_ordering _Val) noexcept { return 0 >= _Val._Value; } #ifdef __cpp_impl_three_way_comparison _NODISCARD friend constexpr strong_ordering operator<=>(const strong_ordering _Val, _Literal_zero) noexcept { return _Val; } _NODISCARD friend constexpr strong_ordering operator<=>(_Literal_zero, const strong_ordering _Val) noexcept { return strong_ordering{static_cast<_Compare_ord>(-_Val._Value)}; } #endif // __cpp_impl_three_way_comparison private: _Compare_t _Value; }; inline constexpr strong_ordering strong_ordering::less(_Compare_ord::less); inline constexpr strong_ordering strong_ordering::equal(_Compare_eq::equal); inline constexpr strong_ordering strong_ordering::equivalent(_Compare_eq::equivalent); inline constexpr strong_ordering strong_ordering::greater(_Compare_ord::greater); // FUNCTION is_eq _NODISCARD constexpr bool is_eq(const partial_ordering _Comp) noexcept { return _Comp == 0; } // FUNCTION is_neq _NODISCARD constexpr bool is_neq(const partial_ordering _Comp) noexcept { return _Comp != 0; } // FUNCTION is_lt _NODISCARD constexpr bool is_lt(const partial_ordering _Comp) noexcept { return _Comp < 0; } // FUNCTION is_lteq _NODISCARD constexpr bool is_lteq(const partial_ordering _Comp) noexcept { return _Comp <= 0; } // FUNCTION is_gt _NODISCARD constexpr bool is_gt(const partial_ordering _Comp) noexcept { return _Comp > 0; } // FUNCTION is_gteq _NODISCARD constexpr bool is_gteq(const partial_ordering _Comp) noexcept { return _Comp >= 0; } // ALIAS TEMPLATE common_comparison_category_t enum _Comparison_category : unsigned char { _Comparison_category_none = 1, _Comparison_category_partial = 2, _Comparison_category_weak = 4, _Comparison_category_strong = 0, }; template inline constexpr unsigned char _Classify_category = _Comparison_category{(_Classify_category<_Types> | ... | _Comparison_category_strong)}; template inline constexpr unsigned char _Classify_category<_Ty> = _Comparison_category_none; template <> inline constexpr unsigned char _Classify_category = _Comparison_category_partial; template <> inline constexpr unsigned char _Classify_category = _Comparison_category_weak; template <> inline constexpr unsigned char _Classify_category = _Comparison_category_strong; template using common_comparison_category_t = conditional_t<(_Classify_category<_Types...> & _Comparison_category_none) != 0, void, conditional_t<(_Classify_category<_Types...> & _Comparison_category_partial) != 0, partial_ordering, conditional_t<(_Classify_category<_Types...> & _Comparison_category_weak) != 0, weak_ordering, strong_ordering>>>; template struct common_comparison_category { using type = common_comparison_category_t<_Types...>; }; #if defined(__cpp_impl_three_way_comparison) && defined(__cpp_lib_concepts) // clang-format off template concept _Compares_as = same_as, _Cat>; template concept three_way_comparable = _Half_equality_comparable<_Ty, _Ty> && _Half_ordered<_Ty, _Ty> && requires(const remove_reference_t<_Ty>& __a, const remove_reference_t<_Ty>& __b) { { __a <=> __b } -> _Compares_as<_Cat>; }; template concept three_way_comparable_with = three_way_comparable<_Ty1, _Cat> && three_way_comparable<_Ty2, _Cat> && common_reference_with&, const remove_reference_t<_Ty2>&> && three_way_comparable&, const remove_reference_t<_Ty2>&>, _Cat> && _Weakly_equality_comparable_with<_Ty1, _Ty2> && _Partially_ordered_with<_Ty1, _Ty2> && requires(const remove_reference_t<_Ty1>& __t, const remove_reference_t<_Ty2>& __u) { { __t <=> __u } -> _Compares_as<_Cat>; { __u <=> __t } -> _Compares_as<_Cat>; }; template using compare_three_way_result_t = decltype(_STD declval&>() <=> _STD declval&>()); template struct compare_three_way_result {}; template requires requires { typename compare_three_way_result_t<_Ty1, _Ty2>; } struct compare_three_way_result<_Ty1, _Ty2> { using type = compare_three_way_result_t<_Ty1, _Ty2>; }; struct compare_three_way { template requires three_way_comparable_with<_Ty1, _Ty2> // TRANSITION, GH-489 constexpr auto operator()(_Ty1&& _Left, _Ty2&& _Right) const noexcept(noexcept(_STD forward<_Ty1>(_Left) <=> _STD forward<_Ty2>(_Right))) /* strengthened */ { return _STD forward<_Ty1>(_Left) <=> _STD forward<_Ty2>(_Right); } using is_transparent = int; }; // clang-format on #endif // defined(__cpp_impl_three_way_comparison) && defined(__cpp_lib_concepts) // Other components not yet implemented _STD_END #pragma pop_macro("new") _STL_RESTORE_CLANG_WARNINGS #pragma warning(pop) #pragma pack(pop) #endif // _HAS_CXX20 #endif // _STL_COMPILER_PREPROCESSOR #endif // _COMPARE_