diff --git a/stl/inc/__msvc_int128.hpp b/stl/inc/__msvc_int128.hpp index d0bb3167b3e..52a6f27ccc5 100644 --- a/stl/inc/__msvc_int128.hpp +++ b/stl/inc/__msvc_int128.hpp @@ -26,9 +26,11 @@ #ifdef __cpp_lib_concepts #include -#define _TEMPLATE_CLASS_INTEGRAL(type) template +#define _TEMPLATE_CLASS_INTEGRAL(type) template +#define _TEMPLATE_CLASS_FLOATING_POINT(type) template #else // ^^^ defined(__cpp_lib_concepts) / !defined(__cpp_lib_concepts) vvv -#define _TEMPLATE_CLASS_INTEGRAL(type) template , int> = 0> +#define _TEMPLATE_CLASS_INTEGRAL(type) template , int> = 0> +#define _TEMPLATE_CLASS_FLOATING_POINT(type) template , int> = 0> #endif // ^^^ !defined(__cpp_lib_concepts) ^^^ #pragma pack(push, _CRT_PACKING) @@ -309,11 +311,6 @@ struct constexpr explicit _Base128(const uint64_t _Low, const uint64_t _High) noexcept : _Word{_Low, _High} {} - _TEMPLATE_CLASS_INTEGRAL(_Ty) - _NODISCARD constexpr explicit operator _Ty() const noexcept { - return static_cast<_Ty>(_Word[0]); - } - _NODISCARD constexpr explicit operator bool() const noexcept { return (_Word[0] | _Word[1]) != 0; } @@ -721,6 +718,36 @@ struct _Unsigned128 : _Base128 { using _Base128::_Base128; constexpr explicit _Unsigned128(const _Base128& _That) noexcept : _Base128{_That} {} +#ifdef __clang__ // TRANSITION, Clang 16 or 17 + constexpr explicit _Unsigned128(const float _Val) noexcept { + _Word[0] = static_cast(_Val); + _Word[1] = static_cast(_Val / 18446744073709551616.0f); + } + + constexpr explicit _Unsigned128(const double _Val) noexcept { + _Word[0] = static_cast(_Val); + _Word[1] = static_cast(_Val / 18446744073709551616.0); + } + + constexpr explicit _Unsigned128(const long double _Val) noexcept : _Unsigned128(static_cast(_Val)) {} +#else // ^^^ workaround / no workaround vvv + _TEMPLATE_CLASS_FLOATING_POINT(_Ty) + constexpr explicit _Unsigned128(const _Ty _Val) noexcept { + _Word[0] = static_cast(_Val); + _Word[1] = static_cast(_Val / static_cast<_Ty>(18446744073709551616.0)); + } +#endif // ^^^ no workaround ^^^ + + _TEMPLATE_CLASS_INTEGRAL(_Ty) + _NODISCARD constexpr explicit operator _Ty() const noexcept { + return static_cast<_Ty>(_Word[0]); + } + + _TEMPLATE_CLASS_FLOATING_POINT(_Ty) + _NODISCARD constexpr explicit operator _Ty() const noexcept { + return static_cast<_Ty>(_Word[1]) * static_cast<_Ty>(18446744073709551616.0) + static_cast<_Ty>(_Word[0]); + } + constexpr _Unsigned128& operator=(const _Base128& _That) noexcept { _Base128::operator=(_That); return *this; @@ -1038,6 +1065,53 @@ struct _Signed128 : _Base128 { using _Base128::_Base128; constexpr explicit _Signed128(const _Base128& _That) noexcept : _Base128{_That} {} +#ifdef __clang__ // TRANSITION, Clang 16 or 17 + constexpr explicit _Signed128(const float _Val) noexcept { + const bool _Negative = _Val < 0.0f; + const float _Absval = _Negative ? -_Val : _Val; + _Word[0] = static_cast(_Absval); + _Word[1] = static_cast(_Absval / 18446744073709551616.0f); + if (_Negative) { + *this = -*this; + } + } + + constexpr explicit _Signed128(const double _Val) noexcept { + const bool _Negative = _Val < 0.0; + const double _Absval = _Negative ? -_Val : _Val; + _Word[0] = static_cast(_Absval); + _Word[1] = static_cast(_Absval / 18446744073709551616.0); + if (_Negative) { + *this = -*this; + } + } + + constexpr explicit _Signed128(const long double _Val) noexcept : _Signed128(static_cast(_Val)) {} +#else // ^^^ workaround / no workaround vvv + _TEMPLATE_CLASS_FLOATING_POINT(_Ty) + constexpr explicit _Signed128(const _Ty _Val) noexcept { + const bool _Negative = _Val < 0.0f; + const _Ty _Absval = _Negative ? -_Val : _Val; + _Word[0] = static_cast(_Absval); + _Word[1] = static_cast(_Absval / static_cast<_Ty>(18446744073709551616.0)); + if (_Negative) { + *this = -*this; + } + } +#endif // ^^^ no workaround ^^^ + + _TEMPLATE_CLASS_INTEGRAL(_Ty) + _NODISCARD constexpr explicit operator _Ty() const noexcept { + return static_cast<_Ty>(_Word[0]); + } + + _TEMPLATE_CLASS_FLOATING_POINT(_Ty) + _NODISCARD constexpr explicit operator _Ty() const noexcept { + const auto _Unsigned_self = static_cast<_Unsigned128>(*this); + return static_cast(_Word[1]) < 0 ? -static_cast<_Ty>(-_Unsigned_self) + : static_cast<_Ty>(_Unsigned_self); + } + constexpr _Signed128& operator=(const _Base128& _That) noexcept { _Base128::operator=(_That); return *this; @@ -1427,6 +1501,7 @@ struct common_type<_Unsigned128, _Signed128> { _STD_END +#undef _TEMPLATE_CLASS_FLOATING_POINT #undef _TEMPLATE_CLASS_INTEGRAL #undef _ZERO_OR_NO_INIT diff --git a/tests/std/tests/P1522R1_difference_type/test.cpp b/tests/std/tests/P1522R1_difference_type/test.cpp index fa26a332c6a..3fe72ae5fa0 100644 --- a/tests/std/tests/P1522R1_difference_type/test.cpp +++ b/tests/std/tests/P1522R1_difference_type/test.cpp @@ -1345,6 +1345,45 @@ constexpr bool test_cross() { return true; } +// Extension: explicit conversion from and to floating-point types + +template +constexpr bool test_one_floating_point() { + constexpr Flt zero = Flt{}; + constexpr Flt one = Flt{1.0}; + constexpr Flt neg_one = Flt{-1.0}; + + assert(_Unsigned128{zero} == _Unsigned128{}); + assert(_Unsigned128{zero} == 0); + assert(static_cast(_Unsigned128{zero}) == Flt{}); + + assert(_Unsigned128{one} == _Unsigned128{1}); + assert(_Unsigned128{one} == 1); + assert(static_cast(_Unsigned128{one}) == Flt{1.0}); + + assert(_Signed128{zero} == _Signed128{}); + assert(_Signed128{zero} == 0); + assert(static_cast(_Signed128{zero}) == Flt{}); + + assert(_Signed128{one} == _Signed128{1}); + assert(_Signed128{one} == 1); + assert(static_cast(_Signed128{one}) == Flt{1.0}); + + assert(_Signed128{neg_one} == _Signed128{-1}); + assert(_Signed128{neg_one} == -1); + assert(static_cast(_Signed128{neg_one}) == Flt{-1.0}); + + return true; +} + +constexpr bool test_floating_point() { + assert(test_one_floating_point()); + assert(test_one_floating_point()); + assert(test_one_floating_point()); + + return true; +} + int main() { test_unsigned(); STATIC_ASSERT(test_unsigned()); @@ -1352,4 +1391,6 @@ int main() { STATIC_ASSERT(test_signed()); test_cross(); STATIC_ASSERT(test_cross()); + test_floating_point(); + STATIC_ASSERT(test_floating_point()); }