diff --git a/stl/CMakeLists.txt b/stl/CMakeLists.txt index 82d2d1e9707..288abdfae8a 100644 --- a/stl/CMakeLists.txt +++ b/stl/CMakeLists.txt @@ -3,6 +3,7 @@ set(HEADERS ${CMAKE_CURRENT_LIST_DIR}/inc/__msvc_all_public_headers.hpp + ${CMAKE_CURRENT_LIST_DIR}/inc/__msvc_int128.hpp ${CMAKE_CURRENT_LIST_DIR}/inc/__msvc_system_error_abi.hpp ${CMAKE_CURRENT_LIST_DIR}/inc/__msvc_tzdb.hpp ${CMAKE_CURRENT_LIST_DIR}/inc/__msvc_xlocinfo_types.hpp diff --git a/stl/inc/__msvc_int128.hpp b/stl/inc/__msvc_int128.hpp new file mode 100644 index 00000000000..e0ee63d6875 --- /dev/null +++ b/stl/inc/__msvc_int128.hpp @@ -0,0 +1,1343 @@ +// __msvc_int128.hpp internal header (core) + +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#pragma once +#ifndef __MSVC_INT128_HPP +#define __MSVC_INT128_HPP + +#include +#if _STL_COMPILER_PREPROCESSOR +#ifdef __cpp_lib_concepts +#include +#include +#include +#include +#include // TRANSITION, GH-2520 + +#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 + +#if defined(_M_X64) && !defined(_M_ARM64EC) +#define _STL_128_INTRINSICS 1 +#ifdef __clang__ // clang doesn't have _udiv128 / _div128 +#define _STL_128_DIV_INTRINSICS 0 +#else // ^^^ Clang / other vvv +#define _STL_128_DIV_INTRINSICS 1 +#endif // ^^^ detect _udiv128 / _div128 ^^^ +#else // ^^^ x64 / other vvv +#define _STL_128_INTRINSICS 0 +#define _STL_128_DIV_INTRINSICS 0 +#endif // defined(_M_X64) && !defined(_M_ARM64EC) + +struct +#ifndef _M_ARM + alignas(16) +#endif + _Base128 { + uint64_t _Word[2]; + + constexpr void _Left_shift(const unsigned char _Count) noexcept { + // _STL_INTERNAL_CHECK(_Count < 128); + if (_Count == 0) { + return; + } + + if (_Count >= 64) { + _Word[1] = _Word[0] << (_Count % 64); + _Word[0] = 0; + return; + } + +#if _STL_128_INTRINSICS + if (!_STD is_constant_evaluated()) { + _Word[1] = __shiftleft128(_Word[0], _Word[1], _Count); + } else +#endif // _STL_128_INTRINSICS + { + _Word[1] = (_Word[1] << _Count) | (_Word[0] >> (64 - _Count)); + } + + _Word[0] <<= _Count; + } + + constexpr void _Unsigned_right_shift(const unsigned char _Count) noexcept { + // _STL_INTERNAL_CHECK(_Count < 128); + if (_Count == 0) { + return; + } + + if (_Count >= 64) { + _Word[0] = _Word[1] >> (_Count % 64); + _Word[1] = 0; + return; + } + +#if _STL_128_INTRINSICS + if (!_STD is_constant_evaluated()) { + _Word[0] = __shiftright128(_Word[0], _Word[1], _Count); + } else +#endif // _STL_128_INTRINSICS + { + _Word[0] = (_Word[0] >> _Count) | (_Word[1] << (64 - _Count)); + } + + _Word[1] >>= _Count; + } + + static constexpr unsigned char _AddCarry64( + unsigned char _Carry, uint64_t _Left, uint64_t _Right, uint64_t& _Result) noexcept { + // _STL_INTERNAL_CHECK(_Carry < 2); +#if _STL_128_INTRINSICS + if (!_STD is_constant_evaluated()) { + return _addcarry_u64(_Carry, _Left, _Right, &_Result); + } +#endif // _STL_128_INTRINSICS + + const uint64_t _Sum = _Left + _Right + _Carry; + _Result = _Sum; + return _Carry ? _Sum <= _Left : _Sum < _Left; + } + + static constexpr unsigned char _SubBorrow64( + unsigned char _Carry, uint64_t _Left, uint64_t _Right, uint64_t& _Result) noexcept { + // _STL_INTERNAL_CHECK(_Carry < 2); +#if _STL_128_INTRINSICS + if (!_STD is_constant_evaluated()) { + return _subborrow_u64(_Carry, _Left, _Right, &_Result); + } +#endif // _STL_128_INTRINSICS + + const auto _Difference = _Left - _Right - _Carry; + _Result = _Difference; + return _Carry ? _Difference >= _Left : _Difference > _Left; + } + + template + static constexpr void _Knuth_4_3_1_M( + const uint32_t (&__u)[__m], const uint32_t (&__v)[__n], uint32_t (&__w)[__n + __m]) noexcept { +#ifdef _ENABLE_STL_INTERNAL_CHECK + constexpr auto _Int_max = size_t{(numeric_limits::max)()}; + _STL_INTERNAL_STATIC_ASSERT(__m <= _Int_max); + _STL_INTERNAL_STATIC_ASSERT(__n <= _Int_max); +#endif // _ENABLE_STL_INTERNAL_CHECK + + for (auto& _Elem : __w) { + _Elem = 0; + } + + for (int __j = 0; __j < static_cast(__n); ++__j) { + // stash Knuth's `k` in the lower 32 bits of __t + uint64_t __t = 0; + for (int __i = 0; __i < static_cast(__m); ++__i) { + __t += static_cast(__u[__i]) * __v[__j] + __w[__i + __j]; + __w[__i + __j] = static_cast(__t); + __t >>= 32; + } + __w[__j + __m] = static_cast(__t); + } + } + + _NODISCARD static constexpr uint64_t _UMul128( + const uint64_t _Left, const uint64_t _Right, uint64_t& _High_result) noexcept { +#if _STL_128_INTRINSICS + if (!_STD is_constant_evaluated()) { + return _umul128(_Left, _Right, &_High_result); + } +#endif // _STL_128_INTRINSICS + + const uint32_t __u[2] = { + static_cast(_Left), + static_cast(_Left >> 32), + }; + const uint32_t __v[2] = { + static_cast(_Right), + static_cast(_Right >> 32), + }; + uint32_t __w[4]; + + // multiply 2-digit numbers with 4-digit result in base 2^32 + _Knuth_4_3_1_M(__u, __v, __w); + + _High_result = (static_cast(__w[3]) << 32) | __w[2]; + return (static_cast(__w[1]) << 32) | __w[0]; + } + + static constexpr void _Knuth_4_3_1_D(uint32_t* const __u, const size_t __u_size, const uint32_t* const __v, + const size_t __v_size, uint32_t* const __q) noexcept { + // Pre: __u + [0, __u_size), __v + [0, __v_size), and __q + [0, __u_size - __v_size) are all valid ranges + // constexpr auto _Int_max = size_t{(numeric_limits::max)()}; + // _STL_INTERNAL_CHECK(__v_size <= _Int_max); + const auto __n = static_cast(__v_size); + // _STL_INTERNAL_CHECK(__u_size > __v_size); + // _STL_INTERNAL_CHECK(__u_size <= _Int_max); + const auto __m = static_cast(__u_size - __v_size - 1); + // _STL_INTERNAL_CHECK(__v[__n - 1] >> 31 != 0); // Arguments are already normalized + + for (auto __j = static_cast(__m); __j >= 0; --__j) { + const auto _Two_digits = (static_cast(__u[__j + __n]) << 32) | __u[__j + __n - 1]; + auto __qhat = _Two_digits / __v[__n - 1]; + auto __rhat = _Two_digits % __v[__n - 1]; + + while ((__qhat >> 32) != 0 + || static_cast(__qhat) * static_cast(__v[__n - 2]) + > ((__rhat << 32) | __u[__j + __n - 2])) { + --__qhat; + __rhat += __v[__n - 1]; + if ((__rhat >> 32) != 0) { + break; + } + } + + int64_t __k = 0; + int64_t __t; + for (int __i = 0; __i < static_cast(__n); ++__i) { + const auto _Prod = static_cast(__qhat) * static_cast(__v[__i]); + __t = __u[__i + __j] - __k - static_cast(_Prod); + __u[__i + __j] = static_cast(__t); + __k = static_cast(_Prod >> 32) - (__t >> 32); + } + __t = __u[__j + __n] - __k; + __u[__j + __n] = static_cast(__t); + + __q[__j] = static_cast(__qhat); + if (__t < 0) { + --__q[__j]; + __k = 0; + for (int __i = 0; __i < static_cast(__n); ++__i) { + __t = __u[__i + __j] + __k + __v[__i]; + __u[__i + __j] = static_cast(__t); + __k = __t >> 32; + } + __u[__j + __n] += static_cast(__k); + } + } + + // quotient is in __q, normalized remainder is in __u + } + + _NODISCARD static constexpr uint64_t _UDiv128( + uint64_t _High, uint64_t _Low, uint64_t _Div, uint64_t& _Remainder) noexcept { + // _STL_INTERNAL_CHECK(_High < _Div); + +#if _STL_128_DIV_INTRINSICS + if (!_STD is_constant_evaluated()) { + return _udiv128(_High, _Low, _Div, &_Remainder); + } +#endif // _STL_128_DIV_INTRINSICS + + const auto __d = _STD countl_zero(static_cast(_Div >> 32)); + if (__d >= 32) { // _Div < 2^32 + auto _Rem = (_High << 32) | (_Low >> 32); + auto _Result = _Rem / static_cast(_Div); + _Rem = ((_Rem % static_cast(_Div)) << 32) | static_cast(_Low); + _Result = (_Result << 32) | (_Rem / static_cast(_Div)); + _Remainder = _Rem % static_cast(_Div); + return _Result; + } + + uint32_t __u[5] = { + static_cast(_Low << __d), + static_cast(_Low >> (32 - __d)), + static_cast(_High << __d), + static_cast(_High >> (32 - __d)), + 0, + }; + if (__d != 0) { + __u[2] |= static_cast(_Low >> (64 - __d)); + __u[4] |= static_cast(_High >> (64 - __d)); + } + + uint32_t __v[2] = { + static_cast(_Div << __d), + static_cast(_Div >> (32 - __d)), + }; + uint32_t __q[3]; + + _Knuth_4_3_1_D(__u, 5, __v, 2, __q); + // _STL_INTERNAL_CHECK(__u[4] == 0); + // _STL_INTERNAL_CHECK(__u[3] == 0); + // _STL_INTERNAL_CHECK(__u[2] == 0); + _Remainder = (static_cast(__u[1]) << (32 - __d)) | (__u[0] >> __d); + + // _STL_INTERNAL_CHECK(__q[2] == 0); + return (static_cast(__q[1]) << 32) | __q[0]; + } + + constexpr _Base128() noexcept : _Word{} {} + + template + constexpr _Base128(const _Ty _Val) noexcept : _Word{static_cast(_Val)} { + if constexpr (signed_integral<_Ty>) { + if (_Val < 0) { + _Word[1] = ~0ull; + } + } + } + + constexpr explicit _Base128(const uint64_t _Low, const uint64_t _High) noexcept : _Word{_Low, _High} {} + + template + _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; + } + + _NODISCARD_FRIEND constexpr bool operator==(const _Base128&, const _Base128&) noexcept = default; + + _NODISCARD_FRIEND constexpr bool operator<(const _Base128& _Left, const _Base128& _Right) noexcept { + if (_Left._Word[1] < _Right._Word[1]) { + return true; + } + + if (_Left._Word[1] > _Right._Word[1]) { + return false; + } + return _Left._Word[0] < _Right._Word[0]; + } + _NODISCARD_FRIEND constexpr bool operator>(const _Base128& _Left, const _Base128& _Right) noexcept { + return _Right < _Left; + } + _NODISCARD_FRIEND constexpr bool operator<=(const _Base128& _Left, const _Base128& _Right) noexcept { + return !(_Right < _Left); + } + _NODISCARD_FRIEND constexpr bool operator>=(const _Base128& _Left, const _Base128& _Right) noexcept { + return !(_Left < _Right); + } + + template + _NODISCARD_FRIEND constexpr _Ty operator<<(const _Ty _Left, const _Base128& _Right) noexcept { + return _Left << _Right._Word[0]; + } + + template + _NODISCARD_FRIEND constexpr _Ty operator>>(const _Ty _Left, const _Base128& _Right) noexcept { + return _Left >> _Right._Word[0]; + } + + template + constexpr _Base128& operator<<=(const _Ty _Count) noexcept { + _Left_shift(static_cast(_Count)); + return *this; + } + + template + friend constexpr _Ty& operator<<=(_Ty& _Left, const _Base128& _Right) noexcept { + _Left <<= _Right._Word[0]; + return _Left; + } + + template + constexpr _Base128& operator>>=(const _Ty _Count) noexcept { + _Unsigned_right_shift(static_cast(_Count)); + return *this; + } + + template + friend constexpr _Ty& operator>>=(_Ty& _Left, const _Base128& _Right) noexcept { + _Left >>= _Right._Word[0]; + return _Left; + } + + constexpr _Base128& operator++() noexcept { + if (++_Word[0] == 0) { + ++_Word[1]; + } + return *this; + } + constexpr _Base128 operator++(int) noexcept { + auto _Tmp = *this; + ++*this; + return _Tmp; + } + + constexpr _Base128& operator--() noexcept { + if (_Word[0]-- == 0) { + --_Word[1]; + } + return *this; + } + constexpr _Base128 operator--(int) noexcept { + auto _Tmp = *this; + --*this; + return _Tmp; + } + + _NODISCARD static constexpr _Base128 _Multiply(const _Base128& _Left, const _Base128& _Right) noexcept { + _Base128 _Result; + _Result._Word[0] = _UMul128(_Left._Word[0], _Right._Word[0], _Result._Word[1]); + _Result._Word[1] += _Left._Word[0] * _Right._Word[1]; + _Result._Word[1] += _Left._Word[1] * _Right._Word[0]; + return _Result; + } + +#if !_STL_128_DIV_INTRINSICS + _NODISCARD static constexpr _Base128 _Divide(const _Base128& _Num, const uint32_t _Den) noexcept { + _Base128 _Result; + _Result._Word[1] = _Num._Word[1] / _Den; + uint64_t _Rem = ((_Num._Word[1] % _Den) << 32) | (_Num._Word[0] >> 32); + _Result._Word[0] = (_Rem / _Den) << 32; + _Rem = ((_Rem % _Den) << 32) | static_cast(_Num._Word[0]); + _Result._Word[0] |= static_cast(_Rem / _Den); + return _Result; + } +#endif // !_STL_128_DIV_INTRINSICS + _NODISCARD static constexpr _Base128 _Divide(const _Base128& _Num, const uint64_t _Den) noexcept { + _Base128 _Result; + _Result._Word[1] = _Num._Word[1] / _Den; + uint64_t _Rem = _Num._Word[1] % _Den; + _Result._Word[0] = _UDiv128(_Rem, _Num._Word[0], _Den, _Rem); + return _Result; + } + _NODISCARD static constexpr _Base128 _Divide(_Base128 _Num, _Base128 _Den) noexcept { + // establish _Den < _Num and _Num._Word[1] > 0 + if (_Den._Word[1] >= _Num._Word[1]) { + if (_Den._Word[1] > _Num._Word[1]) { + return 0; + } + + return _Num._Word[1] == 0 ? _Num._Word[0] / _Den._Word[0] : _Num._Word[0] >= _Den._Word[0]; + } + + // establish _Den has more than 1 non-zero "digit" + if (_Den._Word[1] == 0) { +#if !_STL_128_DIV_INTRINSICS + if (_Den._Word[0] < (1ull << 32)) { + return _Divide(_Num, static_cast(_Den._Word[0])); + } else +#endif // !_STL_128_DIV_INTRINSICS + { + return _Divide(_Num, _Den._Word[0]); + } + } + +#if _STL_128_INTRINSICS + // Knuth 4.3.1D, 2-digit by 2-digit divide in base 2^64 + // _STL_INTERNAL_CHECK(_Den._Word[1] != 0); + // _STL_INTERNAL_CHECK(_Num._Word[1] > _Den._Word[1]); + // Normalize by shifting both left until _Den's high bit is set (So _Den's high digit is >= b / 2) + const auto __d = _STD countl_zero(_Den._Word[1]); + _Den <<= __d; + auto _High_digit = __d == 0 ? 0 : _Num._Word[1] >> (64 - __d); // This creates a third digit for _Num + _Num <<= __d; + + _Base128 __qhat; + __qhat._Word[1] = _High_digit >= _Den._Word[1]; + uint64_t __rhat; + __qhat._Word[0] = _UDiv128(_High_digit >= _Den._Word[1] ? _High_digit - _Den._Word[1] : _High_digit, + _Num._Word[1], _Den._Word[1], __rhat); + + for (;;) { + if (__qhat._Word[1] > 0) { + --__qhat; + } else { + _Base128 _Prod; + _Prod._Word[0] = _UMul128(__qhat._Word[0], _Den._Word[0], _Prod._Word[1]); + if (_Prod <= _Base128{_Num._Word[0], __rhat}) { + break; + } + --__qhat._Word[0]; + } + + const auto _Sum = __rhat + _Den._Word[1]; + if (__rhat > _Sum) { + break; + } + __rhat = _Sum; + } + // _STL_INTERNAL_CHECK(__qhat._Word[1] == 0); + + // [_High_digit | _Num] -= __qhat * _Den [Since __qhat < b, this is 3-digit - 1-digit * 2-digit] + uint64_t _Prod0_hi; + uint64_t _Prod_lo = _UMul128(__qhat._Word[0], _Den._Word[0], _Prod0_hi); + auto _Borrow = _SubBorrow64(0, _Num._Word[0], _Prod_lo, _Num._Word[0]); + uint64_t _Prod1_hi; + _Prod_lo = _UMul128(__qhat._Word[0], _Den._Word[1], _Prod1_hi); + _Prod1_hi += _AddCarry64(0, _Prod_lo, _Prod0_hi, _Prod_lo); + _Borrow = _SubBorrow64(_Borrow, _Num._Word[1], _Prod_lo, _Num._Word[1]); + _Borrow = _SubBorrow64(_Borrow, _High_digit, _Prod1_hi, _High_digit); + if (_Borrow) { + --__qhat._Word[0]; + } + return __qhat; +#else // ^^^ 128-bit intrinsics / no such intrinsics vvv + auto __d = _STD countl_zero(_Den._Word[1]); + const bool _Three_word_den = __d >= 32; + __d &= 31; + uint32_t __u[5]{ + static_cast(_Num._Word[0] << __d), + static_cast(_Num._Word[0] >> (32 - __d)), + static_cast(_Num._Word[1] << __d), + static_cast(_Num._Word[1] >> (32 - __d)), + 0, + }; + uint32_t __v[4] = { + static_cast(_Den._Word[0] << __d), + static_cast(_Den._Word[0] >> (32 - __d)), + static_cast(_Den._Word[1] << __d), + static_cast(_Den._Word[1] >> (32 - __d)), + }; + if (__d != 0) { + __u[2] |= _Num._Word[0] >> (64 - __d); + __u[4] |= _Num._Word[1] >> (64 - __d); + __v[2] |= _Den._Word[0] >> (64 - __d); + } + + uint32_t __q[2]; + if (_Three_word_den) { + // 4-digit by 3-digit base 2^32 division + _Knuth_4_3_1_D(__u, 5, __v, 3, __q); + } else { + // 4-digit by 4-digit base 2^32 division + _Knuth_4_3_1_D(__u, 5, __v, 4, __q); + __q[1] = 0; + } + + return (static_cast(__q[1]) << 32) | __q[0]; +#endif // _STL_128_INTRINSICS + } + +#if !_STL_128_DIV_INTRINSICS + _NODISCARD static constexpr _Base128 _Modulo(const _Base128& _Num, const uint32_t _Den) noexcept { + uint64_t _Rem = _Num._Word[1]; + _Rem = ((_Rem % _Den) << 32) | (_Num._Word[0] >> 32); + _Rem = ((_Rem % _Den) << 32) | static_cast(_Num._Word[0]); + return _Rem % _Den; + } +#endif // !_STL_128_DIV_INTRINSICS + _NODISCARD static constexpr _Base128 _Modulo(const _Base128& _Num, const uint64_t _Den) noexcept { + uint64_t _Rem; + (void) _UDiv128(_Num._Word[1] % _Den, _Num._Word[0], _Den, _Rem); + return _Rem; + } + _NODISCARD static constexpr _Base128 _Modulo(_Base128 _Num, _Base128 _Den) noexcept { + // establish _Den < _Num and _Num._Word[1] > 0 + if (_Den._Word[1] >= _Num._Word[1]) { + if (_Den._Word[1] > _Num._Word[1]) { + return _Num; + } + + if (_Den._Word[0] <= _Num._Word[0]) { + return _Num._Word[1] == 0 ? _Num._Word[0] % _Den._Word[0] : _Num._Word[0] - _Den._Word[0]; + } + + return _Num; + } + + // establish _Den has more than 1 non-zero "digit" + if (_Den._Word[1] == 0) { +#if !_STL_128_DIV_INTRINSICS + if (_Den._Word[0] < (1ull << 32)) { + return _Modulo(_Num, static_cast(_Den._Word[0])); + } else +#endif // !_STL_128_DIV_INTRINSICS + { + return _Modulo(_Num, _Den._Word[0]); + } + } + +#if _STL_128_INTRINSICS + // Knuth 4.3.1D, 2-digit by 2-digit divide in base 2^64 + // _STL_INTERNAL_CHECK(_Den._Word[1] != 0); + // _STL_INTERNAL_CHECK(_Num._Word[1] > _Den._Word[1]); + // Normalize by shifting both left until _Den's high bit is set (So _Den's high digit is >= b / 2) + const auto __d = _STD countl_zero(_Den._Word[1]); + _Den <<= __d; + auto _High_digit = __d == 0 ? 0 : _Num._Word[1] >> (64 - __d); // This creates a third digit for _Num + _Num <<= __d; + + uint64_t __qhat_high = _High_digit >= _Den._Word[1]; + uint64_t __rhat; + uint64_t __qhat = _UDiv128(_High_digit >= _Den._Word[1] ? _High_digit - _Den._Word[1] : _High_digit, + _Num._Word[1], _Den._Word[1], __rhat); + + for (;;) { + if (__qhat_high > 0) { + if (__qhat-- == 0) { + --__qhat_high; + } + } else { + _Base128 _Prod; + _Prod._Word[0] = _UMul128(__qhat, _Den._Word[0], _Prod._Word[1]); + if (_Prod <= _Base128{_Num._Word[0], __rhat}) { + break; + } + --__qhat; + } + + const auto _Sum = __rhat + _Den._Word[1]; + if (__rhat > _Sum) { + break; + } + __rhat = _Sum; + // The addition didn't overflow, so `__rhat < b` holds + } + // _STL_INTERNAL_CHECK(__qhat_high == 0); + + // [_High_digit | _Num] -= __qhat * _Den [3-digit - 1-digit * 2-digit] + uint64_t _Prod0_hi; + uint64_t _Prod_lo = _UMul128(__qhat, _Den._Word[0], _Prod0_hi); + auto _Borrow = _SubBorrow64(0, _Num._Word[0], _Prod_lo, _Num._Word[0]); + uint64_t _Prod1_hi; + _Prod_lo = _UMul128(__qhat, _Den._Word[1], _Prod1_hi); + _Prod1_hi += _AddCarry64(0, _Prod_lo, _Prod0_hi, _Prod_lo); + _Borrow = _SubBorrow64(_Borrow, _Num._Word[1], _Prod_lo, _Num._Word[1]); + _Borrow = _SubBorrow64(_Borrow, _High_digit, _Prod1_hi, _High_digit); + if (_Borrow) { + auto _Carry = _AddCarry64(0, _Num._Word[0], _Den._Word[0], _Num._Word[0]); + (void) _AddCarry64(_Carry, _Num._Word[1], _Den._Word[1], _Num._Word[1]); + } +#else // ^^^ 128-bit intrinsics / no such intrinsics vvv + auto __d = _STD countl_zero(_Den._Word[1]); + const bool _Three_word_den = __d >= 32; + __d &= 31; + uint32_t __u[5]{ + static_cast(_Num._Word[0] << __d), + static_cast(_Num._Word[0] >> (32 - __d)), + static_cast(_Num._Word[1] << __d), + static_cast(_Num._Word[1] >> (32 - __d)), + 0, + }; + uint32_t __v[4] = { + static_cast(_Den._Word[0] << __d), + static_cast(_Den._Word[0] >> (32 - __d)), + static_cast(_Den._Word[1] << __d), + static_cast(_Den._Word[1] >> (32 - __d)), + }; + if (__d != 0) { + __u[2] |= _Num._Word[0] >> (64 - __d); + __u[4] |= _Num._Word[1] >> (64 - __d); + __v[2] |= _Den._Word[0] >> (64 - __d); + } + + uint32_t __q[2]; + if (_Three_word_den) { + // 4-digit by 3-digit base 2^32 division + _Knuth_4_3_1_D(__u, 5, __v, 3, __q); + // _STL_INTERNAL_CHECK(__u[3] == 0); + } else { + // 4-digit by 4-digit base 2^32 division + _Knuth_4_3_1_D(__u, 5, __v, 4, __q); + } + // _STL_INTERNAL_CHECK(__u[4] == 0); + + _Num._Word[0] = (static_cast(__u[1]) << 32) | __u[0]; + _Num._Word[1] = (static_cast(__u[3]) << 32) | __u[2]; +#endif // _STL_128_INTRINSICS + _Num >>= __d; + return _Num; + } + + template + friend constexpr _Ty& operator&=(_Ty& _Left, const _Base128& _Right) noexcept { + _Left &= _Right._Word[0]; + return _Left; + } + + template + friend constexpr _Ty& operator^=(_Ty& _Left, const _Base128& _Right) noexcept { + _Left ^= _Right._Word[0]; + return _Left; + } + + template + friend constexpr _Ty& operator|=(_Ty& _Left, const _Base128& _Right) noexcept { + _Left |= _Right._Word[0]; + return _Left; + } +}; + +struct _Signed128; + +struct _Unsigned128 : _Base128 { + using _Signed_type = _Signed128; + using _Unsigned_type = _Unsigned128; + + using _Base128::_Base128; + constexpr explicit _Unsigned128(const _Base128& _That) noexcept : _Base128{_That} {} + + constexpr _Unsigned128& operator=(const _Base128& _That) noexcept { + _Base128::operator=(_That); + return *this; + } + + _NODISCARD_FRIEND constexpr strong_ordering operator<=>( + const _Unsigned128& _Left, const _Unsigned128& _Right) noexcept { + strong_ordering _Ord = _Left._Word[1] <=> _Right._Word[1]; + if (_Ord == strong_ordering::equal) { + _Ord = _Left._Word[0] <=> _Right._Word[0]; + } + return _Ord; + } + + _NODISCARD_FRIEND constexpr _Unsigned128 operator<<(const _Unsigned128& _Left, const _Base128& _Right) noexcept { + auto _Tmp{_Left}; + _Tmp._Left_shift(static_cast(_Right._Word[0])); + return _Tmp; + } + + template + constexpr _Unsigned128& operator<<=(const _Ty _Count) noexcept { + _Left_shift(static_cast(_Count)); + return *this; + } + constexpr _Unsigned128& operator<<=(const _Base128& _Count) noexcept { + _Left_shift(static_cast(_Count._Word[0])); + return *this; + } + + _NODISCARD_FRIEND constexpr _Unsigned128 operator>>(const _Unsigned128& _Left, const _Base128& _Right) noexcept { + auto _Tmp{_Left}; + _Tmp._Unsigned_right_shift(static_cast(_Right._Word[0])); + return _Tmp; + } + + template + constexpr _Unsigned128& operator>>=(const _Ty _Count) noexcept { + _Unsigned_right_shift(static_cast(_Count)); + return *this; + } + constexpr _Unsigned128& operator>>=(const _Base128& _Count) noexcept { + _Unsigned_right_shift(static_cast(_Count._Word[0])); + return *this; + } + + constexpr _Unsigned128& operator++() noexcept { + if (++_Word[0] == 0) { + ++_Word[1]; + } + return *this; + } + constexpr _Unsigned128 operator++(int) noexcept { + auto _Tmp = *this; + ++*this; + return _Tmp; + } + + constexpr _Unsigned128& operator--() noexcept { + if (_Word[0]-- == 0) { + --_Word[1]; + } + return *this; + } + constexpr _Unsigned128 operator--(int) noexcept { + auto _Tmp = *this; + --*this; + return _Tmp; + } + + _NODISCARD constexpr _Unsigned128 operator+() const noexcept { + return *this; + } + + _NODISCARD constexpr _Unsigned128 operator-() const noexcept { + return _Unsigned128{} - *this; + } + + _NODISCARD constexpr _Unsigned128 operator~() const noexcept { + return _Unsigned128{~_Word[0], ~_Word[1]}; + } + + _NODISCARD_FRIEND constexpr _Unsigned128 operator+(const _Base128& _Left, const _Base128& _Right) noexcept { + _Unsigned128 _Result; + const auto _Carry = _AddCarry64(0, _Left._Word[0], _Right._Word[0], _Result._Word[0]); + _AddCarry64(_Carry, _Left._Word[1], _Right._Word[1], _Result._Word[1]); + return _Result; + } + + constexpr _Unsigned128& operator+=(const _Base128& _That) noexcept { + const auto _Carry = _AddCarry64(0, _Word[0], _That._Word[0], _Word[0]); + _AddCarry64(_Carry, _Word[1], _That._Word[1], _Word[1]); + return *this; + } + template + friend constexpr _Ty& operator+=(_Ty& _Left, const _Unsigned128& _Right) noexcept { + _Left += _Right._Word[0]; + return _Left; + } + + _NODISCARD_FRIEND constexpr _Unsigned128 operator-(const _Base128& _Left, const _Base128& _Right) noexcept { + _Unsigned128 _Result; + const auto _Borrow = _SubBorrow64(0, _Left._Word[0], _Right._Word[0], _Result._Word[0]); + _SubBorrow64(_Borrow, _Left._Word[1], _Right._Word[1], _Result._Word[1]); + return _Result; + } + + constexpr _Unsigned128& operator-=(const _Base128& _That) noexcept { + const auto _Borrow = _SubBorrow64(0, _Word[0], _That._Word[0], _Word[0]); + _SubBorrow64(_Borrow, _Word[1], _That._Word[1], _Word[1]); + return *this; + } + template + friend constexpr _Ty& operator-=(_Ty& _Left, const _Unsigned128& _Right) noexcept { + _Left -= _Right._Word[0]; + return _Left; + } + + _NODISCARD_FRIEND constexpr _Unsigned128 operator*(const _Base128& _Left, const _Base128& _Right) noexcept { + return _Unsigned128{_Base128::_Multiply(_Left, _Right)}; + } + + constexpr _Unsigned128& operator*=(const _Base128& _That) noexcept { + *this = *this * _That; + return *this; + } + template + friend constexpr _Ty& operator*=(_Ty& _Left, const _Unsigned128& _Right) noexcept { + _Left *= _Right._Word[0]; + return _Left; + } + + template + _NODISCARD_FRIEND constexpr _Unsigned128 operator/(const _Unsigned128& _Num, const _Ty _Den) noexcept { +#if !_STL_128_DIV_INTRINSICS + if constexpr (sizeof(_Ty) <= 4) { + return _Unsigned128{_Base128::_Divide(_Num, static_cast(_Den))}; + } else +#endif // !_STL_128_DIV_INTRINSICS + { + return _Unsigned128{_Base128::_Divide(_Num, static_cast(_Den))}; + } + } + _NODISCARD_FRIEND constexpr _Unsigned128 operator/(const _Base128& _Num, const _Base128& _Den) noexcept { + return _Unsigned128{_Base128::_Divide(_Num, _Den)}; + } + + template + constexpr _Unsigned128& operator/=(const _Ty _That) noexcept { +#if !_STL_128_DIV_INTRINSICS + if constexpr (sizeof(_Ty) <= 4) { + *this = _Unsigned128{_Base128::_Divide(*this, static_cast(_That))}; + } else +#endif // !_STL_128_DIV_INTRINSICS + { + *this = _Unsigned128{_Base128::_Divide(*this, static_cast(_That))}; + } + return *this; + } + constexpr _Unsigned128& operator/=(const _Base128& _That) noexcept { + *this = _Unsigned128{_Base128::_Divide(*this, _That)}; + return *this; + } + template + friend constexpr _Ty& operator/=(_Ty& _Left, const _Unsigned128& _Right) noexcept { + if (_Right._Word[1] != 0) { + _Left = 0; + } else { + _Left /= _Right._Word[0]; + } + return _Left; + } + + template + _NODISCARD_FRIEND constexpr _Unsigned128 operator%(const _Base128& _Num, const _Ty _Den) noexcept { +#if !_STL_128_DIV_INTRINSICS + if constexpr (sizeof(_Ty) <= 4) { + return _Unsigned128{_Base128::_Modulo(_Num, static_cast(_Den))}; + } else +#endif // !_STL_128_DIV_INTRINSICS + { + return _Unsigned128{_Base128::_Modulo(_Num, static_cast(_Den))}; + } + } + _NODISCARD_FRIEND constexpr _Unsigned128 operator%(const _Base128& _Num, const _Base128& _Den) noexcept { + return _Unsigned128{_Base128::_Modulo(_Num, _Den)}; + } + + template + constexpr _Unsigned128& operator%=(const _Ty _Den) noexcept { + *this = *this % _Den; + return *this; + } + constexpr _Unsigned128& operator%=(const _Base128& _Den) noexcept { + *this = *this % _Den; + return *this; + } + template + friend constexpr _Ty& operator%=(_Ty& _Left, const _Unsigned128& _Right) noexcept { + if (_Right._Word[1] == 0) { + _Left %= _Right._Word[0]; + } + return _Left; + } + + _NODISCARD_FRIEND constexpr _Unsigned128 operator&(const _Base128& _Left, const _Base128& _Right) noexcept { + return _Unsigned128{_Left._Word[0] & _Right._Word[0], _Left._Word[1] & _Right._Word[1]}; + } + + constexpr _Unsigned128& operator&=(const _Base128& _That) noexcept { + _Word[0] &= _That._Word[0]; + _Word[1] &= _That._Word[1]; + return *this; + } + + _NODISCARD_FRIEND constexpr _Unsigned128 operator^(const _Base128& _Left, const _Base128& _Right) noexcept { + return _Unsigned128{_Left._Word[0] ^ _Right._Word[0], _Left._Word[1] ^ _Right._Word[1]}; + } + + constexpr _Unsigned128& operator^=(const _Base128& _That) noexcept { + _Word[0] ^= _That._Word[0]; + _Word[1] ^= _That._Word[1]; + return *this; + } + + _NODISCARD_FRIEND constexpr _Unsigned128 operator|(const _Base128& _Left, const _Base128& _Right) noexcept { + return _Unsigned128{_Left._Word[0] | _Right._Word[0], _Left._Word[1] | _Right._Word[1]}; + } + + constexpr _Unsigned128& operator|=(const _Base128& _That) noexcept { + _Word[0] |= _That._Word[0]; + _Word[1] |= _That._Word[1]; + return *this; + } +}; + +template +class numeric_limits; +template <> +class numeric_limits<_Unsigned128> : public _Num_int_base { +public: + _NODISCARD static constexpr _Unsigned128(min)() noexcept { + return 0; + } + + _NODISCARD static constexpr _Unsigned128(max)() noexcept { + return _Unsigned128{~0ull, ~0ull}; + } + + _NODISCARD static constexpr _Unsigned128 lowest() noexcept { + return (min) (); + } + + _NODISCARD static constexpr _Unsigned128 epsilon() noexcept { + return 0; + } + + _NODISCARD static constexpr _Unsigned128 round_error() noexcept { + return 0; + } + + _NODISCARD static constexpr _Unsigned128 denorm_min() noexcept { + return 0; + } + + _NODISCARD static constexpr _Unsigned128 infinity() noexcept { + return 0; + } + + _NODISCARD static constexpr _Unsigned128 quiet_NaN() noexcept { + return 0; + } + + _NODISCARD static constexpr _Unsigned128 signaling_NaN() noexcept { + return 0; + } + + static constexpr bool is_modulo = true; + static constexpr int digits = 128; + static constexpr int digits10 = 38; +}; + +template +struct common_type; +template +struct common_type<_Ty, _Unsigned128> { + using type = _Unsigned128; +}; +template +struct common_type<_Unsigned128, _Ty> { + using type = _Unsigned128; +}; + +struct _Signed128 : _Base128 { + using _Signed_type = _Signed128; + using _Unsigned_type = _Unsigned128; + + using _Base128::_Base128; + constexpr explicit _Signed128(const _Base128& _That) noexcept : _Base128{_That} {} + + constexpr _Signed128& operator=(const _Base128& _That) noexcept { + _Base128::operator=(_That); + return *this; + } + + _NODISCARD_FRIEND constexpr strong_ordering operator<=>( + const _Signed128& _Left, const _Signed128& _Right) noexcept { + strong_ordering _Ord = static_cast(_Left._Word[1]) <=> static_cast(_Right._Word[1]); + if (_Ord == strong_ordering::equal) { + _Ord = _Left._Word[0] <=> _Right._Word[0]; + } + return _Ord; + } + + _NODISCARD_FRIEND constexpr _Signed128 operator<<(const _Signed128& _Left, const _Base128& _Right) noexcept { + auto _Tmp{_Left}; + _Tmp._Left_shift(static_cast(_Right._Word[0])); + return _Tmp; + } + + template + constexpr _Signed128& operator<<=(const _Ty _Count) noexcept { + _Left_shift(static_cast(_Count)); + return *this; + } + constexpr _Signed128& operator<<=(const _Base128& _Count) noexcept { + _Left_shift(static_cast(_Count._Word[0])); + return *this; + } + + constexpr void _Signed_right_shift(const unsigned char _Count) noexcept { + if (_Count == 0) { + return; + } + + if (_Count >= 64) { + _Word[0] = static_cast(static_cast(_Word[1]) >> (_Count % 64)); + _Word[1] = (_Word[1] & (1ull << 63)) == 0 ? 0 : ~0ull; + return; + } + +#if _STL_128_INTRINSICS + if (!_STD is_constant_evaluated()) { + _Word[0] = __shiftright128(_Word[0], _Word[1], _Count); + } else +#endif // _STL_128_INTRINSICS + { + _Word[0] = (_Word[0] >> _Count) | (_Word[1] << (64 - _Count)); + } + + _Word[1] = static_cast(static_cast(_Word[1]) >> _Count); + } + + _NODISCARD_FRIEND constexpr _Signed128 operator>>(const _Signed128& _Left, const _Base128& _Right) noexcept { + auto _Tmp{_Left}; + _Tmp._Signed_right_shift(static_cast(_Right._Word[0])); + return _Tmp; + } + + template + constexpr _Signed128& operator>>=(const _Ty _Count) noexcept { + _Signed_right_shift(static_cast(_Count)); + return *this; + } + constexpr _Signed128& operator>>=(const _Base128& _Count) noexcept { + _Signed_right_shift(static_cast(_Count._Word[0])); + return *this; + } + + constexpr _Signed128& operator++() noexcept { + if (++_Word[0] == 0) { + ++_Word[1]; + } + return *this; + } + constexpr _Signed128 operator++(int) noexcept { + auto _Tmp = *this; + ++*this; + return _Tmp; + } + + constexpr _Signed128& operator--() noexcept { + if (_Word[0]-- == 0) { + --_Word[1]; + } + return *this; + } + constexpr _Signed128 operator--(int) noexcept { + auto _Tmp = *this; + --*this; + return _Tmp; + } + + _NODISCARD constexpr _Signed128 operator+() const noexcept { + return *this; + } + + _NODISCARD constexpr _Signed128 operator-() const noexcept { + return _Signed128{} - *this; + } + + _NODISCARD constexpr _Signed128 operator~() const noexcept { + return _Signed128{~_Word[0], ~_Word[1]}; + } + + _NODISCARD_FRIEND constexpr _Signed128 operator+(const _Signed128& _Left, const _Signed128& _Right) noexcept { + _Signed128 _Result; + const auto _Carry = _AddCarry64(0, _Left._Word[0], _Right._Word[0], _Result._Word[0]); + _AddCarry64(_Carry, _Left._Word[1], _Right._Word[1], _Result._Word[1]); + return _Result; + } + + constexpr _Signed128& operator+=(const _Base128& _That) noexcept { + const auto _Carry = _AddCarry64(0, _Word[0], _That._Word[0], _Word[0]); + _AddCarry64(_Carry, _Word[1], _That._Word[1], _Word[1]); + return *this; + } + template + friend constexpr _Ty& operator+=(_Ty& _Left, const _Signed128& _Right) noexcept { + _Left = static_cast<_Ty>(_Signed128{_Left} + _Right); + return _Left; + } + + _NODISCARD_FRIEND constexpr _Signed128 operator-(const _Signed128& _Left, const _Signed128& _Right) noexcept { + _Signed128 _Result; + const auto _Borrow = _SubBorrow64(0, _Left._Word[0], _Right._Word[0], _Result._Word[0]); + _SubBorrow64(_Borrow, _Left._Word[1], _Right._Word[1], _Result._Word[1]); + return _Result; + } + + constexpr _Signed128& operator-=(const _Base128& _That) noexcept { + const auto _Borrow = _SubBorrow64(0, _Word[0], _That._Word[0], _Word[0]); + _SubBorrow64(_Borrow, _Word[1], _That._Word[1], _Word[1]); + return *this; + } + template + friend constexpr _Ty& operator-=(_Ty& _Left, const _Signed128& _Right) noexcept { + _Left = static_cast<_Ty>(_Signed128{_Left} - _Right); + return _Left; + } + + constexpr void _Strip_negative(bool& _Flip) noexcept { + if ((_Word[1] & (1ull << 63)) != 0) { + *this = -*this; + _Flip = !_Flip; + } + } + + _NODISCARD_FRIEND constexpr _Signed128 operator*(_Signed128 _Left, _Signed128 _Right) noexcept { + bool _Negative = false; + _Left._Strip_negative(_Negative); + _Right._Strip_negative(_Negative); + _Signed128 _Result{_Base128::_Multiply(_Left, _Right)}; + if (_Negative) { + _Result = -_Result; + } + return _Result; + } + + template + constexpr _Signed128& operator*=(const _Ty _That) noexcept { + *this = *this * _That; + return *this; + } + constexpr _Signed128& operator*=(const _Signed128& _That) noexcept { + *this = *this * _That; + return *this; + } + constexpr _Signed128& operator*=(const _Unsigned128& _That) noexcept { + *this = _Signed128{static_cast(*this) * _That}; + return *this; + } + template + friend constexpr _Ty& operator*=(_Ty& _Left, const _Signed128& _Right) noexcept { + _Left = static_cast<_Ty>(_Signed128{_Left} * _Right); + return _Left; + } + + template + _NODISCARD_FRIEND constexpr _Signed128 operator/(_Signed128 _Num, _Ty _Den) noexcept { + bool _Negative = false; + _Num._Strip_negative(_Negative); + if constexpr (is_signed_v<_Ty>) { + if (_Den < 0) { + _Den = -_Den; + _Negative = !_Negative; + } + } + + _Signed128 _Result; +#if !_STL_128_DIV_INTRINSICS + if constexpr (sizeof(_Ty) <= 4) { + _Result = _Signed128{_Base128::_Divide(_Num, static_cast(_Den))}; + } else +#endif // !_STL_128_DIV_INTRINSICS + { + _Result = _Signed128{_Base128::_Divide(_Num, static_cast(_Den))}; + } + + if (_Negative) { + _Result = -_Result; + } + return _Result; + } + _NODISCARD_FRIEND constexpr _Signed128 operator/(_Signed128 _Num, _Signed128 _Den) noexcept { + bool _Negative = false; + _Num._Strip_negative(_Negative); + _Den._Strip_negative(_Negative); + _Signed128 _Result{_Base128::_Divide(_Num, _Den)}; + if (_Negative) { + _Result = -_Result; + } + return _Result; + } + + template + constexpr _Signed128& operator/=(const _Ty _That) noexcept { + *this = *this / _That; + return *this; + } + constexpr _Signed128& operator/=(const _Signed128& _That) noexcept { + *this = *this / _That; + return *this; + } + constexpr _Signed128& operator/=(const _Unsigned128& _That) noexcept { + *this = _Signed128{static_cast<_Base128&>(*this) / _That}; + return *this; + } + template + friend constexpr _Ty& operator/=(_Ty& _Left, const _Signed128& _Right) noexcept { + _Left = static_cast<_Ty>(_Signed128{_Left} / _Right); + return _Left; + } + + _NODISCARD_FRIEND constexpr _Signed128 operator%(_Signed128 _Left, _Signed128 _Right) noexcept { + bool _Negative = false; + _Left._Strip_negative(_Negative); + + if ((_Right._Word[1] & (1ull << 63)) != 0) { + _Right = -_Right; + // intentionally not flipping _Negative + } + + _Unsigned128 _Result{_Base128::_Modulo(_Left, _Right)}; + if (_Negative) { + _Result = -_Result; + } + return _Signed128{_Result}; + } + + template + constexpr _Signed128& operator%=(const _Ty _That) noexcept { + *this = *this % _That; + return *this; + } + constexpr _Signed128& operator%=(const _Signed128& _That) noexcept { + *this = *this % _That; + return *this; + } + constexpr _Signed128& operator%=(const _Unsigned128& _That) noexcept { + *this = static_cast(*this) % _That; + return *this; + } + template + friend constexpr _Ty& operator%=(_Ty& _Left, const _Signed128& _Right) noexcept { + _Left = static_cast<_Ty>(_Signed128{_Left} % _Right); + return _Left; + } + + _NODISCARD_FRIEND constexpr _Signed128 operator&(const _Signed128& _Left, const _Signed128& _Right) noexcept { + return _Signed128{_Left._Word[0] & _Right._Word[0], _Left._Word[1] & _Right._Word[1]}; + } + + constexpr _Signed128& operator&=(const _Base128& _That) noexcept { + _Word[0] &= _That._Word[0]; + _Word[1] &= _That._Word[1]; + return *this; + } + + _NODISCARD_FRIEND constexpr _Signed128 operator^(const _Signed128& _Left, const _Signed128& _Right) noexcept { + return _Signed128{_Left._Word[0] ^ _Right._Word[0], _Left._Word[1] ^ _Right._Word[1]}; + } + + constexpr _Signed128& operator^=(const _Base128& _That) noexcept { + _Word[0] ^= _That._Word[0]; + _Word[1] ^= _That._Word[1]; + return *this; + } + + _NODISCARD_FRIEND constexpr _Signed128 operator|(const _Signed128& _Left, const _Signed128& _Right) noexcept { + return _Signed128{_Left._Word[0] | _Right._Word[0], _Left._Word[1] | _Right._Word[1]}; + } + + constexpr _Signed128& operator|=(const _Base128& _That) noexcept { + _Word[0] |= _That._Word[0]; + _Word[1] |= _That._Word[1]; + return *this; + } +}; + +template +class numeric_limits; +template <> +class numeric_limits<_Signed128> : public _Num_int_base { +public: + _NODISCARD static constexpr _Signed128(min)() noexcept { + return _Signed128{0ull, 1ull << 63}; + } + + _NODISCARD static constexpr _Signed128(max)() noexcept { + return _Signed128{~0ull, ~0ull >> 1}; + } + + _NODISCARD static constexpr _Signed128 lowest() noexcept { + return (min) (); + } + + _NODISCARD static constexpr _Signed128 epsilon() noexcept { + return 0; + } + + _NODISCARD static constexpr _Signed128 round_error() noexcept { + return 0; + } + + _NODISCARD static constexpr _Signed128 denorm_min() noexcept { + return 0; + } + + _NODISCARD static constexpr _Signed128 infinity() noexcept { + return 0; + } + + _NODISCARD static constexpr _Signed128 quiet_NaN() noexcept { + return 0; + } + + _NODISCARD static constexpr _Signed128 signaling_NaN() noexcept { + return 0; + } + + static constexpr int digits = 127; + static constexpr int digits10 = 38; +}; + +template +struct common_type<_Ty, _Signed128> { + using type = _Signed128; +}; +template +struct common_type<_Signed128, _Ty> { + using type = _Signed128; +}; + +template <> +struct common_type<_Signed128, _Unsigned128> { + using type = _Unsigned128; +}; +template <> +struct common_type<_Unsigned128, _Signed128> { + using type = _Unsigned128; +}; + +#undef _STL_128_INTRINSICS +#undef _STL_128_DIV_INTRINSICS + +_STD_END + +#pragma pop_macro("new") +_STL_RESTORE_CLANG_WARNINGS +#pragma warning(pop) +#pragma pack(pop) +#endif // __cpp_lib_concepts +#endif // _STL_COMPILER_PREPROCESSOR +#endif // __MSVC_INT128_HPP diff --git a/stl/inc/format b/stl/inc/format index 3f91c7895e7..cd441791bab 100644 --- a/stl/inc/format +++ b/stl/inc/format @@ -40,8 +40,7 @@ #include #if _STL_COMPILER_PREPROCESSOR #ifndef __cpp_lib_format -#pragma message("The contents of are available only in c++latest mode;") -#pragma message("see https://github.com/microsoft/STL/issues/1814 for details.") +#pragma message("The contents of are available only with C++20 or later.") #else // ^^^ !defined(__cpp_lib_format) / defined(__cpp_lib_format) vvv #include diff --git a/stl/inc/header-units.json b/stl/inc/header-units.json index e22b1ce80f4..f15b818629d 100644 --- a/stl/inc/header-units.json +++ b/stl/inc/header-units.json @@ -5,6 +5,7 @@ "Version": "1.0", "BuildAsHeaderUnits": [ // "__msvc_all_public_headers.hpp", // for testing, not production + "__msvc_int128.hpp", "__msvc_system_error_abi.hpp", "__msvc_tzdb.hpp", "__msvc_xlocinfo_types.hpp", diff --git a/stl/inc/ranges b/stl/inc/ranges index acfaca9ffbb..2610a4dbaab 100644 --- a/stl/inc/ranges +++ b/stl/inc/ranges @@ -9,9 +9,9 @@ #include #if _STL_COMPILER_PREPROCESSOR #ifndef __cpp_lib_ranges -#pragma message("The contents of are available only in c++latest mode;") -#pragma message("see https://github.com/microsoft/STL/issues/1814 for details.") +#pragma message("The contents of are available only with C++20 or later.") #else // ^^^ !defined(__cpp_lib_ranges) / defined(__cpp_lib_ranges) vvv +#include <__msvc_int128.hpp> #include #include #include @@ -953,7 +953,9 @@ namespace ranges { } // namespace views template - using _Iota_diff_t = conditional_t, conditional_t<(sizeof(_Ty) < sizeof(int)), int, long long>, + using _Iota_diff_t = conditional_t, + conditional_t>, iter_difference_t<_Ty>>; // clang-format off @@ -981,6 +983,7 @@ namespace ranges { }; template + requires integral<_Iota_diff_t<_Wi>> // TRANSITION, LWG-3670 struct _Ioterator_category_base<_Wi> { using iterator_category = input_iterator_tag; diff --git a/stl/inc/xutility b/stl/inc/xutility index 4a674f4a01d..9eb999a7e59 100644 --- a/stl/inc/xutility +++ b/stl/inc/xutility @@ -740,21 +740,49 @@ concept indirectly_writable = requires(_It&& __i, _Ty&& __t) { }; template -concept _Integer_like = _Is_nonbool_integral>; +inline constexpr bool _Integer_class = requires { + typename _Ty::_Signed_type; + typename _Ty::_Unsigned_type; +}; + +template +concept _Integer_like = _Is_nonbool_integral> || _Integer_class<_Ty>; template concept _Signed_integer_like = _Integer_like<_Ty> && static_cast<_Ty>(-1) < static_cast<_Ty>(0); +template +struct _Make_unsigned_like_impl { + template + using _Apply = typename _Ty::_Unsigned_type; +}; +template <> +struct _Make_unsigned_like_impl { + template + using _Apply = make_unsigned_t<_Ty>; +}; + template -using _Make_unsigned_like_t = make_unsigned_t<_Ty>; +using _Make_unsigned_like_t = typename _Make_unsigned_like_impl<_Integer_class<_Ty>>::template _Apply<_Ty>; template <_Integer_like _Ty> _NODISCARD constexpr auto _To_unsigned_like(const _Ty _Value) noexcept { return static_cast<_Make_unsigned_like_t<_Ty>>(_Value); } +template +struct _Make_signed_like_impl { + template + using _Apply = typename _Ty::_Signed_type; +}; +template <> +struct _Make_signed_like_impl { + template + using _Apply = make_signed_t<_Ty>; +}; + template -using _Make_signed_like_t = make_signed_t<_Ty>; +using _Make_signed_like_t = typename _Make_signed_like_impl<_Integer_class<_Ty>>::template _Apply<_Ty>; template <_Integer_like _Ty> _NODISCARD constexpr auto _To_signed_like(const _Ty _Value) noexcept { @@ -2697,10 +2725,8 @@ namespace ranges { inline constexpr bool enable_view = derived_from<_Ty, view_base> || _Derived_from_specialization_of<_Ty, view_interface>; -#ifdef __cpp_lib_ranges // TRANSITION, GH-1814 template concept view = range<_Ty> && movable<_Ty> && enable_view<_Ty>; -#endif // TRANSITION, GH-1814 template concept output_range = range<_Rng> && output_iterator, _Ty>; @@ -3032,20 +3058,16 @@ namespace ranges { _NODISCARD constexpr _Derived& _Cast() noexcept { static_assert(derived_from<_Derived, view_interface>, "view_interface's template argument D must derive from view_interface (N4849 [view.interface]/2)."); -#ifdef __cpp_lib_ranges // TRANSITION, GH-1814 static_assert(view<_Derived>, "view_interface's template argument must model the view concept (N4849 [view.interface]/2)."); -#endif // TRANSITION, GH-1814 return static_cast<_Derived&>(*this); } _NODISCARD constexpr const _Derived& _Cast() const noexcept { static_assert(derived_from<_Derived, view_interface>, "view_interface's template argument D must derive from view_interface (N4849 [view.interface]/2)."); -#ifdef __cpp_lib_ranges // TRANSITION, GH-1814 static_assert(view<_Derived>, "view_interface's template argument must model the view concept (N4849 [view.interface]/2)."); -#endif // TRANSITION, GH-1814 return static_cast(*this); } diff --git a/stl/inc/yvals.h b/stl/inc/yvals.h index 62fe18694f5..c27ed0d9654 100644 --- a/stl/inc/yvals.h +++ b/stl/inc/yvals.h @@ -206,11 +206,9 @@ _STL_DISABLE_CLANG_WARNINGS #endif // _DEBUG #ifdef _ENABLE_STL_INTERNAL_CHECK -#define _STL_INTERNAL_CHECK(...) _STL_VERIFY(__VA_ARGS__, "STL internal check: " #__VA_ARGS__) -#define _STL_INTERNAL_STATIC_ASSERT(...) static_assert(__VA_ARGS__, #__VA_ARGS__) +#define _STL_INTERNAL_CHECK(...) _STL_VERIFY(__VA_ARGS__, "STL internal check: " #__VA_ARGS__) #else // ^^^ _ENABLE_STL_INTERNAL_CHECK ^^^ // vvv !_ENABLE_STL_INTERNAL_CHECK vvv #define _STL_INTERNAL_CHECK(...) _Analysis_assume_(__VA_ARGS__) -#define _STL_INTERNAL_STATIC_ASSERT(...) #endif // _ENABLE_STL_INTERNAL_CHECK #ifndef _ENABLE_ATOMIC_REF_ALIGNMENT_CHECK diff --git a/stl/inc/yvals_core.h b/stl/inc/yvals_core.h index 98896926d32..e696ff452dd 100644 --- a/stl/inc/yvals_core.h +++ b/stl/inc/yvals_core.h @@ -1291,9 +1291,9 @@ #define __cpp_lib_endian 201907L #define __cpp_lib_erase_if 202002L -#if _HAS_CXX23 && defined(__cpp_lib_concepts) // TRANSITION, GH-395 and GH-1814 +#if defined(__cpp_lib_concepts) // TRANSITION, GH-395 #define __cpp_lib_format 202110L -#endif // _HAS_CXX23 && defined(__cpp_lib_concepts) +#endif // defined(__cpp_lib_concepts) #define __cpp_lib_generic_unordered_lookup 201811L #define __cpp_lib_int_pow2 202002L @@ -1321,9 +1321,9 @@ #define __cpp_lib_math_constants 201907L #define __cpp_lib_polymorphic_allocator 201902L -#if _HAS_CXX23 && defined(__cpp_lib_concepts) // TRANSITION, GH-395 and GH-1814 +#if defined(__cpp_lib_concepts) // TRANSITION, GH-395 #define __cpp_lib_ranges 202110L -#endif // _HAS_CXX23 && defined(__cpp_lib_concepts) +#endif // defined(__cpp_lib_concepts) #define __cpp_lib_remove_cvref 201711L #define __cpp_lib_semaphore 201907L @@ -1498,5 +1498,11 @@ compiler option, or define _ALLOW_RTCc_IN_STL to acknowledge that you have recei #define _STL_UNREACHABLE __assume(false) #endif // __clang__ +#ifdef _ENABLE_STL_INTERNAL_CHECK +#define _STL_INTERNAL_STATIC_ASSERT(...) static_assert(__VA_ARGS__, #__VA_ARGS__) +#else // ^^^ _ENABLE_STL_INTERNAL_CHECK ^^^ // vvv !_ENABLE_STL_INTERNAL_CHECK vvv +#define _STL_INTERNAL_STATIC_ASSERT(...) +#endif // _ENABLE_STL_INTERNAL_CHECK + #endif // _STL_COMPILER_PREPROCESSOR #endif // _YVALS_CORE_H_ diff --git a/tests/std/test.lst b/tests/std/test.lst index 50a5ef224e6..f943543223f 100644 --- a/tests/std/test.lst +++ b/tests/std/test.lst @@ -449,6 +449,7 @@ tests\P1423R3_char8_t_remediation tests\P1425R4_queue_stack_constructors tests\P1502R1_standard_library_header_units tests\P1518R2_stop_overconstraining_allocators +tests\P1522R1_difference_type tests\P1614R2_spaceship tests\P1645R1_constexpr_numeric tests\P1659R3_ranges_alg_ends_with diff --git a/tests/std/tests/GH_000545_include_compare/env.lst b/tests/std/tests/GH_000545_include_compare/env.lst index 642f530ffad..351a8293d9d 100644 --- a/tests/std/tests/GH_000545_include_compare/env.lst +++ b/tests/std/tests/GH_000545_include_compare/env.lst @@ -1,4 +1,4 @@ # Copyright (c) Microsoft Corporation. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -RUNALL_INCLUDE ..\usual_latest_matrix.lst +RUNALL_INCLUDE ..\usual_20_matrix.lst diff --git a/tests/std/tests/GH_001914_cached_position/env.lst b/tests/std/tests/GH_001914_cached_position/env.lst index 18e2d7c71ec..d6d824b5879 100644 --- a/tests/std/tests/GH_001914_cached_position/env.lst +++ b/tests/std/tests/GH_001914_cached_position/env.lst @@ -1,4 +1,4 @@ # Copyright (c) Microsoft Corporation. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -RUNALL_INCLUDE ..\concepts_latest_matrix.lst +RUNALL_INCLUDE ..\concepts_20_matrix.lst diff --git a/tests/std/tests/LWG3480_directory_iterator_range/env.lst b/tests/std/tests/LWG3480_directory_iterator_range/env.lst index 18e2d7c71ec..d6d824b5879 100644 --- a/tests/std/tests/LWG3480_directory_iterator_range/env.lst +++ b/tests/std/tests/LWG3480_directory_iterator_range/env.lst @@ -1,4 +1,4 @@ # Copyright (c) Microsoft Corporation. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -RUNALL_INCLUDE ..\concepts_latest_matrix.lst +RUNALL_INCLUDE ..\concepts_20_matrix.lst diff --git a/tests/std/tests/P0355R7_calendars_and_time_zones_formatting/env.lst b/tests/std/tests/P0355R7_calendars_and_time_zones_formatting/env.lst index 4ca6faed472..1f537b16e72 100644 --- a/tests/std/tests/P0355R7_calendars_and_time_zones_formatting/env.lst +++ b/tests/std/tests/P0355R7_calendars_and_time_zones_formatting/env.lst @@ -1,6 +1,6 @@ # Copyright (c) Microsoft Corporation. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -RUNALL_INCLUDE ..\concepts_latest_matrix.lst +RUNALL_INCLUDE ..\concepts_20_matrix.lst RUNALL_CROSSLIST PM_CL="/utf-8" diff --git a/tests/std/tests/P0645R10_text_formatting_args/env.lst b/tests/std/tests/P0645R10_text_formatting_args/env.lst index 18e2d7c71ec..d6d824b5879 100644 --- a/tests/std/tests/P0645R10_text_formatting_args/env.lst +++ b/tests/std/tests/P0645R10_text_formatting_args/env.lst @@ -1,4 +1,4 @@ # Copyright (c) Microsoft Corporation. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -RUNALL_INCLUDE ..\concepts_latest_matrix.lst +RUNALL_INCLUDE ..\concepts_20_matrix.lst diff --git a/tests/std/tests/P0645R10_text_formatting_custom_formatting/env.lst b/tests/std/tests/P0645R10_text_formatting_custom_formatting/env.lst index 18e2d7c71ec..d6d824b5879 100644 --- a/tests/std/tests/P0645R10_text_formatting_custom_formatting/env.lst +++ b/tests/std/tests/P0645R10_text_formatting_custom_formatting/env.lst @@ -1,4 +1,4 @@ # Copyright (c) Microsoft Corporation. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -RUNALL_INCLUDE ..\concepts_latest_matrix.lst +RUNALL_INCLUDE ..\concepts_20_matrix.lst diff --git a/tests/std/tests/P0645R10_text_formatting_death/env.lst b/tests/std/tests/P0645R10_text_formatting_death/env.lst index 1e9f4b47966..a4b360f3d3d 100644 --- a/tests/std/tests/P0645R10_text_formatting_death/env.lst +++ b/tests/std/tests/P0645R10_text_formatting_death/env.lst @@ -1,4 +1,4 @@ # Copyright (c) Microsoft Corporation. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -RUNALL_INCLUDE ..\strict_winsdk_concepts_latest_matrix.lst +RUNALL_INCLUDE ..\strict_winsdk_concepts_20_matrix.lst diff --git a/tests/std/tests/P0645R10_text_formatting_formatting/env.lst b/tests/std/tests/P0645R10_text_formatting_formatting/env.lst index 18e2d7c71ec..d6d824b5879 100644 --- a/tests/std/tests/P0645R10_text_formatting_formatting/env.lst +++ b/tests/std/tests/P0645R10_text_formatting_formatting/env.lst @@ -1,4 +1,4 @@ # Copyright (c) Microsoft Corporation. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -RUNALL_INCLUDE ..\concepts_latest_matrix.lst +RUNALL_INCLUDE ..\concepts_20_matrix.lst diff --git a/tests/std/tests/P0645R10_text_formatting_legacy_text_encoding/env.lst b/tests/std/tests/P0645R10_text_formatting_legacy_text_encoding/env.lst index 6da55ad3711..6939e946dfe 100644 --- a/tests/std/tests/P0645R10_text_formatting_legacy_text_encoding/env.lst +++ b/tests/std/tests/P0645R10_text_formatting_legacy_text_encoding/env.lst @@ -1,29 +1,29 @@ # Copyright (c) Microsoft Corporation. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -# This is `concepts_latest_matrix.lst` with `/execution-charset:.932` added. +# This is `concepts_20_matrix.lst` with `/execution-charset:.932` added. # clang is excluded since it doesn't support non-UTF-8 execution charsets. RUNALL_INCLUDE ..\prefix.lst RUNALL_CROSSLIST -PM_CL="/w14640 /Zc:threadSafeInit- /EHsc /std:c++latest /execution-charset:.932" +PM_CL="/w14640 /Zc:threadSafeInit- /EHsc /execution-charset:.932" RUNALL_CROSSLIST -PM_CL="/MD /D_ITERATOR_DEBUG_LEVEL=0 /permissive- /Zc:noexceptTypes-" -PM_CL="/MD /D_ITERATOR_DEBUG_LEVEL=1 /permissive-" -PM_CL="/MD /D_ITERATOR_DEBUG_LEVEL=0 /permissive- /Zc:char8_t- /Zc:preprocessor" -PM_CL="/MDd /D_ITERATOR_DEBUG_LEVEL=0 /permissive- /Zc:wchar_t-" -PM_CL="/MDd /D_ITERATOR_DEBUG_LEVEL=1 /permissive-" -PM_CL="/MDd /D_ITERATOR_DEBUG_LEVEL=2 /permissive- /fp:except /Zc:preprocessor" -PM_CL="/MT /D_ITERATOR_DEBUG_LEVEL=0 /permissive-" -PM_CL="/MT /D_ITERATOR_DEBUG_LEVEL=0 /permissive- /analyze:only /analyze:autolog-" -PM_CL="/MT /D_ITERATOR_DEBUG_LEVEL=1 /permissive-" -PM_CL="/MTd /D_ITERATOR_DEBUG_LEVEL=0 /permissive- /fp:strict" -PM_CL="/MTd /D_ITERATOR_DEBUG_LEVEL=1 /permissive-" -PM_CL="/MTd /D_ITERATOR_DEBUG_LEVEL=2 /permissive" -PM_CL="/MTd /D_ITERATOR_DEBUG_LEVEL=2 /permissive- /analyze:only /analyze:autolog-" -PM_CL="/permissive- /Za /MD" -PM_CL="/permissive- /Za /MDd" -# PM_CL="/permissive- /BE /c /MD" -# PM_CL="/permissive- /BE /c /MTd" -# PM_COMPILER="clang-cl" PM_CL="-fno-ms-compatibility -fno-delayed-template-parsing /permissive- /D_HAS_CXX23 /MD" -# PM_COMPILER="clang-cl" PM_CL="-fno-ms-compatibility -fno-delayed-template-parsing /permissive- /D_HAS_CXX23 /MTd /fp:strict" +PM_CL="/MD /D_ITERATOR_DEBUG_LEVEL=0 /std:c++20 /permissive- /Zc:noexceptTypes-" +PM_CL="/MD /D_ITERATOR_DEBUG_LEVEL=1 /std:c++latest /permissive-" +PM_CL="/MD /D_ITERATOR_DEBUG_LEVEL=0 /std:c++latest /permissive- /Zc:char8_t- /Zc:preprocessor" +PM_CL="/MDd /D_ITERATOR_DEBUG_LEVEL=0 /std:c++latest /permissive- /Zc:wchar_t-" +PM_CL="/MDd /D_ITERATOR_DEBUG_LEVEL=1 /std:c++latest /permissive-" +PM_CL="/MDd /D_ITERATOR_DEBUG_LEVEL=2 /std:c++20 /permissive- /fp:except /Zc:preprocessor" +PM_CL="/MT /D_ITERATOR_DEBUG_LEVEL=0 /std:c++latest /permissive-" +PM_CL="/MT /D_ITERATOR_DEBUG_LEVEL=0 /std:c++latest /permissive- /analyze:only /analyze:autolog-" +PM_CL="/MT /D_ITERATOR_DEBUG_LEVEL=1 /std:c++latest /permissive-" +PM_CL="/MTd /D_ITERATOR_DEBUG_LEVEL=0 /std:c++latest /permissive- /fp:strict" +PM_CL="/MTd /D_ITERATOR_DEBUG_LEVEL=1 /std:c++latest /permissive-" +PM_CL="/MTd /D_ITERATOR_DEBUG_LEVEL=2 /std:c++latest /permissive" +PM_CL="/MTd /D_ITERATOR_DEBUG_LEVEL=2 /std:c++latest /permissive- /analyze:only /analyze:autolog-" +PM_CL="/std:c++20 /permissive- /Za /MD" +PM_CL="/std:c++latest /permissive- /Za /MDd" +# PM_CL="/std:c++20 /permissive- /BE /c /MD" +# PM_CL="/std:c++latest /permissive- /BE /c /MTd" +# PM_COMPILER="clang-cl" PM_CL="-fno-ms-compatibility -fno-delayed-template-parsing /std:c++latest /permissive- /MD" +# PM_COMPILER="clang-cl" PM_CL="-fno-ms-compatibility -fno-delayed-template-parsing /std:c++latest /permissive- /D_HAS_CXX23 /MTd /fp:strict" diff --git a/tests/std/tests/P0645R10_text_formatting_parse_contexts/env.lst b/tests/std/tests/P0645R10_text_formatting_parse_contexts/env.lst index 18e2d7c71ec..d6d824b5879 100644 --- a/tests/std/tests/P0645R10_text_formatting_parse_contexts/env.lst +++ b/tests/std/tests/P0645R10_text_formatting_parse_contexts/env.lst @@ -1,4 +1,4 @@ # Copyright (c) Microsoft Corporation. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -RUNALL_INCLUDE ..\concepts_latest_matrix.lst +RUNALL_INCLUDE ..\concepts_20_matrix.lst diff --git a/tests/std/tests/P0645R10_text_formatting_parsing/env.lst b/tests/std/tests/P0645R10_text_formatting_parsing/env.lst index 18e2d7c71ec..d6d824b5879 100644 --- a/tests/std/tests/P0645R10_text_formatting_parsing/env.lst +++ b/tests/std/tests/P0645R10_text_formatting_parsing/env.lst @@ -1,4 +1,4 @@ # Copyright (c) Microsoft Corporation. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -RUNALL_INCLUDE ..\concepts_latest_matrix.lst +RUNALL_INCLUDE ..\concepts_20_matrix.lst diff --git a/tests/std/tests/P0645R10_text_formatting_utf8/env.lst b/tests/std/tests/P0645R10_text_formatting_utf8/env.lst index 4ca6faed472..1f537b16e72 100644 --- a/tests/std/tests/P0645R10_text_formatting_utf8/env.lst +++ b/tests/std/tests/P0645R10_text_formatting_utf8/env.lst @@ -1,6 +1,6 @@ # Copyright (c) Microsoft Corporation. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -RUNALL_INCLUDE ..\concepts_latest_matrix.lst +RUNALL_INCLUDE ..\concepts_20_matrix.lst RUNALL_CROSSLIST PM_CL="/utf-8" diff --git a/tests/std/tests/P0896R4_istream_view/env.lst b/tests/std/tests/P0896R4_istream_view/env.lst index 18e2d7c71ec..d6d824b5879 100644 --- a/tests/std/tests/P0896R4_istream_view/env.lst +++ b/tests/std/tests/P0896R4_istream_view/env.lst @@ -1,4 +1,4 @@ # Copyright (c) Microsoft Corporation. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -RUNALL_INCLUDE ..\concepts_latest_matrix.lst +RUNALL_INCLUDE ..\concepts_20_matrix.lst diff --git a/tests/std/tests/P0896R4_istream_view_death/env.lst b/tests/std/tests/P0896R4_istream_view_death/env.lst index 1e9f4b47966..a4b360f3d3d 100644 --- a/tests/std/tests/P0896R4_istream_view_death/env.lst +++ b/tests/std/tests/P0896R4_istream_view_death/env.lst @@ -1,4 +1,4 @@ # Copyright (c) Microsoft Corporation. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -RUNALL_INCLUDE ..\strict_winsdk_concepts_latest_matrix.lst +RUNALL_INCLUDE ..\strict_winsdk_concepts_20_matrix.lst diff --git a/tests/std/tests/P0896R4_ranges_alg_uninitialized_copy_n/env.lst b/tests/std/tests/P0896R4_ranges_alg_uninitialized_copy_n/env.lst index 18e2d7c71ec..d6d824b5879 100644 --- a/tests/std/tests/P0896R4_ranges_alg_uninitialized_copy_n/env.lst +++ b/tests/std/tests/P0896R4_ranges_alg_uninitialized_copy_n/env.lst @@ -1,4 +1,4 @@ # Copyright (c) Microsoft Corporation. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -RUNALL_INCLUDE ..\concepts_latest_matrix.lst +RUNALL_INCLUDE ..\concepts_20_matrix.lst diff --git a/tests/std/tests/P0896R4_ranges_alg_uninitialized_move_n/env.lst b/tests/std/tests/P0896R4_ranges_alg_uninitialized_move_n/env.lst index 18e2d7c71ec..d6d824b5879 100644 --- a/tests/std/tests/P0896R4_ranges_alg_uninitialized_move_n/env.lst +++ b/tests/std/tests/P0896R4_ranges_alg_uninitialized_move_n/env.lst @@ -1,4 +1,4 @@ # Copyright (c) Microsoft Corporation. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -RUNALL_INCLUDE ..\concepts_latest_matrix.lst +RUNALL_INCLUDE ..\concepts_20_matrix.lst diff --git a/tests/std/tests/P0896R4_ranges_range_machinery/env.lst b/tests/std/tests/P0896R4_ranges_range_machinery/env.lst index 18e2d7c71ec..d6d824b5879 100644 --- a/tests/std/tests/P0896R4_ranges_range_machinery/env.lst +++ b/tests/std/tests/P0896R4_ranges_range_machinery/env.lst @@ -1,4 +1,4 @@ # Copyright (c) Microsoft Corporation. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -RUNALL_INCLUDE ..\concepts_latest_matrix.lst +RUNALL_INCLUDE ..\concepts_20_matrix.lst diff --git a/tests/std/tests/P0896R4_ranges_ref_view/env.lst b/tests/std/tests/P0896R4_ranges_ref_view/env.lst index 18e2d7c71ec..d6d824b5879 100644 --- a/tests/std/tests/P0896R4_ranges_ref_view/env.lst +++ b/tests/std/tests/P0896R4_ranges_ref_view/env.lst @@ -1,4 +1,4 @@ # Copyright (c) Microsoft Corporation. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -RUNALL_INCLUDE ..\concepts_latest_matrix.lst +RUNALL_INCLUDE ..\concepts_20_matrix.lst diff --git a/tests/std/tests/P0896R4_ranges_subrange/env.lst b/tests/std/tests/P0896R4_ranges_subrange/env.lst index 18e2d7c71ec..d6d824b5879 100644 --- a/tests/std/tests/P0896R4_ranges_subrange/env.lst +++ b/tests/std/tests/P0896R4_ranges_subrange/env.lst @@ -1,4 +1,4 @@ # Copyright (c) Microsoft Corporation. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -RUNALL_INCLUDE ..\concepts_latest_matrix.lst +RUNALL_INCLUDE ..\concepts_20_matrix.lst diff --git a/tests/std/tests/P0896R4_views_all/env.lst b/tests/std/tests/P0896R4_views_all/env.lst index 18e2d7c71ec..d6d824b5879 100644 --- a/tests/std/tests/P0896R4_views_all/env.lst +++ b/tests/std/tests/P0896R4_views_all/env.lst @@ -1,4 +1,4 @@ # Copyright (c) Microsoft Corporation. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -RUNALL_INCLUDE ..\concepts_latest_matrix.lst +RUNALL_INCLUDE ..\concepts_20_matrix.lst diff --git a/tests/std/tests/P0896R4_views_common/env.lst b/tests/std/tests/P0896R4_views_common/env.lst index 8ac7033b206..7b6bcff4830 100644 --- a/tests/std/tests/P0896R4_views_common/env.lst +++ b/tests/std/tests/P0896R4_views_common/env.lst @@ -1,4 +1,4 @@ # Copyright (c) Microsoft Corporation. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -RUNALL_INCLUDE ..\strict_concepts_latest_matrix.lst +RUNALL_INCLUDE ..\strict_concepts_20_matrix.lst diff --git a/tests/std/tests/P0896R4_views_counted/env.lst b/tests/std/tests/P0896R4_views_counted/env.lst index 8ac7033b206..7b6bcff4830 100644 --- a/tests/std/tests/P0896R4_views_counted/env.lst +++ b/tests/std/tests/P0896R4_views_counted/env.lst @@ -1,4 +1,4 @@ # Copyright (c) Microsoft Corporation. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -RUNALL_INCLUDE ..\strict_concepts_latest_matrix.lst +RUNALL_INCLUDE ..\strict_concepts_20_matrix.lst diff --git a/tests/std/tests/P0896R4_views_counted_death/env.lst b/tests/std/tests/P0896R4_views_counted_death/env.lst index 1e9f4b47966..a4b360f3d3d 100644 --- a/tests/std/tests/P0896R4_views_counted_death/env.lst +++ b/tests/std/tests/P0896R4_views_counted_death/env.lst @@ -1,4 +1,4 @@ # Copyright (c) Microsoft Corporation. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -RUNALL_INCLUDE ..\strict_winsdk_concepts_latest_matrix.lst +RUNALL_INCLUDE ..\strict_winsdk_concepts_20_matrix.lst diff --git a/tests/std/tests/P0896R4_views_drop/env.lst b/tests/std/tests/P0896R4_views_drop/env.lst index 8ac7033b206..7b6bcff4830 100644 --- a/tests/std/tests/P0896R4_views_drop/env.lst +++ b/tests/std/tests/P0896R4_views_drop/env.lst @@ -1,4 +1,4 @@ # Copyright (c) Microsoft Corporation. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -RUNALL_INCLUDE ..\strict_concepts_latest_matrix.lst +RUNALL_INCLUDE ..\strict_concepts_20_matrix.lst diff --git a/tests/std/tests/P0896R4_views_drop_while/env.lst b/tests/std/tests/P0896R4_views_drop_while/env.lst index 18e2d7c71ec..d6d824b5879 100644 --- a/tests/std/tests/P0896R4_views_drop_while/env.lst +++ b/tests/std/tests/P0896R4_views_drop_while/env.lst @@ -1,4 +1,4 @@ # Copyright (c) Microsoft Corporation. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -RUNALL_INCLUDE ..\concepts_latest_matrix.lst +RUNALL_INCLUDE ..\concepts_20_matrix.lst diff --git a/tests/std/tests/P0896R4_views_drop_while_death/env.lst b/tests/std/tests/P0896R4_views_drop_while_death/env.lst index 1e9f4b47966..a4b360f3d3d 100644 --- a/tests/std/tests/P0896R4_views_drop_while_death/env.lst +++ b/tests/std/tests/P0896R4_views_drop_while_death/env.lst @@ -1,4 +1,4 @@ # Copyright (c) Microsoft Corporation. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -RUNALL_INCLUDE ..\strict_winsdk_concepts_latest_matrix.lst +RUNALL_INCLUDE ..\strict_winsdk_concepts_20_matrix.lst diff --git a/tests/std/tests/P0896R4_views_elements/env.lst b/tests/std/tests/P0896R4_views_elements/env.lst index 8ac7033b206..7b6bcff4830 100644 --- a/tests/std/tests/P0896R4_views_elements/env.lst +++ b/tests/std/tests/P0896R4_views_elements/env.lst @@ -1,4 +1,4 @@ # Copyright (c) Microsoft Corporation. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -RUNALL_INCLUDE ..\strict_concepts_latest_matrix.lst +RUNALL_INCLUDE ..\strict_concepts_20_matrix.lst diff --git a/tests/std/tests/P0896R4_views_empty/env.lst b/tests/std/tests/P0896R4_views_empty/env.lst index 18e2d7c71ec..d6d824b5879 100644 --- a/tests/std/tests/P0896R4_views_empty/env.lst +++ b/tests/std/tests/P0896R4_views_empty/env.lst @@ -1,4 +1,4 @@ # Copyright (c) Microsoft Corporation. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -RUNALL_INCLUDE ..\concepts_latest_matrix.lst +RUNALL_INCLUDE ..\concepts_20_matrix.lst diff --git a/tests/std/tests/P0896R4_views_filter/env.lst b/tests/std/tests/P0896R4_views_filter/env.lst index 8ac7033b206..7b6bcff4830 100644 --- a/tests/std/tests/P0896R4_views_filter/env.lst +++ b/tests/std/tests/P0896R4_views_filter/env.lst @@ -1,4 +1,4 @@ # Copyright (c) Microsoft Corporation. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -RUNALL_INCLUDE ..\strict_concepts_latest_matrix.lst +RUNALL_INCLUDE ..\strict_concepts_20_matrix.lst diff --git a/tests/std/tests/P0896R4_views_filter_death/env.lst b/tests/std/tests/P0896R4_views_filter_death/env.lst index 1e9f4b47966..a4b360f3d3d 100644 --- a/tests/std/tests/P0896R4_views_filter_death/env.lst +++ b/tests/std/tests/P0896R4_views_filter_death/env.lst @@ -1,4 +1,4 @@ # Copyright (c) Microsoft Corporation. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -RUNALL_INCLUDE ..\strict_winsdk_concepts_latest_matrix.lst +RUNALL_INCLUDE ..\strict_winsdk_concepts_20_matrix.lst diff --git a/tests/std/tests/P0896R4_views_filter_iterator/env.lst b/tests/std/tests/P0896R4_views_filter_iterator/env.lst index 8ac7033b206..7b6bcff4830 100644 --- a/tests/std/tests/P0896R4_views_filter_iterator/env.lst +++ b/tests/std/tests/P0896R4_views_filter_iterator/env.lst @@ -1,4 +1,4 @@ # Copyright (c) Microsoft Corporation. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -RUNALL_INCLUDE ..\strict_concepts_latest_matrix.lst +RUNALL_INCLUDE ..\strict_concepts_20_matrix.lst diff --git a/tests/std/tests/P0896R4_views_iota/env.lst b/tests/std/tests/P0896R4_views_iota/env.lst index 8ac7033b206..7b6bcff4830 100644 --- a/tests/std/tests/P0896R4_views_iota/env.lst +++ b/tests/std/tests/P0896R4_views_iota/env.lst @@ -1,4 +1,4 @@ # Copyright (c) Microsoft Corporation. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -RUNALL_INCLUDE ..\strict_concepts_latest_matrix.lst +RUNALL_INCLUDE ..\strict_concepts_20_matrix.lst diff --git a/tests/std/tests/P0896R4_views_iota/test.cpp b/tests/std/tests/P0896R4_views_iota/test.cpp index ed990295ba3..20aea90c5fa 100644 --- a/tests/std/tests/P0896R4_views_iota/test.cpp +++ b/tests/std/tests/P0896R4_views_iota/test.cpp @@ -10,6 +10,8 @@ using namespace std; +static_assert(ranges::_Advanceable); + template concept CanViewIota = requires(W w, B b) { views::iota(w, b); @@ -49,8 +51,10 @@ constexpr void test_integral() { if constexpr (sizeof(T) < sizeof(int)) { static_assert(same_as, int>); - } else { + } else if constexpr (sizeof(T) < sizeof(long long)) { static_assert(same_as, long long>); + } else { + static_assert(same_as, std::_Signed128>); } // iota_view is always a simple-view, i.e., const and non-const are always valid ranges with the same iterators: @@ -73,7 +77,9 @@ constexpr void test_integral() { using I = ranges::iterator_t; static_assert(same_as); - static_assert(same_as::iterator_category, input_iterator_tag>); + if constexpr (integral>) { + static_assert(same_as::iterator_category, input_iterator_tag>); + } assert(I{} == I{T{0}}); static_assert(is_nothrow_default_constructible_v); @@ -211,8 +217,10 @@ constexpr void test_integral() { if constexpr (sizeof(T) < sizeof(int)) { static_assert(same_as, int>); - } else { + } else if constexpr (sizeof(T) < sizeof(long long)) { static_assert(same_as, long long>); + } else { + static_assert(same_as, std::_Signed128>); } { diff --git a/tests/std/tests/P0896R4_views_join/env.lst b/tests/std/tests/P0896R4_views_join/env.lst index 8ac7033b206..7b6bcff4830 100644 --- a/tests/std/tests/P0896R4_views_join/env.lst +++ b/tests/std/tests/P0896R4_views_join/env.lst @@ -1,4 +1,4 @@ # Copyright (c) Microsoft Corporation. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -RUNALL_INCLUDE ..\strict_concepts_latest_matrix.lst +RUNALL_INCLUDE ..\strict_concepts_20_matrix.lst diff --git a/tests/std/tests/P0896R4_views_lazy_split/env.lst b/tests/std/tests/P0896R4_views_lazy_split/env.lst index 8ac7033b206..7b6bcff4830 100644 --- a/tests/std/tests/P0896R4_views_lazy_split/env.lst +++ b/tests/std/tests/P0896R4_views_lazy_split/env.lst @@ -1,4 +1,4 @@ # Copyright (c) Microsoft Corporation. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -RUNALL_INCLUDE ..\strict_concepts_latest_matrix.lst +RUNALL_INCLUDE ..\strict_concepts_20_matrix.lst diff --git a/tests/std/tests/P0896R4_views_reverse/env.lst b/tests/std/tests/P0896R4_views_reverse/env.lst index 8ac7033b206..7b6bcff4830 100644 --- a/tests/std/tests/P0896R4_views_reverse/env.lst +++ b/tests/std/tests/P0896R4_views_reverse/env.lst @@ -1,4 +1,4 @@ # Copyright (c) Microsoft Corporation. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -RUNALL_INCLUDE ..\strict_concepts_latest_matrix.lst +RUNALL_INCLUDE ..\strict_concepts_20_matrix.lst diff --git a/tests/std/tests/P0896R4_views_single/env.lst b/tests/std/tests/P0896R4_views_single/env.lst index 18e2d7c71ec..d6d824b5879 100644 --- a/tests/std/tests/P0896R4_views_single/env.lst +++ b/tests/std/tests/P0896R4_views_single/env.lst @@ -1,4 +1,4 @@ # Copyright (c) Microsoft Corporation. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -RUNALL_INCLUDE ..\concepts_latest_matrix.lst +RUNALL_INCLUDE ..\concepts_20_matrix.lst diff --git a/tests/std/tests/P0896R4_views_split/env.lst b/tests/std/tests/P0896R4_views_split/env.lst index 8ac7033b206..7b6bcff4830 100644 --- a/tests/std/tests/P0896R4_views_split/env.lst +++ b/tests/std/tests/P0896R4_views_split/env.lst @@ -1,4 +1,4 @@ # Copyright (c) Microsoft Corporation. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -RUNALL_INCLUDE ..\strict_concepts_latest_matrix.lst +RUNALL_INCLUDE ..\strict_concepts_20_matrix.lst diff --git a/tests/std/tests/P0896R4_views_split/test.cpp b/tests/std/tests/P0896R4_views_split/test.cpp index 767a8be196d..0061040907b 100644 --- a/tests/std/tests/P0896R4_views_split/test.cpp +++ b/tests/std/tests/P0896R4_views_split/test.cpp @@ -285,7 +285,7 @@ constexpr bool instantiation_test() { instantiator::call>(); { // ensure we get something contiguous - for (string_view sv : "127..0..0..1"sv | views::split(".."sv)) { + for (ranges::contiguous_range auto sv : "127..0..0..1"sv | views::split(".."sv)) { assert(!sv.empty()); } } diff --git a/tests/std/tests/P0896R4_views_take/env.lst b/tests/std/tests/P0896R4_views_take/env.lst index 8ac7033b206..7b6bcff4830 100644 --- a/tests/std/tests/P0896R4_views_take/env.lst +++ b/tests/std/tests/P0896R4_views_take/env.lst @@ -1,4 +1,4 @@ # Copyright (c) Microsoft Corporation. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -RUNALL_INCLUDE ..\strict_concepts_latest_matrix.lst +RUNALL_INCLUDE ..\strict_concepts_20_matrix.lst diff --git a/tests/std/tests/P0896R4_views_take_while/env.lst b/tests/std/tests/P0896R4_views_take_while/env.lst index 8ac7033b206..7b6bcff4830 100644 --- a/tests/std/tests/P0896R4_views_take_while/env.lst +++ b/tests/std/tests/P0896R4_views_take_while/env.lst @@ -1,4 +1,4 @@ # Copyright (c) Microsoft Corporation. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -RUNALL_INCLUDE ..\strict_concepts_latest_matrix.lst +RUNALL_INCLUDE ..\strict_concepts_20_matrix.lst diff --git a/tests/std/tests/P0896R4_views_take_while_death/env.lst b/tests/std/tests/P0896R4_views_take_while_death/env.lst index 1e9f4b47966..a4b360f3d3d 100644 --- a/tests/std/tests/P0896R4_views_take_while_death/env.lst +++ b/tests/std/tests/P0896R4_views_take_while_death/env.lst @@ -1,4 +1,4 @@ # Copyright (c) Microsoft Corporation. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -RUNALL_INCLUDE ..\strict_winsdk_concepts_latest_matrix.lst +RUNALL_INCLUDE ..\strict_winsdk_concepts_20_matrix.lst diff --git a/tests/std/tests/P0896R4_views_transform/env.lst b/tests/std/tests/P0896R4_views_transform/env.lst index 8ac7033b206..7b6bcff4830 100644 --- a/tests/std/tests/P0896R4_views_transform/env.lst +++ b/tests/std/tests/P0896R4_views_transform/env.lst @@ -1,4 +1,4 @@ # Copyright (c) Microsoft Corporation. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -RUNALL_INCLUDE ..\strict_concepts_latest_matrix.lst +RUNALL_INCLUDE ..\strict_concepts_20_matrix.lst diff --git a/tests/std/tests/P0896R4_views_transform_death/env.lst b/tests/std/tests/P0896R4_views_transform_death/env.lst index 1e9f4b47966..a4b360f3d3d 100644 --- a/tests/std/tests/P0896R4_views_transform_death/env.lst +++ b/tests/std/tests/P0896R4_views_transform_death/env.lst @@ -1,4 +1,4 @@ # Copyright (c) Microsoft Corporation. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -RUNALL_INCLUDE ..\strict_winsdk_concepts_latest_matrix.lst +RUNALL_INCLUDE ..\strict_winsdk_concepts_20_matrix.lst diff --git a/tests/std/tests/P1522R1_difference_type/env.lst b/tests/std/tests/P1522R1_difference_type/env.lst new file mode 100644 index 00000000000..7b6bcff4830 --- /dev/null +++ b/tests/std/tests/P1522R1_difference_type/env.lst @@ -0,0 +1,4 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\strict_concepts_20_matrix.lst diff --git a/tests/std/tests/P1522R1_difference_type/test.cpp b/tests/std/tests/P1522R1_difference_type/test.cpp new file mode 100644 index 00000000000..0a2cc61c943 --- /dev/null +++ b/tests/std/tests/P1522R1_difference_type/test.cpp @@ -0,0 +1,1049 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include <__msvc_int128.hpp> +#include +#include +#include +#include +#include +#include +#include + +using std::_Signed128; +using std::_Unsigned128; + +constexpr void check_equal(const auto& x) { + assert(x == x); + assert(!(x != x)); + assert(!(x < x)); + assert(!(x > x)); + assert(x <= x); + assert(x >= x); + assert(x <=> x == 0); +} + +constexpr void check_order(const auto& x, const auto& y, const std::strong_ordering ord) { + assert((x == y) == (ord == std::strong_ordering::equal)); + assert((x != y) == (ord != std::strong_ordering::equal)); + assert((x < y) == (ord == std::strong_ordering::less)); + assert((x > y) == (ord == std::strong_ordering::greater)); + assert((x <= y) == (ord != std::strong_ordering::greater)); + assert((x >= y) == (ord != std::strong_ordering::less)); + + assert((y == x) == (ord == std::strong_ordering::equal)); + assert((y != x) == (ord != std::strong_ordering::equal)); + assert((y < x) == (ord == std::strong_ordering::greater)); + assert((y > x) == (ord == std::strong_ordering::less)); + assert((y <= x) == (ord != std::strong_ordering::less)); + assert((y >= x) == (ord != std::strong_ordering::greater)); + + assert((x <=> y) == (ord <=> 0)); + assert((y <=> x) == (0 <=> ord)); +} + +constexpr bool test_unsigned() { + static_assert(std::regular<_Unsigned128>); + static_assert(std::three_way_comparable<_Unsigned128, std::strong_ordering>); + + static_assert(std::numeric_limits<_Unsigned128>::min() == 0); + static_assert(std::numeric_limits<_Unsigned128>::max() == ~_Unsigned128{}); + static_assert(std::numeric_limits<_Unsigned128>::digits == 128); + static_assert(std::numeric_limits<_Unsigned128>::is_modulo); + + static_assert(std::same_as, _Unsigned128>); + static_assert(std::same_as, _Unsigned128>); + static_assert(std::same_as, _Unsigned128>); + static_assert(std::same_as, _Unsigned128>); + static_assert(std::same_as, _Unsigned128>); +#ifdef __cpp_char8_t + static_assert(std::same_as, _Unsigned128>); +#endif // __cpp_char8_t + static_assert(std::same_as, _Unsigned128>); + static_assert(std::same_as, _Unsigned128>); + static_assert(std::same_as, _Unsigned128>); + static_assert(std::same_as, _Unsigned128>); + static_assert(std::same_as, _Unsigned128>); + static_assert(std::same_as, _Unsigned128>); + static_assert(std::same_as, _Unsigned128>); + static_assert(std::same_as, _Unsigned128>); + static_assert(std::same_as, _Unsigned128>); + static_assert(std::same_as, _Unsigned128>); + static_assert(std::same_as, _Unsigned128>); + + static_assert(std::same_as, _Unsigned128>); + static_assert(std::same_as, _Unsigned128>); + static_assert(std::same_as, _Unsigned128>); + static_assert(std::same_as, _Unsigned128>); + static_assert(std::same_as, _Unsigned128>); +#ifdef __cpp_char8_t + static_assert(std::same_as, _Unsigned128>); +#endif // __cpp_char8_t + static_assert(std::same_as, _Unsigned128>); + static_assert(std::same_as, _Unsigned128>); + static_assert(std::same_as, _Unsigned128>); + static_assert(std::same_as, _Unsigned128>); + static_assert(std::same_as, _Unsigned128>); + static_assert(std::same_as, _Unsigned128>); + static_assert(std::same_as, _Unsigned128>); + static_assert(std::same_as, _Unsigned128>); + static_assert(std::same_as, _Unsigned128>); + static_assert(std::same_as, _Unsigned128>); + static_assert(std::same_as, _Unsigned128>); + + static_assert(std::_Integer_class<_Unsigned128>); + static_assert(std::_Integer_like<_Unsigned128>); + static_assert(!std::_Signed_integer_like<_Unsigned128>); + static_assert(std::same_as, _Unsigned128>); + static_assert(std::same_as, _Signed128>); + + check_equal(_Unsigned128{}); + check_equal(_Unsigned128{42}); + check_equal(_Unsigned128{-42}); + check_equal(_Unsigned128{0x11111111'11111111, 0x22222222'22222222}); + + check_order(_Unsigned128{42}, _Unsigned128{-42}, std::strong_ordering::less); + check_order(_Unsigned128{0, 42}, _Unsigned128{0, 52}, std::strong_ordering::less); // ordered only by MSW + check_order(_Unsigned128{42}, _Unsigned128{52}, std::strong_ordering::less); // ordered only by LSW + check_order(_Unsigned128{0x11111111'11111111, 0x22222222'22222222}, + _Unsigned128{0x01010101'01010101, 0x01010101'01010101}, std::strong_ordering::greater); + + { + _Unsigned128 u{42}; + assert(u._Word[0] == 42); + assert(u._Word[1] == 0); + u += _Unsigned128{0}; + assert(u._Word[0] == 42); + assert(u._Word[1] == 0); + + assert(static_cast(u) == 42); + assert(static_cast(u) == 42); + assert(static_cast(u) == 42); + assert(static_cast(u) == 42); + + assert(static_cast(u) == 42); + assert(static_cast(u) == 42); + assert(static_cast(u) == 42); + assert(static_cast(u) == 42); + + _Unsigned128 nu{-42}; + assert(nu._Word[0] == 0ull - 42); + assert(nu._Word[1] == ~0ull); + + assert(static_cast(nu) == 0ull - 42); + assert(static_cast(nu) == 0u - 42); + assert(static_cast(nu) == 65536 - 42); + assert(static_cast(nu) == 256 - 42); + + assert(static_cast(nu) == -42); + assert(static_cast(nu) == -42); + assert(static_cast(nu) == -42); + assert(static_cast(nu) == -42); + { + _Unsigned128 sum = u + nu; + assert(sum._Word[0] == 0); + assert(sum._Word[1] == 0); + + --sum; + assert(sum._Word[0] == 0ull - 1); + assert(sum._Word[1] == 0ull - 1); + --sum; + assert(sum._Word[0] == 0ull - 2); + assert(sum._Word[1] == 0ull - 1); + ++sum; + assert(sum._Word[0] == 0ull - 1); + assert(sum._Word[1] == 0ull - 1); + ++sum; + assert(sum._Word[0] == 0); + assert(sum._Word[1] == 0); + } + { + _Unsigned128 product = u * u; + assert(product._Word[0] == 42 * 42); + assert(product._Word[1] == 0); + + product = nu * nu; + assert(product._Word[0] == 42 * 42); + assert(product._Word[1] == 0); + + product = _Unsigned128{0x01010101'01010101, 0x01010101'01010101} * 5; + assert(product._Word[0] == 0x05050505'05050505); + assert(product._Word[1] == 0x05050505'05050505); + + product = 5 * _Unsigned128{0x01010101'01010101, 0x01010101'01010101}; + assert(product._Word[0] == 0x05050505'05050505); + assert(product._Word[1] == 0x05050505'05050505); + + product = _Unsigned128{0x01010101'01010101, 0x01010101'01010101}; + product *= product; + assert(product._Word[0] == 0x08070605'04030201); + assert(product._Word[1] == 0x100f0e0d'0c0b0a09); + assert(+product == product); + assert(-product + product == 0); + + product = _Unsigned128{0x01020304'05060708, 0x090a0b0c'0d0e0f00} + * _Unsigned128{0x000f0e0d'0c0b0a09, 0x08070605'04030201}; + assert(product._Word[0] == 0x6dc18e55'16d48f48); + assert(product._Word[1] == 0xdc1b6bce'43cd6c21); + assert(+product == product); + assert(-product + product == 0); + + product <<= 11; + assert(product._Word[0] == 0x0c72a8b6'a47a4000); + assert(product._Word[1] == 0xdb5e721e'6b610b6e); + assert(+product == product); + assert(-product + product == 0); + + product >>= 17; + assert(product._Word[0] == 0x85b70639'545b523d); + assert(product._Word[1] == 0x00006daf'390f35b0); + assert(+product == product); + assert(-product + product == 0); + } + } + { + _Unsigned128 q = _Unsigned128{13} / _Unsigned128{4}; + assert(q._Word[0] == 3); + assert(q._Word[1] == 0); + + q = _Unsigned128{4} / _Unsigned128{13}; + assert(q._Word[0] == 0); + assert(q._Word[1] == 0); + + q = _Unsigned128{0x01010101'01010101, 0x01010101'01010101} / _Unsigned128{13}; + assert(q._Word[0] == 0xc50013c5'0013c500); + assert(q._Word[1] == 0x0013c500'13c50013); + + q = _Unsigned128{0x22222222'22222222, 0x22222222'22222222} + / _Unsigned128{0x11111111'11111111, 0x11111111'11111111}; + assert(q._Word[0] == 2); + assert(q._Word[1] == 0); + + q = (_Unsigned128{1} << 66) / (_Unsigned128{1} << 13); + assert(q._Word[0] == 1ull << 53); + assert(q._Word[1] == 0); + } + { + auto tmp = ~_Unsigned128{}; + assert(tmp._Word[0] == ~0ull); + assert(tmp._Word[1] == ~0ull); + auto q = tmp / std::uint32_t{1}; + assert(q == tmp); + q = tmp / std::uint64_t{1}; + assert(q == tmp); + q = tmp / _Unsigned128{1}; + assert(q == tmp); + + q = tmp / _Unsigned128{1ull << 32}; + assert(q._Word[0] == ~0ull); + assert(q._Word[1] == 0xffffffff); + } + { + _Unsigned128 result{0x01010101'01010101, 0x01010101'01010101}; + _Unsigned128 tmp; + for (tmp = 0xffu; static_cast(tmp); tmp <<= 8, result >>= 8) { + auto q = ~_Unsigned128{} / tmp; + assert(q == result); + auto m = ~_Unsigned128{} % tmp; + auto p = q * tmp; + auto diff = ~_Unsigned128{} - p; + assert(m == diff); + } + assert(tmp == 0); + } + { + _Unsigned128 tmp; + for (tmp = 1; static_cast(tmp); tmp <<= 1) { + assert(tmp % tmp == 0); + } + assert(tmp == 0); + } + { + const _Unsigned128 x{0x01020304'02030405, 0x03040506'04050607}; + const _Unsigned128 y{0x07060504'06050403, 0x05040302'04030101}; + assert(((x & y) == _Unsigned128{0x01020104'02010401, 0x01040102'04010001})); + auto tmp = x; + tmp &= y; + assert(tmp == (x & y)); + + assert(((x | y) == _Unsigned128{0x07060704'06070407, 0x07040706'04070707})); + tmp = x; + tmp |= y; + assert(tmp == (x | y)); + + assert(((x ^ y) == _Unsigned128{0x06040600'04060006, 0x06000604'00060706})); + tmp = x; + tmp ^= y; + assert(tmp == (x ^ y)); + } + { + _Unsigned128 x{}; + assert(++x == 1); + assert(--x == 0); + assert(x == std::numeric_limits<_Unsigned128>::min()); + --x; + assert(x._Word[0] == ~0ull); + assert(x._Word[1] == ~0ull); + assert(x == std::numeric_limits<_Unsigned128>::max()); + --x; + assert(x._Word[0] == (~0ull << 1)); + assert(x._Word[1] == ~0ull); + x._Word[0] = 0; + x._Word[1] = 1; + --x; + assert(x._Word[0] == ~0ull); + assert(x._Word[1] == 0); + ++x; + assert(x._Word[0] == 0); + assert(x._Word[1] == 1); + ++x; + assert(x._Word[0] == 1); + assert(x._Word[1] == 1); + x._Word[0] = ~0ull; + x._Word[1] = static_cast(std::numeric_limits::max()); + ++x; + assert(x._Word[0] == 0); + assert(x._Word[1] == static_cast(std::numeric_limits::min())); + --x; + assert(x._Word[0] == ~0ull); + assert(x._Word[1] == static_cast(std::numeric_limits::max())); + } + + return true; +} + +constexpr bool test_signed() { + static_assert(std::regular<_Signed128>); + static_assert(std::three_way_comparable<_Signed128, std::strong_ordering>); + + static_assert(std::numeric_limits<_Signed128>::min() == _Signed128{0, 1ull << 63}); + static_assert(std::numeric_limits<_Signed128>::max() == _Signed128{~0ull, ~0ull >> 1}); + static_assert(std::numeric_limits<_Signed128>::digits == 127); + static_assert(!std::numeric_limits<_Signed128>::is_modulo); + + static_assert(std::same_as, _Signed128>); + static_assert(std::same_as, _Signed128>); + static_assert(std::same_as, _Signed128>); + static_assert(std::same_as, _Signed128>); + static_assert(std::same_as, _Signed128>); +#ifdef __cpp_char8_t + static_assert(std::same_as, _Signed128>); +#endif // __cpp_char8_t + static_assert(std::same_as, _Signed128>); + static_assert(std::same_as, _Signed128>); + static_assert(std::same_as, _Signed128>); + static_assert(std::same_as, _Signed128>); + static_assert(std::same_as, _Signed128>); + static_assert(std::same_as, _Signed128>); + static_assert(std::same_as, _Signed128>); + static_assert(std::same_as, _Signed128>); + static_assert(std::same_as, _Signed128>); + static_assert(std::same_as, _Signed128>); + + static_assert(std::same_as, _Signed128>); + static_assert(std::same_as, _Signed128>); + static_assert(std::same_as, _Signed128>); + static_assert(std::same_as, _Signed128>); + static_assert(std::same_as, _Signed128>); +#ifdef __cpp_char8_t + static_assert(std::same_as, _Signed128>); +#endif // __cpp_char8_t + static_assert(std::same_as, _Signed128>); + static_assert(std::same_as, _Signed128>); + static_assert(std::same_as, _Signed128>); + static_assert(std::same_as, _Signed128>); + static_assert(std::same_as, _Signed128>); + static_assert(std::same_as, _Signed128>); + static_assert(std::same_as, _Signed128>); + static_assert(std::same_as, _Signed128>); + static_assert(std::same_as, _Signed128>); + static_assert(std::same_as, _Signed128>); + + static_assert(std::_Integer_class<_Signed128>); + static_assert(std::_Integer_like<_Signed128>); + static_assert(std::_Signed_integer_like<_Signed128>); + static_assert(std::same_as, _Unsigned128>); + static_assert(std::same_as, _Signed128>); + + check_equal(_Signed128{}); + check_equal(_Signed128{42}); + check_equal(_Signed128{-42}); + check_equal(_Signed128{0x11111111'11111111, 0x22222222'22222222}); + + check_order(_Signed128{42}, _Signed128{-42}, std::strong_ordering::greater); + check_order(_Signed128{0x11111111'11111111, 0x22222222'22222222}, + _Signed128{0x01010101'01010101, 0x01010101'01010101}, std::strong_ordering::greater); + check_order(_Signed128{~0ull, ~0ull}, _Signed128{-1}, std::strong_ordering::equal); + + check_order(_Signed128{-2}, _Signed128{-1}, std::strong_ordering::less); + check_order(_Signed128{-2}, _Signed128{1}, std::strong_ordering::less); + check_order(_Signed128{2}, _Signed128{-1}, std::strong_ordering::greater); + check_order(_Signed128{2}, _Signed128{1}, std::strong_ordering::greater); + + check_equal(_Signed128{0, 0}); + check_order(_Signed128{0, (1ull << 63)}, _Signed128{0, 0}, std::strong_ordering::less); + check_order(_Signed128{0, (1ull << 63)}, _Signed128{0, (1ull << 63)}, std::strong_ordering::equal); + check_order(_Signed128{0, 0}, _Signed128{1, 0}, std::strong_ordering::less); + check_order(_Signed128{0, (1ull << 63)}, _Signed128{1, 0}, std::strong_ordering::less); + check_order(_Signed128{0, (1ull << 63)}, _Signed128{1, (1ull << 63)}, std::strong_ordering::less); + check_order(_Signed128{0, 0}, _Signed128{0, 1}, std::strong_ordering::less); + check_order(_Signed128{0, (1ull << 63)}, _Signed128{0, 1}, std::strong_ordering::less); + check_order(_Signed128{0, (1ull << 63)}, _Signed128{0, 1 | (1ull << 63)}, std::strong_ordering::less); + check_order(_Signed128{0, 0}, _Signed128{1, 1}, std::strong_ordering::less); + check_order(_Signed128{0, (1ull << 63)}, _Signed128{1, 1}, std::strong_ordering::less); + check_order(_Signed128{0, (1ull << 63)}, _Signed128{1, 1 | (1ull << 63)}, std::strong_ordering::less); + + assert((_Signed128{-2} == _Unsigned128{0ull - 2, ~0ull})); + assert((_Unsigned128{_Signed128{-2}} == _Unsigned128{0ull - 2, ~0ull})); + assert((_Signed128{-2} == _Signed128{_Unsigned128{0ull - 2, ~0ull}})); + + { + _Signed128 u{42}; + assert(u._Word[0] == 42); + assert(u._Word[1] == 0); + u += _Signed128{0}; + assert(u._Word[0] == 42); + assert(u._Word[1] == 0); + + assert(static_cast(u) == 42); + assert(static_cast(u) == 42); + assert(static_cast(u) == 42); + assert(static_cast(u) == 42); + + assert(static_cast(u) == 42); + assert(static_cast(u) == 42); + assert(static_cast(u) == 42); + assert(static_cast(u) == 42); + } + { + _Signed128 nu{-42}; + assert(nu._Word[0] == 0ull - 42); + assert(nu._Word[1] == ~0ull); + + assert(static_cast(nu) == 0ull - 42); + assert(static_cast(nu) == 0u - 42); + assert(static_cast(nu) == 65536 - 42); + assert(static_cast(nu) == 256 - 42); + + assert(static_cast(nu) == -42); + assert(static_cast(nu) == -42); + assert(static_cast(nu) == -42); + assert(static_cast(nu) == -42); + } + + { + _Signed128 u{42}; + _Signed128 v{13}; + { + _Signed128 sum = u + v; + assert(sum._Word[0] == 55); + assert(sum._Word[1] == 0); + sum = v + u; + assert(sum._Word[0] == 55); + assert(sum._Word[1] == 0); + } + { + _Signed128 diff = u - v; + assert(diff._Word[0] == 29); + assert(diff._Word[1] == 0); + diff = v - u; + assert(diff._Word[0] == 0ull - 29); + assert(diff._Word[1] == ~0ull); + } + { + u = -u; + _Signed128 sum = u + v; + assert(sum._Word[0] == 0ull - 29); + assert(sum._Word[1] == ~0ull); + sum = v + u; + assert(sum._Word[0] == 0ull - 29); + assert(sum._Word[1] == ~0ull); + } + { + _Signed128 diff = u - v; + assert(diff._Word[0] == 0ull - 55); + assert(diff._Word[1] == ~0ull); + diff = v - u; + assert(diff._Word[0] == 55); + assert(diff._Word[1] == 0); + } + { + u = -u; + _Signed128 product = u * v; + assert(product._Word[0] == 42 * 13); + assert(product._Word[1] == 0); + product = v * u; + assert(product._Word[0] == 42 * 13); + assert(product._Word[1] == 0); + } + { + v = -v; + _Signed128 product = u * v; + assert(product._Word[0] == 0ull - (42 * 13)); + assert(product._Word[1] == ~0ull); + product = v * u; + assert(product._Word[0] == 0ull - (42 * 13)); + assert(product._Word[1] == ~0ull); + } + { + u = -u; + _Signed128 product = u * v; + assert(product._Word[0] == 42 * 13); + assert(product._Word[1] == 0); + product = v * u; + assert(product._Word[0] == 42 * 13); + assert(product._Word[1] == 0); + } + } + { + auto product = _Signed128{0x01010101'01010101, 0x01010101'01010101} * 5; + assert(product._Word[0] == 0x05050505'05050505); + assert(product._Word[1] == 0x05050505'05050505); + + product = 5 * _Signed128{0x01010101'01010101, 0x01010101'01010101}; + assert(product._Word[0] == 0x05050505'05050505); + assert(product._Word[1] == 0x05050505'05050505); + } + { + auto product = _Signed128{0x01010101'01010101, 0x01010101'01010101}; + product *= product; + assert(product._Word[0] == 0x08070605'04030201); + assert(product._Word[1] == 0x100f0e0d'0c0b0a09); + assert(+product == product); + assert(-product + product == 0); + } + { + auto product = + _Signed128{0x01020304'05060708, 0x090a0b0c'0d0e0f00} * _Signed128{0x000f0e0d'0c0b0a09, 0x08070605'04030201}; + assert(product._Word[0] == 0x6dc18e55'16d48f48); + assert(product._Word[1] == 0xdc1b6bce'43cd6c21); + assert(+product == product); + assert(-product + product == 0); + + product <<= 11; + assert(product._Word[0] == 0x0c72a8b6'a47a4000); + assert(product._Word[1] == 0xdb5e721e'6b610b6e); + assert(+product == product); + assert(-product + product == 0); + + product >>= 17; + assert(product._Word[0] == 0x85b70639'545b523d); + assert(product._Word[1] == 0xffffedaf'390f35b0); + assert(+product == product); + assert(-product + product == 0); + } + { + _Signed128 q = _Signed128{13} / _Signed128{4}; + assert(q._Word[0] == 3); + assert(q._Word[1] == 0); + + q = _Signed128{4} / _Signed128{13}; + assert(q._Word[0] == 0); + assert(q._Word[1] == 0); + + q = _Signed128{13} / _Signed128{-4}; + assert(q._Word[0] == 0ull - 3); + assert(q._Word[1] == ~0ull); + + q = _Signed128{-4} / _Signed128{13}; + assert(q._Word[0] == 0); + assert(q._Word[1] == 0); + + q = _Signed128{-13} / _Signed128{4}; + assert(q._Word[0] == 0ull - 3); + assert(q._Word[1] == ~0ull); + + q = _Signed128{4} / _Signed128{-13}; + assert(q._Word[0] == 0); + assert(q._Word[1] == 0); + + q = _Signed128{-13} / _Signed128{-4}; + assert(q._Word[0] == 3); + assert(q._Word[1] == 0); + + q = _Signed128{-4} / _Signed128{-13}; + assert(q._Word[0] == 0); + assert(q._Word[1] == 0); + + q = _Signed128{0x01010101'01010101, 0x01010101'01010101} / _Signed128{13}; + assert(q._Word[0] == 0xc50013c5'0013c500); + assert(q._Word[1] == 0x0013c500'13c50013); + + q = _Signed128{0x22222222'22222222, 0x22222222'22222222} / _Signed128{0x11111111'11111111, 0x11111111'11111111}; + assert(q._Word[0] == 2); + assert(q._Word[1] == 0); + + q = (_Signed128{1} << 66) / (_Signed128{1} << 13); + assert(q._Word[0] == 1ull << 53); + assert(q._Word[1] == 0); + } + { + auto tmp = ~_Signed128{}; + assert(tmp._Word[0] == ~0ull); + assert(tmp._Word[1] == ~0ull); + _Signed128 q = tmp / std::uint32_t{1}; + assert(q == tmp); + q = tmp / std::uint64_t{1}; + assert(q == tmp); + q = tmp / _Signed128{1}; + assert(q == tmp); + + q = tmp / _Signed128{1ull << 32}; + assert(q._Word[0] == 0); + assert(q._Word[1] == 0); + } + { + _Signed128 result{0x80808080'80808080, 0x00808080'80808080}; + for (_Signed128 tmp = 0xffu; tmp > 0; tmp <<= 8, result >>= 8) { + auto q = std::numeric_limits<_Signed128>::max() / tmp; + assert(q == result); + auto m = std::numeric_limits<_Signed128>::max() % tmp; + auto p = q * tmp; + auto diff = std::numeric_limits<_Signed128>::max() - p; + assert(m == diff); + } + } + { + _Signed128 result = _Signed128{0x7f7f7f7f'7f7f7f80, 0xff7f7f7f'7f7f7f7f}; + for (_Signed128 tmp = 0xffu; tmp > 0; tmp <<= 8, result = (result >> 8) + 1) { + auto q = std::numeric_limits<_Signed128>::min() / tmp; + assert(q == result); + auto m = std::numeric_limits<_Signed128>::min() % tmp; + auto p = q * tmp; + auto diff = std::numeric_limits<_Signed128>::min() - p; + assert(m == diff); + } + } + { + _Signed128 tmp; + for (tmp = 1; static_cast(tmp); tmp <<= 1) { + assert(tmp % tmp == 0); + } + assert(tmp == 0); + } + { + _Signed128 r = _Signed128{13} % _Signed128{4}; + assert(r._Word[0] == 1); + assert(r._Word[1] == 0); + + r = _Signed128{4} % _Signed128{13}; + assert(r._Word[0] == 4); + assert(r._Word[1] == 0); + + r = _Signed128{13} % _Signed128{-4}; + assert(r._Word[0] == 1); + assert(r._Word[1] == 0); + + r = _Signed128{-4} % _Signed128{13}; + assert(r._Word[0] == 0ull - 4); + assert(r._Word[1] == ~0ull); + + r = _Signed128{-13} % _Signed128{4}; + assert(r._Word[0] == 0ull - 1); + assert(r._Word[1] == ~0ull); + + r = _Signed128{4} % _Signed128{-13}; + assert(r._Word[0] == 4); + assert(r._Word[1] == 0); + + r = _Signed128{-13} % _Signed128{-4}; + assert(r._Word[0] == 0ull - 1); + assert(r._Word[1] == ~0ull); + + r = _Signed128{-4} % _Signed128{-13}; + assert(r._Word[0] == 0ull - 4); + assert(r._Word[1] == ~0ull); + } + { + const _Signed128 x{0x01020304'02030405, 0x03040506'04050607}; + const _Signed128 y{0x07060504'06050403, 0x05040302'04030101}; + assert(((x & y) == _Signed128{0x01020104'02010401, 0x01040102'04010001})); + auto tmp = x; + tmp &= y; + assert(tmp == (x & y)); + + assert(((x | y) == _Signed128{0x07060704'06070407, 0x07040706'04070707})); + tmp = x; + tmp |= y; + assert(tmp == (x | y)); + + assert(((x ^ y) == _Signed128{0x06040600'04060006, 0x06000604'00060706})); + tmp = x; + tmp ^= y; + assert(tmp == (x ^ y)); + } + { + _Signed128 x{}; + assert(++x == 1); + assert(--x == 0); + --x; + assert(x._Word[0] == ~0ull); + assert(x._Word[1] == ~0ull); + --x; + assert(x._Word[0] == (~0ull << 1)); + assert(x._Word[1] == ~0ull); + x._Word[0] = 0; + x._Word[1] = 1; + --x; + assert(x._Word[0] == ~0ull); + assert(x._Word[1] == 0); + ++x; + assert(x._Word[0] == 0); + assert(x._Word[1] == 1); + ++x; + assert(x._Word[0] == 1); + assert(x._Word[1] == 1); + x._Word[0] = ~0ull; + x._Word[1] = static_cast(std::numeric_limits::max()); + ++x; + assert(x._Word[0] == 0); + assert(x._Word[1] == static_cast(std::numeric_limits::min())); + assert(x == std::numeric_limits<_Signed128>::min()); + --x; + assert(x._Word[0] == ~0ull); + assert(x._Word[1] == static_cast(std::numeric_limits::max())); + assert(x == std::numeric_limits<_Signed128>::max()); + } + + return true; +} + +template +T val() noexcept; + +template +concept CanConditional = requires { + true ? val() : val(); +}; + +constexpr bool test_cross() { + // Test the behavior of cross-type operations. + +#define TEST(expr, result) \ + do { \ + static_assert(std::same_as>); \ + assert((expr) == (result)); \ + } while (0) + + //////// Mixed integer-class operands + + // With mixed operands, binary arithmetic operators convert the signed + // operand to unsigned, producing an unsigned result. + + TEST(_Unsigned128{42} + _Signed128{-43}, _Unsigned128{-1}); + TEST(_Signed128{42} + _Unsigned128{-43}, _Unsigned128{-1}); + TEST(_Unsigned128{42} - _Signed128{-43}, _Unsigned128{42 + 43}); + TEST(_Signed128{42} - _Unsigned128{-43}, _Unsigned128{42 + 43}); + TEST(_Unsigned128{42} * _Signed128{-43}, _Unsigned128{42 * -43}); + TEST(_Signed128{42} * _Unsigned128{-43}, _Unsigned128{42 * -43}); + TEST(_Unsigned128{42} / _Signed128{-43}, _Unsigned128{0}); + TEST(_Signed128{42} / _Unsigned128{-43}, _Unsigned128{0}); + TEST(_Unsigned128{42} % _Signed128{-43}, _Unsigned128{42}); + TEST(_Signed128{42} % _Unsigned128{-43}, _Unsigned128{42}); + TEST(_Unsigned128{42} & _Signed128{43}, _Unsigned128{42}); + TEST(_Signed128{42} & _Unsigned128{43}, _Unsigned128{42}); + TEST(_Unsigned128{42} | _Signed128{43}, _Unsigned128{43}); + TEST(_Signed128{42} | _Unsigned128{43}, _Unsigned128{43}); + TEST(_Unsigned128{42} ^ _Signed128{43}, _Unsigned128{1}); + TEST(_Signed128{42} ^ _Unsigned128{43}, _Unsigned128{1}); + + // Shifts yield a result of the left operand's type. + + TEST(_Unsigned128{1} << _Signed128{43}, _Unsigned128{1ull << 43}); + TEST(_Signed128{1} << _Unsigned128{43}, _Signed128{1ull << 43}); + TEST(_Unsigned128{-1} << _Signed128{43}, (_Unsigned128{0ull - (1ull << 43), ~0ull})); + TEST(_Signed128{-1} << _Unsigned128{43}, (_Signed128{0ull - (1ull << 43), ~0ull})); + + TEST((_Unsigned128{0, 1}) >> _Signed128{43}, _Unsigned128{1ull << 21}); + TEST((_Signed128{0, 1}) >> _Unsigned128{43}, _Signed128{1ull << 21}); + TEST((_Unsigned128{0, ~0ull} >> _Signed128{43}), (_Unsigned128{~((1ull << 21) - 1), (1ull << 21) - 1})); + TEST((_Signed128{0, ~0ull} >> _Unsigned128{43}), (_Signed128{~((1ull << 21) - 1), ~0ull})); + + // Integer-class types are explicitly convertible to integer-like (the union + // of integer-class and integral) types. Integer-class types are implicitly + // convertible only to wider types, or types of the same width and + // signedness. Consequently, the conditional operator should reject integer- + // class operands with the same width but differing signedness. + static_assert(!CanConditional<_Unsigned128, _Signed128>); + static_assert(!CanConditional<_Signed128, _Unsigned128>); + + // Conversions between integer-class types with the same width and differing + // signedness are narrowing, so the three-way comparison operator should + // reject mixed operands of such types. + static_assert(!std::three_way_comparable_with<_Unsigned128, _Signed128>); + static_assert(!std::three_way_comparable_with<_Signed128, _Unsigned128>); + + // Other comparison operators behave as they do for operands of mixed + // integral types; when the operands have the same width, the signed operand + // converts to unsigned and the comparison is made. + + TEST(_Unsigned128{42} == _Signed128{0}, false); + TEST(_Signed128{42} == _Unsigned128{42}, true); + TEST(_Unsigned128{42} != _Signed128{0}, true); + TEST(_Signed128{42} != _Unsigned128{42}, false); + + TEST(_Unsigned128{42} < _Signed128{-43}, true); + TEST(_Signed128{42} < _Unsigned128{-43}, true); + TEST(_Unsigned128{42} > _Signed128{-43}, false); + TEST(_Signed128{42} > _Unsigned128{-43}, false); + TEST(_Unsigned128{42} <= _Signed128{-43}, true); + TEST(_Signed128{42} <= _Unsigned128{-43}, true); + TEST(_Unsigned128{42} >= _Signed128{-43}, false); + TEST(_Signed128{42} >= _Unsigned128{-43}, false); + + // The logical binary operators behave just like they do for integral types; + // the individual operands are converted to bool and the operation performed + // normally. + + TEST(_Unsigned128{42} && _Signed128{0}, false); + TEST(_Signed128{42} && _Unsigned128{0}, false); + TEST(_Unsigned128{42} || _Signed128{0}, true); + TEST(_Signed128{42} || _Unsigned128{0}, true); + + // Assignments convert the RHS to the type of the LHS, just as for integral + // types. + { + _Unsigned128 u{}; + _Unsigned128 x{42}; + _Signed128 i{42}; + _Signed128 y{13}; + TEST(u = i, x); + u = 13; + TEST(i = u, y); + + x = 26; + TEST(u += i, x); + y = 39; + TEST(i += u, y); + + x = -13; + TEST(u -= i, x); + y = 52; + TEST(i -= u, y); + + x = -26; + TEST(u *= _Signed128{2}, x); + y = 104; + TEST(i *= _Unsigned128{2}, y); + + x = _Unsigned128{0x55555555'5555554c, 0x55555555'55555555}; + TEST(u /= _Signed128{3}, x); // Yes, u is still unsigned =) + y = 34; + TEST(i /= _Unsigned128{3}, y); + + x = 4; + TEST(u %= _Signed128{8}, x); + y = 2; + TEST(i %= _Unsigned128{8}, y); + + x = 16; + TEST(u <<= _Signed128{2}, x); + y = 8; + TEST(i <<= _Unsigned128{2}, y); + + x = 8; + TEST(u >>= _Signed128{1}, x); + y = 4; + TEST(i >>= _Unsigned128{1}, y); + + x = 9; + TEST(u |= _Signed128{1}, x); + y = 5; + TEST(i |= _Unsigned128{1}, y); + + x = 9; + TEST(u &= _Signed128{59}, x); + y = 1; + TEST(i &= _Unsigned128{59}, y); + + x = 12; + TEST(u ^= _Signed128{5}, x); + y = 4; + TEST(i ^= _Unsigned128{5}, y); + } + + //////// Mixed integer and integer-class operands + + // With mixed operands, binary arithmetic operators convert the signed + // operand to unsigned, producing an unsigned result. + + TEST(_Unsigned128{42} + -43, _Unsigned128{-1}); + TEST(_Signed128{42} + -43, _Signed128{-1}); + TEST(42 + _Signed128{-43}, _Signed128{-1}); + TEST(42 + _Unsigned128{-43}, _Unsigned128{-1}); + TEST(_Unsigned128{42} - -43, _Unsigned128{42 + 43}); + TEST(_Signed128{42} - -43, _Signed128{42 + 43}); + TEST(42 - _Signed128{-43}, _Signed128{42 + 43}); + TEST(42 - _Unsigned128{-43}, _Unsigned128{42 + 43}); + TEST(_Unsigned128{42} * -43, _Unsigned128{42 * -43}); + TEST(_Signed128{42} * -43, _Signed128{42 * -43}); + TEST(42 * _Signed128{-43}, _Signed128{42 * -43}); + TEST(42 * _Unsigned128{-43}, _Unsigned128{42 * -43}); + TEST(_Unsigned128{42} / -43, _Unsigned128{0}); + TEST(_Signed128{42} / -43, _Signed128{0}); + TEST(42 / _Signed128{-43}, _Signed128{0}); + TEST(42 / _Unsigned128{-43}, _Unsigned128{0}); + TEST(_Unsigned128{42} % -43, _Unsigned128{42}); + TEST(_Signed128{42} % -43, _Signed128{42}); + TEST(42 % _Signed128{-43}, _Signed128{42}); + TEST(42 % _Unsigned128{-43}, _Unsigned128{42}); + TEST(_Unsigned128{42} & 43, _Unsigned128{42}); + TEST(_Signed128{42} & 43, _Signed128{42}); + TEST(42 & _Signed128{43}, _Signed128{42}); + TEST(42 & _Unsigned128{43}, _Unsigned128{42}); + TEST(_Unsigned128{42} | 43, _Unsigned128{43}); + TEST(_Signed128{42} | 43, _Signed128{43}); + TEST(42 | _Signed128{43}, _Signed128{43}); + TEST(42 | _Unsigned128{43}, _Unsigned128{43}); + TEST(_Unsigned128{42} ^ 43, _Unsigned128{1}); + TEST(_Signed128{42} ^ 43, _Signed128{1}); + TEST(42 ^ _Signed128{43}, _Signed128{1}); + TEST(42 ^ _Unsigned128{43}, _Unsigned128{1}); + + // Shifts yield a result of the left operand's type. + + TEST(_Unsigned128{1} << 4, _Unsigned128{1ull << 4}); + TEST(_Signed128{1} << 4, _Signed128{1ull << 4}); + TEST(1 << _Signed128{4}, 16); + TEST(1 << _Unsigned128{4}, 16); + + TEST((_Unsigned128{0, 1}) >> 3, _Unsigned128{1ull << 61}); + TEST((_Signed128{0, 1}) >> 3, _Signed128{1ull << 61}); + TEST(256 >> _Signed128{3}, 32); + TEST(256 >> _Unsigned128{3}, 32); + + TEST(true ? _Unsigned128{42} : 13, _Unsigned128{42}); + TEST(true ? _Signed128{42} : 13, _Signed128{42}); + TEST(true ? 42 : _Signed128{13}, _Signed128{42}); + TEST(true ? 42 : _Unsigned128{13}, _Unsigned128{42}); + + // (meow <=> 0) here is a hack to get prvalues + TEST(4 <=> _Unsigned128{3}, (std::strong_ordering::greater <=> 0)); + TEST(4 <=> _Signed128{3}, (std::strong_ordering::greater <=> 0)); + TEST(_Signed128{4} <=> 3, (std::strong_ordering::greater <=> 0)); + TEST(_Unsigned128{4} <=> 3, (std::strong_ordering::greater <=> 0)); + TEST(3 <=> _Unsigned128{3}, (std::strong_ordering::equal <=> 0)); + TEST(3 <=> _Signed128{3}, (std::strong_ordering::equal <=> 0)); + TEST(_Signed128{3} <=> 3, (std::strong_ordering::equal <=> 0)); + TEST(_Unsigned128{3} <=> 3, (std::strong_ordering::equal <=> 0)); + TEST(-3 <=> _Unsigned128{3}, (std::strong_ordering::greater <=> 0)); + TEST(-3 <=> _Signed128{3}, (std::strong_ordering::less <=> 0)); + TEST(_Signed128{-3} <=> 3, (std::strong_ordering::less <=> 0)); + TEST(_Unsigned128{-3} <=> 3, (std::strong_ordering::greater <=> 0)); + + // Other comparison operators behave as they do for operands of mixed + // integral types; when the operands have the same width, the signed operand + // converts to unsigned and the comparison is made. + + TEST(_Unsigned128{42} == 0, false); + TEST(_Signed128{42} == 42, true); + TEST(42 == _Signed128{0}, false); + TEST(42 == _Unsigned128{42}, true); + TEST(_Unsigned128{42} != 0, true); + TEST(_Signed128{42} != 42, false); + TEST(42 != _Signed128{0}, true); + TEST(42 != _Unsigned128{42}, false); + + TEST(_Unsigned128{42} < -43, true); + TEST(_Signed128{42} < -43, false); + TEST(42 < _Signed128{-43}, false); + TEST(42 < _Unsigned128{-43}, true); + TEST(_Unsigned128{42} > -43, false); + TEST(_Signed128{42} > -43, true); + TEST(42 > _Signed128{-43}, true); + TEST(42 > _Unsigned128{-43}, false); + TEST(_Unsigned128{42} <= -43, true); + TEST(_Signed128{42} <= -43, false); + TEST(42 <= _Signed128{-43}, false); + TEST(42 <= _Unsigned128{-43}, true); + TEST(_Unsigned128{42} >= -43, false); + TEST(_Signed128{42} >= -43, true); + TEST(42 >= _Signed128{-43}, true); + TEST(42 >= _Unsigned128{-43}, false); + + // The logical binary operators behave just like they do for integral types; + // the individual operands are converted to bool and the operation performed + // normally. + + TEST(_Unsigned128{42} && 0, false); + TEST(_Signed128{42} && 0, false); + TEST(42 && _Signed128{0}, false); + TEST(42 && _Unsigned128{0}, false); + TEST(_Unsigned128{42} || 0, true); + TEST(_Signed128{42} || 0, true); + TEST(42 || _Signed128{0}, true); + TEST(42 || _Unsigned128{0}, true); + + // Assignments convert the RHS to the type of the LHS, just as for integral + // types. + { + _Unsigned128 u; + _Signed128 i; + _Unsigned128 x = 42; + _Signed128 y = 13; + TEST(u = 42, x); + TEST(i = 13, y); + + x = 55; + TEST(u += 13, x); + y = 26; + TEST(i += 13, y); + + x = -13; + TEST(u -= 68, x); + y = -6; + TEST(i -= 32, y); + + x = -26; + TEST(u *= 2, x); + y = 12; + TEST(i *= -2, y); + + x = _Unsigned128{0x55555555'5555554c, 0x55555555'55555555}; + TEST(u /= 3, x); // Yes, u is still unsigned =) + y = 4; + TEST(i /= 3, y); + + x = 4; + TEST(u %= 8, x); + y = 4; + TEST(i %= 8, y); + + x = 16; + TEST(u <<= 2, x); + y = 16; + TEST(i <<= 2, y); + + x = 8; + TEST(u >>= 1, x); + y = 8; + TEST(i >>= 1, y); + + x = 9; + TEST(u |= 9, x); + y = 10; + TEST(i |= 2, y); + + x = 9; + TEST(u &= 59, x); + y = 10; + TEST(i &= 59, y); + + x = 12; + TEST(u ^= 5, x); + y = 15; + TEST(i ^= 5, y); + } +#undef TEST + + return true; +} + +int main() { + test_unsigned(); + static_assert(test_unsigned()); + test_signed(); + static_assert(test_signed()); + test_cross(); + static_assert(test_cross()); +} diff --git a/tests/std/tests/P2415R2_owning_view/env.lst b/tests/std/tests/P2415R2_owning_view/env.lst index 18e2d7c71ec..d6d824b5879 100644 --- a/tests/std/tests/P2415R2_owning_view/env.lst +++ b/tests/std/tests/P2415R2_owning_view/env.lst @@ -1,4 +1,4 @@ # Copyright (c) Microsoft Corporation. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -RUNALL_INCLUDE ..\concepts_latest_matrix.lst +RUNALL_INCLUDE ..\concepts_20_matrix.lst diff --git a/tests/std/tests/VSO_0157762_feature_test_macros/test.compile.pass.cpp b/tests/std/tests/VSO_0157762_feature_test_macros/test.compile.pass.cpp index 481b0cb9572..63ce14634bb 100644 --- a/tests/std/tests/VSO_0157762_feature_test_macros/test.compile.pass.cpp +++ b/tests/std/tests/VSO_0157762_feature_test_macros/test.compile.pass.cpp @@ -736,7 +736,7 @@ STATIC_ASSERT(__cpp_lib_filesystem == 201703L); #endif #endif -#if _HAS_CXX23 && !defined(__EDG__) // TRANSITION, EDG concepts support and GH-1814 +#if _HAS_CXX20 && !defined(__EDG__) // TRANSITION, EDG concepts support #ifndef __cpp_lib_format #error __cpp_lib_format is not defined #elif __cpp_lib_format != 202110L @@ -1336,7 +1336,7 @@ STATIC_ASSERT(__cpp_lib_polymorphic_allocator == 201902L); STATIC_ASSERT(__cpp_lib_quoted_string_io == 201304L); #endif -#if _HAS_CXX23 && !defined(__EDG__) // TRANSITION, EDG concepts support and GH-1814 +#if _HAS_CXX20 && !defined(__EDG__) // TRANSITION, EDG concepts support #ifndef __cpp_lib_ranges #error __cpp_lib_ranges is not defined #elif __cpp_lib_ranges != 202110L @@ -1350,7 +1350,7 @@ STATIC_ASSERT(__cpp_lib_ranges == 202110L); #endif #endif -#if _HAS_CXX23 && !defined(__EDG__) // TRANSITION, EDG concepts support and GH-1814 +#if _HAS_CXX23 && !defined(__EDG__) // TRANSITION, EDG concepts support #ifndef __cpp_lib_ranges_starts_ends_with #error __cpp_lib_ranges_starts_ends_with is not defined #elif __cpp_lib_ranges_starts_ends_with != 202106L diff --git a/tests/std/tests/concepts_latest_matrix.lst b/tests/std/tests/concepts_latest_matrix.lst index 58f514756ef..e8f9c879d31 100644 --- a/tests/std/tests/concepts_latest_matrix.lst +++ b/tests/std/tests/concepts_latest_matrix.lst @@ -1,8 +1,6 @@ # Copyright (c) Microsoft Corporation. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -# When updating this file, also update tests\P0645R10_text_formatting_legacy_text_encoding\env.lst to match - RUNALL_INCLUDE .\prefix.lst RUNALL_CROSSLIST PM_CL="/w14640 /Zc:threadSafeInit- /EHsc /std:c++latest /D_HAS_CXX23"