diff --git a/stl/inc/cmath b/stl/inc/cmath index de7be7abc4..34052e7628 100644 --- a/stl/inc/cmath +++ b/stl/inc/cmath @@ -611,6 +611,53 @@ _STD _Common_float_type_t<_Ty1, _Ty2> remquo(_Ty1 _Left, _Ty2 _Right, int* _Pquo return __builtin_##NAME(_Xx, _Yx); \ } +#define _CLANG_BUILTIN2_ARG_TEMPLATED(NAME, ARG) \ + template , int> = 0> \ + _NODISCARD _Check_return_ inline bool NAME(_In_ ARG _Xx, _In_ _Ty _Yx) noexcept /* strengthened */ { \ + return __builtin_##NAME(static_cast(_Xx), static_cast(_Yx)); \ + } + +#ifdef __cpp_char8_t +#define _CLANG_BUILTIN2_ARG_TEMPLATED_CHAR8_T(NAME) \ + template , int> = 0> \ + _NODISCARD _Check_return_ inline bool NAME(_In_ char8_t _Xx, _In_ _Ty _Yx) noexcept /* strengthened */ { \ + return __builtin_##NAME(static_cast(_Xx), static_cast(_Yx)); \ + } +#else // ^^^ defined(__cpp_char8_t) / !defined(__cpp_char8_t) vvv +#define _CLANG_BUILTIN2_ARG_TEMPLATED_CHAR8_T(NAME) +#endif // ^^^ !defined(__cpp_char8_t) ^^^ + +#ifdef _NATIVE_WCHAR_T_DEFINED +#define _CLANG_BUILTIN2_ARG_TEMPLATED_WCHAR_T(NAME) \ + template , int> = 0> \ + _NODISCARD _Check_return_ inline bool NAME(_In_ wchar_t _Xx, _In_ _Ty _Yx) noexcept /* strengthened */ { \ + return __builtin_##NAME(static_cast(_Xx), static_cast(_Yx)); \ + } +#else // ^^^ defined(_NATIVE_WCHAR_T_DEFINED) / !defined(_NATIVE_WCHAR_T_DEFINED) vvv +#define _CLANG_BUILTIN2_ARG_TEMPLATED_WCHAR_T(NAME) +#endif // ^^^ !defined(_NATIVE_WCHAR_T_DEFINED) ^^^ + +#define _CLANG_BUILTIN2_TEMPLATED(NAME) \ + _CLANG_BUILTIN2_ARG_TEMPLATED(NAME, float) \ + _CLANG_BUILTIN2_ARG_TEMPLATED(NAME, double) \ + _CLANG_BUILTIN2_ARG_TEMPLATED(NAME, long double) \ + _CLANG_BUILTIN2_ARG_TEMPLATED(NAME, signed char) \ + _CLANG_BUILTIN2_ARG_TEMPLATED(NAME, short) \ + _CLANG_BUILTIN2_ARG_TEMPLATED(NAME, int) \ + _CLANG_BUILTIN2_ARG_TEMPLATED(NAME, long) \ + _CLANG_BUILTIN2_ARG_TEMPLATED(NAME, long long) \ + _CLANG_BUILTIN2_ARG_TEMPLATED(NAME, unsigned char) \ + _CLANG_BUILTIN2_ARG_TEMPLATED(NAME, unsigned short) \ + _CLANG_BUILTIN2_ARG_TEMPLATED(NAME, unsigned int) \ + _CLANG_BUILTIN2_ARG_TEMPLATED(NAME, unsigned long) \ + _CLANG_BUILTIN2_ARG_TEMPLATED(NAME, unsigned long long) \ + _CLANG_BUILTIN2_ARG_TEMPLATED(NAME, bool) \ + _CLANG_BUILTIN2_ARG_TEMPLATED(NAME, char) \ + _CLANG_BUILTIN2_ARG_TEMPLATED_CHAR8_T(NAME) \ + _CLANG_BUILTIN2_ARG_TEMPLATED(NAME, char16_t) \ + _CLANG_BUILTIN2_ARG_TEMPLATED(NAME, char32_t) \ + _CLANG_BUILTIN2_ARG_TEMPLATED_WCHAR_T(NAME) + #define _CLANG_BUILTIN1(NAME) \ _CLANG_BUILTIN1_ARG(NAME, float) \ _CLANG_BUILTIN1_ARG(NAME, double) \ @@ -633,19 +680,30 @@ _CLANG_BUILTIN2(islessequal) _CLANG_BUILTIN2(islessgreater) _CLANG_BUILTIN2(isunordered) +_CLANG_BUILTIN2_TEMPLATED(isgreater) +_CLANG_BUILTIN2_TEMPLATED(isgreaterequal) +_CLANG_BUILTIN2_TEMPLATED(isless) +_CLANG_BUILTIN2_TEMPLATED(islessequal) +_CLANG_BUILTIN2_TEMPLATED(islessgreater) +_CLANG_BUILTIN2_TEMPLATED(isunordered) + #undef _CLANG_BUILTIN1_ARG #undef _CLANG_BUILTIN2_ARG #undef _CLANG_BUILTIN1 #undef _CLANG_BUILTIN2 +#undef _CLANG_BUILTIN2_ARG_TEMPLATED +#undef _CLANG_BUILTIN2_ARG_TEMPLATED_CHAR8_T +#undef _CLANG_BUILTIN2_ARG_TEMPLATED_WCHAR_T +#undef _CLANG_BUILTIN2_TEMPLATED #endif // ^^^ defined(__clang__) ^^^ -// TRANSITION, GH-519, should be provided by UCRT +// TRANSITION, DevCom-10294165, should be provided by UCRT template , int> = 0> _NODISCARD _Check_return_ _CONSTEXPR23 int fpclassify(_In_ const _Ty _Ix) noexcept /* strengthened */ { return _Ix == 0 ? FP_ZERO : FP_NORMAL; } -// TRANSITION, GH-519, should be provided by UCRT +// TRANSITION, DevCom-10294165, should be provided by UCRT template , int> = 0> _NODISCARD _Check_return_ _CONSTEXPR23 bool signbit(_In_ const _Ty _Ix) noexcept /* strengthened */ { if constexpr (static_cast<_Ty>(-1) < _Ty{}) { @@ -655,7 +713,7 @@ _NODISCARD _Check_return_ _CONSTEXPR23 bool signbit(_In_ const _Ty _Ix) noexcept } } -// TRANSITION, GH-519, additional overloads are not templated to avoid ambiguity with the major overload in UCRT +// TRANSITION, DevCom-10294165, additional overloads are not templated to avoid ambiguity with the overload in UCRT #define _GENERIC_MATH_ISNORMAL(TYPE) \ _NODISCARD _Check_return_ _CONSTEXPR23 bool isnormal(_In_ const TYPE _Ix) noexcept /* strengthened */ { \ return _Ix != 0; \ @@ -729,7 +787,7 @@ _GENERIC_MATH_ISNORMAL(wchar_t) #define _GENERIC_MATH2I(FUN, CLANG_INTRIN, MSVC_INTRIN) _GENERIC_MATH2_BASE(FUN, _CSTD FUN) #endif // ^^^ intrinsics unavailable ^^^ -// TRANSITION, GH-519, additional overloads are not templated to avoid ambiguity with the major overload in UCRT +// TRANSITION, DevCom-10294165, additional overloads are not templated to avoid ambiguity with the overload in UCRT #define _GENERIC_MATH_CLASSIFY1_RETV_INTEGER(FUN, RETV, TYPE) \ _NODISCARD _Check_return_ _CONSTEXPR23 bool FUN(_In_ TYPE) noexcept /* strengthened */ { \ return RETV; \ diff --git a/tests/std/test.lst b/tests/std/test.lst index 3b22ab147a..7c4c3988dd 100644 --- a/tests/std/test.lst +++ b/tests/std/test.lst @@ -244,6 +244,7 @@ tests\GH_004275_seeking_fancy_iterators tests\GH_004388_unordered_meow_operator_equal tests\GH_004477_mdspan_warning_5246 tests\GH_004597_self_swap +tests\GH_004609_heterogeneous_cmp_overloads tests\GH_004618_mixed_operator_usage_keeps_statistical_properties tests\GH_004618_normal_distribution_avoids_resets tests\GH_004657_expected_constraints_permissive diff --git a/tests/std/tests/GH_000519_cmath_overloads/test.cpp b/tests/std/tests/GH_000519_cmath_overloads/test.cpp index 655622f87a..06d0bf3946 100644 --- a/tests/std/tests/GH_000519_cmath_overloads/test.cpp +++ b/tests/std/tests/GH_000519_cmath_overloads/test.cpp @@ -82,6 +82,10 @@ CONSTEXPR23 void test_bool_overloads() { template CONSTEXPR23 void test_other_integral_overloads() { + constexpr I imax = std::numeric_limits::max(); + constexpr I imaxm1 = static_cast(imax - 1); + constexpr bool narrower_than_double = std::numeric_limits::digits < std::numeric_limits::digits; + // test overloads in std assert(std::fpclassify(I{}) == FP_ZERO); @@ -118,6 +122,14 @@ CONSTEXPR23 void test_other_integral_overloads() { assert(std::islessequal(static_cast(17), static_cast(29))); assert(std::islessgreater(static_cast(17), static_cast(29))); assert(!std::isunordered(static_cast(17), static_cast(29))); + + // test that integers are converted to double + assert(std::isgreater(imax, imaxm1) == narrower_than_double); + assert(std::isgreaterequal(imaxm1, imax) == !narrower_than_double); + assert(std::isless(imaxm1, imax) == narrower_than_double); + assert(std::islessequal(imax, imaxm1) == !narrower_than_double); + assert(std::islessgreater(imax, imaxm1) == narrower_than_double); + assert(!std::isunordered(imax, imaxm1)); } // test overloads in the global namespace @@ -156,6 +168,14 @@ CONSTEXPR23 void test_other_integral_overloads() { assert(::islessequal(static_cast(17), static_cast(29))); assert(::islessgreater(static_cast(17), static_cast(29))); assert(!::isunordered(static_cast(17), static_cast(29))); + + // test that integers are converted to double + assert(::isgreater(imax, imaxm1) == narrower_than_double); + assert(::isgreaterequal(imaxm1, imax) == !narrower_than_double); + assert(::isless(imaxm1, imax) == narrower_than_double); + assert(::islessequal(imax, imaxm1) == !narrower_than_double); + assert(::islessgreater(imax, imaxm1) == narrower_than_double); + assert(!::isunordered(imax, imaxm1)); } } diff --git a/tests/std/tests/GH_004609_heterogeneous_cmp_overloads/env.lst b/tests/std/tests/GH_004609_heterogeneous_cmp_overloads/env.lst new file mode 100644 index 0000000000..19f025bd0e --- /dev/null +++ b/tests/std/tests/GH_004609_heterogeneous_cmp_overloads/env.lst @@ -0,0 +1,4 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\usual_matrix.lst diff --git a/tests/std/tests/GH_004609_heterogeneous_cmp_overloads/test.cpp b/tests/std/tests/GH_004609_heterogeneous_cmp_overloads/test.cpp new file mode 100644 index 0000000000..fae24d3891 --- /dev/null +++ b/tests/std/tests/GH_004609_heterogeneous_cmp_overloads/test.cpp @@ -0,0 +1,1067 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include +#include + +template +void test_heterogeneous_floating_overloads() { + constexpr F1 lhs = static_cast(3.14); + constexpr F1 lhseq = static_cast(23.5); + constexpr F1 linf = std::numeric_limits::infinity(); + constexpr F1 lnan = std::numeric_limits::quiet_NaN(); + + constexpr F2 rhs = static_cast(17.29); + constexpr F2 rhseq = static_cast(23.5); + constexpr F2 rinf = std::numeric_limits::infinity(); + constexpr F2 rnan = std::numeric_limits::quiet_NaN(); + + // test overloads in std + + assert(!std::isgreater(lhs, rhs)); + assert(!std::isgreater(lhs, rinf)); + assert(std::isgreater(lhs, -rinf)); + assert(std::isgreater(rhs, lhs)); + assert(!std::isgreater(rhs, linf)); + assert(std::isgreater(rhs, -linf)); + assert(!std::isgreater(lhseq, rhseq)); + assert(!std::isgreater(rhseq, lhseq)); + assert(!std::isgreater(linf, rinf)); + assert(!std::isgreater(rinf, linf)); + assert(!std::isgreater(lnan, rhs)); + assert(!std::isgreater(lnan, rinf)); + assert(!std::isgreater(lnan, -rinf)); + assert(!std::isgreater(lnan, rnan)); + assert(!std::isgreater(rnan, lhs)); + assert(!std::isgreater(rnan, linf)); + assert(!std::isgreater(rnan, -linf)); + assert(!std::isgreater(rnan, lnan)); + + assert(!std::isgreaterequal(lhs, rhs)); + assert(!std::isgreaterequal(lhs, rinf)); + assert(std::isgreaterequal(lhs, -rinf)); + assert(std::isgreaterequal(rhs, lhs)); + assert(!std::isgreaterequal(rhs, linf)); + assert(std::isgreaterequal(rhs, -linf)); + assert(std::isgreaterequal(lhseq, rhseq)); + assert(std::isgreaterequal(rhseq, lhseq)); + assert(std::isgreaterequal(linf, rinf)); + assert(std::isgreaterequal(rinf, linf)); + assert(!std::isgreaterequal(lnan, rhs)); + assert(!std::isgreaterequal(lnan, rinf)); + assert(!std::isgreaterequal(lnan, -rinf)); + assert(!std::isgreaterequal(lnan, rnan)); + assert(!std::isgreaterequal(rnan, lhs)); + assert(!std::isgreaterequal(rnan, linf)); + assert(!std::isgreaterequal(rnan, -linf)); + assert(!std::isgreaterequal(rnan, lnan)); + + assert(std::isless(lhs, rhs)); + assert(std::isless(lhs, rinf)); + assert(!std::isless(lhs, -rinf)); + assert(!std::isless(rhs, lhs)); + assert(std::isless(rhs, linf)); + assert(!std::isless(rhs, -linf)); + assert(!std::isless(lhseq, rhseq)); + assert(!std::isless(rhseq, lhseq)); + assert(!std::isless(linf, rinf)); + assert(!std::isless(rinf, linf)); + assert(!std::isless(lnan, rhs)); + assert(!std::isless(lnan, rinf)); + assert(!std::isless(lnan, -rinf)); + assert(!std::isless(lnan, rnan)); + assert(!std::isless(rnan, lhs)); + assert(!std::isless(rnan, linf)); + assert(!std::isless(rnan, -linf)); + assert(!std::isless(rnan, lnan)); + + assert(std::islessequal(lhs, rhs)); + assert(std::islessequal(lhs, rinf)); + assert(!std::islessequal(lhs, -rinf)); + assert(!std::islessequal(rhs, lhs)); + assert(std::islessequal(rhs, linf)); + assert(!std::islessequal(rhs, -linf)); + assert(std::islessequal(lhseq, rhseq)); + assert(std::islessequal(rhseq, lhseq)); + assert(std::islessequal(linf, rinf)); + assert(std::islessequal(rinf, linf)); + assert(!std::islessequal(lnan, rhs)); + assert(!std::islessequal(lnan, rinf)); + assert(!std::islessequal(lnan, -rinf)); + assert(!std::islessequal(lnan, rnan)); + assert(!std::islessequal(rnan, lhs)); + assert(!std::islessequal(rnan, linf)); + assert(!std::islessequal(rnan, -linf)); + assert(!std::islessequal(rnan, lnan)); + + assert(std::islessgreater(lhs, rhs)); + assert(std::islessgreater(lhs, rinf)); + assert(std::islessgreater(lhs, -rinf)); + assert(std::islessgreater(rhs, lhs)); + assert(std::islessgreater(rhs, linf)); + assert(std::islessgreater(rhs, -linf)); + assert(!std::islessgreater(lhseq, rhseq)); + assert(!std::islessgreater(rhseq, lhseq)); + assert(!std::islessgreater(linf, rinf)); + assert(!std::islessgreater(rinf, linf)); + assert(!std::islessgreater(lnan, rhs)); + assert(!std::islessgreater(lnan, rinf)); + assert(!std::islessgreater(lnan, -rinf)); + assert(!std::islessgreater(lnan, rnan)); + assert(!std::islessgreater(rnan, lhs)); + assert(!std::islessgreater(rnan, linf)); + assert(!std::islessgreater(rnan, -linf)); + assert(!std::islessgreater(rnan, lnan)); + + assert(!std::isunordered(lhs, rhs)); + assert(!std::isunordered(lhs, rinf)); + assert(!std::isunordered(lhs, -rinf)); + assert(!std::isunordered(rhs, lhs)); + assert(!std::isunordered(rhs, linf)); + assert(!std::isunordered(rhs, -linf)); + assert(!std::isunordered(lhseq, rhseq)); + assert(!std::isunordered(rhseq, lhseq)); + assert(!std::isunordered(linf, rinf)); + assert(!std::isunordered(rinf, linf)); + assert(std::isunordered(lnan, rhs)); + assert(std::isunordered(lnan, rinf)); + assert(std::isunordered(lnan, -rinf)); + assert(std::isunordered(lnan, rnan)); + assert(std::isunordered(rnan, lhs)); + assert(std::isunordered(rnan, linf)); + assert(std::isunordered(rnan, -linf)); + assert(std::isunordered(rnan, lnan)); + + // test overloads in the global namespace + + assert(!::isgreater(lhs, rhs)); + assert(!::isgreater(lhs, rinf)); + assert(::isgreater(lhs, -rinf)); + assert(::isgreater(rhs, lhs)); + assert(!::isgreater(rhs, linf)); + assert(::isgreater(rhs, -linf)); + assert(!::isgreater(lhseq, rhseq)); + assert(!::isgreater(rhseq, lhseq)); + assert(!::isgreater(linf, rinf)); + assert(!::isgreater(rinf, linf)); + assert(!::isgreater(lnan, rhs)); + assert(!::isgreater(lnan, rinf)); + assert(!::isgreater(lnan, -rinf)); + assert(!::isgreater(lnan, rnan)); + assert(!::isgreater(rnan, lhs)); + assert(!::isgreater(rnan, linf)); + assert(!::isgreater(rnan, -linf)); + assert(!::isgreater(rnan, lnan)); + + assert(!::isgreaterequal(lhs, rhs)); + assert(!::isgreaterequal(lhs, rinf)); + assert(::isgreaterequal(lhs, -rinf)); + assert(::isgreaterequal(rhs, lhs)); + assert(!::isgreaterequal(rhs, linf)); + assert(::isgreaterequal(rhs, -linf)); + assert(::isgreaterequal(lhseq, rhseq)); + assert(::isgreaterequal(rhseq, lhseq)); + assert(::isgreaterequal(linf, rinf)); + assert(::isgreaterequal(rinf, linf)); + assert(!::isgreaterequal(lnan, rhs)); + assert(!::isgreaterequal(lnan, rinf)); + assert(!::isgreaterequal(lnan, -rinf)); + assert(!::isgreaterequal(lnan, rnan)); + assert(!::isgreaterequal(rnan, lhs)); + assert(!::isgreaterequal(rnan, linf)); + assert(!::isgreaterequal(rnan, -linf)); + assert(!::isgreaterequal(rnan, lnan)); + + assert(::isless(lhs, rhs)); + assert(::isless(lhs, rinf)); + assert(!::isless(lhs, -rinf)); + assert(!::isless(rhs, lhs)); + assert(::isless(rhs, linf)); + assert(!::isless(rhs, -linf)); + assert(!::isless(lhseq, rhseq)); + assert(!::isless(rhseq, lhseq)); + assert(!::isless(linf, rinf)); + assert(!::isless(rinf, linf)); + assert(!::isless(lnan, rhs)); + assert(!::isless(lnan, rinf)); + assert(!::isless(lnan, -rinf)); + assert(!::isless(lnan, rnan)); + assert(!::isless(rnan, lhs)); + assert(!::isless(rnan, linf)); + assert(!::isless(rnan, -linf)); + assert(!::isless(rnan, lnan)); + + assert(::islessequal(lhs, rhs)); + assert(::islessequal(lhs, rinf)); + assert(!::islessequal(lhs, -rinf)); + assert(!::islessequal(rhs, lhs)); + assert(::islessequal(rhs, linf)); + assert(!::islessequal(rhs, -linf)); + assert(::islessequal(lhseq, rhseq)); + assert(::islessequal(rhseq, lhseq)); + assert(::islessequal(linf, rinf)); + assert(::islessequal(rinf, linf)); + assert(!::islessequal(lnan, rhs)); + assert(!::islessequal(lnan, rinf)); + assert(!::islessequal(lnan, -rinf)); + assert(!::islessequal(lnan, rnan)); + assert(!::islessequal(rnan, lhs)); + assert(!::islessequal(rnan, linf)); + assert(!::islessequal(rnan, -linf)); + assert(!::islessequal(rnan, lnan)); + + assert(::islessgreater(lhs, rhs)); + assert(::islessgreater(lhs, rinf)); + assert(::islessgreater(lhs, -rinf)); + assert(::islessgreater(rhs, lhs)); + assert(::islessgreater(rhs, linf)); + assert(::islessgreater(rhs, -linf)); + assert(!::islessgreater(lhseq, rhseq)); + assert(!::islessgreater(rhseq, lhseq)); + assert(!::islessgreater(linf, rinf)); + assert(!::islessgreater(rinf, linf)); + assert(!::islessgreater(lnan, rhs)); + assert(!::islessgreater(lnan, rinf)); + assert(!::islessgreater(lnan, -rinf)); + assert(!::islessgreater(lnan, rnan)); + assert(!::islessgreater(rnan, lhs)); + assert(!::islessgreater(rnan, linf)); + assert(!::islessgreater(rnan, -linf)); + assert(!::islessgreater(rnan, lnan)); + + assert(!::isunordered(lhs, rhs)); + assert(!::isunordered(lhs, rinf)); + assert(!::isunordered(lhs, -rinf)); + assert(!::isunordered(rhs, lhs)); + assert(!::isunordered(rhs, linf)); + assert(!::isunordered(rhs, -linf)); + assert(!::isunordered(lhseq, rhseq)); + assert(!::isunordered(rhseq, lhseq)); + assert(!::isunordered(linf, rinf)); + assert(!::isunordered(rinf, linf)); + assert(::isunordered(lnan, rhs)); + assert(::isunordered(lnan, rinf)); + assert(::isunordered(lnan, -rinf)); + assert(::isunordered(lnan, rnan)); + assert(::isunordered(rnan, lhs)); + assert(::isunordered(rnan, linf)); + assert(::isunordered(rnan, -linf)); + assert(::isunordered(rnan, lnan)); +} + +template +void test_heterogeneous_mixed_overloads_per_integer_type() { + constexpr F lhs = static_cast(42.0); + constexpr F linf = std::numeric_limits::infinity(); + constexpr F lnan = std::numeric_limits::quiet_NaN(); + + constexpr I rhslt{41}; + constexpr I rhseq{42}; + constexpr I rhsgt{43}; + + // test overloads in std + + assert(std::isgreater(lhs, rhslt)); + assert(!std::isgreater(lhs, rhseq)); + assert(!std::isgreater(lhs, rhsgt)); + assert(std::isgreater(linf, rhseq)); + assert(!std::isgreater(-linf, rhseq)); + assert(!std::isgreater(rhslt, lhs)); + assert(!std::isgreater(rhseq, lhs)); + assert(std::isgreater(rhsgt, lhs)); + assert(!std::isgreater(rhseq, linf)); + assert(std::isgreater(rhseq, -linf)); + assert(!std::isgreater(lnan, rhseq)); + assert(!std::isgreater(rhseq, lnan)); + + assert(std::isgreaterequal(lhs, rhslt)); + assert(std::isgreaterequal(lhs, rhseq)); + assert(!std::isgreaterequal(lhs, rhsgt)); + assert(std::isgreaterequal(linf, rhseq)); + assert(!std::isgreaterequal(-linf, rhseq)); + assert(!std::isgreaterequal(rhslt, lhs)); + assert(std::isgreaterequal(rhseq, lhs)); + assert(std::isgreaterequal(rhsgt, lhs)); + assert(!std::isgreaterequal(rhseq, linf)); + assert(std::isgreaterequal(rhseq, -linf)); + assert(!std::isgreaterequal(lnan, rhseq)); + assert(!std::isgreaterequal(rhseq, lnan)); + + assert(!std::isless(lhs, rhslt)); + assert(!std::isless(lhs, rhseq)); + assert(std::isless(lhs, rhsgt)); + assert(!std::isless(linf, rhseq)); + assert(std::isless(-linf, rhseq)); + assert(std::isless(rhslt, lhs)); + assert(!std::isless(rhseq, lhs)); + assert(!std::isless(rhsgt, lhs)); + assert(std::isless(rhseq, linf)); + assert(!std::isless(rhseq, -linf)); + assert(!std::isless(lnan, rhseq)); + assert(!std::isless(rhseq, lnan)); + + assert(!std::islessequal(lhs, rhslt)); + assert(std::islessequal(lhs, rhseq)); + assert(std::islessequal(lhs, rhsgt)); + assert(!std::islessequal(linf, rhseq)); + assert(std::islessequal(-linf, rhseq)); + assert(std::islessequal(rhslt, lhs)); + assert(std::islessequal(rhseq, lhs)); + assert(!std::islessequal(rhsgt, lhs)); + assert(std::islessequal(rhseq, linf)); + assert(!std::islessequal(rhseq, -linf)); + assert(!std::islessequal(lnan, rhseq)); + assert(!std::islessequal(rhseq, lnan)); + + assert(std::islessgreater(lhs, rhslt)); + assert(!std::islessgreater(lhs, rhseq)); + assert(std::islessgreater(lhs, rhsgt)); + assert(std::islessgreater(linf, rhseq)); + assert(std::islessgreater(-linf, rhseq)); + assert(std::islessgreater(rhslt, lhs)); + assert(!std::islessgreater(rhseq, lhs)); + assert(std::islessgreater(rhsgt, lhs)); + assert(std::islessgreater(rhseq, linf)); + assert(std::islessgreater(rhseq, -linf)); + assert(!std::islessgreater(lnan, rhseq)); + assert(!std::islessgreater(rhseq, lnan)); + + assert(!std::isunordered(lhs, rhslt)); + assert(!std::isunordered(lhs, rhseq)); + assert(!std::isunordered(lhs, rhsgt)); + assert(!std::isunordered(linf, rhseq)); + assert(!std::isunordered(-linf, rhseq)); + assert(!std::isunordered(rhslt, lhs)); + assert(!std::isunordered(rhseq, lhs)); + assert(!std::isunordered(rhsgt, lhs)); + assert(!std::isunordered(rhseq, linf)); + assert(!std::isunordered(rhseq, -linf)); + assert(std::isunordered(lnan, rhseq)); + assert(std::isunordered(rhseq, lnan)); + + // test overloads in the global namespace + + assert(::isgreater(lhs, rhslt)); + assert(!::isgreater(lhs, rhseq)); + assert(!::isgreater(lhs, rhsgt)); + assert(::isgreater(linf, rhseq)); + assert(!::isgreater(-linf, rhseq)); + assert(!::isgreater(rhslt, lhs)); + assert(!::isgreater(rhseq, lhs)); + assert(::isgreater(rhsgt, lhs)); + assert(!::isgreater(rhseq, linf)); + assert(::isgreater(rhseq, -linf)); + assert(!::isgreater(lnan, rhseq)); + assert(!::isgreater(rhseq, lnan)); + + assert(::isgreaterequal(lhs, rhslt)); + assert(::isgreaterequal(lhs, rhseq)); + assert(!::isgreaterequal(lhs, rhsgt)); + assert(::isgreaterequal(linf, rhseq)); + assert(!::isgreaterequal(-linf, rhseq)); + assert(!::isgreaterequal(rhslt, lhs)); + assert(::isgreaterequal(rhseq, lhs)); + assert(::isgreaterequal(rhsgt, lhs)); + assert(!::isgreaterequal(rhseq, linf)); + assert(::isgreaterequal(rhseq, -linf)); + assert(!::isgreaterequal(lnan, rhseq)); + assert(!::isgreaterequal(rhseq, lnan)); + + assert(!::isless(lhs, rhslt)); + assert(!::isless(lhs, rhseq)); + assert(::isless(lhs, rhsgt)); + assert(!::isless(linf, rhseq)); + assert(::isless(-linf, rhseq)); + assert(::isless(rhslt, lhs)); + assert(!::isless(rhseq, lhs)); + assert(!::isless(rhsgt, lhs)); + assert(::isless(rhseq, linf)); + assert(!::isless(rhseq, -linf)); + assert(!::isless(lnan, rhseq)); + assert(!::isless(rhseq, lnan)); + + assert(!::islessequal(lhs, rhslt)); + assert(::islessequal(lhs, rhseq)); + assert(::islessequal(lhs, rhsgt)); + assert(!::islessequal(linf, rhseq)); + assert(::islessequal(-linf, rhseq)); + assert(::islessequal(rhslt, lhs)); + assert(::islessequal(rhseq, lhs)); + assert(!::islessequal(rhsgt, lhs)); + assert(::islessequal(rhseq, linf)); + assert(!::islessequal(rhseq, -linf)); + assert(!::islessequal(lnan, rhseq)); + assert(!::islessequal(rhseq, lnan)); + + assert(::islessgreater(lhs, rhslt)); + assert(!::islessgreater(lhs, rhseq)); + assert(::islessgreater(lhs, rhsgt)); + assert(::islessgreater(linf, rhseq)); + assert(::islessgreater(-linf, rhseq)); + assert(::islessgreater(rhslt, lhs)); + assert(!::islessgreater(rhseq, lhs)); + assert(::islessgreater(rhsgt, lhs)); + assert(::islessgreater(rhseq, linf)); + assert(::islessgreater(rhseq, -linf)); + assert(!::islessgreater(lnan, rhseq)); + assert(!::islessgreater(rhseq, lnan)); + + assert(!::isunordered(lhs, rhslt)); + assert(!::isunordered(lhs, rhseq)); + assert(!::isunordered(lhs, rhsgt)); + assert(!::isunordered(linf, rhseq)); + assert(!::isunordered(-linf, rhseq)); + assert(!::isunordered(rhslt, lhs)); + assert(!::isunordered(rhseq, lhs)); + assert(!::isunordered(rhsgt, lhs)); + assert(!::isunordered(rhseq, linf)); + assert(!::isunordered(rhseq, -linf)); + assert(::isunordered(lnan, rhseq)); + assert(::isunordered(rhseq, lnan)); +} + +template +void test_heterogeneous_mixed_overloads_per_fp_type() { + test_heterogeneous_mixed_overloads_per_integer_type(); + test_heterogeneous_mixed_overloads_per_integer_type(); + test_heterogeneous_mixed_overloads_per_integer_type(); + test_heterogeneous_mixed_overloads_per_integer_type(); + test_heterogeneous_mixed_overloads_per_integer_type(); + test_heterogeneous_mixed_overloads_per_integer_type(); + test_heterogeneous_mixed_overloads_per_integer_type(); + test_heterogeneous_mixed_overloads_per_integer_type(); + test_heterogeneous_mixed_overloads_per_integer_type(); + test_heterogeneous_mixed_overloads_per_integer_type(); + test_heterogeneous_mixed_overloads_per_integer_type(); +#ifdef __cpp_char8_t + test_heterogeneous_mixed_overloads_per_integer_type(); +#endif // defined(__cpp_char8_t) + test_heterogeneous_mixed_overloads_per_integer_type(); + test_heterogeneous_mixed_overloads_per_integer_type(); + test_heterogeneous_mixed_overloads_per_integer_type(); +} + +template +void test_heterogeneous_mixed_overloads_with_bool() { + constexpr F f0{}; + constexpr F f1 = static_cast(1.0); + constexpr F fmid = static_cast(0.5); + constexpr F finf = std::numeric_limits::infinity(); + constexpr F fnan = std::numeric_limits::quiet_NaN(); + + // test overloads in std + + assert(!std::isgreater(f0, false)); + assert(!std::isgreater(f1, true)); + assert(std::isgreater(fmid, false)); + assert(!std::isgreater(fmid, true)); + assert(std::isgreater(finf, false)); + assert(std::isgreater(finf, true)); + assert(!std::isgreater(-finf, false)); + assert(!std::isgreater(-finf, true)); + assert(!std::isgreater(false, f0)); + assert(!std::isgreater(true, f1)); + assert(!std::isgreater(false, fmid)); + assert(std::isgreater(true, fmid)); + assert(!std::isgreater(false, finf)); + assert(!std::isgreater(true, finf)); + assert(std::isgreater(false, -finf)); + assert(std::isgreater(true, -finf)); + assert(!std::isgreater(fnan, false)); + assert(!std::isgreater(fnan, true)); + assert(!std::isgreater(false, fnan)); + assert(!std::isgreater(true, fnan)); + + assert(std::isgreaterequal(f0, false)); + assert(std::isgreaterequal(f1, true)); + assert(std::isgreaterequal(fmid, false)); + assert(!std::isgreaterequal(fmid, true)); + assert(std::isgreaterequal(finf, false)); + assert(std::isgreaterequal(finf, true)); + assert(!std::isgreaterequal(-finf, false)); + assert(!std::isgreaterequal(-finf, true)); + assert(std::isgreaterequal(false, f0)); + assert(std::isgreaterequal(true, f1)); + assert(!std::isgreaterequal(false, fmid)); + assert(std::isgreaterequal(true, fmid)); + assert(!std::isgreaterequal(false, finf)); + assert(!std::isgreaterequal(true, finf)); + assert(std::isgreaterequal(false, -finf)); + assert(std::isgreaterequal(true, -finf)); + assert(!std::isgreaterequal(fnan, false)); + assert(!std::isgreaterequal(fnan, true)); + assert(!std::isgreaterequal(false, fnan)); + assert(!std::isgreaterequal(true, fnan)); + + assert(!std::isless(f0, false)); + assert(!std::isless(f1, true)); + assert(!std::isless(fmid, false)); + assert(std::isless(fmid, true)); + assert(!std::isless(finf, false)); + assert(!std::isless(finf, true)); + assert(std::isless(-finf, false)); + assert(std::isless(-finf, true)); + assert(!std::isless(false, f0)); + assert(!std::isless(true, f1)); + assert(std::isless(false, fmid)); + assert(!std::isless(true, fmid)); + assert(std::isless(false, finf)); + assert(std::isless(true, finf)); + assert(!std::isless(false, -finf)); + assert(!std::isless(true, -finf)); + assert(!std::isless(fnan, false)); + assert(!std::isless(fnan, true)); + assert(!std::isless(false, fnan)); + assert(!std::isless(true, fnan)); + + assert(std::islessequal(f0, false)); + assert(std::islessequal(f1, true)); + assert(!std::islessequal(fmid, false)); + assert(std::islessequal(fmid, true)); + assert(!std::islessequal(finf, false)); + assert(!std::islessequal(finf, true)); + assert(std::islessequal(-finf, false)); + assert(std::islessequal(-finf, true)); + assert(std::islessequal(false, f0)); + assert(std::islessequal(true, f1)); + assert(std::islessequal(false, fmid)); + assert(!std::islessequal(true, fmid)); + assert(std::islessequal(false, finf)); + assert(std::islessequal(true, finf)); + assert(!std::islessequal(false, -finf)); + assert(!std::islessequal(true, -finf)); + assert(!std::islessequal(fnan, false)); + assert(!std::islessequal(fnan, true)); + assert(!std::islessequal(false, fnan)); + assert(!std::islessequal(true, fnan)); + + assert(!std::islessgreater(f0, false)); + assert(!std::islessgreater(f1, true)); + assert(std::islessgreater(fmid, false)); + assert(std::islessgreater(fmid, true)); + assert(std::islessgreater(finf, false)); + assert(std::islessgreater(finf, true)); + assert(std::islessgreater(-finf, false)); + assert(std::islessgreater(-finf, true)); + assert(!std::islessgreater(false, f0)); + assert(!std::islessgreater(true, f1)); + assert(std::islessgreater(false, fmid)); + assert(std::islessgreater(true, fmid)); + assert(std::islessgreater(false, finf)); + assert(std::islessgreater(true, finf)); + assert(std::islessgreater(false, -finf)); + assert(std::islessgreater(true, -finf)); + assert(!std::islessgreater(fnan, false)); + assert(!std::islessgreater(fnan, true)); + assert(!std::islessgreater(false, fnan)); + assert(!std::islessgreater(true, fnan)); + + assert(!std::isunordered(f0, false)); + assert(!std::isunordered(f1, true)); + assert(!std::isunordered(fmid, false)); + assert(!std::isunordered(fmid, true)); + assert(!std::isunordered(finf, false)); + assert(!std::isunordered(finf, true)); + assert(!std::isunordered(-finf, false)); + assert(!std::isunordered(-finf, true)); + assert(!std::isunordered(false, f0)); + assert(!std::isunordered(true, f1)); + assert(!std::isunordered(false, fmid)); + assert(!std::isunordered(true, fmid)); + assert(!std::isunordered(false, finf)); + assert(!std::isunordered(true, finf)); + assert(!std::isunordered(false, -finf)); + assert(!std::isunordered(true, -finf)); + assert(std::isunordered(fnan, false)); + assert(std::isunordered(fnan, true)); + assert(std::isunordered(false, fnan)); + assert(std::isunordered(true, fnan)); + + // test overloads in the global namespace + + assert(!::isgreater(f0, false)); + assert(!::isgreater(f1, true)); + assert(::isgreater(fmid, false)); + assert(!::isgreater(fmid, true)); + assert(::isgreater(finf, false)); + assert(::isgreater(finf, true)); + assert(!::isgreater(-finf, false)); + assert(!::isgreater(-finf, true)); + assert(!::isgreater(false, f0)); + assert(!::isgreater(true, f1)); + assert(!::isgreater(false, fmid)); + assert(::isgreater(true, fmid)); + assert(!::isgreater(false, finf)); + assert(!::isgreater(true, finf)); + assert(::isgreater(false, -finf)); + assert(::isgreater(true, -finf)); + assert(!::isgreater(fnan, false)); + assert(!::isgreater(fnan, true)); + assert(!::isgreater(false, fnan)); + assert(!::isgreater(true, fnan)); + + assert(::isgreaterequal(f0, false)); + assert(::isgreaterequal(f1, true)); + assert(::isgreaterequal(fmid, false)); + assert(!::isgreaterequal(fmid, true)); + assert(::isgreaterequal(finf, false)); + assert(::isgreaterequal(finf, true)); + assert(!::isgreaterequal(-finf, false)); + assert(!::isgreaterequal(-finf, true)); + assert(::isgreaterequal(false, f0)); + assert(::isgreaterequal(true, f1)); + assert(!::isgreaterequal(false, fmid)); + assert(::isgreaterequal(true, fmid)); + assert(!::isgreaterequal(false, finf)); + assert(!::isgreaterequal(true, finf)); + assert(::isgreaterequal(false, -finf)); + assert(::isgreaterequal(true, -finf)); + assert(!::isgreaterequal(fnan, false)); + assert(!::isgreaterequal(fnan, true)); + assert(!::isgreaterequal(false, fnan)); + assert(!::isgreaterequal(true, fnan)); + + assert(!::isless(f0, false)); + assert(!::isless(f1, true)); + assert(!::isless(fmid, false)); + assert(::isless(fmid, true)); + assert(!::isless(finf, false)); + assert(!::isless(finf, true)); + assert(::isless(-finf, false)); + assert(::isless(-finf, true)); + assert(!::isless(false, f0)); + assert(!::isless(true, f1)); + assert(::isless(false, fmid)); + assert(!::isless(true, fmid)); + assert(::isless(false, finf)); + assert(::isless(true, finf)); + assert(!::isless(false, -finf)); + assert(!::isless(true, -finf)); + assert(!::isless(fnan, false)); + assert(!::isless(fnan, true)); + assert(!::isless(false, fnan)); + assert(!::isless(true, fnan)); + + assert(::islessequal(f0, false)); + assert(::islessequal(f1, true)); + assert(!::islessequal(fmid, false)); + assert(::islessequal(fmid, true)); + assert(!::islessequal(finf, false)); + assert(!::islessequal(finf, true)); + assert(::islessequal(-finf, false)); + assert(::islessequal(-finf, true)); + assert(::islessequal(false, f0)); + assert(::islessequal(true, f1)); + assert(::islessequal(false, fmid)); + assert(!::islessequal(true, fmid)); + assert(::islessequal(false, finf)); + assert(::islessequal(true, finf)); + assert(!::islessequal(false, -finf)); + assert(!::islessequal(true, -finf)); + assert(!::islessequal(fnan, false)); + assert(!::islessequal(fnan, true)); + assert(!::islessequal(false, fnan)); + assert(!::islessequal(true, fnan)); + + assert(!::islessgreater(f0, false)); + assert(!::islessgreater(f1, true)); + assert(::islessgreater(fmid, false)); + assert(::islessgreater(fmid, true)); + assert(::islessgreater(finf, false)); + assert(::islessgreater(finf, true)); + assert(::islessgreater(-finf, false)); + assert(::islessgreater(-finf, true)); + assert(!::islessgreater(false, f0)); + assert(!::islessgreater(true, f1)); + assert(::islessgreater(false, fmid)); + assert(::islessgreater(true, fmid)); + assert(::islessgreater(false, finf)); + assert(::islessgreater(true, finf)); + assert(::islessgreater(false, -finf)); + assert(::islessgreater(true, -finf)); + assert(!::islessgreater(fnan, false)); + assert(!::islessgreater(fnan, true)); + assert(!::islessgreater(false, fnan)); + assert(!::islessgreater(true, fnan)); + + assert(!::isunordered(f0, false)); + assert(!::isunordered(f1, true)); + assert(!::isunordered(fmid, false)); + assert(!::isunordered(fmid, true)); + assert(!::isunordered(finf, false)); + assert(!::isunordered(finf, true)); + assert(!::isunordered(-finf, false)); + assert(!::isunordered(-finf, true)); + assert(!::isunordered(false, f0)); + assert(!::isunordered(true, f1)); + assert(!::isunordered(false, fmid)); + assert(!::isunordered(true, fmid)); + assert(!::isunordered(false, finf)); + assert(!::isunordered(true, finf)); + assert(!::isunordered(false, -finf)); + assert(!::isunordered(true, -finf)); + assert(::isunordered(fnan, false)); + assert(::isunordered(fnan, true)); + assert(::isunordered(false, fnan)); + assert(::isunordered(true, fnan)); +} + +void test_all_heterogeneous_floating_overloads() { + test_heterogeneous_floating_overloads(); + test_heterogeneous_floating_overloads(); + test_heterogeneous_floating_overloads(); + test_heterogeneous_floating_overloads(); + test_heterogeneous_floating_overloads(); + test_heterogeneous_floating_overloads(); + + test_heterogeneous_mixed_overloads_per_fp_type(); + test_heterogeneous_mixed_overloads_per_fp_type(); + test_heterogeneous_mixed_overloads_per_fp_type(); + + test_heterogeneous_mixed_overloads_with_bool(); + test_heterogeneous_mixed_overloads_with_bool(); + test_heterogeneous_mixed_overloads_with_bool(); +} + +template , int> = 0> +void test_heterogeneous_integer_overloads_per_rhs_type() {} + +template , int> = 0> +void test_heterogeneous_integer_overloads_per_rhs_type() { + constexpr I1 l0{}; + constexpr I1 l1{1}; + + constexpr I2 r0{}; + constexpr I2 r1{1}; + + // test overloads in std + + assert(!std::isgreater(l0, r0)); + assert(std::isgreater(l1, r0)); + assert(!std::isgreater(l0, r1)); + assert(!std::isgreater(l1, r1)); + + assert(std::isgreaterequal(l0, r0)); + assert(std::isgreaterequal(l1, r0)); + assert(!std::isgreater(l0, r1)); + assert(std::isgreaterequal(l1, r1)); + + assert(!std::isless(l0, r0)); + assert(!std::isless(l1, r0)); + assert(std::isless(l0, r1)); + assert(!std::isless(l1, r1)); + + assert(std::islessequal(l0, r0)); + assert(!std::islessequal(l1, r0)); + assert(std::islessequal(l0, r1)); + assert(std::islessequal(l1, r1)); + + assert(!std::islessgreater(l0, r0)); + assert(std::islessgreater(l1, r0)); + assert(std::islessgreater(l0, r1)); + assert(!std::islessgreater(l1, r1)); + + assert(!std::isunordered(l0, r0)); + assert(!std::isunordered(l1, r0)); + assert(!std::isunordered(l0, r1)); + assert(!std::isunordered(l1, r1)); + + // test overloads in the global namespace + + assert(!::isgreater(l0, r0)); + assert(::isgreater(l1, r0)); + assert(!::isgreater(l0, r1)); + assert(!::isgreater(l1, r1)); + + assert(::isgreaterequal(l0, r0)); + assert(::isgreaterequal(l1, r0)); + assert(!::isgreater(l0, r1)); + assert(::isgreaterequal(l1, r1)); + + assert(!::isless(l0, r0)); + assert(!::isless(l1, r0)); + assert(::isless(l0, r1)); + assert(!::isless(l1, r1)); + + assert(::islessequal(l0, r0)); + assert(!::islessequal(l1, r0)); + assert(::islessequal(l0, r1)); + assert(::islessequal(l1, r1)); + + assert(!::islessgreater(l0, r0)); + assert(::islessgreater(l1, r0)); + assert(::islessgreater(l0, r1)); + assert(!::islessgreater(l1, r1)); + + assert(!::isunordered(l0, r0)); + assert(!::isunordered(l1, r0)); + assert(!::isunordered(l0, r1)); + assert(!::isunordered(l1, r1)); +} + +template +void test_heterogeneous_integer_overloads_with_bool() { + constexpr I lm1{static_cast(-1)}; + constexpr I l0{}; + constexpr I l1{1}; + constexpr I l2{2}; + + // test overloads in std + + assert(std::isgreater(lm1, false) == std::is_unsigned_v); + assert(std::isgreater(lm1, true) == std::is_unsigned_v); + assert(!std::isgreater(l0, false)); + assert(!std::isgreater(l0, true)); + assert(std::isgreater(l1, false)); + assert(!std::isgreater(l1, true)); + assert(std::isgreater(l2, false)); + assert(std::isgreater(l2, true)); + assert(std::isgreater(false, lm1) == std::is_signed_v); + assert(std::isgreater(true, lm1) == std::is_signed_v); + assert(!std::isgreater(false, l0)); + assert(std::isgreater(true, l0)); + assert(!std::isgreater(false, l1)); + assert(!std::isgreater(true, l1)); + assert(!std::isgreater(false, l2)); + assert(!std::isgreater(true, l2)); + + assert(std::isgreaterequal(lm1, false) == std::is_unsigned_v); + assert(std::isgreaterequal(lm1, true) == std::is_unsigned_v); + assert(std::isgreaterequal(l0, false)); + assert(!std::isgreaterequal(l0, true)); + assert(std::isgreaterequal(l1, false)); + assert(std::isgreaterequal(l1, true)); + assert(std::isgreaterequal(l2, false)); + assert(std::isgreaterequal(l2, true)); + assert(std::isgreaterequal(false, lm1) == std::is_signed_v); + assert(std::isgreaterequal(true, lm1) == std::is_signed_v); + assert(std::isgreaterequal(false, l0)); + assert(std::isgreaterequal(true, l0)); + assert(!std::isgreaterequal(false, l1)); + assert(std::isgreaterequal(true, l1)); + assert(!std::isgreaterequal(false, l2)); + assert(!std::isgreaterequal(true, l2)); + + assert(std::isless(lm1, false) == std::is_signed_v); + assert(std::isless(lm1, true) == std::is_signed_v); + assert(!std::isless(l0, false)); + assert(std::isless(l0, true)); + assert(!std::isless(l1, false)); + assert(!std::isless(l1, true)); + assert(!std::isless(l2, false)); + assert(!std::isless(l2, true)); + assert(std::isless(false, lm1) == std::is_unsigned_v); + assert(std::isless(true, lm1) == std::is_unsigned_v); + assert(!std::isless(false, l0)); + assert(!std::isless(true, l0)); + assert(std::isless(false, l1)); + assert(!std::isless(true, l1)); + assert(std::isless(false, l2)); + assert(std::isless(true, l2)); + + assert(std::islessequal(lm1, false) == std::is_signed_v); + assert(std::islessequal(lm1, true) == std::is_signed_v); + assert(std::islessequal(l0, false)); + assert(std::islessequal(l0, true)); + assert(!std::islessequal(l1, false)); + assert(std::islessequal(l1, true)); + assert(!std::islessequal(l2, false)); + assert(!std::islessequal(l2, true)); + assert(std::islessequal(false, lm1) == std::is_unsigned_v); + assert(std::islessequal(true, lm1) == std::is_unsigned_v); + assert(std::islessequal(false, l0)); + assert(!std::islessequal(true, l0)); + assert(std::islessequal(false, l1)); + assert(std::islessequal(true, l1)); + assert(std::islessequal(false, l2)); + assert(std::islessequal(true, l2)); + + assert(std::islessgreater(lm1, false)); + assert(std::islessgreater(lm1, true)); + assert(!std::islessgreater(l0, false)); + assert(std::islessgreater(l0, true)); + assert(std::islessgreater(l1, false)); + assert(!std::islessgreater(l1, true)); + assert(std::islessgreater(l2, false)); + assert(std::islessgreater(l2, true)); + assert(std::islessgreater(false, lm1)); + assert(std::islessgreater(true, lm1)); + assert(!std::islessgreater(false, l0)); + assert(std::islessgreater(true, l0)); + assert(std::islessgreater(false, l1)); + assert(!std::islessgreater(true, l1)); + assert(std::islessgreater(false, l2)); + assert(std::islessgreater(true, l2)); + + assert(!std::isunordered(lm1, false)); + assert(!std::isunordered(lm1, true)); + assert(!std::isunordered(l0, false)); + assert(!std::isunordered(l0, true)); + assert(!std::isunordered(l1, false)); + assert(!std::isunordered(l1, true)); + assert(!std::isunordered(l2, false)); + assert(!std::isunordered(l2, true)); + assert(!std::isunordered(false, lm1)); + assert(!std::isunordered(true, lm1)); + assert(!std::isunordered(false, l0)); + assert(!std::isunordered(true, l0)); + assert(!std::isunordered(false, l1)); + assert(!std::isunordered(true, l1)); + assert(!std::isunordered(false, l2)); + assert(!std::isunordered(true, l2)); + + // test overloads in the global namespace + + assert(::isgreater(lm1, false) == std::is_unsigned_v); + assert(::isgreater(lm1, true) == std::is_unsigned_v); + assert(!::isgreater(l0, false)); + assert(!::isgreater(l0, true)); + assert(::isgreater(l1, false)); + assert(!::isgreater(l1, true)); + assert(::isgreater(l2, false)); + assert(::isgreater(l2, true)); + assert(::isgreater(false, lm1) == std::is_signed_v); + assert(::isgreater(true, lm1) == std::is_signed_v); + assert(!::isgreater(false, l0)); + assert(::isgreater(true, l0)); + assert(!::isgreater(false, l1)); + assert(!::isgreater(true, l1)); + assert(!::isgreater(false, l2)); + assert(!::isgreater(true, l2)); + + assert(::isgreaterequal(lm1, false) == std::is_unsigned_v); + assert(::isgreaterequal(lm1, true) == std::is_unsigned_v); + assert(::isgreaterequal(l0, false)); + assert(!::isgreaterequal(l0, true)); + assert(::isgreaterequal(l1, false)); + assert(::isgreaterequal(l1, true)); + assert(::isgreaterequal(l2, false)); + assert(::isgreaterequal(l2, true)); + assert(::isgreaterequal(false, lm1) == std::is_signed_v); + assert(::isgreaterequal(true, lm1) == std::is_signed_v); + assert(::isgreaterequal(false, l0)); + assert(::isgreaterequal(true, l0)); + assert(!::isgreaterequal(false, l1)); + assert(::isgreaterequal(true, l1)); + assert(!::isgreaterequal(false, l2)); + assert(!::isgreaterequal(true, l2)); + + assert(::isless(lm1, false) == std::is_signed_v); + assert(::isless(lm1, true) == std::is_signed_v); + assert(!::isless(l0, false)); + assert(::isless(l0, true)); + assert(!::isless(l1, false)); + assert(!::isless(l1, true)); + assert(!::isless(l2, false)); + assert(!::isless(l2, true)); + assert(::isless(false, lm1) == std::is_unsigned_v); + assert(::isless(true, lm1) == std::is_unsigned_v); + assert(!::isless(false, l0)); + assert(!::isless(true, l0)); + assert(::isless(false, l1)); + assert(!::isless(true, l1)); + assert(::isless(false, l2)); + assert(::isless(true, l2)); + + assert(::islessequal(lm1, false) == std::is_signed_v); + assert(::islessequal(lm1, true) == std::is_signed_v); + assert(::islessequal(l0, false)); + assert(::islessequal(l0, true)); + assert(!::islessequal(l1, false)); + assert(::islessequal(l1, true)); + assert(!::islessequal(l2, false)); + assert(!::islessequal(l2, true)); + assert(::islessequal(false, lm1) == std::is_unsigned_v); + assert(::islessequal(true, lm1) == std::is_unsigned_v); + assert(::islessequal(false, l0)); + assert(!::islessequal(true, l0)); + assert(::islessequal(false, l1)); + assert(::islessequal(true, l1)); + assert(::islessequal(false, l2)); + assert(::islessequal(true, l2)); + + assert(::islessgreater(lm1, false)); + assert(::islessgreater(lm1, true)); + assert(!::islessgreater(l0, false)); + assert(::islessgreater(l0, true)); + assert(::islessgreater(l1, false)); + assert(!::islessgreater(l1, true)); + assert(::islessgreater(l2, false)); + assert(::islessgreater(l2, true)); + assert(::islessgreater(false, lm1)); + assert(::islessgreater(true, lm1)); + assert(!::islessgreater(false, l0)); + assert(::islessgreater(true, l0)); + assert(::islessgreater(false, l1)); + assert(!::islessgreater(true, l1)); + assert(::islessgreater(false, l2)); + assert(::islessgreater(true, l2)); + + assert(!::isunordered(lm1, false)); + assert(!::isunordered(lm1, true)); + assert(!::isunordered(l0, false)); + assert(!::isunordered(l0, true)); + assert(!::isunordered(l1, false)); + assert(!::isunordered(l1, true)); + assert(!::isunordered(l2, false)); + assert(!::isunordered(l2, true)); + assert(!::isunordered(false, lm1)); + assert(!::isunordered(true, lm1)); + assert(!::isunordered(false, l0)); + assert(!::isunordered(true, l0)); + assert(!::isunordered(false, l1)); + assert(!::isunordered(true, l1)); + assert(!::isunordered(false, l2)); + assert(!::isunordered(true, l2)); +} + +template +void test_heterogeneous_integer_overloads_per_integer_type() { + test_heterogeneous_integer_overloads_per_rhs_type(); + test_heterogeneous_integer_overloads_per_rhs_type(); + test_heterogeneous_integer_overloads_per_rhs_type(); + test_heterogeneous_integer_overloads_per_rhs_type(); + test_heterogeneous_integer_overloads_per_rhs_type(); + test_heterogeneous_integer_overloads_per_rhs_type(); + test_heterogeneous_integer_overloads_per_rhs_type(); + test_heterogeneous_integer_overloads_per_rhs_type(); + test_heterogeneous_integer_overloads_per_rhs_type(); + test_heterogeneous_integer_overloads_per_rhs_type(); + test_heterogeneous_integer_overloads_per_rhs_type(); +#ifdef __cpp_char8_t + test_heterogeneous_integer_overloads_per_rhs_type(); +#endif // defined(__cpp_char8_t) + test_heterogeneous_integer_overloads_per_rhs_type(); + test_heterogeneous_integer_overloads_per_rhs_type(); + test_heterogeneous_integer_overloads_per_rhs_type(); + + test_heterogeneous_integer_overloads_with_bool(); +} + +void test_all_heterogeneous_integer_overloads() { + test_heterogeneous_integer_overloads_per_integer_type(); + test_heterogeneous_integer_overloads_per_integer_type(); + test_heterogeneous_integer_overloads_per_integer_type(); + test_heterogeneous_integer_overloads_per_integer_type(); + test_heterogeneous_integer_overloads_per_integer_type(); + test_heterogeneous_integer_overloads_per_integer_type(); + test_heterogeneous_integer_overloads_per_integer_type(); + test_heterogeneous_integer_overloads_per_integer_type(); + test_heterogeneous_integer_overloads_per_integer_type(); + test_heterogeneous_integer_overloads_per_integer_type(); + test_heterogeneous_integer_overloads_per_integer_type(); +#ifdef __cpp_char8_t + test_heterogeneous_integer_overloads_per_integer_type(); +#endif // defined(__cpp_char8_t) + test_heterogeneous_integer_overloads_per_integer_type(); + test_heterogeneous_integer_overloads_per_integer_type(); + test_heterogeneous_integer_overloads_per_integer_type(); +} + +int main() { + test_all_heterogeneous_floating_overloads(); + test_all_heterogeneous_integer_overloads(); +}