diff --git a/azure-devops/run-build.yml b/azure-devops/run-build.yml index 0a517388607..2d52b453755 100644 --- a/azure-devops/run-build.yml +++ b/azure-devops/run-build.yml @@ -4,8 +4,6 @@ jobs: - job: ${{ parameters.targetPlatform }} timeoutInMinutes: 360 - pool: - name: $(agentPool) variables: buildOutputLocation: 'D:\build\${{ parameters.targetPlatform }}' @@ -74,7 +72,7 @@ jobs: - task: CmdLine@2 displayName: 'Run Tests' timeoutInMinutes: 120 - condition: in('${{ parameters.targetPlatform }}', 'x64', 'x86') + condition: and(succeeded(), in('${{ parameters.targetPlatform }}', 'x64', 'x86')) inputs: workingDirectory: $(buildOutputLocation) script: | @@ -85,7 +83,7 @@ jobs: - task: PublishTestResults@2 displayName: 'Publish Tests' timeoutInMinutes: 10 - condition: in('${{ parameters.targetPlatform }}', 'x64', 'x86') + condition: and(succeededOrFailed(), in('${{ parameters.targetPlatform }}', 'x64', 'x86')) inputs: searchFolder: $(buildOutputLocation) testResultsFormat: JUnit diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 69437b81002..49c9a55da32 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -4,9 +4,10 @@ # Build STL targeting x86, x64, arm, arm64 variables: - agentPool: 'StlBuild-2020-09-14' tmpDir: 'D:\Temp' +pool: 'StlBuild-2020-09-14' + stages: - stage: Code_Format displayName: 'Code Format' @@ -14,9 +15,6 @@ stages: - job: Code_Format_Validation timeoutInMinutes: 90 displayName: 'Validation' - pool: - name: $(agentPool) - variables: buildOutputLocation: 'D:\tools' steps: @@ -43,6 +41,7 @@ stages: - task: BatchScript@1 displayName: 'Enforce clang-format' timeoutInMinutes: 60 + condition: succeededOrFailed() inputs: filename: 'azure-devops/enforce-clang-format.cmd' failOnStandardError: true @@ -51,6 +50,7 @@ stages: - task: BatchScript@1 displayName: 'Validate Files' timeoutInMinutes: 2 + condition: succeededOrFailed() inputs: filename: 'azure-devops/validate-files.cmd' failOnStandardError: true diff --git a/docs/cgmanifest.json b/docs/cgmanifest.json index baf87f71fa7..89ca6e7b688 100644 --- a/docs/cgmanifest.json +++ b/docs/cgmanifest.json @@ -14,7 +14,7 @@ "type": "git", "git": { "repositoryUrl": "https://github.com/microsoft/STL.git", - "commitHash": "81d88bd8e40b2b229776a9602c8bf5f49c128a9b" + "commitHash": "c70b7a830eda523a69934ba949ac700da2c0dfd2" } } }, diff --git a/stl/CMakeLists.txt b/stl/CMakeLists.txt index 74c5f383bfc..394f28cd064 100644 --- a/stl/CMakeLists.txt +++ b/stl/CMakeLists.txt @@ -180,6 +180,7 @@ set(HEADERS ${CMAKE_CURRENT_LIST_DIR}/inc/sstream ${CMAKE_CURRENT_LIST_DIR}/inc/stack ${CMAKE_CURRENT_LIST_DIR}/inc/stdexcept + ${CMAKE_CURRENT_LIST_DIR}/inc/stop_token ${CMAKE_CURRENT_LIST_DIR}/inc/streambuf ${CMAKE_CURRENT_LIST_DIR}/inc/string ${CMAKE_CURRENT_LIST_DIR}/inc/string_view @@ -437,11 +438,11 @@ function(add_stl_dlls D_SUFFIX THIS_CONFIG_DEFINITIONS THIS_CONFIG_COMPILE_OPTIO target_compile_options(msvcp${D_SUFFIX}_eha_objects PRIVATE "${THIS_CONFIG_COMPILE_OPTIONS};${GL_FLAG};/EHa") add_library(msvcp${D_SUFFIX} SHARED) - target_link_libraries(msvcp${D_SUFFIX} PRIVATE msvcp${D_SUFFIX}_eha_objects msvcp${D_SUFFIX}_objects "${TOOLSET_LIB}/vcruntime${D_SUFFIX}.lib" "${TOOLSET_LIB}/msvcrt${D_SUFFIX}.lib" "ucrt${D_SUFFIX}.lib" "${TOOLSET_LIB}/concrt${D_SUFFIX}.lib" "delayimp.lib") + target_link_libraries(msvcp${D_SUFFIX} PRIVATE msvcp${D_SUFFIX}_eha_objects msvcp${D_SUFFIX}_objects "${TOOLSET_LIB}/vcruntime${D_SUFFIX}.lib" "${TOOLSET_LIB}/msvcrt${D_SUFFIX}.lib" "ucrt${D_SUFFIX}.lib") set_target_properties(msvcp${D_SUFFIX} PROPERTIES ARCHIVE_OUTPUT_NAME "msvcp140_base${D_SUFFIX}${VCLIBS_SUFFIX}") set_target_properties(msvcp${D_SUFFIX} PROPERTIES ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}") set_target_properties(msvcp${D_SUFFIX} PROPERTIES OUTPUT_NAME "msvcp140${D_SUFFIX}${VCLIBS_SUFFIX}") - target_link_options(msvcp${D_SUFFIX} PRIVATE "${THIS_CONFIG_LINK_OPTIONS};/delayload:concrt140${D_SUFFIX}.dll") + target_link_options(msvcp${D_SUFFIX} PRIVATE "${THIS_CONFIG_LINK_OPTIONS}") # import library 'statics' add_library(msvcp${D_SUFFIX}_implib_objects OBJECT ${IMPLIB_SOURCES}) diff --git a/stl/aliases/amd64/std_init_once_begin_initialize.obj b/stl/aliases/amd64/std_init_once_begin_initialize.obj index 452313ab3f7..5b310a11bf8 100644 Binary files a/stl/aliases/amd64/std_init_once_begin_initialize.obj and b/stl/aliases/amd64/std_init_once_begin_initialize.obj differ diff --git a/stl/aliases/amd64/std_init_once_complete.obj b/stl/aliases/amd64/std_init_once_complete.obj index 1bb2f105747..31e048d3b76 100644 Binary files a/stl/aliases/amd64/std_init_once_complete.obj and b/stl/aliases/amd64/std_init_once_complete.obj differ diff --git a/stl/aliases/arm/std_init_once_begin_initialize.obj b/stl/aliases/arm/std_init_once_begin_initialize.obj index 452313ab3f7..9279800efe2 100644 Binary files a/stl/aliases/arm/std_init_once_begin_initialize.obj and b/stl/aliases/arm/std_init_once_begin_initialize.obj differ diff --git a/stl/aliases/arm/std_init_once_complete.obj b/stl/aliases/arm/std_init_once_complete.obj index 1bb2f105747..746e0214d46 100644 Binary files a/stl/aliases/arm/std_init_once_complete.obj and b/stl/aliases/arm/std_init_once_complete.obj differ diff --git a/stl/aliases/arm64/std_init_once_begin_initialize.obj b/stl/aliases/arm64/std_init_once_begin_initialize.obj index 452313ab3f7..3c7dfc80dfd 100644 Binary files a/stl/aliases/arm64/std_init_once_begin_initialize.obj and b/stl/aliases/arm64/std_init_once_begin_initialize.obj differ diff --git a/stl/aliases/arm64/std_init_once_complete.obj b/stl/aliases/arm64/std_init_once_complete.obj index 1bb2f105747..306df8aa000 100644 Binary files a/stl/aliases/arm64/std_init_once_complete.obj and b/stl/aliases/arm64/std_init_once_complete.obj differ diff --git a/stl/aliases/arm64ec/std_init_once_begin_initialize.obj b/stl/aliases/arm64ec/std_init_once_begin_initialize.obj new file mode 100644 index 00000000000..593e6c144ab Binary files /dev/null and b/stl/aliases/arm64ec/std_init_once_begin_initialize.obj differ diff --git a/stl/aliases/arm64ec/std_init_once_complete.obj b/stl/aliases/arm64ec/std_init_once_complete.obj new file mode 100644 index 00000000000..35149685437 Binary files /dev/null and b/stl/aliases/arm64ec/std_init_once_complete.obj differ diff --git a/stl/aliases/chpe/std_init_once_begin_initialize.obj b/stl/aliases/chpe/std_init_once_begin_initialize.obj index b82e6958524..40bfc75fdfd 100644 Binary files a/stl/aliases/chpe/std_init_once_begin_initialize.obj and b/stl/aliases/chpe/std_init_once_begin_initialize.obj differ diff --git a/stl/aliases/chpe/std_init_once_complete.obj b/stl/aliases/chpe/std_init_once_complete.obj index 82b42bedef0..79707d2fc5b 100644 Binary files a/stl/aliases/chpe/std_init_once_complete.obj and b/stl/aliases/chpe/std_init_once_complete.obj differ diff --git a/stl/aliases/generate.cmd b/stl/aliases/generate.cmd index 6a6ceb50b4d..afad08f9bd9 100644 --- a/stl/aliases/generate.cmd +++ b/stl/aliases/generate.cmd @@ -11,12 +11,14 @@ rmdir /s /q amd64 rmdir /s /q arm rmdir /s /q arm64 rmdir /s /q chpe +rmdir /s /q arm64ec mkdir i386 mkdir amd64 mkdir arm mkdir arm64 mkdir chpe +mkdir arm64ec :: __std_init_once_begin_initialize ..\..\..\..\..\tools\x86\aliasobj.exe ^ @@ -31,11 +33,20 @@ mkdir chpe __imp___std_init_once_begin_initialize ^ __imp_InitOnceBeginInitialize ^ arm\std_init_once_begin_initialize.obj -copy amd64\std_init_once_begin_initialize.obj arm64\std_init_once_begin_initialize.obj +..\..\..\..\..\tools\amd64\aliasobj.exe ^ + /machine:arm64 ^ + __imp___std_init_once_begin_initialize ^ + __imp_InitOnceBeginInitialize ^ + arm64\std_init_once_begin_initialize.obj ..\..\..\..\..\tools\x86\aliasobj.exe ^ __imp_#__std_init_once_begin_initialize@16 ^ __imp_#InitOnceBeginInitialize@16 ^ chpe\std_init_once_begin_initialize.obj +..\..\..\..\..\tools\amd64\aliasobj.exe ^ + /machine:arm64ec ^ + __imp___std_init_once_begin_initialize ^ + __imp_InitOnceBeginInitialize ^ + arm64ec\std_init_once_begin_initialize.obj :: __std_init_once_complete ..\..\..\..\..\tools\x86\aliasobj.exe ^ @@ -50,8 +61,17 @@ copy amd64\std_init_once_begin_initialize.obj arm64\std_init_once_begin_initiali __imp___std_init_once_complete ^ __imp_InitOnceComplete ^ arm\std_init_once_complete.obj -copy amd64\std_init_once_complete.obj arm64\std_init_once_complete.obj +..\..\..\..\..\tools\amd64\aliasobj.exe ^ + /machine:arm64 ^ + __imp___std_init_once_complete ^ + __imp_InitOnceComplete ^ + arm64\std_init_once_complete.obj ..\..\..\..\..\tools\x86\aliasobj.exe ^ __imp_#__std_init_once_complete@12 ^ __imp_#InitOnceComplete@12 ^ chpe\std_init_once_complete.obj +..\..\..\..\..\tools\amd64\aliasobj.exe ^ + /machine:arm64ec ^ + __imp___std_init_once_complete ^ + __imp_InitOnceComplete ^ + arm64ec\std_init_once_complete.obj diff --git a/stl/aliases/i386/std_init_once_begin_initialize.obj b/stl/aliases/i386/std_init_once_begin_initialize.obj index 46243a4db69..139493af042 100644 Binary files a/stl/aliases/i386/std_init_once_begin_initialize.obj and b/stl/aliases/i386/std_init_once_begin_initialize.obj differ diff --git a/stl/aliases/i386/std_init_once_complete.obj b/stl/aliases/i386/std_init_once_complete.obj index 59a56df8052..c8a07b412d9 100644 Binary files a/stl/aliases/i386/std_init_once_complete.obj and b/stl/aliases/i386/std_init_once_complete.obj differ diff --git a/stl/inc/__msvc_all_public_headers.hpp b/stl/inc/__msvc_all_public_headers.hpp index 3ba146c97bc..912896ed2d9 100644 --- a/stl/inc/__msvc_all_public_headers.hpp +++ b/stl/inc/__msvc_all_public_headers.hpp @@ -108,6 +108,7 @@ #include #include #include +#include #endif // _M_CEE_PURE #ifndef _M_CEE diff --git a/stl/inc/atomic b/stl/inc/atomic index 07fd8d8316d..78820eb37b3 100644 --- a/stl/inc/atomic +++ b/stl/inc/atomic @@ -31,7 +31,7 @@ _STL_DISABLE_CLANG_WARNINGS #define _Compiler_barrier() _STL_DISABLE_DEPRECATED_WARNING _ReadWriteBarrier() _STL_RESTORE_DEPRECATED_WARNING -#if defined(_M_ARM) || defined(_M_ARM64) +#if defined(_M_ARM) || defined(_M_ARM64) || defined(_M_ARM64EC) #define _Memory_barrier() __dmb(0xB) // inner shared data memory barrier #define _Compiler_or_memory_barrier() _Memory_barrier() #elif defined(_M_IX86) || defined(_M_X64) @@ -69,18 +69,18 @@ extern "C" _NODISCARD char __stdcall __std_atomic_has_cmpxchg16b() noexcept; // MACRO _ATOMIC_HAS_DCAS // Controls whether atomic::is_always_lock_free triggers for sizeof(void *) or 2 * sizeof(void *) -#if _STD_ATOMIC_ALWAYS_USE_CMPXCHG16B == 1 || !defined(_M_X64) +#if _STD_ATOMIC_ALWAYS_USE_CMPXCHG16B == 1 || !defined(_M_X64) || defined(_M_ARM64EC) #define _ATOMIC_HAS_DCAS 1 #else // ^^^ We always have DCAS / We only sometimes have DCAS vvv #define _ATOMIC_HAS_DCAS 0 -#endif // _STD_ATOMIC_ALWAYS_USE_CMPXCHG16B == 1 || !defined(_M_X64) +#endif // _STD_ATOMIC_ALWAYS_USE_CMPXCHG16B == 1 || !defined(_M_X64) || defined(_M_ARM64EC) // MACRO _ATOMIC_CHOOSE_INTRINSIC -#if defined(_M_IX86) || defined(_M_X64) +#if defined(_M_IX86) || (defined(_M_X64) && !defined(_M_ARM64EC)) #define _ATOMIC_CHOOSE_INTRINSIC(_Order, _Result, _Intrinsic, ...) \ _Check_memory_order(_Order); \ _Result = _Intrinsic(__VA_ARGS__) -#elif defined(_M_ARM) || defined(_M_ARM64) +#elif defined(_M_ARM) || defined(_M_ARM64) || defined(_M_ARM64EC) #define _ATOMIC_CHOOSE_INTRINSIC(_Order, _Result, _Intrinsic, ...) \ switch (_Order) { \ case memory_order_relaxed: \ @@ -335,7 +335,7 @@ struct _Atomic_storage_traits { // properties for how _Ty is stored in an atomic : sizeof(_Ty) == 2 ? 2 : sizeof(_Ty) <= 4 ? 4 : sizeof(_Ty) <= 8 ? 8 -#if defined(_M_X64) || defined(_M_ARM64) +#if defined(_M_X64) || defined(_M_ARM64) || defined(_M_ARM64EC) : sizeof(_Ty) <= 16 ? 16 #endif // 64 bits : sizeof(_Ty); @@ -639,7 +639,7 @@ struct _Atomic_storage<_Ty, 1> { // lock-free using 1-byte intrinsics void store(const _TVal _Value) noexcept { // store with sequential consistency const auto _Mem = _Atomic_address_as(_Storage); const char _As_bytes = _Atomic_reinterpret_as(_Value); -#if defined(_M_ARM) || defined(_M_ARM64) +#if defined(_M_ARM) || defined(_M_ARM64) || defined(_M_ARM64EC) _Memory_barrier(); __iso_volatile_store8(_Mem, _As_bytes); _Memory_barrier(); @@ -760,7 +760,7 @@ struct _Atomic_storage<_Ty, 2> { // lock-free using 2-byte intrinsics void store(const _TVal _Value) noexcept { // store with sequential consistency const auto _Mem = _Atomic_address_as(_Storage); const short _As_bytes = _Atomic_reinterpret_as(_Value); -#if defined(_M_ARM) || defined(_M_ARM64) +#if defined(_M_ARM) || defined(_M_ARM64) || defined(_M_ARM64EC) _Memory_barrier(); __iso_volatile_store16(_Mem, _As_bytes); _Memory_barrier(); @@ -878,7 +878,7 @@ struct _Atomic_storage<_Ty, 4> { // lock-free using 4-byte intrinsics } void store(const _TVal _Value) noexcept { // store with sequential consistency -#if defined(_M_ARM) || defined(_M_ARM64) +#if defined(_M_ARM) || defined(_M_ARM64) || defined(_M_ARM64EC) _Memory_barrier(); __iso_volatile_store32(_Atomic_address_as(_Storage), _Atomic_reinterpret_as(_Value)); _Memory_barrier(); @@ -1158,7 +1158,7 @@ struct _Atomic_storage<_Ty&, 16> { // lock-free using 16-byte intrinsics } _NODISCARD _TVal load(const memory_order _Order) const noexcept { // load with given memory order -#ifdef _M_ARM64 +#if defined(_M_ARM64) || defined(_M_ARM64EC) long long* const _Storage_ptr = const_cast(_Atomic_address_as(_Storage)); _Int128 _Result{}; // atomic CAS 0 with 0 switch (_Order) { @@ -1218,7 +1218,7 @@ struct _Atomic_storage<_Ty&, 16> { // lock-free using 16-byte intrinsics _Int128 _Mask_val{}; _CSTD memcpy(&_Mask_val, _Mask._Ptr(), sizeof(_TVal)); for (;;) { -#ifdef _M_ARM64 +#if defined(_M_ARM64) || defined(_M_ARM64EC) _ATOMIC_CHOOSE_INTRINSIC(_Order, _Result, _InterlockedCompareExchange128, _Atomic_address_as(_Storage), _Desired_bytes._High, _Desired_bytes._Low, &_Expected_temp._Low); @@ -1244,7 +1244,7 @@ struct _Atomic_storage<_Ty&, 16> { // lock-free using 16-byte intrinsics } } #endif // _CMPXCHG_MASK_OUT_PADDING_BITS -#ifdef _M_ARM64 +#if defined(_M_ARM64) || defined(_M_ARM64EC) _ATOMIC_CHOOSE_INTRINSIC(_Order, _Result, _InterlockedCompareExchange128, _Atomic_address_as(_Storage), _Desired_bytes._High, _Desired_bytes._Low, &_Expected_temp._Low); #else // ^^^ _M_ARM64 / _M_X64 vvv @@ -1365,7 +1365,7 @@ struct _Atomic_integral<_Ty, 1> : _Atomic_storage<_Ty> { // atomic integral oper } _TVal operator--(int) noexcept { - return static_cast<_Ty>(_InterlockedExchangeAdd8(_Atomic_address_as(this->_Storage), -1)); + return static_cast<_TVal>(_InterlockedExchangeAdd8(_Atomic_address_as(this->_Storage), -1)); } _TVal operator--() noexcept { @@ -1810,6 +1810,22 @@ struct _Atomic_integral_facade<_Ty&> : _Atomic_integral<_Ty&> { return fetch_add(_Negate(_Operand), _Order); } + _Ty operator++(int) const noexcept { + return const_cast<_Atomic_integral_facade*>(this)->_Base::operator++(0); + } + + _Ty operator++() const noexcept { + return const_cast<_Atomic_integral_facade*>(this)->_Base::operator++(); + } + + _Ty operator--(int) const noexcept { + return const_cast<_Atomic_integral_facade*>(this)->_Base::operator--(0); + } + + _Ty operator--() const noexcept { + return const_cast<_Atomic_integral_facade*>(this)->_Base::operator--(); + } + _Ty operator+=(const _Ty _Operand) const noexcept { return static_cast<_Ty>(fetch_add(_Operand) + _Operand); } @@ -2970,6 +2986,69 @@ inline void atomic_flag_notify_all(volatile atomic_flag* const _Flag) noexcept { inline void atomic_flag_notify_all(atomic_flag* const _Flag) noexcept { return _Flag->notify_all(); } + +template +class _Locked_pointer { +public: + static_assert(alignof(_Ty) >= (1 << 2), "2 low order bits are needed by _Locked_pointer"); + static constexpr uintptr_t _Lock_mask = 3; + static constexpr uintptr_t _Not_locked = 0; + static constexpr uintptr_t _Locked_notify_not_needed = 1; + static constexpr uintptr_t _Locked_notify_needed = 2; + static constexpr uintptr_t _Ptr_value_mask = ~_Lock_mask; + + constexpr _Locked_pointer() noexcept : _Storage{} {} + explicit _Locked_pointer(_Ty* const _Ptr) noexcept : _Storage{reinterpret_cast(_Ptr)} {} + + _Locked_pointer(const _Locked_pointer&) = delete; + _Locked_pointer& operator=(const _Locked_pointer&) = delete; + + _NODISCARD _Ty* _Lock_and_load() noexcept { + uintptr_t _Rep = _Storage.load(memory_order_relaxed); + for (;;) { + switch (_Rep & _Lock_mask) { + case _Not_locked: // Can try to lock now + if (_Storage.compare_exchange_weak(_Rep, _Rep | _Locked_notify_not_needed)) { + return reinterpret_cast<_Ty*>(_Rep); + } + _YIELD_PROCESSOR(); + break; + + case _Locked_notify_not_needed: // Try to set "notify needed" and wait + if (!_Storage.compare_exchange_weak(_Rep, (_Rep & _Ptr_value_mask) | _Locked_notify_needed)) { + // Failed to set notify needed flag, try again + _YIELD_PROCESSOR(); + break; + } + _Rep = (_Rep & _Ptr_value_mask) | _Locked_notify_needed; + [[fallthrough]]; + + case _Locked_notify_needed: // "Notify needed" is already set, just wait + _Storage.wait(_Rep, memory_order_relaxed); + _Rep = _Storage.load(memory_order_relaxed); + break; + + default: // Unrecognized bit pattern + _CSTD abort(); + } + } + } + + void _Store_and_unlock(_Ty* const _Value) noexcept { + const auto _Rep = _Storage.exchange(reinterpret_cast(_Value)); + if ((_Rep & _Lock_mask) == _Locked_notify_needed) { + // As we don't count waiters, every waiter is notified, and then some may re-request notification + _Storage.notify_all(); + } + } + + _NODISCARD _Ty* _Unsafe_load_relaxed() const noexcept { + return reinterpret_cast<_Ty*>(_Storage.load(memory_order_relaxed)); + } + +private: + atomic _Storage; +}; #endif // _HAS_CXX20 _STD_END diff --git a/stl/inc/charconv b/stl/inc/charconv index f222d291e8e..ae2cbb5cac7 100644 --- a/stl/inc/charconv +++ b/stl/inc/charconv @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -450,40 +451,6 @@ _NODISCARD inline _Big_integer_flt _Make_big_integer_flt_power_of_two(const uint return _Xval; } -_NODISCARD inline uint32_t _Bit_scan_reverse(const uint32_t _Value) noexcept { - unsigned long _Index; // Intentionally uninitialized for better codegen - - if (_BitScanReverse(&_Index, _Value)) { - return _Index + 1; - } - - return 0; -} - -_NODISCARD inline uint32_t _Bit_scan_reverse(const uint64_t _Value) noexcept { - unsigned long _Index; // Intentionally uninitialized for better codegen - -#ifdef _WIN64 - if (_BitScanReverse64(&_Index, _Value)) { - return _Index + 1; - } -#else // ^^^ 64-bit ^^^ / vvv 32-bit vvv - uint32_t _Ui32 = static_cast(_Value >> 32); - - if (_BitScanReverse(&_Index, _Ui32)) { - return _Index + 1 + 32; - } - - _Ui32 = static_cast(_Value); - - if (_BitScanReverse(&_Index, _Ui32)) { - return _Index + 1; - } -#endif // ^^^ 32-bit ^^^ - - return 0; -} - _NODISCARD inline uint32_t _Bit_scan_reverse(const _Big_integer_flt& _Xval) noexcept { if (_Xval._Myused == 0) { return 0; @@ -1225,52 +1192,123 @@ _NODISCARD inline bool _Should_round_up( // The caller must pass true for _Has_zero_tail if all discarded bits were zeroes. _NODISCARD inline uint64_t _Right_shift_with_rounding( const uint64_t _Value, const uint32_t _Shift, const bool _Has_zero_tail) noexcept { - // If we'd need to shift further than it is possible to shift, the answer is always zero: - if (_Shift >= 64) { - return 0; + constexpr uint32_t _Total_number_of_bits = 64; + if (_Shift >= _Total_number_of_bits) { + if (_Shift == _Total_number_of_bits) { + constexpr uint64_t _Extra_bits_mask = (1ULL << (_Total_number_of_bits - 1)) - 1; + constexpr uint64_t _Round_bit_mask = (1ULL << (_Total_number_of_bits - 1)); + + const bool _Round_bit = (_Value & _Round_bit_mask) != 0; + const bool _Tail_bits = !_Has_zero_tail || (_Value & _Extra_bits_mask) != 0; + + // We round up the answer to 1 if the answer is greater than 0.5. Otherwise, we round down the answer to 0 + // if either [1] the answer is less than 0.5 or [2] the answer is exactly 0.5. + return static_cast(_Round_bit && _Tail_bits); + } else { + // If we'd need to shift 65 or more bits, the answer is less than 0.5 and is always rounded to zero: + return 0; + } } - const uint64_t _Extra_bits_mask = (1ULL << (_Shift - 1)) - 1; - const uint64_t _Round_bit_mask = (1ULL << (_Shift - 1)); - const uint64_t _Lsb_bit_mask = 1ULL << _Shift; + // Reference implementation with suboptimal codegen: + // const uint64_t _Extra_bits_mask = (1ULL << (_Shift - 1)) - 1; + // const uint64_t _Round_bit_mask = (1ULL << (_Shift - 1)); + // const uint64_t _Lsb_bit_mask = 1ULL << _Shift; - const bool _Lsb_bit = (_Value & _Lsb_bit_mask) != 0; - const bool _Round_bit = (_Value & _Round_bit_mask) != 0; - const bool _Tail_bits = !_Has_zero_tail || (_Value & _Extra_bits_mask) != 0; + // const bool _Lsb_bit = (_Value & _Lsb_bit_mask) != 0; + // const bool _Round_bit = (_Value & _Round_bit_mask) != 0; + // const bool _Tail_bits = !_Has_zero_tail || (_Value & _Extra_bits_mask) != 0; - return (_Value >> _Shift) + _Should_round_up(_Lsb_bit, _Round_bit, _Tail_bits); -} + // return (_Value >> _Shift) + _Should_round_up(_Lsb_bit, _Round_bit, _Tail_bits); -// Converts the floating-point value [sign] 0.mantissa * 2^exponent into the correct form for _FloatingType and -// stores the result into the _Result object. The caller must ensure that the mantissa and exponent are correctly -// computed such that either [1] the most significant bit of the mantissa is in the correct position for the -// _FloatingType, or [2] the exponent has been correctly adjusted to account for the shift of the mantissa that -// will be required. + // Example for optimized implementation: Let _Shift be 8. + // Bit index: ...[8]76543210 + // _Value: ...[L]RTTTTTTT + // By focusing on the bit at index _Shift, we can avoid unnecessary branching and shifting. -// This function correctly handles range errors and stores a zero or infinity in the _Result object -// on underflow and overflow errors, respectively. This function correctly forms denormal numbers when required. + // Bit index: ...[8]76543210 + // _Lsb_bit: ...[L]RTTTTTTT + const uint64_t _Lsb_bit = _Value; -// If the provided mantissa has more bits of precision than can be stored in the _Result object, the mantissa is -// rounded to the available precision. Thus, if possible, the caller should provide a mantissa with at least one -// more bit of precision than is required, to ensure that the mantissa is correctly rounded. -// (The caller should not round the mantissa before calling this function.) + // Bit index: ...9[8]76543210 + // _Round_bit: ...L[R]TTTTTTT0 + const uint64_t _Round_bit = _Value << 1; + + // We can detect (without branching) whether any of the trailing bits are set. + // Due to _Should_round below, this computation will be used if and only if R is 1, so we can assume that here. + // Bit index: ...9[8]76543210 + // _Round_bit: ...L[1]TTTTTTT0 + // _Has_tail_bits: ....[H]........ + + // If all of the trailing bits T are 0, and _Has_zero_tail is true, + // then `_Round_bit - static_cast(_Has_zero_tail)` will produce 0 for H (due to R being 1). + // If any of the trailing bits T are 1, or _Has_zero_tail is false, + // then `_Round_bit - static_cast(_Has_zero_tail)` will produce 1 for H (due to R being 1). + const uint64_t _Has_tail_bits = _Round_bit - static_cast(_Has_zero_tail); + + // Finally, we can use _Should_round_up() logic with bitwise-AND and bitwise-OR, + // selecting just the bit at index _Shift. + const uint64_t _Should_round = ((_Round_bit & (_Has_tail_bits | _Lsb_bit)) >> _Shift) & uint64_t{1}; + + // This rounding technique is dedicated to the memory of Peppermint. =^..^= + return (_Value >> _Shift) + _Should_round; +} + +// Converts the floating-point value [sign] (mantissa / 2^(precision-1)) * 2^exponent into the correct form for +// _FloatingType and stores the result into the _Result object. +// The caller must ensure that the mantissa and exponent are correctly computed such that either: +// [1] min_exponent <= exponent <= max_exponent && 2^(precision-1) <= mantissa <= 2^precision, or +// [2] exponent == min_exponent && 0 < mantissa <= 2^(precision-1). +// (The caller should round the mantissa before calling this function. The caller doesn't need to renormalize the +// mantissa when the mantissa carries over to a higher bit after rounding up.) + +// This function correctly handles overflow and stores an infinity in the _Result object. +// (The result overflows if and only if exponent == max_exponent && mantissa == 2^precision) template -_NODISCARD errc _Assemble_floating_point_value_t(const bool _Is_negative, const int32_t _Exponent, +void _Assemble_floating_point_value_no_shift(const bool _Is_negative, const int32_t _Exponent, const typename _Floating_type_traits<_FloatingType>::_Uint_type _Mantissa, _FloatingType& _Result) noexcept { + // The following code assembles floating-point values based on an alternative interpretation of the IEEE 754 binary + // floating-point format. It is valid for all of the following cases: + // [1] normal value, + // [2] normal value, needs renormalization and exponent increment after rounding up the mantissa, + // [3] normal value, overflows after rounding up the mantissa, + // [4] subnormal value, + // [5] subnormal value, becomes a normal value after rounding up the mantissa. + + // Examples for float: + // | Case | Input | Exponent | Exponent | Exponent | Rounded | Result Bits | Result | + // | | | | + Bias - 1 | Component | Mantissa | | | + // | ---- | ------------- | -------- | ---------- | ---------- | --------- | ----------- | --------------- | + // | [1] | 1.000000p+0 | +0 | 126 | 0x3f000000 | 0x800000 | 0x3f800000 | 0x1.000000p+0 | + // | [2] | 1.ffffffp+0 | +0 | 126 | 0x3f000000 | 0x1000000 | 0x40000000 | 0x1.000000p+1 | + // | [3] | 1.ffffffp+127 | +127 | 253 | 0x7e800000 | 0x1000000 | 0x7f800000 | inf | + // | [4] | 0.fffffep-126 | -126 | 0 | 0x00000000 | 0x7fffff | 0x007fffff | 0x0.fffffep-126 | + // | [5] | 0.ffffffp-126 | -126 | 0 | 0x00000000 | 0x800000 | 0x00800000 | 0x1.000000p-126 | using _Floating_traits = _Floating_type_traits<_FloatingType>; using _Uint_type = typename _Floating_traits::_Uint_type; _Uint_type _Sign_component = _Is_negative; _Sign_component <<= _Floating_traits::_Sign_shift; - _Uint_type _Exponent_component = static_cast(_Exponent + _Floating_traits::_Exponent_bias); + _Uint_type _Exponent_component = static_cast(_Exponent + (_Floating_traits::_Exponent_bias - 1)); _Exponent_component <<= _Floating_traits::_Exponent_shift; - _Result = _Bit_cast<_FloatingType>(_Sign_component | _Exponent_component | _Mantissa); - - return errc{}; + _Result = _Bit_cast<_FloatingType>(_Sign_component | (_Exponent_component + _Mantissa)); } +// Converts the floating-point value [sign] (mantissa / 2^(precision-1)) * 2^exponent into the correct form for +// _FloatingType and stores the result into the _Result object. The caller must ensure that the mantissa and exponent +// are correctly computed such that either [1] the most significant bit of the mantissa is in the correct position for +// the _FloatingType, or [2] the exponent has been correctly adjusted to account for the shift of the mantissa that will +// be required. + +// This function correctly handles range errors and stores a zero or infinity in the _Result object +// on underflow and overflow errors, respectively. This function correctly forms denormal numbers when required. + +// If the provided mantissa has more bits of precision than can be stored in the _Result object, the mantissa is +// rounded to the available precision. Thus, if possible, the caller should provide a mantissa with at least one +// more bit of precision than is required, to ensure that the mantissa is correctly rounded. +// (The caller should not round the mantissa before calling this function.) template _NODISCARD errc _Assemble_floating_point_value(const uint64_t _Initial_mantissa, const int32_t _Initial_exponent, const bool _Is_negative, const bool _Has_zero_tail, _FloatingType& _Result) noexcept { @@ -1283,36 +1321,35 @@ _NODISCARD errc _Assemble_floating_point_value(const uint64_t _Initial_mantissa, const int32_t _Normal_mantissa_shift = static_cast(_Traits::_Mantissa_bits - _Initial_mantissa_bits); const int32_t _Normal_exponent = _Initial_exponent - _Normal_mantissa_shift; - uint64_t _Mantissa = _Initial_mantissa; - int32_t _Exponent = _Normal_exponent; - if (_Normal_exponent > _Traits::_Maximum_binary_exponent) { // The exponent is too large to be represented by the floating-point type; report the overflow condition: _Assemble_floating_point_infinity(_Is_negative, _Result); return errc::result_out_of_range; // Overflow example: "1e+1000" } + uint64_t _Mantissa = _Initial_mantissa; + int32_t _Exponent = _Normal_exponent; + errc _Error_code{}; + if (_Normal_exponent < _Traits::_Minimum_binary_exponent) { // The exponent is too small to be represented by the floating-point type as a normal value, but it may be - // representable as a denormal value. Compute the number of bits by which we need to shift the mantissa - // in order to form a denormal number. (The subtraction of an extra 1 is to account for the hidden bit of - // the mantissa that is not available for use when representing a denormal.) - const int32_t _Denormal_mantissa_shift = - _Normal_mantissa_shift + _Normal_exponent + _Traits::_Exponent_bias - 1; + // representable as a denormal value. - // Denormal values have an exponent of zero, so the debiased exponent is the negation of the exponent bias: - _Exponent = -_Traits::_Exponent_bias; + // The exponent of subnormal values (as defined by the mathematical model of floating-point numbers, not the + // exponent field in the bit representation) is equal to the minimum exponent of normal values. + _Exponent = _Traits::_Minimum_binary_exponent; + + // Compute the number of bits by which we need to shift the mantissa in order to form a denormal number. + const int32_t _Denormal_mantissa_shift = _Initial_exponent - _Exponent; if (_Denormal_mantissa_shift < 0) { - // Use two steps for right shifts: for a shift of N bits, we first shift by N-1 bits, - // then shift the last bit and use its value to round the mantissa. _Mantissa = _Right_shift_with_rounding(_Mantissa, static_cast(-_Denormal_mantissa_shift), _Has_zero_tail); - // If the mantissa is now zero, we have underflowed: + // from_chars in MSVC STL and strto[f|d|ld] in UCRT reports underflow only when the result is zero after + // rounding to the floating-point format. This behavior is different from IEEE 754 underflow exception. if (_Mantissa == 0) { - _Assemble_floating_point_zero(_Is_negative, _Result); - return errc::result_out_of_range; // Underflow example: "1e-1000" + _Error_code = errc::result_out_of_range; // Underflow example: "1e-1000" } // When we round the mantissa, the result may be so large that the number becomes a normal value. @@ -1325,49 +1362,37 @@ _NODISCARD errc _Assemble_floating_point_value(const uint64_t _Initial_mantissa, // 0x00800000 is 24 bits, which is more than the 23 bits available in the mantissa. // Thus, we have rounded our denormal number into a normal number. - // We detect this case here and re-adjust the mantissa and exponent appropriately, to form a normal number: - if (_Mantissa > _Traits::_Denormal_mantissa_mask) { - // The mantissa is already in the correct position for a normal value. (The carried over bit when we - // added 1 to round the mantissa is in the correct position for the hidden bit.) - // _Denormal_mantissa_shift is the actual number of bits by which we have shifted the mantissa into its - // final position. - _Exponent = _Initial_exponent - _Denormal_mantissa_shift; - } + // We detect this case here and re-adjust the mantissa and exponent appropriately, to form a normal number. + // This is handled by _Assemble_floating_point_value_no_shift. } else { _Mantissa <<= _Denormal_mantissa_shift; } } else { if (_Normal_mantissa_shift < 0) { - // Use two steps for right shifts: for a shift of N bits, we first shift by N-1 bits, - // then shift the last bit and use its value to round the mantissa. _Mantissa = _Right_shift_with_rounding(_Mantissa, static_cast(-_Normal_mantissa_shift), _Has_zero_tail); // When we round the mantissa, it may produce a result that is too large. In this case, // we divide the mantissa by two and increment the exponent (this does not change the value). - if (_Mantissa > _Traits::_Normal_mantissa_mask) { - _Mantissa >>= 1; - ++_Exponent; - - // The increment of the exponent may have generated a value too large to be represented. - // In this case, report the overflow: - if (_Exponent > _Traits::_Maximum_binary_exponent) { - _Assemble_floating_point_infinity(_Is_negative, _Result); - return errc::result_out_of_range; // Overflow example: "1.ffffffp+127" for float - // Overflow example: "1.fffffffffffff8p+1023" for double - } + // This is handled by _Assemble_floating_point_value_no_shift. + + // The increment of the exponent may have generated a value too large to be represented. + // In this case, report the overflow: + if (_Mantissa > _Traits::_Normal_mantissa_mask && _Exponent == _Traits::_Maximum_binary_exponent) { + _Error_code = errc::result_out_of_range; // Overflow example: "1.ffffffp+127" for float + // Overflow example: "1.fffffffffffff8p+1023" for double } - } else if (_Normal_mantissa_shift > 0) { + } else { _Mantissa <<= _Normal_mantissa_shift; } } - // Unset the hidden bit in the mantissa and assemble the floating-point value from the computed components: - _Mantissa &= _Traits::_Denormal_mantissa_mask; - + // Assemble the floating-point value from the computed components: using _Uint_type = typename _Traits::_Uint_type; - return _Assemble_floating_point_value_t(_Is_negative, _Exponent, static_cast<_Uint_type>(_Mantissa), _Result); + _Assemble_floating_point_value_no_shift(_Is_negative, _Exponent, static_cast<_Uint_type>(_Mantissa), _Result); + + return _Error_code; } // This function is part of the fast track for integer floating-point strings. It takes an integer and a sign and diff --git a/stl/inc/chrono b/stl/inc/chrono index 4991b19d61a..8405b26be58 100644 --- a/stl/inc/chrono +++ b/stl/inc/chrono @@ -575,10 +575,8 @@ namespace chrono { // CLOCKS struct system_clock { // wraps GetSystemTimePreciseAsFileTime/GetSystemTimeAsFileTime - using rep = long long; - - using period = ratio_multiply, nano>; - + using rep = long long; + using period = ratio<1, 10'000'000>; // 100 nanoseconds using duration = chrono::duration; using time_point = chrono::time_point; static constexpr bool is_steady = false; @@ -588,11 +586,11 @@ namespace chrono { } _NODISCARD static __time64_t to_time_t(const time_point& _Time) noexcept { // convert to __time64_t - return static_cast<__time64_t>(_Time.time_since_epoch().count() / _XTIME_TICKS_PER_TIME_T); + return duration_cast(_Time.time_since_epoch()).count(); } _NODISCARD static time_point from_time_t(__time64_t _Tm) noexcept { // convert from __time64_t - return time_point(duration(_Tm * _XTIME_TICKS_PER_TIME_T)); + return time_point{seconds{_Tm}}; } }; diff --git a/stl/inc/complex b/stl/inc/complex index 2bbba58573b..8a39add392f 100644 --- a/stl/inc/complex +++ b/stl/inc/complex @@ -21,7 +21,7 @@ _STL_DISABLE_CLANG_WARNINGS #undef new #ifndef _C_COMPLEX_T -#define _C_COMPLEX_T +#define _C_COMPLEX_T // Also defined by UCRT struct _C_double_complex { double _Val[2]; @@ -223,13 +223,21 @@ public: } static bool _Isinf(_Ty _Left) { // test for infinity +#if defined(__INTEL_COMPILER) && defined(__LONG_DOUBLE_SIZE__) && __LONG_DOUBLE_SIZE__ == 80 + return _CSTD _LDtest(&_Left) == _INFCODE; +#else // ^^^ 80-bit long double (not supported by MSVC in general, see GH-1316) / 64-bit long double vvv const auto _Uint = _Bit_cast(_Left); return (_Uint & 0x7fffffffffffffffU) == 0x7ff0000000000000U; +#endif // ^^^ 64-bit long double ^^^ } static _CONSTEXPR20 bool _Isnan(_Ty _Left) { +#if defined(__INTEL_COMPILER) && defined(__LONG_DOUBLE_SIZE__) && __LONG_DOUBLE_SIZE__ == 80 + return _CSTD _LDtest(&_Left) == _NANCODE; +#else // ^^^ 80-bit long double (not supported by MSVC in general, see GH-1316) / 64-bit long double vvv const auto _Uint = _Bit_cast(_Left); return (_Uint & 0x7fffffffffffffffU) > 0x7ff0000000000000U; +#endif // ^^^ 64-bit long double ^^^ } static constexpr _Ty _Nanv() { // return NaN @@ -694,17 +702,6 @@ public: constexpr complex(const _Ty& _Realval = 0, const _Ty& _Imagval = 0) : _Complex_base(_Realval, _Imagval) {} - constexpr complex(const _Fcomplex_value& _Right) - : _Complex_base(_Right._Val[_RE], _Right._Val[_IM]) {} - - constexpr complex(const _Dcomplex_value& _Right) - : _Complex_base( - static_cast(_Right._Val[_RE]), static_cast(_Right._Val[_IM])) {} - - constexpr complex(const _Lcomplex_value& _Right) - : _Complex_base( - static_cast(_Right._Val[_RE]), static_cast(_Right._Val[_IM])) {} - _CONSTEXPR20 complex& operator=(const _Ty& _Right) { _Val[_RE] = _Right; _Val[_IM] = 0; @@ -797,13 +794,6 @@ public: constexpr complex(const _Ty& _Realval = 0, const _Ty& _Imagval = 0) : _Complex_base(_Realval, _Imagval) {} - constexpr complex(const _Dcomplex_value& _Right) - : _Complex_base(_Right._Val[_RE], _Right._Val[_IM]) {} - - constexpr complex(const _Lcomplex_value& _Right) - : _Complex_base( - static_cast(_Right._Val[_RE]), static_cast(_Right._Val[_IM])) {} - _CONSTEXPR20 complex& operator=(const _Ty& _Right) { _Val[_RE] = _Right; _Val[_IM] = 0; @@ -896,9 +886,6 @@ public: constexpr complex(const _Ty& _Realval = 0, const _Ty& _Imagval = 0) : _Complex_base(_Realval, _Imagval) {} - constexpr complex(const _Lcomplex_value& _Right) - : _Complex_base(_Right._Val[_RE], _Right._Val[_IM]) {} - _CONSTEXPR20 complex& operator=(const _Ty& _Right) { _Val[_RE] = _Right; _Val[_IM] = 0; @@ -1866,65 +1853,22 @@ _NODISCARD complex<_Upgrade_to_double<_Ty>> proj(_Ty _Left) { // FUNCTION TEMPLATE pow template _NODISCARD complex<_Common_float_type_t<_Ty1, _Ty2>> pow(const complex<_Ty1>& _Left, const complex<_Ty2>& _Right) { - using type = complex<_Common_float_type_t<_Ty1, _Ty2>>; - return _STD pow(type(_Left), type(_Right)); + using _Type = complex<_Common_float_type_t<_Ty1, _Ty2>>; + return _STD pow(_Type(_Left), _Type(_Right)); } -template , int> = 0> +template , int> = 0> _NODISCARD complex<_Common_float_type_t<_Ty1, _Ty2>> pow(const complex<_Ty1>& _Left, const _Ty2& _Right) { - using type = complex<_Common_float_type_t<_Ty1, _Ty2>>; - return _STD pow(type(_Left), type(_Right)); -} - -template && is_integral_v<_Ty2>, int> = 0> -_NODISCARD complex<_Common_float_type_t<_Ty1, _Ty2>> pow(const complex<_Ty1>& _Left, const _Ty2 _Right) { - using type = complex<_Common_float_type_t<_Ty1, _Ty2>>; - - type _Tmp = _Left; - auto _Count = static_cast>(_Right); - - if (_Right < 0) { - _Count = 0 - _Count; // safe negation as unsigned - } - - for (type _Zv(1);; _Tmp *= _Tmp) { // fold in _Left ^ (2 ^ _Count) as needed - if ((_Count & 1) != 0) { - _Zv *= _Tmp; - } - - if ((_Count >>= 1) == 0) { - return _Right < 0 ? type(1) / _Zv : _Zv; - } - } + using _Promoted = _Common_float_type_t<_Ty1, _Ty2>; + using _Type = complex<_Promoted>; + return _STD pow(_Type(_Left), _Type(static_cast<_Promoted>(_Right))); } -template && is_integral_v<_Ty2>, int> = 0> -_NODISCARD complex<_Ty1> pow(const complex<_Ty1>& _Left, _Ty2 _Right) { - // raise Gaussian integer to an integer power - using type = complex<_Ty1>; - - type _Ans = type(1, 0); - - if (_Right < 0) { - _Ans = type(0, 0); // ignore 1/type(0, 0) error - } else if (0 < _Right) { // raise to a positive power - for (type _Factor = _Left;; _Factor *= _Factor) { // fold in _Left^(2^N)) - if ((_Right & 1) != 0) { - _Ans *= _Factor; - } - - if ((_Right >>= 1) == 0) { - break; - } - } - } - return _Ans; -} - -template +template , int> = 0> _NODISCARD complex<_Common_float_type_t<_Ty1, _Ty2>> pow(const _Ty1& _Left, const complex<_Ty2>& _Right) { - using type = complex<_Common_float_type_t<_Ty1, _Ty2>>; - return _STD pow(type(_Left), type(_Right)); + using _Promoted = _Common_float_type_t<_Ty1, _Ty2>; + using _Type = complex<_Promoted>; + return _STD pow(_Type(static_cast<_Promoted>(_Left)), _Type(_Right)); } // FUNCTION TEMPLATE operator>> diff --git a/stl/inc/condition_variable b/stl/inc/condition_variable index 0fdd0e13306..1289183537c 100644 --- a/stl/inc/condition_variable +++ b/stl/inc/condition_variable @@ -12,6 +12,9 @@ #include #include #include +#if _HAS_CXX20 +#include +#endif // _HAS_CXX20 #pragma pack(push, _CRT_PACKING) #pragma warning(push, _STL_WARNING_LEVEL) @@ -25,6 +28,27 @@ _STL_DISABLE_CLANG_WARNINGS #endif // _M_CEE _STD_BEGIN +template +struct _Unlock_guard { + explicit _Unlock_guard(_Lock& _Mtx_) : _Mtx(_Mtx_) { + _Mtx.unlock(); + } + + ~_Unlock_guard() noexcept /* terminates */ { + // relock mutex or terminate() + // condition_variable_any wait functions are required to terminate if + // the mutex cannot be relocked; + // we slam into noexcept here for easier user debugging. + _Mtx.lock(); + } + + _Unlock_guard(const _Unlock_guard&) = delete; + _Unlock_guard& operator=(const _Unlock_guard&) = delete; + +private: + _Lock& _Mtx; +}; + class condition_variable_any { // class for waiting for conditions with any kind of mutex public: condition_variable_any() : _Myptr{_STD make_shared()} { @@ -50,20 +74,17 @@ public: template void wait(_Lock& _Lck) noexcept /* terminates */ { // wait for signal - { - const shared_ptr _Ptr = _Myptr; // for immunity to *this destruction - lock_guard _Guard{*_Ptr}; - _Lck.unlock(); - _Cnd_wait(_Mycnd(), _Ptr->_Mymtx()); - } // unlock - - _Lck.lock(); - } + const shared_ptr _Ptr = _Myptr; // for immunity to *this destruction + unique_lock _Guard{*_Ptr}; + _Unlock_guard<_Lock> _Unlock_outer{_Lck}; + _Cnd_wait(_Mycnd(), _Ptr->_Mymtx()); + _Guard.unlock(); + } // relock _Lck template - void wait(_Lock& _Lck, _Predicate _Pred) noexcept(noexcept(!_Pred())) /* strengthened */ { + void wait(_Lock& _Lck, _Predicate _Pred) noexcept(noexcept(static_cast(_Pred()))) /* strengthened */ { // wait for signal and check predicate - while (!_Pred()) { + while (!static_cast(_Pred())) { wait(_Lck); } } @@ -89,8 +110,8 @@ public: template cv_status wait_for(_Lock& _Lck, const chrono::duration<_Rep, _Period>& _Rel_time) { // wait for duration if (_Rel_time <= chrono::duration<_Rep, _Period>::zero()) { - _Lck.unlock(); - _Relock(_Lck); + _Unlock_guard<_Lock> _Unlock_outer{_Lck}; + (void) _Unlock_outer; return cv_status::timeout; } @@ -128,6 +149,93 @@ public: return true; } +#if _HAS_CXX20 +private: + struct _Cv_any_notify_all { + condition_variable_any* _This; + + explicit _Cv_any_notify_all(condition_variable_any* _This_) : _This{_This_} {} + + _Cv_any_notify_all(const _Cv_any_notify_all&) = delete; + _Cv_any_notify_all& operator=(const _Cv_any_notify_all&) = delete; + + void operator()() const noexcept { + _This->notify_all(); + } + }; + +public: + template + bool wait(_Lock& _Lck, stop_token _Stoken, _Predicate _Pred) noexcept( + noexcept(static_cast(_Pred()))) /* strengthened */ { + // TRANSITION, ABI: Due to the unsynchronized delivery of notify_all by _Stoken, + // this implementation cannot tolerate *this destruction while an interruptible wait + // is outstanding. A future ABI should store both the internal CV and internal mutex + // in the reference counted block to allow this. + stop_callback<_Cv_any_notify_all> _Cb{_Stoken, this}; + for (;;) { + if (_Pred()) { + return true; + } + + unique_lock _Guard{*_Myptr}; + if (_Stoken.stop_requested()) { + _Guard.unlock(); + return _Pred(); + } + + _Unlock_guard<_Lock> _Unlock_outer{_Lck}; + _Cnd_wait(_Mycnd(), _Myptr->_Mymtx()); + _Guard.unlock(); + } // relock + } + + template + bool wait_until( + _Lock& _Lck, stop_token _Stoken, const chrono::time_point<_Clock, _Duration>& _Abs_time, _Predicate _Pred) { + stop_callback<_Cv_any_notify_all> _Cb{_Stoken, this}; + for (;;) { + if (_Pred()) { + return true; + } + + unique_lock _Guard{*_Myptr}; + if (_Stoken.stop_requested()) { + break; + } + + _Unlock_guard<_Lock> _Unlock_outer{_Lck}; + const auto _Now = _Clock::now(); + if (_Now >= _Abs_time) { + break; + } + + const auto _Rel_time = _Abs_time - _Now; + // TRANSITION, ABI: The standard says that we should use a steady clock, + // but unfortunately our ABI speaks struct xtime, which is relative to the system clock. + _CSTD xtime _Tgt; + (void) _To_xtime_10_day_clamped(_Tgt, _Rel_time); + const int _Res = _Cnd_timedwait(_Mycnd(), _Myptr->_Mymtx(), &_Tgt); + _Guard.unlock(); + + switch (_Res) { + case _Thrd_timedout: + case _Thrd_success: + break; + default: + _Throw_C_error(_Res); + } + } // relock + + return _Pred(); + } + + template + bool wait_for(_Lock& _Lck, stop_token _Stoken, const chrono::duration<_Rep, _Period>& _Rel_time, _Predicate _Pred) { + return wait_until(_Lck, _STD move(_Stoken), chrono::steady_clock::now() + _Rel_time, _STD move(_Pred)); + } +#endif // _HAS_CXX20 + private: shared_ptr _Myptr; @@ -139,16 +247,11 @@ private: template cv_status _Wait_until(_Lock& _Lck, const xtime* const _Abs_time) { // wait for signal with timeout - int _Res; - - { - const shared_ptr _Ptr = _Myptr; // for immunity to *this destruction - lock_guard _Guard{*_Ptr}; - _Lck.unlock(); - _Res = _Cnd_timedwait(_Mycnd(), _Ptr->_Mymtx(), _Abs_time); - } // unlock - - _Relock(_Lck); + const shared_ptr _Ptr = _Myptr; // for immunity to *this destruction + unique_lock _Guard{*_Ptr}; + _Unlock_guard<_Lock> _Unlock_outer{_Lck}; + const int _Res = _Cnd_timedwait(_Mycnd(), _Ptr->_Mymtx(), _Abs_time); + _Guard.unlock(); switch (_Res) { case _Thrd_success: @@ -159,13 +262,6 @@ private: _Throw_C_error(_Res); } } - - template - static void _Relock(_Lock& _Lck) noexcept /* terminates */ { // relock external mutex or terminate() - // Wait functions are required to terminate if the mutex cannot be locked; - // we slam into noexcept here for easier user debugging. - _Lck.lock(); - } }; inline void notify_all_at_thread_exit(condition_variable& _Cnd, unique_lock _Lck) { diff --git a/stl/inc/deque b/stl/inc/deque index 3da10106758..829ab6709a7 100644 --- a/stl/inc/deque +++ b/stl/inc/deque @@ -22,22 +22,14 @@ _STL_DISABLE_CLANG_WARNINGS #undef new _STD_BEGIN -// DEQUE PARAMETERS -#define _DEQUEMAPSIZ 8 // minimum map size, at least 1 -#define _DEQUESIZ \ - (sizeof(value_type) <= 1 \ - ? 16 \ - : sizeof(value_type) <= 2 \ - ? 8 \ - : sizeof(value_type) <= 4 ? 4 \ - : sizeof(value_type) <= 8 ? 2 : 1) // elements per block (a power of 2) - // CLASS TEMPLATE _Deque_unchecked_const_iterator template class _Deque_unchecked_const_iterator { private: using _Size_type = typename _Mydeque::size_type; + static constexpr int _Block_size = _Mydeque::_Block_size; + public: using iterator_category = random_access_iterator_tag; @@ -53,7 +45,7 @@ public: _NODISCARD reference operator*() const noexcept { _Size_type _Block = _Mycont->_Getblock(_Myoff); - _Size_type _Off = _Myoff % _DEQUESIZ; + _Size_type _Off = _Myoff % _Block_size; return _Mycont->_Map[_Block][_Off]; } @@ -239,6 +231,8 @@ class _Deque_const_iterator : public _Iterator_base12 { private: using _Size_type = typename _Mydeque::size_type; + static constexpr int _Block_size = _Mydeque::_Block_size; + public: using iterator_category = random_access_iterator_tag; @@ -248,7 +242,7 @@ public: using reference = const value_type&; using _Mydeque_t = _Mydeque; // helper for expression evaluator - enum { _EEN_DS = _DEQUESIZ }; // helper for expression evaluator + enum { _EEN_DS = _Block_size }; // helper for expression evaluator _Deque_const_iterator() noexcept : _Myoff(0) { _Setcont(nullptr); } @@ -266,7 +260,7 @@ public: #endif // _ITERATOR_DEBUG_LEVEL != 0 _Size_type _Block = _Mycont->_Getblock(_Myoff); - _Size_type _Off = _Myoff % _DEQUESIZ; + _Size_type _Off = _Myoff % _Block_size; return _Mycont->_Map[_Block][_Off]; } @@ -541,11 +535,18 @@ public: using const_reference = const value_type&; using _Mapptr = typename _Val_types::_Mapptr; +private: + static constexpr size_t _Bytes = sizeof(value_type); + +public: + static constexpr int _Block_size = + _Bytes <= 1 ? 16 : _Bytes <= 2 ? 8 : _Bytes <= 4 ? 4 : _Bytes <= 8 ? 2 : 1; // elements per block (a power of 2) + _Deque_val() noexcept : _Map(), _Mapsize(0), _Myoff(0), _Mysize(0) {} size_type _Getblock(size_type _Off) const noexcept { - // NB: _Mapsize and _DEQUESIZ are guaranteed to be powers of 2 - return (_Off / _DEQUESIZ) & (_Mapsize - 1); + // NB: _Mapsize and _Block_size are guaranteed to be powers of 2 + return (_Off / _Block_size) & (_Mapsize - 1); } _Mapptr _Map; // pointer to array of pointers to blocks @@ -574,6 +575,9 @@ private: _Deque_iter_types<_Ty, typename _Alty_traits::size_type, typename _Alty_traits::difference_type, typename _Alty_traits::pointer, typename _Alty_traits::const_pointer, _Ty&, const _Ty&, _Mapptr>>>; + static constexpr int _Minimum_map_size = 8; + static constexpr int _Block_size = _Scary_val::_Block_size; + public: using allocator_type = _Alloc; using value_type = _Ty; @@ -591,7 +595,7 @@ public: using reverse_iterator = _STD reverse_iterator; using const_reverse_iterator = _STD reverse_iterator; - enum { _EEN_DS = _DEQUESIZ }; // helper for expression evaluator + enum { _EEN_DS = _Block_size }; // helper for expression evaluator deque() : _Mypair(_Zero_then_variadic_args_t{}) { _Get_data()._Alloc_proxy(static_cast<_Alproxy_ty>(_Getal())); @@ -675,34 +679,6 @@ private: _Guard._Target = nullptr; } -#define _PUSH_FRONT_BEGIN \ - if (_Myoff() % _DEQUESIZ == 0 && _Mapsize() <= (_Mysize() + _DEQUESIZ) / _DEQUESIZ) { \ - _Growmap(1); \ - } \ - _Myoff() &= _Mapsize() * _DEQUESIZ - 1; \ - size_type _Newoff = _Myoff() != 0 ? _Myoff() : _Mapsize() * _DEQUESIZ; \ - size_type _Block = _Getblock(--_Newoff); \ - if (_Map()[_Block] == nullptr) { \ - _Map()[_Block] = _Getal().allocate(_DEQUESIZ); \ - } - -#define _PUSH_FRONT_END \ - _Myoff() = _Newoff; \ - ++_Mysize() - -#define _PUSH_BACK_BEGIN \ - if ((_Myoff() + _Mysize()) % _DEQUESIZ == 0 && _Mapsize() <= (_Mysize() + _DEQUESIZ) / _DEQUESIZ) { \ - _Growmap(1); \ - } \ - _Myoff() &= _Mapsize() * _DEQUESIZ - 1; \ - size_type _Newoff = _Myoff() + _Mysize(); \ - size_type _Block = _Getblock(_Newoff); \ - if (_Map()[_Block] == nullptr) { \ - _Map()[_Block] = _Getal().allocate(_DEQUESIZ); \ - } - -#define _PUSH_BACK_END ++_Mysize() - public: deque(deque&& _Right) : _Mypair(_One_then_variadic_args_t{}, _STD move(_Right._Getal())) { _Get_data()._Alloc_proxy(static_cast<_Alproxy_ty>(_Getal())); @@ -786,10 +762,7 @@ private: public: void push_front(_Ty&& _Val) { - _Orphan_all(); - _PUSH_FRONT_BEGIN; - _Alty_traits::construct(_Getal(), _Unfancy(_Map()[_Block] + _Newoff % _DEQUESIZ), _STD move(_Val)); - _PUSH_FRONT_END; + emplace_front(_STD move(_Val)); } void push_back(_Ty&& _Val) { @@ -804,10 +777,22 @@ public: template decltype(auto) emplace_front(_Valty&&... _Val) { _Orphan_all(); - _PUSH_FRONT_BEGIN; + + if (_Myoff() % _Block_size == 0 && _Mapsize() <= (_Mysize() + _Block_size) / _Block_size) { + _Growmap(1); + } + _Myoff() &= _Mapsize() * _Block_size - 1; + size_type _Newoff = _Myoff() != 0 ? _Myoff() : _Mapsize() * _Block_size; + size_type _Block = _Getblock(--_Newoff); + if (_Map()[_Block] == nullptr) { + _Map()[_Block] = _Getal().allocate(_Block_size); + } + _Alty_traits::construct( - _Getal(), _Unfancy(_Map()[_Block] + _Newoff % _DEQUESIZ), _STD forward<_Valty>(_Val)...); - _PUSH_FRONT_END; + _Getal(), _Unfancy(_Map()[_Block] + _Newoff % _Block_size), _STD forward<_Valty>(_Val)...); + + _Myoff() = _Newoff; + ++_Mysize(); #if _HAS_CXX17 return front(); @@ -817,10 +802,7 @@ public: template decltype(auto) emplace_back(_Valty&&... _Val) { _Orphan_all(); - _PUSH_BACK_BEGIN; - _Alty_traits::construct( - _Getal(), _Unfancy(_Map()[_Block] + _Newoff % _DEQUESIZ), _STD forward<_Valty>(_Val)...); - _PUSH_BACK_END; + _Emplace_back_internal(_STD forward<_Valty>(_Val)...); #if _HAS_CXX17 return back(); @@ -963,11 +945,12 @@ public: } void shrink_to_fit() { - size_type _Oldcapacity = _DEQUESIZ * _Mapsize(); + size_type _Oldcapacity = _Block_size * _Mapsize(); size_type _Newcapacity = _Oldcapacity / 2; - if (_Newcapacity < _DEQUESIZ * _DEQUEMAPSIZ) - _Newcapacity = _DEQUESIZ * _DEQUEMAPSIZ; + if (_Newcapacity < _Block_size * _Minimum_map_size) { + _Newcapacity = _Block_size * _Minimum_map_size; + } if ((empty() && 0 < _Mapsize()) || (!empty() && size() <= _Newcapacity && _Newcapacity < _Oldcapacity)) { // worth shrinking, do it @@ -1015,8 +998,10 @@ public: } _NODISCARD const_reference at(size_type _Pos) const { - if (_Mysize() <= _Pos) + if (_Mysize() <= _Pos) { _Xran(); + } + return *(begin() + static_cast(_Pos)); } @@ -1077,10 +1062,7 @@ public: } void push_front(const _Ty& _Val) { - _Orphan_all(); - _PUSH_FRONT_BEGIN; - _Alty_traits::construct(_Getal(), _Unfancy(_Map()[_Block] + _Newoff % _DEQUESIZ), _Val); - _PUSH_FRONT_END; + emplace_front(_Val); } void pop_front() noexcept /* strengthened */ { @@ -1090,7 +1072,7 @@ public: } else { // something to erase, do it _Orphan_off(_Myoff()); size_type _Block = _Getblock(_Myoff()); - _Alty_traits::destroy(_Getal(), _Unfancy(_Map()[_Block] + _Myoff() % _DEQUESIZ)); + _Alty_traits::destroy(_Getal(), _Unfancy(_Map()[_Block] + _Myoff() % _Block_size)); if (--_Mysize() == 0) { _Myoff() = 0; } else { @@ -1100,7 +1082,7 @@ public: #else // _ITERATOR_DEBUG_LEVEL == 2 size_type _Block = _Getblock(_Myoff()); - _Alty_traits::destroy(_Getal(), _Unfancy(_Map()[_Block] + _Myoff() % _DEQUESIZ)); + _Alty_traits::destroy(_Getal(), _Unfancy(_Map()[_Block] + _Myoff() % _Block_size)); if (--_Mysize() == 0) { _Myoff() = 0; } else { @@ -1112,9 +1094,20 @@ public: private: template void _Emplace_back_internal(_Tys&&... _Vals) { - _PUSH_BACK_BEGIN; - _Alty_traits::construct(_Getal(), _Unfancy(_Map()[_Block] + _Newoff % _DEQUESIZ), _STD forward<_Tys>(_Vals)...); - _PUSH_BACK_END; + if ((_Myoff() + _Mysize()) % _Block_size == 0 && _Mapsize() <= (_Mysize() + _Block_size) / _Block_size) { + _Growmap(1); + } + _Myoff() &= _Mapsize() * _Block_size - 1; + size_type _Newoff = _Myoff() + _Mysize(); + size_type _Block = _Getblock(_Newoff); + if (_Map()[_Block] == nullptr) { + _Map()[_Block] = _Getal().allocate(_Block_size); + } + + _Alty_traits::construct( + _Getal(), _Unfancy(_Map()[_Block] + _Newoff % _Block_size), _STD forward<_Tys>(_Vals)...); + + ++_Mysize(); } public: @@ -1131,7 +1124,7 @@ public: size_type _Newoff = _Myoff() + _Mysize() - 1; _Orphan_off(_Newoff); size_type _Block = _Getblock(_Newoff); - _Alty_traits::destroy(_Getal(), _Unfancy(_Map()[_Block] + _Newoff % _DEQUESIZ)); + _Alty_traits::destroy(_Getal(), _Unfancy(_Map()[_Block] + _Newoff % _Block_size)); if (--_Mysize() == 0) { _Myoff() = 0; } @@ -1140,7 +1133,7 @@ public: #else // _ITERATOR_DEBUG_LEVEL == 2 size_type _Newoff = _Myoff() + _Mysize() - 1; size_type _Block = _Getblock(_Newoff); - _Alty_traits::destroy(_Getal(), _Unfancy(_Map()[_Block] + _Newoff % _DEQUESIZ)); + _Alty_traits::destroy(_Getal(), _Unfancy(_Map()[_Block] + _Newoff % _Block_size)); if (--_Mysize() == 0) { _Myoff() = 0; } @@ -1428,13 +1421,13 @@ private: } void _Growmap(size_type _Count) { // grow map by at least _Count pointers, _Mapsize() a power of 2 - static_assert(1 < _DEQUEMAPSIZ, "The _Xlen() test should always be performed."); + static_assert(1 < _Minimum_map_size, "The _Xlen() test should always be performed."); _Alpty _Almap(_Getal()); size_type _Newsize = 0 < _Mapsize() ? _Mapsize() : 1; - while (_Newsize - _Mapsize() < _Count || _Newsize < _DEQUEMAPSIZ) { + while (_Newsize - _Mapsize() < _Count || _Newsize < _Minimum_map_size) { // scale _Newsize to 2^N >= _Mapsize() + _Count - if (max_size() / _DEQUESIZ - _Newsize < _Newsize) { + if (max_size() / _Block_size - _Newsize < _Newsize) { _Xlen(); // result too long } @@ -1442,7 +1435,7 @@ private: } _Count = _Newsize - _Mapsize(); - size_type _Myboff = _Myoff() / _DEQUESIZ; + size_type _Myboff = _Myoff() / _Block_size; _Mapptr _Newmap = _Almap.allocate(_Mapsize() + _Count); _Mapptr _Myptr = _Newmap + _Myboff; @@ -1476,7 +1469,7 @@ private: for (size_type _Block = _Mapsize(); 0 < _Block;) { // free storage for a block and destroy pointer if (_Map()[--_Block]) { // free block and destroy its pointer - _Getal().deallocate(_Map()[_Block], _DEQUESIZ); + _Getal().deallocate(_Map()[_Block], _Block_size); _Destroy_in_place(_Map()[_Block]); } } diff --git a/stl/inc/execution b/stl/inc/execution index 427ea5d0dac..6f8efed4843 100644 --- a/stl/inc/execution +++ b/stl/inc/execution @@ -1091,8 +1091,7 @@ struct _Static_partitioned_all_of_family2 { // all_of/any_of/none_of task schedu if (!_Key) { return _Cancellation_status::_Canceled; } - // Once _Key is obtained, the amount of work should not be discarded; see GH-818. - // GH-818: https://github.com/microsoft/STL/issues/818 + // Once _Key is obtained, the amount of work should not be discarded (see GH-818). const auto _Range = _Basis._Get_chunk(_Key); for (auto _First = _Range._First; _First != _Range._Last; ++_First) { @@ -1326,7 +1325,7 @@ struct _Static_partitioned_find2 { if (!_Key) { return _Cancellation_status::_Canceled; } - // Once _Key is obtained, the amount of work should not be discarded; see GH-818. + // Once _Key is obtained, the amount of work should not be discarded (see GH-818). const auto _Range = _Basis._Get_chunk(_Key); const auto _This_find = _Fx(_Range._First, _Range._Last); @@ -1531,7 +1530,7 @@ struct _Static_partitioned_find_end_backward2 { if (!_Key) { return _Cancellation_status::_Canceled; } - // Once _Key is obtained, the amount of work should not be discarded; see GH-818. + // Once _Key is obtained, the amount of work should not be discarded (see GH-818). const auto _Chunk_number = _Key._Chunk_number; const auto _Range = _Basis._Get_chunk(_Key); @@ -1652,7 +1651,7 @@ struct _Static_partitioned_adjacent_find2 { if (!_Key) { return _Cancellation_status::_Canceled; } - // Once _Key is obtained, the amount of work should not be discarded; see GH-818. + // Once _Key is obtained, the amount of work should not be discarded (see GH-818). const auto _Chunk_number = _Key._Chunk_number; const auto _Range = _Basis._Get_chunk(_Key); @@ -1868,7 +1867,7 @@ struct _Static_partitioned_mismatch2 { if (!_Key) { return _Cancellation_status::_Canceled; } - // Once _Key is obtained, the amount of work should not be discarded; see GH-818. + // Once _Key is obtained, the amount of work should not be discarded (see GH-818). const auto _Chunk_number = _Key._Chunk_number; const auto _Range1 = _Basis1._Get_chunk(_Key); @@ -2000,7 +1999,7 @@ struct _Static_partitioned_equal2 { if (!_Key) { return _Cancellation_status::_Canceled; } - // Once _Key is obtained, the amount of work should not be discarded; see GH-818. + // Once _Key is obtained, the amount of work should not be discarded (see GH-818). const auto _Range1 = _Basis1._Get_chunk(_Key); const auto _Range2_first = _Basis2._Get_chunk(_Key)._First; @@ -2119,7 +2118,7 @@ struct _Static_partitioned_search2 { if (!_Key) { return _Cancellation_status::_Canceled; } - // Once _Key is obtained, the amount of work should not be discarded; see GH-818. + // Once _Key is obtained, the amount of work should not be discarded (see GH-818). const auto _Range = _Basis._Get_chunk(_Key); for (auto _Candidate = _Range._First; _Candidate != _Range._Last; ++_Candidate) { @@ -2238,7 +2237,7 @@ struct _Static_partitioned_search_n2 { if (!_Key) { return _Cancellation_status::_Canceled; } - // Once _Key is obtained, the amount of work should not be discarded; see GH-818. + // Once _Key is obtained, the amount of work should not be discarded (see GH-818). const auto _Range = _Basis._Get_chunk(_Key); @@ -3069,7 +3068,7 @@ struct _Static_partitioned_is_sorted_until { if (!_Key) { return _Cancellation_status::_Canceled; } - // Once _Key is obtained, the amount of work should not be discarded; see GH-818. + // Once _Key is obtained, the amount of work should not be discarded (see GH-818). auto _Range = _Basis._Get_chunk(_Key); auto _Next = _Range._First; @@ -3184,7 +3183,7 @@ struct _Static_partitioned_is_partitioned { if (!_Key) { return _Cancellation_status::_Canceled; } - // Once _Key is obtained, the amount of work should not be discarded; see GH-818. + // Once _Key is obtained, the amount of work should not be discarded (see GH-818). // looking at chunks from either end, moving in towards the middle auto _Target_chunk_number = _Key._Chunk_number >> 1; @@ -3297,7 +3296,7 @@ struct _Static_partitioned_is_heap_until { if (!_Key) { return _Cancellation_status::_Canceled; } - // Once _Key is obtained, the amount of work should not be discarded; see GH-818. + // Once _Key is obtained, the amount of work should not be discarded (see GH-818). const auto _Chunk_range_size = _Key._Size; const auto _Chunk_offset = _Key._Start_at; diff --git a/stl/inc/filesystem b/stl/inc/filesystem index a2f4bd1dd09..948ac146e73 100644 --- a/stl/inc/filesystem +++ b/stl/inc/filesystem @@ -525,10 +525,10 @@ namespace filesystem { auto _Last = _First + _Str.size(); const auto _Relative_path = _Find_relative_path(_First, _Last); // case 1: relative-path ends in a directory-separator, remove the separator to remove "magic empty path" - // for example: R"(/foo/bar/\//\)" + // for example: R"(/cat/dog/\//\)" // case 2: relative-path doesn't end in a directory-separator, remove the filename and last directory-separator // to prevent creation of a "magic empty path" - // for example: "/foo/bar" + // for example: "/cat/dog" while (_Relative_path != _Last && !_Is_slash(_Last[-1])) { // handle case 2 by removing trailing filename, puts us into case 1 --_Last; @@ -769,12 +769,12 @@ namespace filesystem { path& operator/=(const path& _Other) { // set *this to the path lexically resolved by _Other relative to *this // examples: - // path("foo") / "c:/bar"; // yields "c:/bar" - // path("foo") / "c:"; // yields "c:" + // path("cat") / "c:/dog"; // yields "c:/dog" + // path("cat") / "c:"; // yields "c:" // path("c:") / ""; // yields "c:" - // path("c:foo") / "/bar"; // yields "c:/bar" - // path("c:foo") / "c:bar"; // yields "c:foo/bar" - // path("c:foo") / "d:bar"; // yields "d:bar" + // path("c:cat") / "/dog"; // yields "c:/dog" + // path("c:cat") / "c:dog"; // yields "c:cat/dog" + // path("c:cat") / "d:dog"; // yields "d:dog" // several places herein quote the standard, but the standard's variable p is replaced with _Other if (_Other.is_absolute()) { // if _Other.is_absolute(), then op=(_Other) @@ -814,8 +814,8 @@ namespace filesystem { // If there is a trailing slash not part of root_directory, then !has_filename, so only // (!has_root_directory && is_absolute) remains // Going through our root_name kinds: - // X:foo\ needs a root_directory to be absolute - // \\server\foo must have a root_directory to exist with a relative_path + // X:cat\ needs a root_directory to be absolute + // \\server\cat must have a root_directory to exist with a relative_path // \\?\ must have a root_directory to exist // As a result, the test fails if there is a trailing slash. // If there is no trailing slash, then has_filename, so the test passes. @@ -1235,7 +1235,7 @@ namespace filesystem { // all other paths are absolute const auto _First = _Text.data(); const auto _Last = _First + _Text.size(); - if (_Has_drive_letter_prefix(_First, _Last)) { // test for X:\ but not X:foo + if (_Has_drive_letter_prefix(_First, _Last)) { // test for X:\ but not X:cat return _Last - _First >= 3 && _Is_slash(_First[2]); } @@ -1642,11 +1642,11 @@ namespace filesystem { // calculate a hash value for _Path // See path::compare; we effectively decompose the path with special handling for root_name, root_directory. // Examples: - // c:\foo\bar => {"c:", true , "foo", "bar"} - // c:foo\bar => {"c:", false, "foo", "bar"} - // \foo\bar => {"" , true , "foo", "bar"} - // foo\bar => {"" , false, "foo", "bar"} - // c:\foo\bar\ => {"c:", true , "foo", "bar", ""} + // c:\cat\dog => {"c:", true , "cat", "dog"} + // c:cat\dog => {"c:", false, "cat", "dog"} + // \cat\dog => {"" , true , "cat", "dog"} + // cat\dog => {"" , false, "cat", "dog"} + // c:\cat\dog\ => {"c:", true , "cat", "dog", ""} size_t _Val = _FNV_offset_basis; const auto& _Text = _Path.native(); const auto _First = _Text.data(); @@ -1658,7 +1658,7 @@ namespace filesystem { // The remaining path elements, including root_directory, are effectively hashed by normalizing each // directory-separator into a single preferred-separator when that goes into the hash function. - // path::compare has special handling for root_directory to ensure c:\foo sorts before c:foo, but hash only + // path::compare has special handling for root_directory to ensure c:\cat sorts before c:cat, but hash only // cares about equality, so no special case is necessary. bool _Slash_inserted = false; for (; _Next != _Last; ++_Next) { @@ -2112,7 +2112,7 @@ namespace filesystem { // ALIAS file_time_type struct _File_time_clock { // Implementation of trivial-clock using rep = long long; - using period = ratio_multiply, nano>; + using period = chrono::system_clock::period; using duration = chrono::duration; using time_point = chrono::time_point<_File_time_clock>; @@ -3750,6 +3750,11 @@ namespace filesystem { // FUNCTION create_directories inline bool create_directories(const path& _Path, error_code& _Ec) { + if (_Path.empty()) { + _Ec = _Make_ec(__std_win_error::_Path_not_found); + return false; + } + _Ec.clear(); // for exception safety const wstring& _Text = _Path.native(); wstring _Tmp; @@ -3767,11 +3772,11 @@ namespace filesystem { _Cursor = _Root_path_end; // When creating directories, sometimes we get error reports on earlier directories. - // Consider a case like X:\foo\bar\baz, where we get the following errors: + // Consider a case like X:\cat\dog\elk, where we get the following errors: // X: ERROR_ACCESS_DENIED - // X:\foo ERROR_ALREADY_EXISTS - // X:\foo\bar ERROR_ACCESS_DENIED - // X:\foo\bar\baz ERROR_FILE_NOT_FOUND + // X:\cat ERROR_ALREADY_EXISTS + // X:\cat\dog ERROR_ACCESS_DENIED + // X:\cat\dog\elk ERROR_FILE_NOT_FOUND // Here, the previous access denied error prevented us from creating a parent directory, // and the subsequent ERROR_FILE_NOT_FOUND is not the interesting error for the user. // Therefore: diff --git a/stl/inc/functional b/stl/inc/functional index 05b969b5ef2..bfc928f5dd2 100644 --- a/stl/inc/functional +++ b/stl/inc/functional @@ -747,20 +747,11 @@ struct _Invoker_ret { // selected for _Rx being cv void template struct _Invoker_ret<_Rx, false> { // selected for all _Rx other than cv void and _Unforced -#ifdef __EDG__ // TRANSITION, VSO-1132186 - template class _Is_nothrow = _Select_invoke_traits<_Fx, _Valtys...>::template _Is_nothrow_invocable_r> - static _CONSTEXPR20 _Rx _Call(_Fx&& _Func, _Valtys&&... _Vals) noexcept(_Is_nothrow<_Rx>::value) { - // INVOKE, implicitly converted to _Rx - return _STD invoke(static_cast<_Fx&&>(_Func), static_cast<_Valtys&&>(_Vals)...); - } -#else // ^^^ workaround / no workaround vvv template static _CONSTEXPR20 _Rx _Call(_Fx&& _Func, _Valtys&&... _Vals) noexcept(_Select_invoke_traits<_Fx, _Valtys...>::template _Is_nothrow_invocable_r<_Rx>::value) { // INVOKE, implicitly converted to _Rx return _STD invoke(static_cast<_Fx&&>(_Func), static_cast<_Valtys&&>(_Vals)...); } -#endif // TRANSITION, VSO-1132186 }; template <> @@ -1472,24 +1463,6 @@ public: _Call_binder(_Invoker_ret<_Ret>{}, _Seq{}, _Mypair._Get_first(), _Mypair._Myval2, \ _STD forward_as_tuple(_STD forward<_Unbound>(_Unbargs)...)) -#ifdef __EDG__ // TRANSITION, VSO-1132105 - template - _CONSTEXPR20 auto operator()(_Unbound&&... _Unbargs) noexcept(noexcept(_Call_binder(_Invoker_ret<_Ret>{}, _Seq{}, - _STD declval<_First&>(), _STD declval<_Second&>(), _STD forward_as_tuple(_STD forward<_Unbound>(_Unbargs)...)))) - -> decltype(_Call_binder(_Invoker_ret<_Ret>{}, _Seq{}, _STD declval<_First&>(), _STD declval<_Second&>(), - _STD forward_as_tuple(_STD forward<_Unbound>(_Unbargs)...))) { - return _CALL_BINDER; - } - - template - _CONSTEXPR20 auto operator()(_Unbound&&... _Unbargs) const - noexcept(noexcept(_Call_binder(_Invoker_ret<_Ret>{}, _Seq{}, _STD declval(), - _STD declval(), _STD forward_as_tuple(_STD forward<_Unbound>(_Unbargs)...)))) - -> decltype(_Call_binder(_Invoker_ret<_Ret>{}, _Seq{}, _STD declval(), - _STD declval(), _STD forward_as_tuple(_STD forward<_Unbound>(_Unbargs)...))) { - return _CALL_BINDER; - } -#else // ^^^ workaround / no workaround vvv template _CONSTEXPR20 auto operator()(_Unbound&&... _Unbargs) noexcept(noexcept(_CALL_BINDER)) -> decltype(_CALL_BINDER) { return _CALL_BINDER; @@ -1500,7 +1473,6 @@ public: -> decltype(_CALL_BINDER) { return _CALL_BINDER; } -#endif // TRANSITION, VSO-1132105 #undef _CALL_BINDER }; @@ -1557,24 +1529,18 @@ constexpr auto _Call_front_binder(index_sequence<_Ix...>, _Cv_FD&& _Obj, _Cv_tup template class _Front_binder { // wrap bound callable object and arguments private: - static_assert(is_constructible_v, _Fx>, - "std::bind_front() requires the decayed callable to be constructible from an undecayed callable"); - static_assert(is_move_constructible_v>, - "std::bind_front() requires the decayed callable to be move constructible"); - static_assert(conjunction_v, _Types>...>, - "std::bind_front() requires the decayed bound arguments to be constructible from undecayed bound arguments"); - static_assert(conjunction_v>...>, - "std::bind_front() requires the decayed bound arguments to be move constructible"); + using _Seq = index_sequence_for<_Types...>; - using _Seq = index_sequence_for<_Types...>; - using _First = decay_t<_Fx>; - using _Second = tuple...>; + _Compressed_pair<_Fx, tuple<_Types...>> _Mypair; - _Compressed_pair<_First, _Second> _Mypair; + _STL_INTERNAL_STATIC_ASSERT(is_same_v<_Fx, decay_t<_Fx>>); + _STL_INTERNAL_STATIC_ASSERT((is_same_v<_Types, decay_t<_Types>> && ...)); public: - constexpr explicit _Front_binder(_Fx&& _Func, _Types&&... _Args) - : _Mypair(_One_then_variadic_args_t{}, _STD forward<_Fx>(_Func), _STD forward<_Types>(_Args)...) {} + template , _Front_binder>, int> = 0> + constexpr explicit _Front_binder(_FxInit&& _Func, _TypesInit&&... _Args) + : _Mypair(_One_then_variadic_args_t{}, _STD forward<_FxInit>(_Func), _STD forward<_TypesInit>(_Args)...) {} template constexpr auto operator()(_Unbound&&... _Unbargs) & noexcept(noexcept( @@ -1614,7 +1580,16 @@ public: // FUNCTION TEMPLATE bind_front template _NODISCARD constexpr auto bind_front(_Fx&& _Func, _Types&&... _Args) { - return _Front_binder<_Fx, _Types...>(_STD forward<_Fx>(_Func), _STD forward<_Types>(_Args)...); + static_assert(is_constructible_v, _Fx>, + "std::bind_front requires the decayed callable to be constructible from an undecayed callable"); + static_assert(is_move_constructible_v>, + "std::bind_front requires the decayed callable to be move constructible"); + static_assert(conjunction_v, _Types>...>, + "std::bind_front requires the decayed bound arguments to be constructible from undecayed bound arguments"); + static_assert(conjunction_v>...>, + "std::bind_front requires the decayed bound arguments to be move constructible"); + + return _Front_binder, decay_t<_Types>...>(_STD forward<_Fx>(_Func), _STD forward<_Types>(_Args)...); } #endif // _HAS_CXX20 diff --git a/stl/inc/iterator b/stl/inc/iterator index fa219671771..42b7bd52160 100644 --- a/stl/inc/iterator +++ b/stl/inc/iterator @@ -227,34 +227,38 @@ private: // CLASS TEMPLATE istream_iterator template , class _Diff = ptrdiff_t> -class istream_iterator { // wrap _Ty extracts from input stream as input iterator +class istream_iterator { public: using iterator_category = input_iterator_tag; using value_type = _Ty; using difference_type = _Diff; using pointer = const _Ty*; using reference = const _Ty&; - - using char_type = _Elem; - using traits_type = _Traits; - using istream_type = basic_istream<_Elem, _Traits>; + using char_type = _Elem; + using traits_type = _Traits; + using istream_type = basic_istream<_Elem, _Traits>; static_assert(conjunction_v, is_copy_constructible<_Ty>, is_copy_assignable<_Ty>>, "istream_iterator requires T to be default constructible, copy constructible, and copy assignable. " "(N4835 [istream.iterator]/2)"); - constexpr istream_iterator() {} + constexpr istream_iterator() noexcept(is_nothrow_default_constructible_v<_Ty>) /* strengthened */ {} + +#ifdef __cpp_lib_concepts + constexpr istream_iterator(default_sentinel_t) noexcept(is_nothrow_default_constructible_v<_Ty>) // strengthened + {} +#endif // __cpp_lib_concepts istream_iterator(istream_type& _Istr) : _Myistr(_STD addressof(_Istr)) { _Getval(); } - _NODISCARD const _Ty& operator*() const { + _NODISCARD const _Ty& operator*() const noexcept /* strengthened */ { _STL_ASSERT(_Myistr, "The stored stream pointer in_stream must be non-null"); return _Myval; } - _NODISCARD const _Ty* operator->() const { + _NODISCARD const _Ty* operator->() const noexcept /* strengthened */ { _STL_ASSERT(_Myistr, "The stored stream pointer in_stream must be non-null"); return _STD addressof(_Myval); } @@ -270,10 +274,16 @@ public: return _Tmp; } - bool _Equal(const istream_iterator& _Right) const { + _NODISCARD bool _Equal(const istream_iterator& _Right) const noexcept { return _Myistr == _Right._Myistr; } +#ifdef __cpp_lib_concepts + _NODISCARD friend bool operator==(const istream_iterator& _Left, default_sentinel_t) noexcept /* strengthened */ { + return !_Left._Myistr; + } +#endif // __cpp_lib_concepts + private: void _Getval() { // get a _Ty value if possible _STL_ASSERT(_Myistr, "The stored stream pointer in_stream must be non-null"); @@ -288,31 +298,38 @@ private: template _NODISCARD bool operator==(const istream_iterator<_Ty, _Elem, _Traits, _Diff>& _Left, - const istream_iterator<_Ty, _Elem, _Traits, _Diff>& _Right) { + const istream_iterator<_Ty, _Elem, _Traits, _Diff>& _Right) noexcept /* strengthened */ { return _Left._Equal(_Right); } template _NODISCARD bool operator!=(const istream_iterator<_Ty, _Elem, _Traits, _Diff>& _Left, - const istream_iterator<_Ty, _Elem, _Traits, _Diff>& _Right) { + const istream_iterator<_Ty, _Elem, _Traits, _Diff>& _Right) noexcept /* strengthened */ { return !(_Left == _Right); } // CLASS TEMPLATE ostream_iterator template > -class ostream_iterator { // wrap _Ty inserts to output stream as output iterator +class ostream_iterator { public: using iterator_category = output_iterator_tag; using value_type = void; - using difference_type = void; - using pointer = void; - using reference = void; - +#ifdef __cpp_lib_concepts + using difference_type = ptrdiff_t; +#else + using difference_type = void; +#endif + using pointer = void; + using reference = void; using char_type = _Elem; using traits_type = _Traits; using ostream_type = basic_ostream<_Elem, _Traits>; - ostream_iterator(ostream_type& _Ostr, const _Elem* const _Delim = nullptr) +#ifdef __cpp_lib_concepts + constexpr ostream_iterator() noexcept = default; +#endif // __cpp_lib_concepts + + ostream_iterator(ostream_type& _Ostr, const _Elem* const _Delim = nullptr) noexcept /* strengthened */ : _Mydelim(_Delim), _Myostr(_STD addressof(_Ostr)) {} ostream_iterator& operator=(const _Ty& _Val) { // insert value into output stream, followed by delimiter @@ -324,56 +341,59 @@ public: return *this; } - _NODISCARD ostream_iterator& operator*() { // pretend to return designated value + _NODISCARD ostream_iterator& operator*() noexcept /* strengthened */ { return *this; } - ostream_iterator& operator++() { // pretend to preincrement + ostream_iterator& operator++() noexcept /* strengthened */ { return *this; } - ostream_iterator& operator++(int) { // pretend to postincrement + ostream_iterator& operator++(int) noexcept /* strengthened */ { return *this; } -protected: - const _Elem* _Mydelim; // pointer to delimiter string (NB: not freed) - ostream_type* _Myostr; // pointer to output stream +private: + const _Elem* _Mydelim = nullptr; // pointer to delimiter string (NB: not freed) + ostream_type* _Myostr = nullptr; // pointer to output stream }; // CLASS TEMPLATE istreambuf_iterator template -class istreambuf_iterator { // wrap stream buffer as input iterator +class istreambuf_iterator { public: using iterator_category = input_iterator_tag; using value_type = _Elem; using difference_type = typename _Traits::off_type; using pointer = const _Elem*; using reference = _Elem; - - using char_type = _Elem; - using traits_type = _Traits; - using streambuf_type = basic_streambuf<_Elem, _Traits>; - using istream_type = basic_istream<_Elem, _Traits>; - - using int_type = typename traits_type::int_type; + using char_type = _Elem; + using traits_type = _Traits; + using int_type = typename traits_type::int_type; + using streambuf_type = basic_streambuf<_Elem, _Traits>; + using istream_type = basic_istream<_Elem, _Traits>; constexpr istreambuf_iterator() noexcept : _Strbuf(nullptr), _Got(true), _Val() {} - - istreambuf_iterator(streambuf_type* _Sb) noexcept : _Strbuf(_Sb), _Got(!_Sb), _Val() {} +#ifdef __cpp_lib_concepts + constexpr istreambuf_iterator(default_sentinel_t) noexcept : _Strbuf(nullptr), _Got(true), _Val() {} +#endif // __cpp_lib_concepts istreambuf_iterator(istream_type& _Istr) noexcept : _Strbuf(_Istr.rdbuf()), _Got(!_Strbuf), _Val() {} + istreambuf_iterator(streambuf_type* _Sb) noexcept : _Strbuf(_Sb), _Got(!_Sb), _Val() {} + private: class _Istreambuf_proxy { public: - _NODISCARD _Elem operator*() const { + _NODISCARD _Elem operator*() const noexcept(is_nothrow_copy_constructible_v<_Elem>) /* strengthened */ { return _Keep; } private: friend istreambuf_iterator; - _Istreambuf_proxy(streambuf_type* _Strbuf_, _Elem _Keep_) : _Strbuf(_Strbuf_), _Keep(_Keep_) {} + _Istreambuf_proxy(streambuf_type* _Strbuf_, _Elem _Keep_) noexcept( + is_nothrow_copy_constructible_v<_Elem>) // strengthened + : _Strbuf(_Strbuf_), _Keep(_Keep_) {} streambuf_type* _Strbuf; _Elem _Keep; @@ -425,6 +445,16 @@ public: return (!_Strbuf && !_Right._Strbuf) || (_Strbuf && _Right._Strbuf); } +#ifdef __cpp_lib_concepts + _NODISCARD friend bool operator==(const istreambuf_iterator& _Left, default_sentinel_t) { + if (!_Left._Got) { + _Left._Peek(); + } + + return !_Left._Strbuf; + } +#endif // __cpp_lib_concepts + private: void _Inc() { // skip to next input element if (!_Strbuf || traits_type::eq_int_type(traits_type::eof(), _Strbuf->sbumpc())) { @@ -466,22 +496,29 @@ _NODISCARD bool operator!=( // CLASS TEMPLATE ostreambuf_iterator template -class ostreambuf_iterator { // wrap stream buffer as output iterator +class ostreambuf_iterator { public: using iterator_category = output_iterator_tag; using value_type = void; - using difference_type = void; - using pointer = void; - using reference = void; - +#ifdef __cpp_lib_concepts + using difference_type = ptrdiff_t; +#else + using difference_type = void; +#endif + using pointer = void; + using reference = void; using char_type = _Elem; using traits_type = _Traits; using streambuf_type = basic_streambuf<_Elem, _Traits>; using ostream_type = basic_ostream<_Elem, _Traits>; - ostreambuf_iterator(streambuf_type* _Sb) noexcept : _Failed(false), _Strbuf(_Sb) {} +#ifdef __cpp_lib_concepts + constexpr ostreambuf_iterator() noexcept = default; +#endif // __cpp_lib_concepts + + ostreambuf_iterator(streambuf_type* _Sb) noexcept : _Strbuf(_Sb) {} - ostreambuf_iterator(ostream_type& _Ostr) noexcept : _Failed(false), _Strbuf(_Ostr.rdbuf()) {} + ostreambuf_iterator(ostream_type& _Ostr) noexcept : _Strbuf(_Ostr.rdbuf()) {} ostreambuf_iterator& operator=(_Elem _Right) { // store element and increment if (!_Strbuf || traits_type::eq_int_type(_Traits::eof(), _Strbuf->sputc(_Right))) { @@ -491,15 +528,15 @@ public: return *this; } - _NODISCARD ostreambuf_iterator& operator*() { // pretend to get designated element + _NODISCARD ostreambuf_iterator& operator*() noexcept /* strengthened */ { return *this; } - ostreambuf_iterator& operator++() { // pretend to preincrement + ostreambuf_iterator& operator++() noexcept /* strengthened */ { return *this; } - ostreambuf_iterator& operator++(int) { // pretend to postincrement + ostreambuf_iterator& operator++(int) noexcept /* strengthened */ { return *this; } @@ -508,8 +545,8 @@ public: } private: - bool _Failed; // true if any stores have failed - streambuf_type* _Strbuf; // the wrapped stream buffer + bool _Failed = false; // true if any stores have failed + streambuf_type* _Strbuf = nullptr; }; #ifdef __cpp_lib_concepts @@ -557,12 +594,12 @@ public: } } -#if 0 // TRANSITION, VSO-1174090 +#if 0 // TRANSITION, VSO-1225825 // clang-format off _Variantish(const _Variantish&) requires is_trivially_copy_constructible_v<_It> && is_trivially_copy_constructible_v<_Se> = default; // clang-format on -#endif // TRANSITION, VSO-1174090 +#endif // TRANSITION, VSO-1225825 _Variantish(const _Variantish& _That) noexcept( noexcept(is_nothrow_copy_constructible_v<_It>&& is_nothrow_copy_constructible_v<_Se>)) @@ -579,12 +616,12 @@ public: } } -#if 0 // TRANSITION, VSO-1174090 +#if 0 // TRANSITION, VSO-1225825 // clang-format off _Variantish(_Variantish&&) requires is_trivially_move_constructible_v<_It> && is_trivially_move_constructible_v<_Se> = default; // clang-format on -#endif // TRANSITION, VSO-1174090 +#endif // TRANSITION, VSO-1225825 _Variantish(_Variantish&& _That) noexcept( is_nothrow_move_constructible_v<_It>&& is_nothrow_move_constructible_v<_Se>) @@ -601,16 +638,17 @@ public: } } -#if 0 // TRANSITION, VSO-1174090 +#if 0 // TRANSITION, VSO-1225825 // clang-format off ~_Variantish() requires is_trivially_destructible_v<_It> && is_trivially_destructible_v<_Se> = default; // clang-format on -#endif // TRANSITION, VSO-1174090 +#endif // TRANSITION, VSO-1225825 + ~_Variantish() { _Raw_clear(); } -#if 0 // TRANSITION, VSO-1174090 +#if 0 // TRANSITION, VSO-1225825 // clang-format off _Variantish& operator=(const _Variantish&) requires is_trivially_destructible_v<_It> && is_trivially_destructible_v<_Se> @@ -619,7 +657,7 @@ public: && is_trivially_copy_assignable_v<_It> && is_trivially_copy_assignable_v<_Se> = default; // clang-format on -#endif // TRANSITION, VSO-1174090 +#endif // TRANSITION, VSO-1225825 _Variantish& operator=(const _Variantish& _That) noexcept( is_nothrow_copy_constructible_v<_It>&& is_nothrow_copy_constructible_v<_Se>&& @@ -657,7 +695,7 @@ public: return *this; } -#if 0 // TRANSITION, VSO-1174090 +#if 0 // TRANSITION, VSO-1225825 // clang-format off _Variantish& operator=(_Variantish&&) requires is_trivially_destructible_v<_It> && is_trivially_destructible_v<_Se> @@ -666,7 +704,7 @@ public: && is_trivially_move_assignable_v<_It> && is_trivially_move_assignable_v<_Se> = default; // clang-format on -#endif // TRANSITION, VSO-1174090 +#endif // TRANSITION, VSO-1225825 _Variantish& operator=(_Variantish&& _That) noexcept( is_nothrow_move_constructible_v<_It>&& is_nothrow_move_constructible_v<_Se>&& diff --git a/stl/inc/memory b/stl/inc/memory index 42ad7303c0e..eafeefd38b9 100644 --- a/stl/inc/memory +++ b/stl/inc/memory @@ -56,6 +56,72 @@ namespace ranges { concept _No_throw_forward_range = _No_throw_input_range<_Rng> && _No_throw_forward_iterator>; // clang-format on + + // ALIAS TEMPLATE uninitialized_copy_result + template + using uninitialized_copy_result = in_out_result<_In, _Out>; + + // VARIABLE ranges::uninitialized_copy + class _Uninitialized_copy_fn : private _Not_quite_object { + public: + using _Not_quite_object::_Not_quite_object; + + // clang-format off + template _Se, _No_throw_forward_iterator _Out, + _No_throw_sentinel_for<_Out> _OSe> + requires constructible_from, iter_reference_t<_It>> + uninitialized_copy_result<_It, _Out> operator()(_It _First1, _Se _Last1, _Out _First2, _OSe _Last2) const { + // clang-format on + _Adl_verify_range(_First1, _Last1); + _Adl_verify_range(_First2, _Last2); + auto _UResult = + _Uninitialized_copy_unchecked(_Get_unwrapped(_STD move(_First1)), _Get_unwrapped(_STD move(_Last1)), + _Get_unwrapped(_STD move(_First2)), _Get_unwrapped(_STD move(_Last2))); + + _Seek_wrapped(_First1, _STD move(_UResult.in)); + _Seek_wrapped(_First2, _STD move(_UResult.out)); + return {_STD move(_First1), _STD move(_First2)}; + } + + // clang-format off + template + requires constructible_from, range_reference_t<_Rng1>> + uninitialized_copy_result, borrowed_iterator_t<_Rng2>> operator()( + _Rng1&& _Range1, _Rng2&& _Range2) const { + // clang-format on + auto _First1 = _RANGES begin(_Range1); + auto _UResult = _Uninitialized_copy_unchecked( + _Get_unwrapped(_STD move(_First1)), _Uend(_Range1), _Ubegin(_Range2), _Uend(_Range2)); + + _Seek_wrapped(_First1, _STD move(_UResult.in)); + return {_STD move(_First1), _Rewrap_iterator(_Range2, _STD move(_UResult.out))}; + } + + private: + template + _NODISCARD static uninitialized_copy_result<_It, _Out> _Uninitialized_copy_unchecked( + _It _IFirst, const _Se _ILast, _Out _OFirst, const _OSe _OLast) { + _STL_INTERNAL_STATIC_ASSERT(input_iterator<_It>); + _STL_INTERNAL_STATIC_ASSERT(sentinel_for<_Se, _It>); + _STL_INTERNAL_STATIC_ASSERT(_No_throw_forward_iterator<_Out>); + _STL_INTERNAL_STATIC_ASSERT(_No_throw_sentinel_for<_OSe, _Out>); + _STL_INTERNAL_STATIC_ASSERT(constructible_from, iter_reference_t<_It>>); + + if constexpr (is_same_v<_Se, _It> && _Ptr_copy_cat<_It, _Out>::_Really_trivial) { + return _Copy_memcpy_common(_IFirst, _ILast, _OFirst, _OLast); + } else { + _Uninitialized_backout _Backout{_STD move(_OFirst)}; + + for (; _IFirst != _ILast && _Backout._Last != _OLast; ++_IFirst) { + _Backout._Emplace_back(*_IFirst); + } + + return {_STD move(_IFirst), _Backout._Release()}; + } + } + }; + + inline constexpr _Uninitialized_copy_fn uninitialized_copy{_Not_quite_object::_Construct_tag{}}; } // namespace ranges #endif // __cpp_lib_concepts @@ -65,23 +131,25 @@ template _NoThrowFwdIt uninitialized_copy_n(const _InIt _First, const _Diff _Count_raw, _NoThrowFwdIt _Dest) { // copy [_First, _First + _Count) to [_Dest, ...) _Algorithm_int_t<_Diff> _Count = _Count_raw; - if (0 < _Count) { - auto _UFirst = _Get_unwrapped_n(_First, _Count); - auto _UDest = _Get_unwrapped_n(_Dest, _Count); - if constexpr (_Ptr_copy_cat::_Really_trivial) { - _UDest = _Copy_memmove(_UFirst, _UFirst + _Count, _UDest); - } else { - _Uninitialized_backout _Backout{_UDest}; - for (; 0 < _Count; --_Count, (void) ++_UFirst) { - _Backout._Emplace_back(*_UFirst); - } + if (_Count <= 0) { + return _Dest; + } - _UDest = _Backout._Release(); + auto _UFirst = _Get_unwrapped_n(_First, _Count); + auto _UDest = _Get_unwrapped_n(_Dest, _Count); + if constexpr (_Ptr_copy_cat::_Really_trivial) { + _UDest = _Copy_memmove(_UFirst, _UFirst + _Count, _UDest); + } else { + _Uninitialized_backout _Backout{_UDest}; + + for (; _Count > 0; --_Count, (void) ++_UFirst) { + _Backout._Emplace_back(*_UFirst); } - _Seek_wrapped(_Dest, _UDest); + _UDest = _Backout._Release(); } + _Seek_wrapped(_Dest, _UDest); return _Dest; } #else // ^^^ _HAS_IF_CONSTEXPR / !_HAS_IF_CONSTEXPR vvv @@ -89,7 +157,8 @@ template _NoThrowFwdIt _Uninitialized_copy_n_unchecked2(_InIt _First, _Diff _Count, const _NoThrowFwdIt _Dest, false_type) { // copy [_First, _First + _Count) to [_Dest, ...), no special optimization _Uninitialized_backout<_NoThrowFwdIt> _Backout{_Dest}; - for (; 0 < _Count; --_Count, (void) ++_First) { + + for (; _Count > 0; --_Count, (void) ++_First) { _Backout._Emplace_back(*_First); } @@ -106,17 +175,65 @@ template _NoThrowFwdIt uninitialized_copy_n(const _InIt _First, const _Diff _Count_raw, _NoThrowFwdIt _Dest) { // copy [_First, _First + _Count) to [_Dest, ...)] _Algorithm_int_t<_Diff> _Count = _Count_raw; - if (0 < _Count) { - auto _UFirst = _Get_unwrapped_n(_First, _Count); - auto _UDest = _Get_unwrapped_n(_Dest, _Count); - _Seek_wrapped(_Dest, _Uninitialized_copy_n_unchecked2(_UFirst, _Count, _UDest, - bool_constant<_Ptr_copy_cat::_Really_trivial>{})); + if (_Count <= 0) { + return _Dest; } + auto _UFirst = _Get_unwrapped_n(_First, _Count); + auto _UDest = _Get_unwrapped_n(_Dest, _Count); + _Seek_wrapped(_Dest, _Uninitialized_copy_n_unchecked2(_UFirst, _Count, _UDest, + bool_constant<_Ptr_copy_cat::_Really_trivial>{})); return _Dest; } #endif // _HAS_IF_CONSTEXPR +#ifdef __cpp_lib_concepts +namespace ranges { + // ALIAS TEMPLATE uninitialized_copy_n_result + template + using uninitialized_copy_n_result = in_out_result<_In, _Out>; + + // VARIABLE ranges::uninitialized_copy_n + class _Uninitialized_copy_n_fn : private _Not_quite_object { + public: + using _Not_quite_object::_Not_quite_object; + + // clang-format off + template _OSe> + requires constructible_from, iter_reference_t<_It>> + uninitialized_copy_n_result<_It, _Out> operator()( + _It _First1, iter_difference_t<_It> _Count, _Out _First2, _OSe _Last2) const { + // clang-format on + if (_Count <= 0) { + return {_STD move(_First1), _STD move(_First2)}; + } + + _Adl_verify_range(_First2, _Last2); + auto _IFirst = _Get_unwrapped_n(_STD move(_First1), _Count); + auto _OFirst = _Get_unwrapped(_STD move(_First2)); + const auto _OLast = _Get_unwrapped(_STD move(_Last2)); + if constexpr (_Ptr_copy_cat<_It, _Out>::_Really_trivial) { + _OFirst = _Copy_memcpy_common(_IFirst, _IFirst + _Count, _OFirst, _OLast); + } else { + _Uninitialized_backout _Backout{_STD move(_OFirst)}; + + for (; _Count > 0 && _OFirst != _OLast; --_Count, (void) ++_IFirst) { + _Backout._Emplace_back(*_IFirst); + } + + _OFirst = _Backout._Release(); + } + + _Seek_wrapped(_First1, _IFirst); + _Seek_wrapped(_First2, _OFirst); + return {_STD move(_First1), _STD move(_First2)}; + } + }; + + inline constexpr _Uninitialized_copy_n_fn uninitialized_copy_n{_Not_quite_object::_Construct_tag{}}; +} // namespace ranges +#endif // __cpp_lib_concepts + #if _HAS_CXX17 // FUNCTION TEMPLATE uninitialized_move template @@ -142,10 +259,10 @@ namespace ranges { using _Not_quite_object::_Not_quite_object; // clang-format off - template _Se1, _No_throw_forward_iterator _It2, - _No_throw_sentinel_for<_It2> _Se2> - requires constructible_from, iter_rvalue_reference_t<_It1>> - uninitialized_move_result<_It1, _It2> operator()(_It1 _First1, _Se1 _Last1, _It2 _First2, _Se2 _Last2) const { + template _Se, _No_throw_forward_iterator _Out, + _No_throw_sentinel_for<_Out> _OSe> + requires constructible_from, iter_rvalue_reference_t<_It>> + uninitialized_move_result<_It, _Out> operator()(_It _First1, _Se _Last1, _Out _First2, _OSe _Last2) const { // clang-format on _Adl_verify_range(_First1, _Last1); _Adl_verify_range(_First2, _Last2); @@ -173,22 +290,26 @@ namespace ranges { } private: - template - _NODISCARD static uninitialized_move_result<_It1, _It2> _Uninitialized_move_unchecked( - _It1 _IFirst, const _Se1 _ILast, _It2 _OFirst, const _Se2 _OLast) { - _STL_INTERNAL_STATIC_ASSERT(input_iterator<_It1>); - _STL_INTERNAL_STATIC_ASSERT(sentinel_for<_Se1, _It1>); - _STL_INTERNAL_STATIC_ASSERT(_No_throw_forward_iterator<_It2>); - _STL_INTERNAL_STATIC_ASSERT(_No_throw_sentinel_for<_Se2, _It2>); - _STL_INTERNAL_STATIC_ASSERT(constructible_from, iter_rvalue_reference_t<_It1>>); - - _Uninitialized_backout _Backout{_STD move(_OFirst)}; - - for (; _IFirst != _ILast && _Backout._Last != _OLast; ++_IFirst) { - _Backout._Emplace_back(_RANGES iter_move(_IFirst)); - } + template + _NODISCARD static uninitialized_move_result<_It, _Out> _Uninitialized_move_unchecked( + _It _IFirst, const _Se _ILast, _Out _OFirst, const _OSe _OLast) { + _STL_INTERNAL_STATIC_ASSERT(input_iterator<_It>); + _STL_INTERNAL_STATIC_ASSERT(sentinel_for<_Se, _It>); + _STL_INTERNAL_STATIC_ASSERT(_No_throw_forward_iterator<_Out>); + _STL_INTERNAL_STATIC_ASSERT(_No_throw_sentinel_for<_OSe, _Out>); + _STL_INTERNAL_STATIC_ASSERT(constructible_from, iter_rvalue_reference_t<_It>>); + + if constexpr (is_same_v<_Se, _It> && _Ptr_move_cat<_It, _Out>::_Really_trivial) { + return _Copy_memcpy_common(_IFirst, _ILast, _OFirst, _OLast); + } else { + _Uninitialized_backout _Backout{_STD move(_OFirst)}; + + for (; _IFirst != _ILast && _Backout._Last != _OLast; ++_IFirst) { + _Backout._Emplace_back(_RANGES iter_move(_IFirst)); + } - return {_STD move(_IFirst), _Backout._Release()}; + return {_STD move(_IFirst), _Backout._Release()}; + } } }; @@ -201,52 +322,156 @@ template pair<_InIt, _NoThrowFwdIt> uninitialized_move_n(_InIt _First, const _Diff _Count_raw, _NoThrowFwdIt _Dest) { // move [_First, _First + _Count) to [_Dest, ...) _Algorithm_int_t<_Diff> _Count = _Count_raw; - if (0 < _Count) { - auto _UFirst = _Get_unwrapped_n(_First, _Count); - auto _UDest = _Get_unwrapped_n(_Dest, _Count); - if constexpr (_Ptr_move_cat::_Really_trivial) { - _UDest = _Copy_memmove(_UFirst, _UFirst + _Count, _UDest); - _UFirst += _Count; - } else { - _Uninitialized_backout _Backout{_UDest}; - for (; 0 < _Count; --_Count, (void) ++_UFirst) { - _Backout._Emplace_back(_STD move(*_UFirst)); - } + if (_Count <= 0) { + return {_First, _Dest}; + } - _UDest = _Backout._Release(); + auto _UFirst = _Get_unwrapped_n(_First, _Count); + auto _UDest = _Get_unwrapped_n(_Dest, _Count); + if constexpr (_Ptr_move_cat::_Really_trivial) { + _UDest = _Copy_memmove(_UFirst, _UFirst + _Count, _UDest); + _UFirst += _Count; + } else { + _Uninitialized_backout _Backout{_UDest}; + + for (; _Count > 0; --_Count, (void) ++_UFirst) { + _Backout._Emplace_back(_STD move(*_UFirst)); } - _Seek_wrapped(_Dest, _UDest); - _Seek_wrapped(_First, _UFirst); + _UDest = _Backout._Release(); } + _Seek_wrapped(_Dest, _UDest); + _Seek_wrapped(_First, _UFirst); return {_First, _Dest}; } #endif // _HAS_CXX17 + +#ifdef __cpp_lib_concepts +namespace ranges { + // ALIAS TEMPLATE uninitialized_move_n_result + template + using uninitialized_move_n_result = in_out_result<_In, _Out>; + + // VARIABLE ranges::uninitialized_move_n + class _Uninitialized_move_n_fn : private _Not_quite_object { + public: + using _Not_quite_object::_Not_quite_object; + + // clang-format off + template _OSe> + requires constructible_from, iter_rvalue_reference_t<_It>> + uninitialized_move_n_result<_It, _Out> operator()( + _It _First1, iter_difference_t<_It> _Count, _Out _First2, _OSe _Last2) const { + // clang-format on + if (_Count <= 0) { + return {_STD move(_First1), _STD move(_First2)}; + } + + _Adl_verify_range(_First2, _Last2); + auto _IFirst = _Get_unwrapped_n(_STD move(_First1), _Count); + auto _OFirst = _Get_unwrapped(_STD move(_First2)); + const auto _OLast = _Get_unwrapped(_STD move(_Last2)); + if constexpr (_Ptr_move_cat<_It, _Out>::_Really_trivial) { + _OFirst = _Copy_memcpy_common(_IFirst, _IFirst + _Count, _OFirst, _OLast); + } else { + _Uninitialized_backout _Backout{_STD move(_OFirst)}; + + for (; _Count > 0 && _Backout._Last != _OLast; --_Count, (void) ++_IFirst) { + _Backout._Emplace_back(_RANGES iter_move(_IFirst)); + } + + _OFirst = _Backout._Release(); + } + + _Seek_wrapped(_First1, _IFirst); + _Seek_wrapped(_First2, _OFirst); + return {_STD move(_First1), _STD move(_First2)}; + } + }; + + inline constexpr _Uninitialized_move_n_fn uninitialized_move_n{_Not_quite_object::_Construct_tag{}}; + + // VARIABLE ranges::uninitialized_fill + class _Uninitialized_fill_fn : private _Not_quite_object { + public: + using _Not_quite_object::_Not_quite_object; + + // clang-format off + template <_No_throw_forward_iterator _It, _No_throw_sentinel_for<_It> _Se, class _Ty> + requires constructible_from, const _Ty&> + _It operator()(_It _First, _Se _Last, const _Ty& _Val) const { + // clang-format on + _Adl_verify_range(_First, _Last); + auto _UResult = _Uninitialized_fill_unchecked( + _Get_unwrapped(_STD move(_First)), _Get_unwrapped(_STD move(_Last)), _Val); + + _Seek_wrapped(_First, _STD move(_UResult)); + return _First; + } + + // clang-format off + template <_No_throw_forward_range _Rng, class _Ty> + requires constructible_from, const _Ty&> + borrowed_iterator_t<_Rng> operator()(_Rng&& _Range, const _Ty& _Val) const { + // clang-format on + return _Rewrap_iterator(_Range, _Uninitialized_fill_unchecked(_Ubegin(_Range), _Uend(_Range), _Val)); + } + + private: + template + _NODISCARD static _It _Uninitialized_fill_unchecked(_It _OFirst, const _Se _OLast, const _Ty& _Val) { + _STL_INTERNAL_STATIC_ASSERT(_No_throw_forward_iterator<_It>); + _STL_INTERNAL_STATIC_ASSERT(_No_throw_sentinel_for<_Se, _It>); + _STL_INTERNAL_STATIC_ASSERT(constructible_from, const _Ty&>); + + if constexpr (_Fill_memset_is_safe<_It, _Ty>) { + const auto _OFinal = _RANGES next(_OFirst, _STD move(_OLast)); + const auto _Diff = static_cast(_OFinal - _OFirst); + _Fill_memset(_OFirst, _Val, _Diff); + return _OFinal; + } else { + _Uninitialized_backout _Backout{_STD move(_OFirst)}; + + while (_Backout._Last != _OLast) { + _Backout._Emplace_back(_Val); + } + + return _Backout._Release(); + } + } + }; + + inline constexpr _Uninitialized_fill_fn uninitialized_fill{_Not_quite_object::_Construct_tag{}}; +} // namespace ranges +#endif // __cpp_lib_concepts + // FUNCTION TEMPLATE uninitialized_fill_n #if _HAS_IF_CONSTEXPR template _NoThrowFwdIt uninitialized_fill_n(_NoThrowFwdIt _First, const _Diff _Count_raw, const _Tval& _Val) { // copy _Count copies of _Val to raw _First _Algorithm_int_t<_Diff> _Count = _Count_raw; - if (0 < _Count) { - auto _UFirst = _Get_unwrapped_n(_First, _Count); - if constexpr (_Fill_memset_is_safe<_Unwrapped_n_t, _Tval>) { - _Fill_memset(_UFirst, _Val, _Count); - _UFirst += _Count; - } else { - _Uninitialized_backout<_Unwrapped_n_t> _Backout{_UFirst}; - for (; 0 < _Count; --_Count) { - _Backout._Emplace_back(_Val); - } + if (_Count <= 0) { + return _First; + } - _UFirst = _Backout._Release(); + auto _UFirst = _Get_unwrapped_n(_First, _Count); + if constexpr (_Fill_memset_is_safe<_Unwrapped_n_t, _Tval>) { + _Fill_memset(_UFirst, _Val, static_cast(_Count)); + _UFirst += _Count; + } else { + _Uninitialized_backout<_Unwrapped_n_t> _Backout{_UFirst}; + + for (; _Count > 0; --_Count) { + _Backout._Emplace_back(_Val); } - _Seek_wrapped(_First, _UFirst); + _UFirst = _Backout._Release(); } + _Seek_wrapped(_First, _UFirst); return _First; } #else // ^^^ _HAS_IF_CONSTEXPR // !_HAS_IF_CONSTEXPR vvv @@ -255,7 +480,7 @@ _NoThrowFwdIt _Uninitialized_fill_n_unchecked1( const _NoThrowFwdIt _First, _Diff _Count, const _Tval& _Val, false_type) { // copy _Count copies of _Val to raw _First, no special optimization _Uninitialized_backout<_NoThrowFwdIt> _Backout{_First}; - for (; 0 < _Count; --_Count) { + for (; _Count > 0; --_Count) { _Backout._Emplace_back(_Val); } @@ -274,37 +499,132 @@ template _NoThrowFwdIt uninitialized_fill_n(_NoThrowFwdIt _First, const _Diff _Count_raw, const _Tval& _Val) { // copy _Count copies of _Val to raw _First _Algorithm_int_t<_Diff> _Count = _Count_raw; - if (0 < _Count) { - auto _UFirst = _Get_unwrapped_n(_STD move(_First), _Count); - _Seek_wrapped(_First, _Uninitialized_fill_n_unchecked1(_STD move(_UFirst), _Count, _Val, - bool_constant<_Fill_memset_is_safe<_Unwrapped_t<_NoThrowFwdIt>, _Tval>>{})); + if (_Count <= 0) { + return _First; } + auto _UFirst = _Get_unwrapped_n(_STD move(_First), _Count); + _Seek_wrapped(_First, _Uninitialized_fill_n_unchecked1(_STD move(_UFirst), _Count, _Val, + bool_constant<_Fill_memset_is_safe<_Unwrapped_t<_NoThrowFwdIt>, _Tval>>{})); return _First; } #endif // _HAS_IF_CONSTEXPR +#ifdef __cpp_lib_concepts +namespace ranges { + // VARIABLE ranges::uninitialized_fill_n + class _Uninitialized_fill_n_fn : private _Not_quite_object { + public: + using _Not_quite_object::_Not_quite_object; + + // clang-format off + template <_No_throw_forward_iterator _It, class _Ty> + requires constructible_from, const _Ty&> + _It operator()(_It _First, iter_difference_t<_It> _Count, const _Ty& _Val) const { + // clang-format on + if (_Count <= 0) { + return _First; + } + + auto _UFirst = _Get_unwrapped_n(_STD move(_First), _Count); + if constexpr (_Fill_memset_is_safe<_It, _Ty>) { + _Fill_memset(_UFirst, _Val, static_cast(_Count)); + _Seek_wrapped(_First, _UFirst + _Count); + } else { + _Uninitialized_backout _Backout{_STD move(_UFirst)}; + + for (; _Count > 0; --_Count) { + _Backout._Emplace_back(_Val); + } + + _Seek_wrapped(_First, _Backout._Release()); + } + return _First; + } + }; + + inline constexpr _Uninitialized_fill_n_fn uninitialized_fill_n{_Not_quite_object::_Construct_tag{}}; +} // namespace ranges +#endif // __cpp_lib_concepts + +// FUNCTION TEMPLATE construct_at #if _HAS_CXX20 template -auto construct_at(_Ty* const _Location, _Types&&... _Args) noexcept(noexcept(::new (const_cast( - static_cast(_Location))) _Ty(_STD forward<_Types>(_Args)...))) // strengthened +_CONSTEXPR20_DYNALLOC auto construct_at(_Ty* const _Location, _Types&&... _Args) noexcept( + noexcept(::new (const_cast(static_cast(_Location))) + _Ty(_STD forward<_Types>(_Args)...))) // strengthened -> decltype( ::new (const_cast(static_cast(_Location))) _Ty(_STD forward<_Types>(_Args)...)) { return ::new (const_cast(static_cast(_Location))) _Ty(_STD forward<_Types>(_Args)...); } +#ifdef __cpp_lib_concepts namespace ranges { - using _STD construct_at; + // VARIABLE ranges::construct_at + class _Construct_at_fn : private _Not_quite_object { + public: + using _Not_quite_object::_Not_quite_object; + + // clang-format off + template + requires requires(void* _Void_ptr, _Types&&... _Args) { + ::new (_Void_ptr) _Ty(static_cast<_Types&&>(_Args)...); + } + _CONSTEXPR20_DYNALLOC _Ty* operator()(_Ty* _Location, _Types&&... _Args) const + noexcept(noexcept(::new (const_cast(static_cast(_Location))) + _Ty(_STD forward<_Types>(_Args)...))) /* strengthened */ { + // clang-format on + return ::new (const_cast(static_cast(_Location))) + _Ty(_STD forward<_Types>(_Args)...); + } + }; + + inline constexpr _Construct_at_fn construct_at{_Not_quite_object::_Construct_tag{}}; } // namespace ranges +#endif // __cpp_lib_concepts #endif // _HAS_CXX20 #if _HAS_CXX17 // FUNCTION TEMPLATE destroy_at template -void destroy_at(_Ty* const _Location) noexcept /* strengthened */ { - _Location->~_Ty(); +_CONSTEXPR20_DYNALLOC void destroy_at(_Ty* const _Location) noexcept /* strengthened */ { +#if _HAS_CXX20 + if constexpr (is_array_v<_Ty>) { + _Destroy_range(_STD begin(*_Location), _STD end(*_Location)); + } else +#endif // _HAS_CXX20 + { + _Location->~_Ty(); + } } +#ifdef __cpp_lib_concepts +namespace ranges { + // VARIABLE ranges::destroy_at + // clang-format off + template <_No_throw_input_iterator _It, _No_throw_sentinel_for<_It> _Se> + requires destructible> + _NODISCARD _CONSTEXPR20_DYNALLOC _It _Destroy_unchecked(_It _First, _Se _Last) noexcept; + // clang-format on + + class _Destroy_at_fn : private _Not_quite_object { + public: + using _Not_quite_object::_Not_quite_object; + + template + _CONSTEXPR20_DYNALLOC void operator()(_Ty* const _Location) const noexcept { + if constexpr (is_array_v<_Ty>) { + (void) _RANGES _Destroy_unchecked(_RANGES begin(*_Location), _RANGES end(*_Location)); + } else { + _Location->~_Ty(); + } + } + }; + + inline constexpr _Destroy_at_fn destroy_at{_Not_quite_object::_Construct_tag{}}; +} // namespace ranges +#endif // __cpp_lib_concepts + // FUNCTION TEMPLATE destroy template void destroy(const _NoThrowFwdIt _First, const _NoThrowFwdIt _Last) { // destroy all elements in [_First, _Last) @@ -312,68 +632,258 @@ void destroy(const _NoThrowFwdIt _First, const _NoThrowFwdIt _Last) { // destroy _Destroy_range(_Get_unwrapped(_First), _Get_unwrapped(_Last)); } +#ifdef __cpp_lib_concepts +namespace ranges { + // VARIABLE ranges::destroy + // clang-format off + template <_No_throw_input_iterator _It, _No_throw_sentinel_for<_It> _Se> + requires destructible> + _NODISCARD _CONSTEXPR20_DYNALLOC _It _Destroy_unchecked(_It _First, const _Se _Last) noexcept { + // clang-format on + for (; _First != _Last; ++_First) { + _RANGES destroy_at(_STD addressof(*_First)); + } + + return _First; + } + + class _Destroy_fn : private _Not_quite_object { + public: + using _Not_quite_object::_Not_quite_object; + + // clang-format off + template <_No_throw_input_iterator _It, _No_throw_sentinel_for<_It> _Se> + requires destructible> + /* _CONSTEXPR20_DYNALLOC */ _It operator()(_It _First, _Se _Last) const noexcept { + // clang-format on + _Adl_verify_range(_First, _Last); + _Seek_wrapped(_First, + _RANGES _Destroy_unchecked(_Get_unwrapped(_STD move(_First)), _Get_unwrapped(_STD move(_Last)))); + return _First; + } + + // clang-format off + template <_No_throw_input_range _Rng> + requires destructible> + /* _CONSTEXPR20_DYNALLOC */ borrowed_iterator_t<_Rng> operator()(_Rng&& _Range) const noexcept { + // clang-format on + auto _First = _RANGES begin(_Range); + _Seek_wrapped(_First, _RANGES _Destroy_unchecked(_Get_unwrapped(_STD move(_First)), _Uend(_Range))); + return _First; + } + }; + + inline constexpr _Destroy_fn destroy{_Not_quite_object::_Construct_tag{}}; +} // namespace ranges +#endif // __cpp_lib_concepts + // FUNCTION TEMPLATE destroy_n template _NoThrowFwdIt destroy_n(_NoThrowFwdIt _First, const _Diff _Count_raw) { // destroy all elements in [_First, _First + _Count) _Algorithm_int_t<_Diff> _Count = _Count_raw; - if (0 < _Count) { - auto _UFirst = _Get_unwrapped_n(_First, _Count); - if constexpr (is_trivially_destructible_v<_Iter_value_t<_NoThrowFwdIt>>) { - _STD advance(_UFirst, _Count); - } else { - do { - _Destroy_in_place(*_UFirst); - ++_UFirst; - --_Count; - } while (0 < _Count); - } + if (_Count <= 0) { + return _First; + } - _Seek_wrapped(_First, _UFirst); + auto _UFirst = _Get_unwrapped_n(_First, _Count); + if constexpr (is_trivially_destructible_v<_Iter_value_t<_NoThrowFwdIt>>) { + _STD advance(_UFirst, _Count); + } else { + for (; _Count > 0; --_Count, (void) ++_UFirst) { + _Destroy_in_place(*_UFirst); + } } + _Seek_wrapped(_First, _UFirst); return _First; } +#ifdef __cpp_lib_concepts +namespace ranges { + // VARIABLE ranges::destroy_n + class _Destroy_n_fn : private _Not_quite_object { + public: + using _Not_quite_object::_Not_quite_object; + + // clang-format off + template <_No_throw_input_iterator _It> + requires destructible> + /* _CONSTEXPR20_DYNALLOC */ _It operator()(_It _First, const iter_difference_t<_It> _Count) const noexcept { + // clang-format on + if (_Count <= 0) { + return _First; + } + + auto _UFirst = _Get_unwrapped_n(_STD move(_First), _Count); + if constexpr (is_trivially_destructible_v>) { + _RANGES advance(_UFirst, _Count); + } else { + do { + _RANGES destroy_at(_STD addressof(*_UFirst)); + ++_UFirst; + --_Count; + } while (_Count > 0); + } + + _Seek_wrapped(_First, _STD move(_UFirst)); + return _First; + } + }; + + inline constexpr _Destroy_n_fn destroy_n{_Not_quite_object::_Construct_tag{}}; +} // namespace ranges +#endif // __cpp_lib_concepts + // FUNCTION TEMPLATE uninitialized_default_construct +template +_NODISCARD void* _Voidify_iter(_Iter _It) noexcept { + return const_cast(static_cast(_STD addressof(*_It))); +} + template void uninitialized_default_construct(const _NoThrowFwdIt _First, const _NoThrowFwdIt _Last) { // default-initialize all elements in [_First, _Last) - using _Ty = _Iter_value_t<_NoThrowFwdIt>; + using _Ty = remove_reference_t<_Iter_ref_t<_NoThrowFwdIt>>; _Adl_verify_range(_First, _Last); if constexpr (!is_trivially_default_constructible_v<_Ty>) { - const auto _ULast = _Get_unwrapped(_Last); _Uninitialized_backout _Backout{_Get_unwrapped(_First)}; - for (; _Backout._Last != _ULast; ++_Backout._Last) { - ::new (static_cast(_Unfancy(_Backout._Last))) _Ty; + + for (const auto _ULast = _Get_unwrapped(_Last); _Backout._Last != _ULast; ++_Backout._Last) { + ::new (_Voidify_iter(_Backout._Last)) _Ty; } _Backout._Release(); } } +#ifdef __cpp_lib_concepts +namespace ranges { + // VARIABLE ranges::uninitialized_default_construct + class _Uninitialized_default_construct_fn : private _Not_quite_object { + public: + using _Not_quite_object::_Not_quite_object; + + // clang-format off + template <_No_throw_forward_iterator _It, _No_throw_sentinel_for<_It> _Se> + requires default_initializable> + _It operator()(_It _First, _Se _Last) const { + // clang-format on + _Adl_verify_range(_First, _Last); + auto _UResult = _Uninitialized_default_construct_unchecked( + _Get_unwrapped(_STD move(_First)), _Get_unwrapped(_STD move(_Last))); + + _Seek_wrapped(_First, _STD move(_UResult)); + return _First; + } + + // clang-format off + template <_No_throw_forward_range _Rng> + requires default_initializable> + borrowed_iterator_t<_Rng> operator()(_Rng&& _Range) const { + // clang-format on + auto _UResult = _Uninitialized_default_construct_unchecked(_Ubegin(_Range), _Uend(_Range)); + + return _Rewrap_iterator(_Range, _STD move(_UResult)); + } + + private: + template + _NODISCARD static _It _Uninitialized_default_construct_unchecked(_It _OFirst, const _Se _OLast) { + _STL_INTERNAL_STATIC_ASSERT(_No_throw_forward_iterator<_It>); + _STL_INTERNAL_STATIC_ASSERT(_No_throw_sentinel_for<_Se, _It>); + _STL_INTERNAL_STATIC_ASSERT(default_initializable>); + + using _Ty = remove_reference_t>; + if constexpr (is_trivially_default_constructible_v<_Ty>) { + _RANGES advance(_OFirst, _OLast); + return _OFirst; + } else { + _Uninitialized_backout _Backout{_STD move(_OFirst)}; + + for (; _Backout._Last != _OLast; ++_Backout._Last) { + ::new (_Voidify_iter(_Backout._Last)) _Ty; + } + + return _Backout._Release(); + } + } + }; + + inline constexpr _Uninitialized_default_construct_fn uninitialized_default_construct{ + _Not_quite_object::_Construct_tag{}}; +} // namespace ranges +#endif // __cpp_lib_concepts + // FUNCTION TEMPLATE uninitialized_default_construct_n template _NoThrowFwdIt uninitialized_default_construct_n(_NoThrowFwdIt _First, const _Diff _Count_raw) { // default-initialize all elements in [_First, _First + _Count_raw) using _Ty = _Iter_value_t<_NoThrowFwdIt>; _Algorithm_int_t<_Diff> _Count = _Count_raw; - if (0 < _Count) { - if constexpr (is_trivially_default_constructible_v<_Ty>) { - _STD advance(_First, _Count); - } else { - _Uninitialized_backout _Backout{_Get_unwrapped_n(_First, _Count)}; - for (; 0 < _Count; ++_Backout._Last, (void) --_Count) { - ::new (static_cast(_Unfancy(_Backout._Last))) _Ty; - } + if (_Count <= 0) { + return _First; + } + + if constexpr (is_trivially_default_constructible_v<_Ty>) { + _STD advance(_First, _Count); + } else { + _Uninitialized_backout _Backout{_Get_unwrapped_n(_First, _Count)}; - _Seek_wrapped(_First, _Backout._Release()); + for (; _Count > 0; ++_Backout._Last, (void) --_Count) { + ::new (_Voidify_iter(_Backout._Last)) _Ty; } - } + _Seek_wrapped(_First, _Backout._Release()); + } return _First; } +#ifdef __cpp_lib_concepts +namespace ranges { + // VARIABLE ranges::uninitialized_default_construct_n + class _Uninitialized_default_construct_n_fn : private _Not_quite_object { + public: + using _Not_quite_object::_Not_quite_object; + + // clang-format off + template <_No_throw_forward_iterator _It> + requires default_initializable> + _It operator()(_It _First, iter_difference_t<_It> _Count) const { + // clang-format on + if (_Count <= 0) { + return _First; + } + + using _Ty = remove_reference_t>; + if constexpr (is_trivially_default_constructible_v<_Ty>) { + _RANGES advance(_First, _Count); + } else if constexpr (is_nothrow_default_constructible_v<_Ty>) { + auto _UFirst = _Get_unwrapped_n(_STD move(_First), _Count); + + for (; _Count > 0; --_Count, (void) ++_UFirst) { + ::new (_Voidify_iter(_UFirst)) _Ty; + } + + _Seek_wrapped(_First, _STD move(_UFirst)); + } else { + _Uninitialized_backout _Backout{_Get_unwrapped_n(_STD move(_First), _Count)}; + + for (; _Count > 0; --_Count, (void) ++_Backout._Last) { + ::new (_Voidify_iter(_Backout._Last)) _Ty; + } + + _Seek_wrapped(_First, _Backout._Release()); + } + return _First; + } + }; + + inline constexpr _Uninitialized_default_construct_n_fn uninitialized_default_construct_n{ + _Not_quite_object::_Construct_tag{}}; +} // namespace ranges +#endif // __cpp_lib_concepts + // FUNCTION TEMPLATE uninitialized_value_construct template void uninitialized_value_construct(const _NoThrowFwdIt _First, const _NoThrowFwdIt _Last) { @@ -385,6 +895,7 @@ void uninitialized_value_construct(const _NoThrowFwdIt _First, const _NoThrowFwd _Zero_range(_UFirst, _ULast); } else { _Uninitialized_backout _Backout{_UFirst}; + while (_Backout._Last != _ULast) { _Backout._Emplace_back(); } @@ -393,18 +904,115 @@ void uninitialized_value_construct(const _NoThrowFwdIt _First, const _NoThrowFwd } } +#ifdef __cpp_lib_concepts +namespace ranges { + // VARIABLE ranges::uninitialized_value_construct + class _Uninitialized_value_construct_fn : private _Not_quite_object { + public: + using _Not_quite_object::_Not_quite_object; + + // clang-format off + template <_No_throw_forward_iterator _It, _No_throw_sentinel_for<_It> _Se> + requires default_initializable> + _It operator()(_It _First, _Se _Last) const { + // clang-format on + _Adl_verify_range(_First, _Last); + auto _UResult = _Uninitialized_value_construct_unchecked( + _Get_unwrapped(_STD move(_First)), _Get_unwrapped(_STD move(_Last))); + + _Seek_wrapped(_First, _STD move(_UResult)); + return _First; + } + + // clang-format off + template <_No_throw_forward_range _Rng> + requires default_initializable> + borrowed_iterator_t<_Rng> operator()(_Rng&& _Range) const { + // clang-format on + auto _UResult = _Uninitialized_value_construct_unchecked(_Ubegin(_Range), _Uend(_Range)); + + return _Rewrap_iterator(_Range, _STD move(_UResult)); + } + + private: + template + _NODISCARD static _It _Uninitialized_value_construct_unchecked(_It _OFirst, const _Se _OLast) { + _STL_INTERNAL_STATIC_ASSERT(_No_throw_forward_iterator<_It>); + _STL_INTERNAL_STATIC_ASSERT(_No_throw_sentinel_for<_Se, _It>); + _STL_INTERNAL_STATIC_ASSERT(default_initializable>); + + if constexpr (_Use_memset_value_construct_v<_It>) { + const auto _OFinal = _RANGES next(_OFirst, _STD move(_OLast)); + const auto _Count = static_cast(_OFinal - _OFirst); + _CSTD memset(_OFirst, 0, _Count); + return _OFinal; + } else { + _Uninitialized_backout _Backout{_STD move(_OFirst)}; + + while (_Backout._Last != _OLast) { + _Backout._Emplace_back(); + } + + return _Backout._Release(); + } + } + }; + + inline constexpr _Uninitialized_value_construct_fn uninitialized_value_construct{ + _Not_quite_object::_Construct_tag{}}; +} // namespace ranges +#endif // __cpp_lib_concepts + // FUNCTION TEMPLATE uninitialized_value_construct_n template _NoThrowFwdIt uninitialized_value_construct_n(_NoThrowFwdIt _First, const _Diff _Count_raw) { // value-initialize all elements in [_First, _First + _Count_raw) _Algorithm_int_t<_Diff> _Count = _Count_raw; - if (0 < _Count) { - _Seek_wrapped(_First, _Uninitialized_value_construct_n_unchecked1(_Get_unwrapped_n(_First, _Count), _Count)); + if (_Count <= 0) { + return _First; } + _Seek_wrapped(_First, _Uninitialized_value_construct_n_unchecked1(_Get_unwrapped_n(_First, _Count), _Count)); return _First; } +#ifdef __cpp_lib_concepts +namespace ranges { + // VARIABLE ranges::uninitialized_value_construct_n + class _Uninitialized_value_construct_n_fn : private _Not_quite_object { + public: + using _Not_quite_object::_Not_quite_object; + + // clang-format off + template <_No_throw_forward_iterator _It> + requires default_initializable> + _It operator()(_It _First, iter_difference_t<_It> _Count) const { + // clang-format on + if (_Count <= 0) { + return _First; + } + + auto _UFirst = _Get_unwrapped_n(_STD move(_First), _Count); + if constexpr (_Use_memset_value_construct_v<_It>) { + _CSTD memset(_UFirst, 0, static_cast(_Count)); + _Seek_wrapped(_First, _UFirst + _Count); + } else { + _Uninitialized_backout _Backout{_STD move(_UFirst)}; + + for (; _Count > 0; --_Count) { + _Backout._Emplace_back(); + } + + _Seek_wrapped(_First, _Backout._Release()); + } + return _First; + } + }; + + inline constexpr _Uninitialized_value_construct_n_fn uninitialized_value_construct_n{ + _Not_quite_object::_Construct_tag{}}; +} // namespace ranges +#endif // __cpp_lib_concepts #endif // _HAS_CXX17 @@ -2360,7 +2968,7 @@ _NODISCARD enable_if_t, shared_ptr<_Ty>> allocate_shared _Alblock _Rebound(_Al); _Alloc_construct_ptr _Constructor{_Rebound}; _Constructor._Allocate(); - ::new (static_cast(_Unfancy(_Constructor._Ptr))) _Refc(_Al); + ::new (_Voidify_iter(_Constructor._Ptr)) _Refc(_Al); shared_ptr<_Ty> _Ret; const auto _Ptr = static_cast*>(_Constructor._Ptr->_Storage._Value); _Ret._Set_ptr_rep_and_enable_shared(_Ptr, _Unfancy(_Constructor._Release())); @@ -2376,7 +2984,7 @@ _NODISCARD enable_if_t, shared_ptr<_Ty>> allocate_shared _Alblock _Rebound(_Al); _Alloc_construct_ptr _Constructor{_Rebound}; _Constructor._Allocate(); - ::new (static_cast(_Unfancy(_Constructor._Ptr))) _Refc(_Al, _Val); + ::new (_Voidify_iter(_Constructor._Ptr)) _Refc(_Al, _Val); shared_ptr<_Ty> _Ret; const auto _Ptr = static_cast*>(_Constructor._Ptr->_Storage._Value); _Ret._Set_ptr_rep_and_enable_shared(_Ptr, _Unfancy(_Constructor._Release())); @@ -2673,10 +3281,10 @@ public: } pointer release() noexcept { - return _STD exchange(_Mypair._Myval2, pointer()); + return _STD exchange(_Mypair._Myval2, nullptr); } - void reset(pointer _Ptr = pointer()) noexcept { + void reset(pointer _Ptr = nullptr) noexcept { pointer _Old = _STD exchange(_Mypair._Myval2, _Ptr); if (_Old) { _Mypair._Get_first()(_Old); @@ -2805,7 +3413,7 @@ public: } pointer release() noexcept { - return _STD exchange(_Mypair._Myval2, pointer()); + return _STD exchange(_Mypair._Myval2, nullptr); } template > @@ -3079,15 +3687,17 @@ inline void* align(size_t _Bound, size_t _Size, void*& _Ptr, size_t& _Space) noe return _Ptr; } -#if _HAS_CXX20 && 0 +#if _HAS_CXX20 template -_NODISCARD constexpr _Ty* assume_aligned(_Ty* _Ptr) noexcept /* strengthened */ { - // this enforces the requirement that _Nx be a power of two - __builtin_assume_aligned(_Ptr, _Nx); - - return _Ptr; +_NODISCARD constexpr _Ty* assume_aligned(_Ty* const _Ptr) noexcept /* strengthened */ { + if (_STD is_constant_evaluated()) { + return _Ptr; + } else { + // this enforces the requirement that _Nx be a power of two + return static_cast<_Ty*>(__builtin_assume_aligned(_Ptr, _Nx)); + } } -#endif // _HAS_CXX20 && 0 +#endif // _HAS_CXX20 // SPIN LOCKS _EXTERN_C @@ -3199,65 +3809,16 @@ _CXX20_DEPRECATE_OLD_SHARED_PTR_ATOMIC_SUPPORT bool atomic_compare_exchange_stro template class alignas(2 * sizeof(void*)) _Atomic_ptr_base { // overalignment is to allow potential future use of cmpxchg16b - - static_assert(alignof(_Ref_count_base) >= (1 << 2), "Two bits don't fit as low bits"); - - static constexpr uintptr_t _Lock_mask = 3; - static constexpr uintptr_t _Not_locked = 0; - static constexpr uintptr_t _Locked_notify_not_needed = 1; - static constexpr uintptr_t _Locked_notify_needed = 2; - static constexpr uintptr_t _Ptr_value_mask = ~_Lock_mask; - protected: constexpr _Atomic_ptr_base() noexcept = default; - _Atomic_ptr_base(_Ty* const _Px, _Ref_count_base* const _Ref) noexcept - : _Ptr(_Px), _Repptr(reinterpret_cast(_Ref)) {} - - _NODISCARD _Ref_count_base* _Lock_and_load() const noexcept { - uintptr_t _Rep = _Repptr.load(memory_order_relaxed); - for (;;) { - switch (_Rep & _Lock_mask) { - case _Not_locked: // Can try to lock now - if (_Repptr.compare_exchange_weak(_Rep, _Rep | _Locked_notify_not_needed)) { - return reinterpret_cast<_Ref_count_base*>(_Rep); - } - _YIELD_PROCESSOR(); - break; - - case _Locked_notify_not_needed: // Try to set "notify needed" and wait - if (!_Repptr.compare_exchange_weak(_Rep, (_Rep & _Ptr_value_mask) | _Locked_notify_needed)) { - // Failed to put notify needed flag on, try again - _YIELD_PROCESSOR(); - break; - } - _Rep = (_Rep & _Ptr_value_mask) | _Locked_notify_needed; - [[fallthrough]]; - - case _Locked_notify_needed: // "Notify needed" is already set, just wait - _Repptr.wait(_Rep, memory_order_relaxed); - _Rep = _Repptr.load(memory_order_relaxed); - break; - - default: // Unrecognized bit pattern - _CSTD abort(); - } - } - } - - void _Store_and_unlock(_Ref_count_base* const _Value) const noexcept { - uintptr_t _Rep = _Repptr.exchange(reinterpret_cast(_Value)); - if ((_Rep & _Lock_mask) == _Locked_notify_needed) { - // As we don't count waiters, every waiter is notified, and then some may re-request notification - _Repptr.notify_all(); - } - } + _Atomic_ptr_base(_Ty* const _Px, _Ref_count_base* const _Ref) noexcept : _Ptr(_Px), _Repptr(_Ref) {} void _Wait(_Ty* _Old, memory_order) const noexcept { for (;;) { - auto _Rep = _Lock_and_load(); + auto _Rep = _Repptr._Lock_and_load(); bool _Equal = _Ptr.load(memory_order_relaxed) == _Old; - _Store_and_unlock(_Rep); + _Repptr._Store_and_unlock(_Rep); if (!_Equal) { break; } @@ -3274,7 +3835,7 @@ protected: } atomic<_Ty*> _Ptr{nullptr}; - mutable atomic _Repptr{0}; + mutable _Locked_pointer<_Ref_count_base> _Repptr; }; template @@ -3293,22 +3854,22 @@ public: void store(shared_ptr<_Ty> _Value, const memory_order _Order = memory_order_seq_cst) noexcept { _Check_store_memory_order(_Order); - const auto _Rep = this->_Lock_and_load(); + const auto _Rep = this->_Repptr._Lock_and_load(); _Ty* const _Tmp = _Value._Ptr; _Value._Ptr = this->_Ptr.load(memory_order_relaxed); this->_Ptr.store(_Tmp, memory_order_relaxed); - this->_Store_and_unlock(_Value._Rep); + this->_Repptr._Store_and_unlock(_Value._Rep); _Value._Rep = _Rep; } _NODISCARD shared_ptr<_Ty> load(const memory_order _Order = memory_order_seq_cst) const noexcept { _Check_load_memory_order(_Order); shared_ptr<_Ty> _Result; - const auto _Rep = this->_Lock_and_load(); + const auto _Rep = this->_Repptr._Lock_and_load(); _Result._Ptr = this->_Ptr.load(memory_order_relaxed); _Result._Rep = _Rep; _Result._Incref(); - this->_Store_and_unlock(_Rep); + this->_Repptr._Store_and_unlock(_Rep); return _Result; } @@ -3319,10 +3880,10 @@ public: shared_ptr<_Ty> exchange(shared_ptr<_Ty> _Value, const memory_order _Order = memory_order_seq_cst) noexcept { _Check_memory_order(_Order); shared_ptr<_Ty> _Result; - _Result._Rep = this->_Lock_and_load(); + _Result._Rep = this->_Repptr._Lock_and_load(); _Result._Ptr = this->_Ptr.load(memory_order_relaxed); this->_Ptr.store(_Value._Ptr, memory_order_relaxed); - this->_Store_and_unlock(_Value._Rep); + this->_Repptr._Store_and_unlock(_Value._Rep); _Value._Ptr = nullptr; // ownership of _Value ref has been given to this, silence decrement _Value._Rep = nullptr; return _Result; @@ -3346,20 +3907,20 @@ public: bool compare_exchange_strong(shared_ptr<_Ty>& _Expected, shared_ptr<_Ty> _Desired, const memory_order _Order = memory_order_seq_cst) noexcept { _Check_memory_order(_Order); - auto _Rep = this->_Lock_and_load(); + auto _Rep = this->_Repptr._Lock_and_load(); if (this->_Ptr.load(memory_order_relaxed) == _Expected._Ptr && _Rep == _Expected._Rep) { _Ty* const _Tmp = _Desired._Ptr; _Desired._Ptr = this->_Ptr.load(memory_order_relaxed); this->_Ptr.store(_Tmp, memory_order_relaxed); _STD swap(_Rep, _Desired._Rep); - this->_Store_and_unlock(_Rep); + this->_Repptr._Store_and_unlock(_Rep); return true; } _Ref_count_base* _Expected_rep = _Expected._Rep; _Expected._Ptr = this->_Ptr.load(memory_order_relaxed); _Expected._Rep = _Rep; _Expected._Incref(); - this->_Store_and_unlock(_Rep); + this->_Repptr._Store_and_unlock(_Rep); if (_Expected_rep) { _Expected_rep->_Decref(); } @@ -3387,7 +3948,7 @@ public: } ~atomic() { - const auto _Rep = reinterpret_cast<_Ref_count_base*>(this->_Repptr.load(memory_order_relaxed)); + const auto _Rep = this->_Repptr._Unsafe_load_relaxed(); if (_Rep) { _Rep->_Decref(); } @@ -3410,22 +3971,22 @@ public: void store(weak_ptr<_Ty> _Value, const memory_order _Order = memory_order_seq_cst) noexcept { _Check_store_memory_order(_Order); - const auto _Rep = this->_Lock_and_load(); + const auto _Rep = this->_Repptr._Lock_and_load(); _Ty* const _Tmp = _Value._Ptr; _Value._Ptr = this->_Ptr.load(memory_order_relaxed); this->_Ptr.store(_Tmp, memory_order_relaxed); - this->_Store_and_unlock(_Value._Rep); + this->_Repptr._Store_and_unlock(_Value._Rep); _Value._Rep = _Rep; } _NODISCARD weak_ptr<_Ty> load(const memory_order _Order = memory_order_seq_cst) const noexcept { _Check_load_memory_order(_Order); weak_ptr<_Ty> _Result; - const auto _Rep = this->_Lock_and_load(); + const auto _Rep = this->_Repptr._Lock_and_load(); _Result._Ptr = this->_Ptr.load(memory_order_relaxed); _Result._Rep = _Rep; _Result._Incwref(); - this->_Store_and_unlock(_Rep); + this->_Repptr._Store_and_unlock(_Rep); return _Result; } @@ -3436,10 +3997,10 @@ public: weak_ptr<_Ty> exchange(weak_ptr<_Ty> _Value, const memory_order _Order = memory_order_seq_cst) noexcept { _Check_memory_order(_Order); weak_ptr<_Ty> _Result; - _Result._Rep = this->_Lock_and_load(); + _Result._Rep = this->_Repptr._Lock_and_load(); _Result._Ptr = this->_Ptr.load(memory_order_relaxed); this->_Ptr.store(_Value._Ptr, memory_order_relaxed); - this->_Store_and_unlock(_Value._Rep); + this->_Repptr._Store_and_unlock(_Value._Rep); _Value._Ptr = nullptr; // ownership of _Value ref has been given to this, silence decrement _Value._Rep = nullptr; return _Result; @@ -3463,20 +4024,20 @@ public: bool compare_exchange_strong( weak_ptr<_Ty>& _Expected, weak_ptr<_Ty> _Desired, const memory_order _Order = memory_order_seq_cst) noexcept { _Check_memory_order(_Order); - auto _Rep = this->_Lock_and_load(); + auto _Rep = this->_Repptr._Lock_and_load(); if (this->_Ptr.load(memory_order_relaxed) == _Expected._Ptr && _Rep == _Expected._Rep) { _Ty* const _Tmp = _Desired._Ptr; _Desired._Ptr = this->_Ptr.load(memory_order_relaxed); this->_Ptr.store(_Tmp, memory_order_relaxed); _STD swap(_Rep, _Desired._Rep); - this->_Store_and_unlock(_Rep); + this->_Repptr._Store_and_unlock(_Rep); return true; } const auto _Expected_rep = _Expected._Rep; _Expected._Ptr = this->_Ptr.load(memory_order_relaxed); _Expected._Rep = _Rep; _Expected._Incwref(); - this->_Store_and_unlock(_Rep); + this->_Repptr._Store_and_unlock(_Rep); if (_Expected_rep) { _Expected_rep->_Decwref(); } @@ -3504,7 +4065,7 @@ public: } ~atomic() { - const auto _Rep = reinterpret_cast<_Ref_count_base*>(this->_Repptr.load(memory_order_relaxed)); + const auto _Rep = this->_Repptr._Unsafe_load_relaxed(); if (_Rep) { _Rep->_Decwref(); } diff --git a/stl/inc/random b/stl/inc/random index ebb66b92c05..1854b1f234d 100644 --- a/stl/inc/random +++ b/stl/inc/random @@ -7,12 +7,14 @@ #ifndef _RANDOM_ #define _RANDOM_ #include + #if _STL_COMPILER_PREPROCESSOR #include #include #include #include #include +#include #include #pragma pack(push, _CRT_PACKING) @@ -2025,6 +2027,45 @@ basic_ostream<_Elem, _Traits>& operator<<(basic_ostream<_Elem, _Traits>& _Ostr, return _Dist._Write(_Ostr); } +// FUNCTION TEMPLATE _Float_upper_bound + +// Returns smallest _Flt such that static_cast<_Ty>(_Result) > _Val. +// First truncate to largest _Flt <= _Val, then add ceil(ulp). + +template +_NODISCARD _Flt _Float_upper_bound(_Ty _Val) { + static_assert(is_unsigned_v<_Ty> && is_integral_v<_Ty> && is_floating_point_v<_Flt>, + "invalid template argument for _Float_upper_bound"); + constexpr auto _Ty_digits = numeric_limits<_Ty>::digits; + constexpr auto _Flt_digits = numeric_limits<_Flt>::digits; + using _Ty_32or64 = conditional_t<_Ty_digits <= 32, uint32_t, uint64_t>; + + if _CONSTEXPR_IF (_Ty_digits <= _Flt_digits) { + return static_cast<_Flt>(_Val) + _Flt{1}; + } else { +#pragma warning(push) +#pragma warning(disable : 4146 4293) // unary minus of unsigned, negative shift + constexpr auto _Mask = static_cast<_Ty>(-1) << (_Ty_digits - _Flt_digits); +#ifdef _M_CEE_PURE + constexpr auto _Ty_32or64_digits = numeric_limits<_Ty_32or64>::digits; + const auto _Log_plus1 = _Ty_32or64_digits - _Countl_zero_fallback(static_cast<_Ty_32or64>(_Val | _Ty{1})); +#else // _M_CEE_PURE + const auto _Log_plus1 = _Bit_scan_reverse(static_cast<_Ty_32or64>(_Val | _Ty{1})); +#endif // _M_CEE_PURE + const auto _Shifted_mask = _Mask >> (_Ty_digits - _Log_plus1); + const auto _Ceil_ulp = _Shifted_mask & -_Shifted_mask; + _Val &= _Shifted_mask; + if (_Val == _Mask) { + // integer add would overflow + constexpr auto _Big_ulp = static_cast<_Flt>(_Mask & -_Mask); + return static_cast<_Flt>(_Val) + _Big_ulp; + } else { + return static_cast<_Flt>(_Val + _Ceil_ulp); + } +#pragma warning(pop) + } +} + // CLASS TEMPLATE geometric_distribution template class geometric_distribution { // geometric distribution @@ -2123,7 +2164,15 @@ public: private: template result_type _Eval(_Engine& _Eng, const param_type& _Par0) const { - return static_cast<_Ty>(_CSTD log(_NRAND(_Eng, _Ty1)) / _Par0._Log_1_p); + using _Uty = make_unsigned_t<_Ty>; + constexpr auto _Ty_max{(numeric_limits<_Ty>::max)()}; + const auto _Ty1_max{_Float_upper_bound<_Ty1>(static_cast<_Uty>(_Ty_max))}; + + _Ty1 _Val; + do { + _Val = _CSTD log(_NRAND(_Eng, _Ty1)) / _Par0._Log_1_p; + } while (_Val >= _Ty1_max); + return static_cast<_Ty>(_Val); } param_type _Par; @@ -2287,12 +2336,17 @@ private: } for (;;) { // generate and reject + using _Uty = make_unsigned_t<_Ty>; + constexpr auto _Ty_max{(numeric_limits<_Ty>::max)()}; + const auto _Ty1_max{_Float_upper_bound<_Ty1>(static_cast<_Uty>(_Ty_max))}; + _Ty _Res; _Ty1 _Yx; for (;;) { // generate a tentative value - _Yx = static_cast<_Ty1>(_CSTD tan(_Pi * _NRAND(_Eng, _Ty1))); - _Res = static_cast<_Ty>(_Par0._Sqrt * _Yx + _Par0._Mean); - if (_Ty{0} <= _Res) { + _Yx = static_cast<_Ty1>(_CSTD tan(_Pi * _NRAND(_Eng, _Ty1))); + const _Ty1 _Mx{_Par0._Sqrt * _Yx + _Par0._Mean}; + if (0.0 <= _Mx && _Mx < _Ty1_max) { + _Res = static_cast<_Ty>(_Mx); break; } } @@ -2469,12 +2523,16 @@ private: // events are rare, use Poisson distribution _Res = _Par0._Small(_Eng); } else { // no shortcuts + using _Uty = make_unsigned_t<_Ty>; + const auto _Ty1_Tx{_Float_upper_bound<_Ty1>(static_cast<_Uty>(_Par0._Tx))}; + for (;;) { // generate and reject _Ty1 _Yx; for (;;) { // generate a tentative value - _Yx = static_cast<_Ty1>(_CSTD tan(_Pi * _NRAND(_Eng, _Ty1))); - _Res = static_cast<_Ty>(_Par0._Sqrt * _Yx + _Par0._Mean); - if (_Ty{0} <= _Res && _Res <= _Par0._Tx) { + _Yx = static_cast<_Ty1>(_CSTD tan(_Pi * _NRAND(_Eng, _Ty1))); + const _Ty1 _Mx{_Par0._Sqrt * _Yx + _Par0._Mean}; + if (0.0 <= _Mx && _Mx < _Ty1_Tx) { + _Res = static_cast<_Ty>(_Mx); break; } } @@ -2932,15 +2990,32 @@ private: _Ty _Vx1; _Ty _Vx2; _Ty _Sx; - for (;;) { // reject bad values + for (;;) { // reject bad values to avoid generating NaN/Inf on the next calculations _Vx1 = 2 * _NRAND(_Eng, _Ty) - 1; _Vx2 = 2 * _NRAND(_Eng, _Ty) - 1; _Sx = _Vx1 * _Vx1 + _Vx2 * _Vx2; - if (_Sx < 1) { + if (_Sx < _Ty{1} && _Vx1 != _Ty{0} && _Vx2 != _Ty{0}) { + // good values! break; } } - const auto _Fx = static_cast<_Ty>(_CSTD sqrt(-2.0 * _CSTD log(_Sx) / _Sx)); + + _Ty _LogSx; + if (_Sx > _Ty{1e-4}) { + _LogSx = _STD log(_Sx); + } else { + // Bad _Sx value! Very small values will overflow log(_Sx) / _Sx. + // Generate a new value based on scaling method. + const _Ty _Ln2{_Ty{0.69314718055994530941723212145818}}; + const _Ty _Maxabs{(_STD max)(_STD abs(_Vx1), _STD abs(_Vx2))}; + const int _ExpMax{_STD ilogb(_Maxabs)}; + _Vx1 = _STD scalbn(_Vx1, -_ExpMax); + _Vx2 = _STD scalbn(_Vx2, -_ExpMax); + _Sx = _Vx1 * _Vx1 + _Vx2 * _Vx2; + _LogSx = _STD log(_Sx) + static_cast<_Ty>(_ExpMax) * (_Ln2 * 2); + } + + const auto _Fx = _Ty{_STD sqrt(_Ty{-2} * _LogSx / _Sx)}; if (_Keep) { // save second value for next call _Xx2 = _Fx * _Vx2; _Valid = true; @@ -3122,7 +3197,7 @@ private: return _Par0._Beta * _Par0._Exp(_Eng); } - if ((_Count = static_cast(_Par0._Alpha)) == _Par0._Alpha && _Count < 20) { + if (_Par0._Alpha < 20.0 && (_Count = static_cast(_Par0._Alpha)) == _Par0._Alpha) { // _Alpha is small integer, compute directly _Yx = _NRAND(_Eng, _Ty); while (--_Count) { // adjust result @@ -3864,7 +3939,7 @@ public: _Px1 = _CSTD pow(_Px1, _Ty{1} / _Ax); _Px2 = _CSTD pow(_Px2, _Ty{1} / _Bx); _Wx = _Px1 + _Px2; - if (_Wx <= _Ty{1}) { + if (_Wx <= _Ty{1} && _Wx != _Ty{0}) { break; } } @@ -3872,11 +3947,21 @@ public: } else { // use gamma distributions instead _Ty _Px1; _Ty _Px2; + _Ty _PSum; gamma_distribution<_Ty> _Dist1(_Ax, 1); gamma_distribution<_Ty> _Dist2(_Bx, 1); - _Px1 = _Dist1(_Eng); - _Px2 = _Dist2(_Eng); - return _Px1 / (_Px1 + _Px2); + + for (;;) { // reject pairs whose sum is zero + _Px1 = _Dist1(_Eng); + _Px2 = _Dist2(_Eng); + _PSum = _Px1 + _Px2; + + if (_PSum != _Ty{0}) { + break; + } + } + + return _Px1 / _PSum; } } @@ -4001,12 +4086,18 @@ private: _Ty _Px; _Ty _Vx1; _Ty _Vx2; + const _Ty _Vx3{1}; _Vx1 = static_cast<_Ty>(_Par0._Mx) * static_cast<_Ty>(0.5); _Vx2 = static_cast<_Ty>(_Par0._Nx) * static_cast<_Ty>(0.5); _Beta_distribution<_Ty> _Dist(_Vx1, _Vx2); - _Px = _Dist(_Eng); + for (;;) { // reject bad values + _Px = _Dist(_Eng); + if (_Px != _Vx3) { + break; + } + } - return (_Vx2 / _Vx1) * (_Px / (_Ty{1} - _Px)); + return (_Vx2 / _Vx1) * (_Px / (_Vx3 - _Px)); } param_type _Par; @@ -4137,13 +4228,13 @@ private: _Vx2 = _Dist(_Eng); _Rs = _Vx1 * _Vx1 + _Vx2 * _Vx2; - if (_Rs < _Ty{1}) { + // very small _Rs will overflow on pow(_Rx0, -_Ty{4} / _Par0._Nx) + if (_Rs < _Ty{1} && _Rs > _Ty{1e-12}) { break; } } - _Rx0 = _CSTD sqrt(_Rs); - - return _Vx1 * _CSTD sqrt(_Par0._Nx * (_CSTD pow(_Rx0, -_Ty{4} / _Par0._Nx) - _Ty{1}) / _Rs); + _Rx0 = _STD sqrt(_Rs); + return _Vx1 * _STD sqrt(_Par0._Nx * (_STD pow(_Rx0, -_Ty{4} / _Par0._Nx) - _Ty{1}) / _Rs); } param_type _Par; diff --git a/stl/inc/ranges b/stl/inc/ranges index 0abfedeb742..776e1310efe 100644 --- a/stl/inc/ranges +++ b/stl/inc/ranges @@ -15,9 +15,9 @@ #include #include -#if 1 // TRANSITION, VSO-1174090 +#if 1 // TRANSITION, VSO-1225825 #include -#endif // TRANSITION, VSO-1174090 +#endif // TRANSITION, VSO-1225825 #pragma pack(push, _CRT_PACKING) #pragma warning(push, _STL_WARNING_LEVEL) @@ -87,8 +87,8 @@ namespace ranges { // clang-format off template requires _Can_compose<_Derived, const _Other&> - constexpr auto operator|(const _Base<_Other>& __r) && noexcept(noexcept( - _Pipeline{static_cast<_Derived&&>(*this), static_cast(__r)})) { + constexpr auto operator|(const _Base<_Other>& __r) && noexcept( + noexcept(_Pipeline{static_cast<_Derived&&>(*this), static_cast(__r)})) { // clang-format on _STL_INTERNAL_STATIC_ASSERT(derived_from<_Derived, _Base<_Derived>>); _STL_INTERNAL_STATIC_ASSERT(derived_from<_Other, _Base<_Other>>); @@ -109,8 +109,8 @@ namespace ranges { // clang-format off template requires _Can_compose - constexpr auto operator|(const _Base<_Other>& __r) const& noexcept(noexcept( - _Pipeline{static_cast(*this), static_cast(__r)})) { + constexpr auto operator|(const _Base<_Other>& __r) const& noexcept( + noexcept(_Pipeline{static_cast(*this), static_cast(__r)})) { // clang-format on _STL_INTERNAL_STATIC_ASSERT(derived_from<_Derived, _Base<_Derived>>); _STL_INTERNAL_STATIC_ASSERT(derived_from<_Other, _Base<_Other>>); @@ -118,14 +118,24 @@ namespace ranges { } template <_Can_pipe _Left> - friend constexpr auto operator|(_Left&& __l, const _Base& __r) noexcept( - noexcept(static_cast(__r)(_STD forward<_Left>(__l)))) { + friend constexpr auto operator|(_Left&& __l, const _Base& __r) +#ifdef __EDG__ // TRANSITION, VSO-1222776 + noexcept(noexcept(_STD declval()(_STD forward<_Left>(__l)))) +#else // ^^^ workaround / no workaround vvv + noexcept(noexcept(static_cast(__r)(_STD forward<_Left>(__l)))) +#endif // TRANSITION, VSO-1222776 + { return static_cast(__r)(_STD forward<_Left>(__l)); } template <_Can_pipe<_Derived> _Left> - friend constexpr auto operator|(_Left&& __l, _Base&& __r) noexcept( - noexcept(static_cast<_Derived&&>(__r)(_STD forward<_Left>(__l)))) { + friend constexpr auto operator|(_Left&& __l, _Base&& __r) +#ifdef __EDG__ // TRANSITION, VSO-1222776 + noexcept(noexcept(_STD declval<_Derived>()(_STD forward<_Left>(__l)))) +#else // ^^^ workaround / no workaround vvv + noexcept(noexcept(static_cast<_Derived&&>(__r)(_STD forward<_Left>(__l)))) +#endif // TRANSITION, VSO-1222776 + { return static_cast<_Derived&&>(__r)(_STD forward<_Left>(__l)); } }; @@ -234,7 +244,7 @@ namespace ranges { using _Cached_position_t = conditional_t<_Enable, _Cached_position<_Rng, _Derived>, view_interface<_Derived>>; // CLASS TEMPLATE ranges::_Semiregular_box -#if 0 // TRANSITION, VSO-1174090 +#if 0 // TRANSITION, VSO-1225825 template <_Copy_constructible_object _Ty> class _Semiregular_box { public: @@ -432,9 +442,9 @@ namespace ranges { public: using optional<_Ty>::optional; - _Semiregular_box_copy() = default; + _Semiregular_box_copy() = default; _Semiregular_box_copy(const _Semiregular_box_copy&) = default; - _Semiregular_box_copy(_Semiregular_box_copy&&) = default; + _Semiregular_box_copy(_Semiregular_box_copy&&) = default; _Semiregular_box_copy& operator=(_Semiregular_box_copy&&) = default; _Semiregular_box_copy& operator=(const _Semiregular_box_copy& _That) noexcept( @@ -459,9 +469,9 @@ namespace ranges { public: using _Choose_semiregular_box_copy<_Ty>::_Choose_semiregular_box_copy; - _Semiregular_box_move() = default; + _Semiregular_box_move() = default; _Semiregular_box_move(const _Semiregular_box_move&) = default; - _Semiregular_box_move(_Semiregular_box_move&&) = default; + _Semiregular_box_move(_Semiregular_box_move&&) = default; _Semiregular_box_move& operator=(const _Semiregular_box_move&) = default; _Semiregular_box_move& operator=(_Semiregular_box_move&& _That) noexcept(is_nothrow_move_constructible_v<_Ty>) { @@ -521,7 +531,7 @@ namespace ranges { private: /* [[no_unique_address]] */ _Ty _Val = _Ty(); }; -#endif // TRANSITION, VSO-1174090 +#endif // TRANSITION, VSO-1225825 // CLASS TEMPLATE ranges::empty_view // clang-format off diff --git a/stl/inc/stop_token b/stl/inc/stop_token new file mode 100644 index 00000000000..ac4bc775af4 --- /dev/null +++ b/stl/inc/stop_token @@ -0,0 +1,398 @@ +// stop_token standard header + +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#pragma once +#ifndef _STOP_TOKEN_ +#define _STOP_TOKEN_ +#include +#if _STL_COMPILER_PREPROCESSOR + +#if !_HAS_CXX20 +#pragma message("The contents of are available only with C++20 or later.") +#else // ^^^ !_HAS_CXX20 / _HAS_CXX20 vvv + +#include +#include +#include + +#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 +struct nostopstate_t { + explicit nostopstate_t() = default; +}; + +inline constexpr nostopstate_t nostopstate{}; + +struct _Stop_state; +class stop_token; + +class _Stop_callback_base { + friend _Stop_state; + +private: + using _Callback_fn = void(__cdecl*)(_Stop_callback_base*) _NOEXCEPT_FNPTR; + +public: + explicit _Stop_callback_base(const _Callback_fn _Fn_) noexcept : _Fn{_Fn_} {} + + _Stop_callback_base(const _Stop_callback_base&) = delete; + _Stop_callback_base& operator=(const _Stop_callback_base&) = delete; + +protected: + // if _Token is _Stop_requested, calls the callback; + // otherwise, inserts *this into the callback list if stop is possible + inline void _Attach(const stop_token& _Token) noexcept; + inline void _Attach(stop_token&& _Token) noexcept; + + // if *this is in a callback list, removes it + inline void _Detach() noexcept; + +private: + template + void _Do_attach(conditional_t<_Transfer_ownership, _Stop_state*&, _Stop_state* const> _State) noexcept; + +protected: + _Stop_state* _Parent = nullptr; + _Stop_callback_base* _Next = nullptr; + _Stop_callback_base* _Prev = nullptr; + _Callback_fn _Fn; +}; + +struct _Stop_state { + atomic _Stop_tokens = 1; // plus one shared by all stop_sources + atomic _Stop_sources = 2; // plus the low order bit is the stop requested bit + _Locked_pointer<_Stop_callback_base> _Callbacks; + // always uses relaxed operations; ordering provided by the _Callbacks lock + // (atomic just to get wait/notify support) + atomic _Current_callback = nullptr; + _Thrd_id_t _Stopping_thread = 0; + + _NODISCARD bool _Stop_requested() const noexcept { + return (_Stop_sources.load() & uint32_t{1}) != 0; + } + + _NODISCARD bool _Stop_possible() const noexcept { + return _Stop_sources.load() != 0; + } + + _NODISCARD bool _Request_stop() noexcept { + // Attempts to request stop and call callbacks, returns whether request was successful + if ((_Stop_sources.fetch_or(uint32_t{1}) & uint32_t{1}) != 0) { + // another thread already requested + return false; + } + + _Stopping_thread = _Thrd_id(); + for (;;) { + auto _Head = _Callbacks._Lock_and_load(); + _Current_callback.store(_Head, memory_order_relaxed); + _Current_callback.notify_all(); + if (_Head == nullptr) { + _Callbacks._Store_and_unlock(nullptr); + return true; + } + + const auto _Next = _STD exchange(_Head->_Next, nullptr); + _STL_INTERNAL_CHECK(_Head->_Prev == nullptr); + if (_Next != nullptr) { + _Next->_Prev = nullptr; + } + + _Callbacks._Store_and_unlock(_Next); // unlock before running _Head so other registrations + // can detach without blocking on the callback + + _Head->_Fn(_Head); // might destroy *_Head + } + } +}; + +class stop_source; + +class stop_token { + friend stop_source; + friend _Stop_callback_base; + +public: + stop_token() noexcept : _State{} {} + stop_token(const stop_token& _Other) noexcept : _State{_Other._State} { + const auto _Local = _State; + if (_Local != nullptr) { + _Local->_Stop_tokens.fetch_add(1, memory_order_relaxed); + } + } + + stop_token(stop_token&& _Other) noexcept : _State{_STD exchange(_Other._State, nullptr)} {} + stop_token& operator=(const stop_token& _Other) noexcept { + stop_token{_Other}.swap(*this); + return *this; + } + + stop_token& operator=(stop_token&& _Other) noexcept { + stop_token{_STD move(_Other)}.swap(*this); + return *this; + } + + ~stop_token() { + const auto _Local = _State; + if (_Local != nullptr) { + if (_Local->_Stop_tokens.fetch_sub(1, memory_order_acq_rel) == 1) { + delete _Local; + } + } + } + + void swap(stop_token& _Other) noexcept { + _STD swap(_State, _Other._State); + } + + _NODISCARD bool stop_requested() const noexcept { + const auto _Local = _State; + return _Local != nullptr && _Local->_Stop_requested(); + } + + _NODISCARD bool stop_possible() const noexcept { + const auto _Local = _State; + return _Local != nullptr && _Local->_Stop_possible(); + } + + _NODISCARD friend bool operator==(const stop_token& _Lhs, const stop_token& _Rhs) noexcept = default; + + friend void swap(stop_token& _Lhs, stop_token& _Rhs) noexcept { + _STD swap(_Lhs._State, _Rhs._State); + } + +private: + explicit stop_token(_Stop_state* const _State_) : _State{_State_} {} + + _Stop_state* _State; +}; + +class stop_source { +public: + stop_source() : _State{new _Stop_state} {} + explicit stop_source(nostopstate_t) noexcept : _State{} {} + stop_source(const stop_source& _Other) noexcept : _State{_Other._State} { + const auto _Local = _State; + if (_Local != nullptr) { + _Local->_Stop_sources.fetch_add(2, memory_order_relaxed); + } + } + + stop_source(stop_source&& _Other) noexcept : _State{_STD exchange(_Other._State, nullptr)} {} + stop_source& operator=(const stop_source& _Other) noexcept { + stop_source{_Other}.swap(*this); + return *this; + } + + stop_source& operator=(stop_source&& _Other) noexcept { + stop_source{_STD move(_Other)}.swap(*this); + return *this; + } + + ~stop_source() { + const auto _Local = _State; + if (_Local != nullptr) { + if ((_Local->_Stop_sources.fetch_sub(2, memory_order_acq_rel) >> 1) == 1) { + if (_Local->_Stop_tokens.fetch_sub(1, memory_order_acq_rel) == 1) { + delete _Local; + } + } + } + } + + void swap(stop_source& _Other) noexcept { + _STD swap(_State, _Other._State); + } + + _NODISCARD stop_token get_token() const noexcept { + const auto _Local = _State; + if (_Local != nullptr) { + _Local->_Stop_tokens.fetch_add(1, memory_order_relaxed); + } + + return stop_token{_Local}; + } + + _NODISCARD bool stop_requested() const noexcept { + const auto _Local = _State; + return _Local != nullptr && _Local->_Stop_requested(); + } + + _NODISCARD bool stop_possible() const noexcept { + return _State != nullptr; + } + + bool request_stop() noexcept { + const auto _Local = _State; + return _Local && _Local->_Request_stop(); + } + + _NODISCARD friend bool operator==(const stop_source& _Lhs, const stop_source& _Rhs) noexcept = default; + + friend void swap(stop_source& _Lhs, stop_source& _Rhs) noexcept { + _STD swap(_Lhs._State, _Rhs._State); + } + +private: + _Stop_state* _State; +}; + +template +void _Stop_callback_base::_Do_attach( + conditional_t<_Transfer_ownership, _Stop_state*&, _Stop_state* const> _State_raw) noexcept { + const auto _State = _State_raw; // avoid an indirection in all of the below + if (_State == nullptr) { + return; + } + + // fast path check if the state is already known + auto _Local_sources = _State->_Stop_sources.load(); + if ((_Local_sources & uint32_t{1}) != 0) { + // stop already requested + _Fn(this); + return; + } + + if (_Local_sources == 0) { + return; // stop not possible + } + + // fast path doesn't know, so try to insert + auto _Head = _State->_Callbacks._Lock_and_load(); + // recheck the state in case it changed while we were waiting to acquire the lock + _Local_sources = _State->_Stop_sources.load(); + if ((_Local_sources & uint32_t{1}) != 0) { + // stop already requested + _State->_Callbacks._Store_and_unlock(_Head); + _Fn(this); + return; + } + + if (_Local_sources != 0) { + // stop possible, do the insert + _Parent = _State; + _Next = _Head; + if constexpr (_Transfer_ownership) { + _State_raw = nullptr; + } else { + _State->_Stop_tokens.fetch_add(1, memory_order_relaxed); + } + + if (_Head != nullptr) { + _Head->_Prev = this; + } + + _Head = this; + } + + _State->_Callbacks._Store_and_unlock(_Head); +} + +inline void _Stop_callback_base::_Attach(const stop_token& _Token) noexcept { + this->_Do_attach(_Token._State); +} + +inline void _Stop_callback_base::_Attach(stop_token&& _Token) noexcept { + this->_Do_attach(_Token._State); +} + +inline void _Stop_callback_base::_Detach() noexcept { + stop_token _Token{_Parent}; // transfers ownership + if (_Token._State == nullptr) { + // callback was never inserted into the list + return; + } + + auto _Head = _Token._State->_Callbacks._Lock_and_load(); + if (this == _Head) { + // we are still in the list, so the callback is not being request_stop'd + const auto _Local_next = _Next; + if (_Local_next != nullptr) { + _Local_next->_Prev = nullptr; + } + + _STL_INTERNAL_CHECK(_Prev == nullptr); + _Token._State->_Callbacks._Store_and_unlock(_Next); + return; + } + + const auto _Local_prev = _Prev; + if (_Local_prev != nullptr) { + // we are still in the list, so the callback is not being request_stop'd, and there is at least one other + // callback still registered + const auto _Local_next = _Next; + if (_Local_next != nullptr) { + _Next->_Prev = _Local_prev; + } + + _Prev->_Next = _Local_next; + _Token._State->_Callbacks._Store_and_unlock(_Head); + return; + } + + // we aren't in the callback list even though we were added to it, so the stop requesting thread is attempting to + // call the callback + _STL_INTERNAL_CHECK((_Token._State->_Stop_sources.load() & uint32_t{1}) != 0); + if (_Token._State->_Current_callback.load(memory_order_acquire) != this + || _Token._State->_Stopping_thread == _Thrd_id()) { + // the callback is done or the dtor is being recursively reentered, do not block + _Token._State->_Callbacks._Store_and_unlock(_Head); + return; + } + + // the callback is being executed by another thread, block until it is complete + _Token._State->_Callbacks._Store_and_unlock(_Head); + _Token._State->_Current_callback.wait(this, memory_order_acquire); +} + +template +class stop_callback : public _Stop_callback_base { +public: + using callback_type = _Callback; + + template , int> = 0> + explicit stop_callback(const stop_token& _Token, _CbInitTy&& _Cb_) noexcept( + is_nothrow_constructible_v<_Callback, _CbInitTy>) + : _Stop_callback_base{_Invoke_by_stop}, _Cb(_STD forward<_CbInitTy>(_Cb_)) { + _Attach(_Token); + } + + template , int> = 0> + explicit stop_callback(stop_token&& _Token, _CbInitTy&& _Cb_) noexcept( + is_nothrow_constructible_v<_Callback, _CbInitTy>) + : _Stop_callback_base{_Invoke_by_stop}, _Cb(_STD forward<_CbInitTy>(_Cb_)) { + _Attach(_STD move(_Token)); + } + + ~stop_callback() { + _Detach(); + } + +private: + static void __cdecl _Invoke_by_stop(_Stop_callback_base* const _This) noexcept // terminates + { + _STD forward<_Callback>(static_cast(_This)->_Cb)(); + } + + _Callback _Cb; +}; + +template +stop_callback(stop_token, _Callback) -> stop_callback<_Callback>; + +_STD_END +#pragma pop_macro("new") +_STL_RESTORE_CLANG_WARNINGS +#pragma warning(pop) +#pragma pack(pop) +#endif // _HAS_CXX20 +#endif // _STL_COMPILER_PREPROCESSOR +#endif // _STOP_TOKEN_ diff --git a/stl/inc/thread b/stl/inc/thread index 7a1d332d12b..20d6ee84272 100644 --- a/stl/inc/thread +++ b/stl/inc/thread @@ -13,6 +13,9 @@ #include #include #include +#if _HAS_CXX20 +#include +#endif // _HAS_CXX20 #ifdef _M_CEE_PURE #error is not supported when compiling with /clr:pure. @@ -26,6 +29,10 @@ _STL_DISABLE_CLANG_WARNINGS #undef new _STD_BEGIN +#if _HAS_CXX20 +class jthread; +#endif // _HAS_CXX20 + class thread { // class for observing and managing threads public: class id; @@ -35,6 +42,10 @@ public: thread() noexcept : _Thr{} {} private: +#if _HAS_CXX20 + friend jthread; +#endif // _HAS_CXX20 + template static unsigned int __stdcall _Invoke(void* _RawVals) noexcept /* terminates */ { // adapt invoke of user's callable object to _beginthreadex's thread procedure @@ -50,9 +61,8 @@ private: return &_Invoke<_Tuple, _Indices...>; } -public: - template , thread>, int> = 0> - explicit thread(_Fn&& _Fx, _Args&&... _Ax) { + template + void _Start(_Fn&& _Fx, _Args&&... _Ax) { using _Tuple = tuple, decay_t<_Args>...>; auto _Decay_copied = _STD make_unique<_Tuple>(_STD forward<_Fn>(_Fx), _STD forward<_Args>(_Ax)...); constexpr auto _Invoker_proc = _Get_invoke<_Tuple>(make_index_sequence<1 + sizeof...(_Args)>{}); @@ -73,6 +83,12 @@ public: } } +public: + template , thread>, int> = 0> + explicit thread(_Fn&& _Fx, _Args&&... _Ax) { + _Start(_STD forward<_Fn>(_Fx), _STD forward<_Args>(_Ax)...); + } + ~thread() noexcept { if (joinable()) { _STD terminate(); @@ -240,6 +256,96 @@ struct hash { return _Hash_representation(_Keyval._Id); } }; + +#if _HAS_CXX20 +class jthread { +public: + using id = thread::id; + using native_handle_type = thread::native_handle_type; + + jthread() noexcept : _Impl{}, _Ssource{nostopstate} {} + + template , jthread>, int> = 0> + explicit jthread(_Fn&& _Fx, _Args&&... _Ax) { + if constexpr (is_invocable_v, stop_token, decay_t<_Args>...>) { + _Impl._Start(_STD forward<_Fn>(_Fx), _Ssource.get_token(), _STD forward<_Args>(_Ax)...); + } else { + _Impl._Start(_STD forward<_Fn>(_Fx), _STD forward<_Args>(_Ax)...); + } + } + + ~jthread() { + _Try_cancel_and_join(); + } + + jthread(const jthread&) = delete; + jthread(jthread&&) noexcept = default; + jthread& operator=(const jthread&) = delete; + + jthread& operator=(jthread&& _Other) noexcept { + // note: the standard specifically disallows making self-move-assignment a no-op here + // N4861 [thread.jthread.cons]/13 + // Effects: If joinable() is true, calls request_stop() and then join(). Assigns the state + // of x to *this and sets x to a default constructed state. + _Try_cancel_and_join(); + _Impl = _STD move(_Other._Impl); + _Ssource = _STD move(_Other._Ssource); + return *this; + } + + void swap(jthread& _Other) noexcept { + _Impl.swap(_Other._Impl); + _Ssource.swap(_Other._Ssource); + } + + _NODISCARD bool joinable() const noexcept { + return _Impl.joinable(); + } + + void join() { + _Impl.join(); + } + + void detach() { + _Impl.detach(); + } + + _NODISCARD id get_id() const noexcept { + return _Impl.get_id(); + } + + _NODISCARD stop_source get_stop_source() noexcept { + return _Ssource; + } + + _NODISCARD stop_token get_stop_token() const noexcept { + return _Ssource.get_token(); + } + + bool request_stop() noexcept { + return _Ssource.request_stop(); + } + + friend void swap(jthread& _Lhs, jthread& _Rhs) noexcept { + _Lhs.swap(_Rhs); + } + + _NODISCARD static unsigned int hardware_concurrency() noexcept { + return thread::hardware_concurrency(); + } + +private: + void _Try_cancel_and_join() noexcept { + if (_Impl.joinable()) { + _Ssource.request_stop(); + _Impl.join(); + } + } + + thread _Impl; + stop_source _Ssource; +}; +#endif // _HAS_CXX20 _STD_END #pragma pop_macro("new") diff --git a/stl/inc/type_traits b/stl/inc/type_traits index 477f3a47e12..cae9e1b0baf 100644 --- a/stl/inc/type_traits +++ b/stl/inc/type_traits @@ -1657,6 +1657,32 @@ template using is_nothrow_convertible = _Is_nothrow_convertible<_From, _To>; #endif // _HAS_CXX20 +template +_Ty _Returns_exactly() noexcept; // not defined + +template +struct _Invoke_convertible : false_type {}; + +template +struct _Invoke_convertible<_From, _To, void_t(_Returns_exactly<_From>()))>> + : true_type {}; + +template +struct _Invoke_nothrow_convertible : bool_constant(_Returns_exactly<_From>()))> {}; + +template +struct _Invoke_traits_common { + using type = _Result; + using _Is_invocable = true_type; + using _Is_nothrow_invocable = bool_constant<_Nothrow>; + template + using _Is_invocable_r = bool_constant, _Invoke_convertible>>; + template + using _Is_nothrow_invocable_r = bool_constant, + conjunction<_Invoke_convertible, _Invoke_nothrow_convertible>>>>; +}; + template struct _Invoke_traits_zero { // selected when _Callable isn't callable with zero _Args @@ -1672,17 +1698,8 @@ template using _Decltype_invoke_zero = decltype(_STD declval<_Callable>()()); template -struct _Invoke_traits_zero>, _Callable> { - // selected when _Callable is callable with zero _Args - using type = _Decltype_invoke_zero<_Callable>; - using _Is_invocable = true_type; - using _Is_nothrow_invocable = bool_constant()())>; - template - using _Is_invocable_r = bool_constant, is_convertible>>; - template - using _Is_nothrow_invocable_r = bool_constant< - conjunction_v<_Is_nothrow_invocable, disjunction, _Is_nothrow_convertible>>>; -}; +struct _Invoke_traits_zero>, _Callable> + : _Invoke_traits_common<_Decltype_invoke_zero<_Callable>, noexcept(_STD declval<_Callable>()())> {}; template struct _Invoke_traits_nonzero { @@ -1701,18 +1718,9 @@ using _Decltype_invoke_nonzero = decltype( template struct _Invoke_traits_nonzero>, _Callable, _Ty1, - _Types2...> { - // selected when _Callable is callable with nonzero _Args - using type = _Decltype_invoke_nonzero<_Callable, _Ty1, _Types2...>; - using _Is_invocable = true_type; - using _Is_nothrow_invocable = bool_constant::_Call( - _STD declval<_Callable>(), _STD declval<_Ty1>(), _STD declval<_Types2>()...))>; - template - using _Is_invocable_r = bool_constant, is_convertible>>; - template - using _Is_nothrow_invocable_r = bool_constant< - conjunction_v<_Is_nothrow_invocable, disjunction, _Is_nothrow_convertible>>>; -}; + _Types2...> : _Invoke_traits_common<_Decltype_invoke_nonzero<_Callable, _Ty1, _Types2...>, + noexcept(_Invoker1<_Callable, _Ty1>::_Call( + _STD declval<_Callable>(), _STD declval<_Ty1>(), _STD declval<_Types2>()...))> {}; template using _Select_invoke_traits = conditional_t, diff --git a/stl/inc/utility b/stl/inc/utility index 1727b5ca4b6..53e38b608af 100644 --- a/stl/inc/utility +++ b/stl/inc/utility @@ -697,7 +697,7 @@ _NODISCARD constexpr bool cmp_greater_equal(const _Ty1 _Left, const _Ty2 _Right) // FUNCTION TEMPLATE in_range template -_NODISCARD constexpr _Ty _Min_limit() noexcept { // same as (numeric_limits<_Ty>::min)(), less throughput cost +_NODISCARD _CONSTEVAL _Ty _Min_limit() noexcept { // same as (numeric_limits<_Ty>::min)(), less throughput cost static_assert(_Is_standard_integer<_Ty>); // doesn't attempt to handle all types if constexpr (is_signed_v<_Ty>) { constexpr auto _Unsigned_max = static_cast>(-1); @@ -708,7 +708,7 @@ _NODISCARD constexpr _Ty _Min_limit() noexcept { // same as (numeric_limits<_Ty> } template -_NODISCARD constexpr _Ty _Max_limit() noexcept { // same as (numeric_limits<_Ty>::max)(), less throughput cost +_NODISCARD _CONSTEVAL _Ty _Max_limit() noexcept { // same as (numeric_limits<_Ty>::max)(), less throughput cost static_assert(_Is_standard_integer<_Ty>); // doesn't attempt to handle all types if constexpr (is_signed_v<_Ty>) { constexpr auto _Unsigned_max = static_cast>(-1); diff --git a/stl/inc/vector b/stl/inc/vector index 0fe4e0079ab..5a08f9d8f9f 100644 --- a/stl/inc/vector +++ b/stl/inc/vector @@ -374,6 +374,9 @@ public: _Vector_val() noexcept : _Myfirst(), _Mylast(), _Myend() {} + _Vector_val(pointer _First, pointer _Last, pointer _End) noexcept + : _Myfirst(_First), _Mylast(_Last), _Myend(_End) {} + void _Swap_val(_Vector_val& _Right) noexcept { this->_Swap_proxy_and_iterators(_Right); _Swap_adl(_Myfirst, _Right._Myfirst); @@ -387,9 +390,9 @@ public: _Mylast = _Right._Mylast; _Myend = _Right._Myend; - _Right._Myfirst = pointer(); - _Right._Mylast = pointer(); - _Right._Myend = pointer(); + _Right._Myfirst = nullptr; + _Right._Mylast = nullptr; + _Right._Myend = nullptr; } pointer _Myfirst; // pointer to beginning of array @@ -578,9 +581,13 @@ private: } public: - vector(vector&& _Right) noexcept : _Mypair(_One_then_variadic_args_t{}, _STD move(_Right._Getal())) { + vector(vector&& _Right) noexcept + : _Mypair(_One_then_variadic_args_t{}, _STD move(_Right._Getal()), + _STD exchange(_Right._Mypair._Myval2._Myfirst, nullptr), + _STD exchange(_Right._Mypair._Myval2._Mylast, nullptr), + _STD exchange(_Right._Mypair._Myval2._Myend, nullptr)) { _Mypair._Myval2._Alloc_proxy(_GET_PROXY_ALLOCATOR(_Alty, _Getal())); - _Move_construct(_Right, true_type{}); + _Mypair._Myval2._Swap_proxy_and_iterators(_Right._Mypair._Myval2); } vector(vector&& _Right, const _Alloc& _Al) noexcept(_Alty_traits::is_always_equal::value) // strengthened @@ -1292,9 +1299,9 @@ private: _Destroy(_Myfirst, _Mylast); _Getal().deallocate(_Myfirst, static_cast(_Myend - _Myfirst)); - _Myfirst = pointer(); - _Mylast = pointer(); - _Myend = pointer(); + _Myfirst = nullptr; + _Mylast = nullptr; + _Myend = nullptr; } _Buy_raw(_Newcapacity); @@ -1695,9 +1702,9 @@ private: _Destroy(_Myfirst, _Mylast); _Getal().deallocate(_Myfirst, static_cast(_Myend - _Myfirst)); - _Myfirst = pointer(); - _Mylast = pointer(); - _Myend = pointer(); + _Myfirst = nullptr; + _Mylast = nullptr; + _Myend = nullptr; } } diff --git a/stl/inc/xatomic.h b/stl/inc/xatomic.h index 4a96fef4303..3298d828ae8 100644 --- a/stl/inc/xatomic.h +++ b/stl/inc/xatomic.h @@ -26,14 +26,14 @@ _STL_DISABLE_CLANG_WARNINGS #define _CONCAT(x, y) _CONCATX(x, y) // Interlocked intrinsic mapping for _nf/_acq/_rel -#if defined(_M_CEE_PURE) || defined(_M_IX86) || defined(_M_X64) +#if defined(_M_CEE_PURE) || defined(_M_IX86) || (defined(_M_X64) && !defined(_M_ARM64EC)) #define _INTRIN_RELAXED(x) x #define _INTRIN_ACQUIRE(x) x #define _INTRIN_RELEASE(x) x #define _INTRIN_ACQ_REL(x) x #define _YIELD_PROCESSOR() -#elif defined(_M_ARM) || defined(_M_ARM64) +#elif defined(_M_ARM) || defined(_M_ARM64) || defined(_M_ARM64EC) #define _INTRIN_RELAXED(x) _CONCAT(x, _nf) #define _INTRIN_ACQUIRE(x) _CONCAT(x, _acq) #define _INTRIN_RELEASE(x) _CONCAT(x, _rel) diff --git a/stl/inc/xbit_ops.h b/stl/inc/xbit_ops.h index 6f224585e1b..ca2aaa37e3b 100644 --- a/stl/inc/xbit_ops.h +++ b/stl/inc/xbit_ops.h @@ -9,6 +9,7 @@ #include #if _STL_COMPILER_PREPROCESSOR +#include #include #pragma pack(push, _CRT_PACKING) @@ -51,6 +52,40 @@ _NODISCARD inline unsigned long _Ceiling_of_log_2(const size_t _Value) noexcept return 1 + _Floor_of_log_2(_Value - 1); } +_NODISCARD inline uint32_t _Bit_scan_reverse(const uint32_t _Value) noexcept { + unsigned long _Index; // Intentionally uninitialized for better codegen + + if (_BitScanReverse(&_Index, _Value)) { + return _Index + 1; + } + + return 0; +} + +_NODISCARD inline uint32_t _Bit_scan_reverse(const uint64_t _Value) noexcept { + unsigned long _Index; // Intentionally uninitialized for better codegen + +#ifdef _WIN64 + if (_BitScanReverse64(&_Index, _Value)) { + return _Index + 1; + } +#else // ^^^ 64-bit ^^^ / vvv 32-bit vvv + uint32_t _Ui32 = static_cast(_Value >> 32); + + if (_BitScanReverse(&_Index, _Ui32)) { + return _Index + 1 + 32; + } + + _Ui32 = static_cast(_Value); + + if (_BitScanReverse(&_Index, _Ui32)) { + return _Index + 1; + } +#endif // ^^^ 32-bit ^^^ + + return 0; +} + _STD_END #pragma pop_macro("new") diff --git a/stl/inc/xhash b/stl/inc/xhash index 761b5d385c3..39eeba36edd 100644 --- a/stl/inc/xhash +++ b/stl/inc/xhash @@ -319,9 +319,9 @@ struct _Hash_vec { void _Tidy() noexcept { _Destroy_range(_Mypair._Myval2._Myfirst, _Mypair._Myval2._Mylast); _Mypair._Get_first().deallocate(_Mypair._Myval2._Myfirst, size()); - _Mypair._Myval2._Myfirst = pointer(); - _Mypair._Myval2._Mylast = pointer(); - _Mypair._Myval2._Myend = pointer(); + _Mypair._Myval2._Myfirst = nullptr; + _Mypair._Myval2._Mylast = nullptr; + _Mypair._Myval2._Myend = nullptr; } ~_Hash_vec() { @@ -472,7 +472,7 @@ private: _Min_buckets_construct_ptr(const _Min_buckets_construct_ptr&) = delete; _NODISCARD pointer _Release(_Unchecked_iterator _Newend) noexcept { _STD uninitialized_fill(_Base, _Base + _Min_buckets * 2, _Newend); - return _STD exchange(_Base, pointer()); + return _STD exchange(_Base, nullptr); } ~_Min_buckets_construct_ptr() { if (_Base) { diff --git a/stl/inc/xlocale b/stl/inc/xlocale index 3f2a2a488de..d95168e49af 100644 --- a/stl/inc/xlocale +++ b/stl/inc/xlocale @@ -2345,6 +2345,17 @@ protected: virtual __CLR_OR_THIS_CALL ~codecvt_byname() noexcept {} }; +// CTYPE CODE BITS +#define _XA 0x100 // extra alphabetic +#define _BB _CONTROL // BEL, BS, etc. +#define _CN _SPACE // CR, FF, HT, NL, VT +#define _DI _DIGIT // '0'-'9' +#define _LO _LOWER // 'a'-'z' +#define _PU _PUNCT // punctuation +#define _SP _BLANK // space +#define _UP _UPPER // 'A'-'Z' +#define _XD _HEX // '0'-'9', 'A'-'F', 'a'-'f' + // STRUCT ctype_base struct _CRTIMP2_PURE_IMPORT ctype_base : locale::facet { // base for ctype enum { // constants for character classifications @@ -2356,10 +2367,10 @@ struct _CRTIMP2_PURE_IMPORT ctype_base : locale::facet { // base for ctype lower = _LO, print = _DI | _LO | _PU | _SP | _UP | _XA | _XD, punct = _PU, - space = _CN | _SP | _XS, + space = _CN | _SP, upper = _UP, xdigit = _XD, - blank = _CN | _SP | _XS | _XB + blank = _CN | _SP }; using mask = short; // to match @@ -2368,6 +2379,16 @@ struct _CRTIMP2_PURE_IMPORT ctype_base : locale::facet { // base for ctype __CLR_OR_THIS_CALL ~ctype_base() noexcept {} }; +#undef _XA +#undef _BB +#undef _CN +#undef _DI +#undef _LO +#undef _PU +#undef _SP +#undef _UP +#undef _XD + // CLASS TEMPLATE ctype template class ctype : public ctype_base { // facet for classifying elements, converting cases diff --git a/stl/inc/xlocinfo.h b/stl/inc/xlocinfo.h index 5cfba660a07..9891775d16a 100644 --- a/stl/inc/xlocinfo.h +++ b/stl/inc/xlocinfo.h @@ -23,19 +23,6 @@ _STL_DISABLE_CLANG_WARNINGS _EXTERN_C_UNLESS_PURE -// CTYPE CODE BITS -#define _XB 0x000 // extra blank -#define _XA 0x100 // extra alphabetic -#define _XS 0x000 // extra space -#define _BB _CONTROL // BEL, BS, etc. -#define _CN _SPACE // CR, FF, HT, NL, VT -#define _DI _DIGIT // '0'-'9' -#define _LO _LOWER // 'a'-'z' -#define _PU _PUNCT // punctuation -#define _SP _BLANK // space -#define _UP _UPPER // 'A'-'Z' -#define _XD _HEX // '0'-'9', 'A'-'F', 'a'-'f' - // SUPPLEMENTAL LOCALE MACROS AND DECLARATIONS #define _X_ALL LC_ALL #define _X_COLLATE LC_COLLATE diff --git a/stl/inc/xloctime b/stl/inc/xloctime index baf58d94310..1dbf298843e 100644 --- a/stl/inc/xloctime +++ b/stl/inc/xloctime @@ -134,7 +134,7 @@ public: _First = do_get(_First, _Last, _Iosbase, _State, _Pt, _Specifier, _Modifier); // convert a single field if (_State != ios_base::goodbit) { - // Failed to convert the field. Do not proceed to the next fields. Return with failed _State. + // _State is fail, eof, or bad. Do not proceed to the next fields. Return with current _State. break; } } diff --git a/stl/inc/xmemory b/stl/inc/xmemory index c723ab4d262..7ad649cf512 100644 --- a/stl/inc/xmemory +++ b/stl/inc/xmemory @@ -257,10 +257,10 @@ _Pointer _Refancy(_Pointer _Ptr) noexcept { // FUNCTION TEMPLATE _Destroy_in_place template -/* _CONSTEXPR20_DYNALLOC */ void _Destroy_range(_NoThrowFwdIt _First, _NoThrowSentinel _Last) noexcept; +_CONSTEXPR20_DYNALLOC void _Destroy_range(_NoThrowFwdIt _First, _NoThrowSentinel _Last) noexcept; template -/* _CONSTEXPR20_DYNALLOC */ void _Destroy_in_place(_Ty& _Obj) noexcept { +_CONSTEXPR20_DYNALLOC void _Destroy_in_place(_Ty& _Obj) noexcept { #if _HAS_IF_CONSTEXPR if constexpr (is_array_v<_Ty>) { _Destroy_range(_Obj, _Obj + extent_v<_Ty>); @@ -951,8 +951,7 @@ void _Pocs(_Alloc& _Left, _Alloc& _Right) noexcept { // FUNCTION TEMPLATE _Destroy_range WITH ALLOC template -/* _CONSTEXPR20_DYNALLOC */ void _Destroy_range( - _Alloc_ptr_t<_Alloc> _First, const _Alloc_ptr_t<_Alloc> _Last, _Alloc& _Al) noexcept { +void _Destroy_range(_Alloc_ptr_t<_Alloc> _First, const _Alloc_ptr_t<_Alloc> _Last, _Alloc& _Al) noexcept { // note that this is an optimization for debug mode codegen; in release mode the BE removes all of this using _Ty = typename _Alloc::value_type; if _CONSTEXPR_IF (!conjunction_v, _Uses_default_destroy<_Alloc, _Ty*>>) { @@ -964,7 +963,7 @@ template // FUNCTION TEMPLATE _Destroy_range template -/* _CONSTEXPR20_DYNALLOC */ void _Destroy_range(_NoThrowFwdIt _First, const _NoThrowSentinel _Last) noexcept { +_CONSTEXPR20_DYNALLOC void _Destroy_range(_NoThrowFwdIt _First, const _NoThrowSentinel _Last) noexcept { // note that this is an optimization for debug mode codegen; in release mode the BE removes all of this if _CONSTEXPR_IF (!is_trivially_destructible_v<_Iter_value_t<_NoThrowFwdIt>>) { for (; _First != _Last; ++_First) { @@ -1425,18 +1424,18 @@ struct _Uninitialized_backout { // struct to undo partially constructed ranges i _Uninitialized_backout(const _Uninitialized_backout&) = delete; _Uninitialized_backout& operator=(const _Uninitialized_backout&) = delete; - /* _CONSTEXPR20_DYNALLOC */ ~_Uninitialized_backout() { + ~_Uninitialized_backout() { _Destroy_range(_First, _Last); } template - /* _CONSTEXPR20_DYNALLOC */ void _Emplace_back(_Types&&... _Vals) { + void _Emplace_back(_Types&&... _Vals) { // construct a new element at *_Last and increment _Construct_in_place(*_Last, _STD forward<_Types>(_Vals)...); ++_Last; } - /* _CONSTEXPR20_DYNALLOC */ _NoThrowFwdIt _Release() { // suppress any exception handling backout and return _Last + _NoThrowFwdIt _Release() { // suppress any exception handling backout and return _Last _First = _Last; return _Last; } diff --git a/stl/inc/xnode_handle.h b/stl/inc/xnode_handle.h index 2c21bc39928..d962579a054 100644 --- a/stl/inc/xnode_handle.h +++ b/stl/inc/xnode_handle.h @@ -80,21 +80,21 @@ class _Node_handle : public _Base<_Node_handle<_Node, _Alloc, _Base, _Types...>, aligned_union_t<0, _Alloc> _Alloc_storage; // Invariant: contains a live _Alloc iff _Ptr != nullptr void _Clear() noexcept { // destroy any contained node and return to the empty state - if (_Ptr) { + if (_Ptr != nullptr) { _Alloc& _Al = _Getal(); + _Alty_traits::destroy(_Al, _STD addressof(_Ptr->_Myval)); _Alnode _Node_alloc{_Al}; - _Alnode_traits::destroy(_Node_alloc, _STD addressof(_Ptr->_Myval)); _Node::_Freenode0(_Node_alloc, _Ptr); _Destroy_in_place(_Al); _Ptr = nullptr; } } - _Node_handle(const _Nodeptr _My_ptr, const _Alloc& _My_alloc) noexcept - : _Ptr{_My_ptr} { // Initialize a _Node_handle that holds the specified node - // pre: _My_ptr != nullptr - // pre: _Alloc can release _Ptr - _Construct_in_place(_Getal(), _My_alloc); + _Node_handle(const _Nodeptr _Ptr_, const _Alloc& _Al) noexcept + : _Ptr{_Ptr_} { // Initialize a _Node_handle that holds the specified node + // pre: _Alloc can release _Ptr + _STL_INTERNAL_CHECK(_Ptr_ != nullptr); + _Construct_in_place(_Getal(), _Al); } public: @@ -105,7 +105,7 @@ class _Node_handle : public _Base<_Node_handle<_Node, _Alloc, _Base, _Types...>, } _Node_handle(_Node_handle&& _That) noexcept : _Ptr{_That._Ptr} { // steal node and allocator (if any) from _That - if (_Ptr) { + if (_Ptr != nullptr) { _That._Ptr = nullptr; _Alloc& _That_al = _That._Getal(); _Construct_in_place(_Getal(), _STD move(_That_al)); @@ -115,8 +115,8 @@ class _Node_handle : public _Base<_Node_handle<_Node, _Alloc, _Base, _Types...>, _Node_handle& operator=(_Node_handle&& _That) noexcept /* strengthened */ { // steal state from _That - if (!_Ptr) { - if (_That._Ptr) { + if (_Ptr == nullptr) { + if (_That._Ptr != nullptr) { _Alloc& _That_al = _That._Getal(); _Construct_in_place(_Getal(), _STD move(_That_al)); _Destroy_in_place(_That_al); @@ -126,14 +126,14 @@ class _Node_handle : public _Base<_Node_handle<_Node, _Alloc, _Base, _Types...>, return *this; } - if (!_That._Ptr || this == _STD addressof(_That)) { + if (_That._Ptr == nullptr || this == _STD addressof(_That)) { _Clear(); return *this; } _Alloc& _Al = _Getal(); + _Alty_traits::destroy(_Al, _STD addressof(_Ptr->_Myval)); _Alnode _Node_alloc{_Al}; - _Alnode_traits::destroy(_Node_alloc, _STD addressof(_Ptr->_Myval)); _Alnode_traits::deallocate(_Node_alloc, _Ptr, 1); _Alloc& _That_al = _That._Getal(); @@ -148,15 +148,16 @@ class _Node_handle : public _Base<_Node_handle<_Node, _Alloc, _Base, _Types...>, return _Ptr; } - _Alloc& _Getal() noexcept { // pre: !empty() + _Alloc& _Getal() noexcept { return reinterpret_cast<_Alloc&>(_Alloc_storage); } - const _Alloc& _Getal() const noexcept { // pre: !empty() + const _Alloc& _Getal() const noexcept { + _STL_INTERNAL_CHECK(!empty()); return reinterpret_cast(_Alloc_storage); } _NODISCARD allocator_type get_allocator() const noexcept /* strengthened */ { - // pre: !empty() + _STL_INTERNAL_CHECK(!empty()); return _Getal(); } @@ -169,14 +170,14 @@ class _Node_handle : public _Base<_Node_handle<_Node, _Alloc, _Base, _Types...>, } _Nodeptr _Release() noexcept { // extract the node from *this - // pre: !empty() + _STL_INTERNAL_CHECK(!empty()); _Destroy_in_place(_Getal()); return _STD exchange(_Ptr, nullptr); } void swap(_Node_handle& _That) noexcept /* strengthened */ { - if (_Ptr) { - if (_That._Ptr) { + if (_Ptr != nullptr) { + if (_That._Ptr != nullptr) { _Pocs(_Getal(), _That._Getal()); } else { _Alloc& _Al = _Getal(); @@ -184,7 +185,7 @@ class _Node_handle : public _Base<_Node_handle<_Node, _Alloc, _Base, _Types...>, _Destroy_in_place(_Al); } } else { - if (!_That._Ptr) { + if (_That._Ptr == nullptr) { return; } @@ -200,8 +201,8 @@ class _Node_handle : public _Base<_Node_handle<_Node, _Alloc, _Base, _Types...>, static _Node_handle _Make(const _Nodeptr _Ptr, const allocator_type& _Al) { // initialize a _Node_handle that holds _Ptr and _Al - // pre: _Ptr != nullptr // pre: _Al can release _Ptr + _STL_INTERNAL_CHECK(_Ptr != nullptr); return _Node_handle{_Ptr, _Al}; } }; diff --git a/stl/inc/xpolymorphic_allocator.h b/stl/inc/xpolymorphic_allocator.h index 4aa55864f94..d34da64fe10 100644 --- a/stl/inc/xpolymorphic_allocator.h +++ b/stl/inc/xpolymorphic_allocator.h @@ -140,7 +140,7 @@ namespace pmr { // CLASS memory_resource class __declspec(novtable) memory_resource { public: - virtual ~memory_resource() noexcept {} + virtual ~memory_resource() noexcept = default; _NODISCARD __declspec(allocator) void* allocate(_CRT_GUARDOVERFLOW const size_t _Bytes, const size_t _Align = alignof(max_align_t)) { // allocate _Bytes bytes of memory with alignment _Align @@ -186,7 +186,11 @@ namespace pmr { } // CLASS TEMPLATE polymorphic_allocator +#if _HAS_CXX20 && defined(__cpp_lib_byte) + template +#else template +#endif // _HAS_CXX20 && defined(__cpp_lib_byte) class polymorphic_allocator { public: template @@ -222,6 +226,47 @@ namespace pmr { _Resource->deallocate(_Ptr, _Count * sizeof(_Ty), alignof(_Ty)); } +#if _HAS_CXX20 + _NODISCARD __declspec(allocator) void* allocate_bytes( + const size_t _Bytes, const size_t _Align = alignof(max_align_t)) { + return _Resource->allocate(_Bytes, _Align); + } + + void deallocate_bytes(void* const _Ptr, const size_t _Bytes, + const size_t _Align = alignof(max_align_t)) noexcept /* strengthened */ { + _Resource->deallocate(_Ptr, _Bytes, _Align); + } + + template + _NODISCARD __declspec(allocator) _Uty* allocate_object(_CRT_GUARDOVERFLOW const size_t _Count = 1) { + void* const _Vp = allocate_bytes(_Get_size_of_n(_Count), alignof(_Uty)); + return static_cast<_Uty*>(_Vp); + } + + template + void deallocate_object(_Uty* const _Ptr, const size_t _Count = 1) noexcept /* strengthened */ { + deallocate_bytes(_Ptr, _Count * sizeof(_Uty), alignof(_Uty)); + } + + template + _NODISCARD __declspec(allocator) _Uty* new_object(_Types&&... _Args) { + _Uty* const _Ptr = allocate_object<_Uty>(); + _TRY_BEGIN + construct(_Ptr, _STD forward<_Types>(_Args)...); + _CATCH_ALL + deallocate_object(_Ptr); + _RERAISE; + _CATCH_END + return _Ptr; + } + + template + void delete_object(_Uty* const _Ptr) noexcept /* strengthened */ { + _Destroy_in_place(*_Ptr); + deallocate_object(_Ptr); + } +#endif // _HAS_CXX20 + template void construct(_Uty* const _Ptr, _Types&&... _Args) { // propagate allocator *this if uses_allocator_v<_Uty, polymorphic_allocator> diff --git a/stl/inc/xstddef b/stl/inc/xstddef index 32cd98a5a54..6d067214921 100644 --- a/stl/inc/xstddef +++ b/stl/inc/xstddef @@ -375,10 +375,6 @@ _STD_END #define _MEMBER_CALL_CV_REF_NOEXCEPT(FUNC) _MEMBER_CALL_CV_REF(FUNC, ) #endif // __cpp_noexcept_function_type -#define _CLASS_DEFINE_CONST(CLASS) \ - CLASS(_EMPTY_ARGUMENT) \ - CLASS(const) - #ifdef __cpp_noexcept_function_type #define _CLASS_DEFINE_CV_REF_NOEXCEPT(CLASS) \ CLASS(_EMPTY_ARGUMENT) \ diff --git a/stl/inc/xstring b/stl/inc/xstring index a1ac9f75908..e3fcec57484 100644 --- a/stl/inc/xstring +++ b/stl/inc/xstring @@ -2713,7 +2713,7 @@ private: auto& _Right_data = _Right._Mypair._Myval2; if (_Right_data._Large_string_engaged()) { // steal buffer _Construct_in_place(_My_data._Bx._Ptr, _Right_data._Bx._Ptr); - _Right_data._Bx._Ptr = pointer(); + _Right_data._Bx._Ptr = nullptr; _Swap_proxy_and_iterators(_Right); } else { // copy small string buffer _Traits::copy(_My_data._Bx._Buf, _Right_data._Bx._Buf, _Right_data._Mysize + 1); diff --git a/stl/inc/xtimec.h b/stl/inc/xtimec.h index b5cc5ab3082..67b75522d16 100644 --- a/stl/inc/xtimec.h +++ b/stl/inc/xtimec.h @@ -30,8 +30,6 @@ _CRTIMP2_PURE int __cdecl xtime_get(xtime*, int); _CRTIMP2_PURE long __cdecl _Xtime_diff_to_millis(const xtime*); _CRTIMP2_PURE long __cdecl _Xtime_diff_to_millis2(const xtime*, const xtime*); _CRTIMP2_PURE long long __cdecl _Xtime_get_ticks(); -#define _XTIME_NSECS_PER_TICK 100 -#define _XTIME_TICKS_PER_TIME_T 10000000LL _CRTIMP2_PURE long long __cdecl _Query_perf_counter(); _CRTIMP2_PURE long long __cdecl _Query_perf_frequency(); diff --git a/stl/inc/xutility b/stl/inc/xutility index 9658711f8ac..7dbdc5aa5b6 100644 --- a/stl/inc/xutility +++ b/stl/inc/xutility @@ -21,7 +21,7 @@ _STL_DISABLE_CLANG_WARNINGS #pragma push_macro("new") #undef new -#if (defined(_M_IX86) || defined(_M_X64)) && !defined(_M_CEE_PURE) && !defined(_M_HYBRID) +#if (defined(_M_IX86) || defined(_M_X64)) && !defined(_M_CEE_PURE) && !defined(_M_HYBRID) && !defined(_M_ARM64EC) #define _USE_STD_VECTOR_ALGORITHMS 1 #else #define _USE_STD_VECTOR_ALGORITHMS 0 @@ -474,21 +474,11 @@ concept _Cpp17_input_iterator = _Cpp17_iterator<_It> requires signed_integral::difference_type>; }; -#if 1 // TRANSITION, VSO-1002863 -template -using _Member_iterator_category = typename _Ty::iterator_category; -#endif // TRANSITION, VSO-1002863 - template requires (!_Has_iter_types<_It> && _Cpp17_iterator<_It> && !_Cpp17_input_iterator<_It> // Implements the proposed resolution of LWG-3283: -#if 1 // TRANSITION, VSO-1002863 - && (!requires { typename _It::iterator_category; } - || derived_from<_Member_iterator_category<_It>, output_iterator_tag>)) -#else // ^^^ workaround / no workaround vvv && (!requires { typename _It::iterator_category; } || derived_from)) -#endif // TRANSITION, VSO-1002863 struct _Iterator_traits_base<_It> { using iterator_category = output_iterator_tag; using difference_type = @@ -1494,20 +1484,20 @@ _INLINE_VAR constexpr bool template constexpr void _Seek_wrapped(_Iter& _It, _UIter&& _UIt) { if constexpr (_Wrapped_seekable_v<_Iter, _UIter>) { - _It._Seek_to(static_cast<_UIter&&>(_UIt)); + _It._Seek_to(_STD forward<_UIter>(_UIt)); } else { - _It = static_cast<_UIter&&>(_UIt); + _It = _STD forward<_UIter>(_UIt); } } #else // ^^^ _HAS_IF_CONSTEXPR / !_HAS_IF_CONSTEXPR vvv template , int> = 0> constexpr void _Seek_wrapped(_Iter& _It, _UIter&& _UIt) { - _It._Seek_to(static_cast<_UIter&&>(_UIt)); + _It._Seek_to(_STD forward<_UIter>(_UIt)); } template , int> = 0> constexpr void _Seek_wrapped(_Iter& _It, _UIter&& _UIt) { - _It = static_cast<_UIter&&>(_UIt); + _It = _STD forward<_UIter>(_UIt); } template @@ -4124,22 +4114,22 @@ public: } _NODISCARD friend constexpr reference iter_move(const move_iterator& _It) -#ifdef __EDG__ // TRANSITION, VSO-1132105 +#ifdef __EDG__ // TRANSITION, VSO-1222776 noexcept(noexcept(_RANGES iter_move(_STD declval()))) #else // ^^^ workaround / no workaround vvv noexcept(noexcept(_RANGES iter_move(_It._Current))) -#endif // TRANSITION, VSO-1132105 +#endif // TRANSITION, VSO-1222776 { return _RANGES iter_move(_It._Current); } template _Iter2> friend constexpr void iter_swap(const move_iterator& _Left, const move_iterator<_Iter2>& _Right) -#ifdef __EDG__ // TRANSITION, VSO-1132105 +#ifdef __EDG__ // TRANSITION, VSO-1222776 noexcept(noexcept(_RANGES iter_swap(_STD declval(), _STD declval()))) #else // ^^^ workaround / no workaround vvv noexcept(noexcept(_RANGES iter_swap(_Left._Current, _Right.base()))) -#endif // TRANSITION, VSO-1132105 +#endif // TRANSITION, VSO-1222776 { _RANGES iter_swap(_Left._Current, _Right.base()); } @@ -4378,6 +4368,17 @@ _OutIt _Copy_memmove(move_iterator<_InIt> _First, move_iterator<_InIt> _Last, _O return _Copy_memmove(_First.base(), _Last.base(), _Dest); } +template +_OutIt _Copy_memcpy_common(_InIt _IFirst, _InIt _ILast, _OutIt _OFirst, _OutIt _OLast) noexcept { + const auto _IFirst_ch = const_cast(reinterpret_cast(_IFirst)); + const auto _ILast_ch = const_cast(reinterpret_cast(_ILast)); + const auto _OFirst_ch = const_cast(reinterpret_cast(_OFirst)); + const auto _OLast_ch = const_cast(reinterpret_cast(_OLast)); + const auto _Count = static_cast((_STD min)(_ILast_ch - _IFirst_ch, _OLast_ch - _OFirst_ch)); + _CSTD memcpy(_OFirst_ch, _IFirst_ch, _Count); + return reinterpret_cast<_OutIt>(_OFirst_ch + _Count); +} + #if _HAS_IF_CONSTEXPR // VARIABLE TEMPLATE _Is_vb_iterator template diff --git a/stl/inc/ymath.h b/stl/inc/ymath.h index 850ccd6e173..112f9cfa075 100644 --- a/stl/inc/ymath.h +++ b/stl/inc/ymath.h @@ -23,13 +23,6 @@ _EXTERN_C_UNLESS_PURE #define _INFCODE 1 #define _NANCODE 2 -// MACROS FOR _Feraise ARGUMENT -#define _FE_DIVBYZERO 0x04 -#define _FE_INEXACT 0x20 -#define _FE_INVALID 0x01 -#define _FE_OVERFLOW 0x08 -#define _FE_UNDERFLOW 0x10 - void __CLRCALL_PURE_OR_CDECL _Feraise(int); union _Dconst { // pun float types as integer array diff --git a/stl/inc/yvals_core.h b/stl/inc/yvals_core.h index 0d62a90da3e..dcfd6744b1a 100644 --- a/stl/inc/yvals_core.h +++ b/stl/inc/yvals_core.h @@ -137,6 +137,7 @@ // P0202R3 constexpr For And exchange() // P0318R1 unwrap_reference, unwrap_ref_decay // P0325R4 to_array() +// P0339R6 polymorphic_allocator<> // P0356R5 bind_front() // P0357R3 Supporting Incomplete Types In reference_wrapper // P0415R1 constexpr For (Again) @@ -159,6 +160,7 @@ // P0646R1 list/forward_list remove()/remove_if()/unique() Return size_type // P0653R2 to_address() // P0655R1 visit() +// P0660R10 And jthread // P0674R1 make_shared() For Arrays // P0718R2 atomic>, atomic> // P0758R1 is_nothrow_convertible @@ -176,6 +178,7 @@ // P0966R1 string::reserve() Should Not Shrink // P1001R2 execution::unseq // P1006R1 constexpr For pointer_traits::pointer_to() +// P1007R3 assume_aligned() // P1023R0 constexpr For std::array Comparisons // P1024R3 Enhancing span Usability // P1032R1 Miscellaneous constexpr @@ -498,7 +501,7 @@ #define _CPPLIB_VER 650 #define _MSVC_STL_VERSION 142 -#define _MSVC_STL_UPDATE 202009L +#define _MSVC_STL_UPDATE 202010L #ifndef _ALLOW_COMPILER_AND_STL_VERSION_MISMATCH #ifdef __EDG__ @@ -541,6 +544,13 @@ #define _CONSTEXPR20 inline #endif // ^^^ inline (not constexpr) in C++17 and earlier ^^^ +// Functions that became constexpr in C++20 via P0784R7 +#if _HAS_CXX20 && defined(__cpp_constexpr_dynamic_alloc) +#define _CONSTEXPR20_DYNALLOC constexpr +#else +#define _CONSTEXPR20_DYNALLOC inline +#endif + // P0607R0 Inline Variables For The STL #if _HAS_CXX17 #define _INLINE_VAR inline @@ -1142,6 +1152,7 @@ #define __cpp_lib_atomic_value_initialization 201911L #if _HAS_CXX20 +#define __cpp_lib_assume_aligned 201811L #define __cpp_lib_atomic_flag_test 201907L #define __cpp_lib_atomic_float 201711L #define __cpp_lib_atomic_lock_free_type_aliases 201907L @@ -1189,9 +1200,11 @@ #define __cpp_lib_interpolate 201902L #define __cpp_lib_is_constant_evaluated 201811L #define __cpp_lib_is_nothrow_convertible 201806L +#define __cpp_lib_jthread 201911L #define __cpp_lib_latch 201907L #define __cpp_lib_list_remove_return_type 201806L #define __cpp_lib_math_constants 201907L +#define __cpp_lib_polymorphic_allocator 201902L #define __cpp_lib_remove_cvref 201711L #define __cpp_lib_semaphore 201907L #define __cpp_lib_shift 201806L diff --git a/stl/msbuild/stl_1/md/msvcp_1_app/msvcp_1.nativeproj b/stl/msbuild/stl_1/md/msvcp_1_app/msvcp_1.nativeproj index 5e13d2fe317..966b3699874 100644 --- a/stl/msbuild/stl_1/md/msvcp_1_app/msvcp_1.nativeproj +++ b/stl/msbuild/stl_1/md/msvcp_1_app/msvcp_1.nativeproj @@ -8,6 +8,7 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception md app + true diff --git a/stl/msbuild/stl_1/md/msvcp_1_kernel32/msvcp_1.nativeproj b/stl/msbuild/stl_1/md/msvcp_1_kernel32/msvcp_1.nativeproj index d7898159df7..781acdc848d 100644 --- a/stl/msbuild/stl_1/md/msvcp_1_kernel32/msvcp_1.nativeproj +++ b/stl/msbuild/stl_1/md/msvcp_1_kernel32/msvcp_1.nativeproj @@ -8,6 +8,7 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception md kernel32 + true diff --git a/stl/msbuild/stl_1/md/msvcp_1_onecore/msvcp_1.nativeproj b/stl/msbuild/stl_1/md/msvcp_1_onecore/msvcp_1.nativeproj index 6e20d6fb826..4b1ddcbfce3 100644 --- a/stl/msbuild/stl_1/md/msvcp_1_onecore/msvcp_1.nativeproj +++ b/stl/msbuild/stl_1/md/msvcp_1_onecore/msvcp_1.nativeproj @@ -8,6 +8,7 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception md onecore + true diff --git a/stl/msbuild/stl_1/stl_1.files.settings.targets b/stl/msbuild/stl_1/stl_1.files.settings.targets index 8c423bd34ec..7c36449ea49 100644 --- a/stl/msbuild/stl_1/stl_1.files.settings.targets +++ b/stl/msbuild/stl_1/stl_1.files.settings.targets @@ -11,6 +11,7 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception "> nativecpp + diff --git a/stl/msbuild/stl_1/xmd/msvcp_1_app/msvcp_1.nativeproj b/stl/msbuild/stl_1/xmd/msvcp_1_app/msvcp_1.nativeproj index 1aab5e5dca5..b386bc9bc49 100644 --- a/stl/msbuild/stl_1/xmd/msvcp_1_app/msvcp_1.nativeproj +++ b/stl/msbuild/stl_1/xmd/msvcp_1_app/msvcp_1.nativeproj @@ -8,6 +8,7 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception xmd app + true diff --git a/stl/msbuild/stl_1/xmd/msvcp_1_kernel32/msvcp_1.nativeproj b/stl/msbuild/stl_1/xmd/msvcp_1_kernel32/msvcp_1.nativeproj index 8fa99a499a3..d834b6edd69 100644 --- a/stl/msbuild/stl_1/xmd/msvcp_1_kernel32/msvcp_1.nativeproj +++ b/stl/msbuild/stl_1/xmd/msvcp_1_kernel32/msvcp_1.nativeproj @@ -8,6 +8,7 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception xmd kernel32 + true diff --git a/stl/msbuild/stl_1/xmd/msvcp_1_onecore/msvcp_1.nativeproj b/stl/msbuild/stl_1/xmd/msvcp_1_onecore/msvcp_1.nativeproj index ac04b45e21a..3eeaf9b1d62 100644 --- a/stl/msbuild/stl_1/xmd/msvcp_1_onecore/msvcp_1.nativeproj +++ b/stl/msbuild/stl_1/xmd/msvcp_1_onecore/msvcp_1.nativeproj @@ -8,6 +8,7 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception xmd onecore + true diff --git a/stl/msbuild/stl_2/md/msvcp_2_app/msvcp_2.nativeproj b/stl/msbuild/stl_2/md/msvcp_2_app/msvcp_2.nativeproj index 87924c5deb5..9747790c304 100644 --- a/stl/msbuild/stl_2/md/msvcp_2_app/msvcp_2.nativeproj +++ b/stl/msbuild/stl_2/md/msvcp_2_app/msvcp_2.nativeproj @@ -8,6 +8,7 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception md app + true diff --git a/stl/msbuild/stl_2/md/msvcp_2_kernel32/msvcp_2.nativeproj b/stl/msbuild/stl_2/md/msvcp_2_kernel32/msvcp_2.nativeproj index 7940363b805..bcff4e94ca8 100644 --- a/stl/msbuild/stl_2/md/msvcp_2_kernel32/msvcp_2.nativeproj +++ b/stl/msbuild/stl_2/md/msvcp_2_kernel32/msvcp_2.nativeproj @@ -8,6 +8,7 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception md kernel32 + true diff --git a/stl/msbuild/stl_2/md/msvcp_2_onecore/msvcp_2.nativeproj b/stl/msbuild/stl_2/md/msvcp_2_onecore/msvcp_2.nativeproj index a7231361640..38e5772cb39 100644 --- a/stl/msbuild/stl_2/md/msvcp_2_onecore/msvcp_2.nativeproj +++ b/stl/msbuild/stl_2/md/msvcp_2_onecore/msvcp_2.nativeproj @@ -8,6 +8,7 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception md onecore + true diff --git a/stl/msbuild/stl_2/msvcp_2.settings.targets b/stl/msbuild/stl_2/msvcp_2.settings.targets index 79540664211..afcc4c12419 100644 --- a/stl/msbuild/stl_2/msvcp_2.settings.targets +++ b/stl/msbuild/stl_2/msvcp_2.settings.targets @@ -36,6 +36,8 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception $(CrtBuildDir)\msvcprt_2$(BuildSuffix).$(MsvcpFlavor).import_only.lib $(LibOutputFileName).$(MsvcpFlavor) $(IntermediateOutputDirectory)\$(DllDefName).def + $(IntermediateOutputDirectoryEC)\$(DllDefName).def + $(IntermediateOutputDirectory)\$(DllDefName).def true $(OutputPath)\$(OutputName)$(_PDB_VER_NAME_)$(DllPdbFlavorSuffix) diff --git a/stl/msbuild/stl_2/stl_2.files.settings.targets b/stl/msbuild/stl_2/stl_2.files.settings.targets index 4f28e08a72d..0b5a57a2c3d 100644 --- a/stl/msbuild/stl_2/stl_2.files.settings.targets +++ b/stl/msbuild/stl_2/stl_2.files.settings.targets @@ -11,6 +11,7 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception "> nativecpp + diff --git a/stl/msbuild/stl_2/xmd/msvcp_2_app/msvcp_2.nativeproj b/stl/msbuild/stl_2/xmd/msvcp_2_app/msvcp_2.nativeproj index 757adf81842..5751496f0f4 100644 --- a/stl/msbuild/stl_2/xmd/msvcp_2_app/msvcp_2.nativeproj +++ b/stl/msbuild/stl_2/xmd/msvcp_2_app/msvcp_2.nativeproj @@ -8,6 +8,7 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception xmd app + true diff --git a/stl/msbuild/stl_2/xmd/msvcp_2_kernel32/msvcp_2.nativeproj b/stl/msbuild/stl_2/xmd/msvcp_2_kernel32/msvcp_2.nativeproj index b60a98908bc..0c78314cdc8 100644 --- a/stl/msbuild/stl_2/xmd/msvcp_2_kernel32/msvcp_2.nativeproj +++ b/stl/msbuild/stl_2/xmd/msvcp_2_kernel32/msvcp_2.nativeproj @@ -8,6 +8,7 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception xmd kernel32 + true diff --git a/stl/msbuild/stl_2/xmd/msvcp_2_onecore/msvcp_2.nativeproj b/stl/msbuild/stl_2/xmd/msvcp_2_onecore/msvcp_2.nativeproj index 3c0fd24d2a6..96281b17219 100644 --- a/stl/msbuild/stl_2/xmd/msvcp_2_onecore/msvcp_2.nativeproj +++ b/stl/msbuild/stl_2/xmd/msvcp_2_onecore/msvcp_2.nativeproj @@ -8,6 +8,7 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception xmd onecore + true diff --git a/stl/msbuild/stl_atomic_wait/md/msvcp_atomic_wait_app/msvcp_atomic_wait.nativeproj b/stl/msbuild/stl_atomic_wait/md/msvcp_atomic_wait_app/msvcp_atomic_wait.nativeproj index e22fbab9c1b..25ee294c299 100644 --- a/stl/msbuild/stl_atomic_wait/md/msvcp_atomic_wait_app/msvcp_atomic_wait.nativeproj +++ b/stl/msbuild/stl_atomic_wait/md/msvcp_atomic_wait_app/msvcp_atomic_wait.nativeproj @@ -8,6 +8,7 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception md app + true diff --git a/stl/msbuild/stl_atomic_wait/md/msvcp_atomic_wait_kernel32/msvcp_atomic_wait.nativeproj b/stl/msbuild/stl_atomic_wait/md/msvcp_atomic_wait_kernel32/msvcp_atomic_wait.nativeproj index e009997783c..fa3b0cb07d1 100644 --- a/stl/msbuild/stl_atomic_wait/md/msvcp_atomic_wait_kernel32/msvcp_atomic_wait.nativeproj +++ b/stl/msbuild/stl_atomic_wait/md/msvcp_atomic_wait_kernel32/msvcp_atomic_wait.nativeproj @@ -8,6 +8,7 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception md kernel32 + true diff --git a/stl/msbuild/stl_atomic_wait/md/msvcp_atomic_wait_onecore/msvcp_atomic_wait.nativeproj b/stl/msbuild/stl_atomic_wait/md/msvcp_atomic_wait_onecore/msvcp_atomic_wait.nativeproj index 774d8aa1b5a..5ecec8dcfc2 100644 --- a/stl/msbuild/stl_atomic_wait/md/msvcp_atomic_wait_onecore/msvcp_atomic_wait.nativeproj +++ b/stl/msbuild/stl_atomic_wait/md/msvcp_atomic_wait_onecore/msvcp_atomic_wait.nativeproj @@ -8,6 +8,7 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception md onecore + true diff --git a/stl/msbuild/stl_atomic_wait/stl_atomic_wait.files.settings.targets b/stl/msbuild/stl_atomic_wait/stl_atomic_wait.files.settings.targets index e7cc52c398d..05ac026443d 100644 --- a/stl/msbuild/stl_atomic_wait/stl_atomic_wait.files.settings.targets +++ b/stl/msbuild/stl_atomic_wait/stl_atomic_wait.files.settings.targets @@ -17,4 +17,21 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception nativecpp + + + + + $(IntermediateOutputDirectoryEC)\atomic_wait.obj; + $(IntermediateOutputDirectoryEC)\parallel_algorithms.obj; + + + + + + + + + diff --git a/stl/msbuild/stl_atomic_wait/xmd/msvcp_atomic_wait_app/msvcp_atomic_wait.nativeproj b/stl/msbuild/stl_atomic_wait/xmd/msvcp_atomic_wait_app/msvcp_atomic_wait.nativeproj index 6d99c3ab360..3cf18558d38 100644 --- a/stl/msbuild/stl_atomic_wait/xmd/msvcp_atomic_wait_app/msvcp_atomic_wait.nativeproj +++ b/stl/msbuild/stl_atomic_wait/xmd/msvcp_atomic_wait_app/msvcp_atomic_wait.nativeproj @@ -8,6 +8,7 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception xmd app + true diff --git a/stl/msbuild/stl_atomic_wait/xmd/msvcp_atomic_wait_kernel32/msvcp_atomic_wait.nativeproj b/stl/msbuild/stl_atomic_wait/xmd/msvcp_atomic_wait_kernel32/msvcp_atomic_wait.nativeproj index 9fe52b880d3..1226365ae6b 100644 --- a/stl/msbuild/stl_atomic_wait/xmd/msvcp_atomic_wait_kernel32/msvcp_atomic_wait.nativeproj +++ b/stl/msbuild/stl_atomic_wait/xmd/msvcp_atomic_wait_kernel32/msvcp_atomic_wait.nativeproj @@ -8,6 +8,7 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception xmd kernel32 + true diff --git a/stl/msbuild/stl_atomic_wait/xmd/msvcp_atomic_wait_onecore/msvcp_atomic_wait.nativeproj b/stl/msbuild/stl_atomic_wait/xmd/msvcp_atomic_wait_onecore/msvcp_atomic_wait.nativeproj index 54f964b787a..6b512a2847c 100644 --- a/stl/msbuild/stl_atomic_wait/xmd/msvcp_atomic_wait_onecore/msvcp_atomic_wait.nativeproj +++ b/stl/msbuild/stl_atomic_wait/xmd/msvcp_atomic_wait_onecore/msvcp_atomic_wait.nativeproj @@ -8,6 +8,7 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception xmd onecore + true diff --git a/stl/msbuild/stl_base/libcp.settings.targets b/stl/msbuild/stl_base/libcp.settings.targets index 3176a88f2f3..336c34ac84c 100644 --- a/stl/msbuild/stl_base/libcp.settings.targets +++ b/stl/msbuild/stl_base/libcp.settings.targets @@ -25,12 +25,17 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception $(OutputLibPath)$(OutputName)$(PdbVerName).pdb + $(OutputLibPath)$(OutputName).arm64.pdb $(ClDefines);_STL_CONCRT_SUPPORT $(ClDefines);_VCRT_ALLOW_INTERNALS + + + + diff --git a/stl/msbuild/stl_base/md/msvcp_app/msvcp.nativeproj b/stl/msbuild/stl_base/md/msvcp_app/msvcp.nativeproj index dd16e3096e5..acddd63ea73 100644 --- a/stl/msbuild/stl_base/md/msvcp_app/msvcp.nativeproj +++ b/stl/msbuild/stl_base/md/msvcp_app/msvcp.nativeproj @@ -8,6 +8,7 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception md app + true diff --git a/stl/msbuild/stl_base/md/msvcp_kernel32/msvcp.nativeproj b/stl/msbuild/stl_base/md/msvcp_kernel32/msvcp.nativeproj index 4077e457f8b..1a605f5a8c5 100644 --- a/stl/msbuild/stl_base/md/msvcp_kernel32/msvcp.nativeproj +++ b/stl/msbuild/stl_base/md/msvcp_kernel32/msvcp.nativeproj @@ -8,6 +8,7 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception md kernel32 + true diff --git a/stl/msbuild/stl_base/md/msvcp_onecore/msvcp.nativeproj b/stl/msbuild/stl_base/md/msvcp_onecore/msvcp.nativeproj index d5467e4b419..991f19e2f12 100644 --- a/stl/msbuild/stl_base/md/msvcp_onecore/msvcp.nativeproj +++ b/stl/msbuild/stl_base/md/msvcp_onecore/msvcp.nativeproj @@ -8,6 +8,7 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception md onecore + true diff --git a/stl/msbuild/stl_base/msvcp.settings.targets b/stl/msbuild/stl_base/msvcp.settings.targets index f1756369e8a..1155276faab 100644 --- a/stl/msbuild/stl_base/msvcp.settings.targets +++ b/stl/msbuild/stl_base/msvcp.settings.targets @@ -10,8 +10,6 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception $(MsvcpFlavor) true - true - true true @@ -41,15 +39,17 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception $(CrtBuildDir)\msvcprt_base$(BuildSuffix).$(MsvcpFlavor).import_only.lib $(LibOutputFileName).$(MsvcpFlavor) $(IntermediateOutputDirectory)\$(DllDefName).def + $(IntermediateOutputDirectoryEC)\$(DllDefName).def + $(IntermediateOutputDirectory)\$(DllDefName).def $(ClDefines);_STL_CONCRT_SUPPORT true $(OutputPath)\$(OutputName)$(_PDB_VER_NAME_)$(DllPdbFlavorSuffix) + $(OutputPath)\$(OutputName).arm64$(DllPdbFlavorSuffix) -debugtype:cv,fixup $(LinkAdditionalOptions) -opt:ref,icf=3 $(LinkAdditionalOptions) -opt:ref,noicf $(LinkAdditionalOptions) - /delayload:concrt$(VCToolsProdVerSuffix)$(BuildSuffix)$(MsvcpFlavorSuffix).dll $(LinkAdditionalOptions) -nodefaultlib:libcpmt$(BuildSuffix).lib $(LinkAdditionalOptions) -nodefaultlib:$(LibOutputFile) $(LinkAdditionalOptions) @@ -75,14 +75,6 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - - - - - - - - + + + + $(IntermediateOutputDirectoryEC)\_tolower.obj; + $(IntermediateOutputDirectoryEC)\_toupper.obj; + $(IntermediateOutputDirectoryEC)\atomic.obj; + $(IntermediateOutputDirectoryEC)\cthread.obj; + $(IntermediateOutputDirectoryEC)\xnotify.obj; + $(IntermediateOutputDirectoryEC)\xtime.obj; + $(IntermediateOutputDirectoryEC)\xcosh.obj; + $(IntermediateOutputDirectoryEC)\xdint.obj; + $(IntermediateOutputDirectoryEC)\xdnorm.obj; + $(IntermediateOutputDirectoryEC)\xdscale.obj; + $(IntermediateOutputDirectoryEC)\xdtento.obj; + $(IntermediateOutputDirectoryEC)\xdtest.obj; + $(IntermediateOutputDirectoryEC)\xdunscal.obj; + $(IntermediateOutputDirectoryEC)\xexp.obj; + $(IntermediateOutputDirectoryEC)\xfcosh.obj; + $(IntermediateOutputDirectoryEC)\xfdint.obj; + $(IntermediateOutputDirectoryEC)\xfdnorm.obj; + $(IntermediateOutputDirectoryEC)\xfdscale.obj; + $(IntermediateOutputDirectoryEC)\xfdtento.obj; + $(IntermediateOutputDirectoryEC)\xfdtest.obj; + $(IntermediateOutputDirectoryEC)\xfdunsca.obj; + $(IntermediateOutputDirectoryEC)\xferaise.obj; + $(IntermediateOutputDirectoryEC)\xfexp.obj; + $(IntermediateOutputDirectoryEC)\xfprec.obj; + $(IntermediateOutputDirectoryEC)\xfsinh.obj; + $(IntermediateOutputDirectoryEC)\xfvalues.obj; + $(IntermediateOutputDirectoryEC)\xgetwctype.obj; + $(IntermediateOutputDirectoryEC)\xlcosh.obj; + $(IntermediateOutputDirectoryEC)\xldint.obj; + $(IntermediateOutputDirectoryEC)\xldscale.obj; + $(IntermediateOutputDirectoryEC)\xldtento.obj; + $(IntermediateOutputDirectoryEC)\xldtest.obj; + $(IntermediateOutputDirectoryEC)\xldunsca.obj; + $(IntermediateOutputDirectoryEC)\xlexp.obj; + $(IntermediateOutputDirectoryEC)\xlpoly.obj; + $(IntermediateOutputDirectoryEC)\xlprec.obj; + $(IntermediateOutputDirectoryEC)\xlsinh.obj; + $(IntermediateOutputDirectoryEC)\xlvalues.obj; + $(IntermediateOutputDirectoryEC)\xmbtowc.obj; + $(IntermediateOutputDirectoryEC)\xmtx.obj; + $(IntermediateOutputDirectoryEC)\xpoly.obj; + $(IntermediateOutputDirectoryEC)\xprec.obj; + $(IntermediateOutputDirectoryEC)\xsinh.obj; + $(IntermediateOutputDirectoryEC)\xstod.obj; + $(IntermediateOutputDirectoryEC)\xstof.obj; + $(IntermediateOutputDirectoryEC)\xstoflt.obj; + $(IntermediateOutputDirectoryEC)\xstol.obj; + $(IntermediateOutputDirectoryEC)\xstold.obj; + $(IntermediateOutputDirectoryEC)\xstoll.obj; + $(IntermediateOutputDirectoryEC)\xstopfx.obj; + $(IntermediateOutputDirectoryEC)\xstoul.obj; + $(IntermediateOutputDirectoryEC)\xstoull.obj; + $(IntermediateOutputDirectoryEC)\xstoxflt.obj; + $(IntermediateOutputDirectoryEC)\xstrcoll.obj; + $(IntermediateOutputDirectoryEC)\xstrxfrm.obj; + $(IntermediateOutputDirectoryEC)\xtowlower.obj; + $(IntermediateOutputDirectoryEC)\xtowupper.obj; + $(IntermediateOutputDirectoryEC)\xvalues.obj; + $(IntermediateOutputDirectoryEC)\xwcscoll.obj; + $(IntermediateOutputDirectoryEC)\xwcsxfrm.obj; + $(IntermediateOutputDirectoryEC)\xwctomb.obj; + $(IntermediateOutputDirectoryEC)\xwstod.obj; + $(IntermediateOutputDirectoryEC)\xwstof.obj; + $(IntermediateOutputDirectoryEC)\xwstoflt.obj; + $(IntermediateOutputDirectoryEC)\xwstold.obj; + $(IntermediateOutputDirectoryEC)\xwstopfx.obj; + $(IntermediateOutputDirectoryEC)\xwstoxfl.obj; + $(IntermediateOutputDirectoryEC)\excptptr.obj; + $(IntermediateOutputDirectoryEC)\StlCompareStringA.obj; + $(IntermediateOutputDirectoryEC)\StlCompareStringW.obj; + $(IntermediateOutputDirectoryEC)\StlLCMapStringA.obj; + $(IntermediateOutputDirectoryEC)\StlLCMapStringW.obj; + $(IntermediateOutputDirectoryEC)\winapinls.obj; + $(IntermediateOutputDirectoryEC)\cerr.obj; + $(IntermediateOutputDirectoryEC)\cin.obj; + $(IntermediateOutputDirectoryEC)\clog.obj; + $(IntermediateOutputDirectoryEC)\cout.obj; + $(IntermediateOutputDirectoryEC)\filesys.obj; + $(IntermediateOutputDirectoryEC)\fiopen.obj; + $(IntermediateOutputDirectoryEC)\future.obj; + $(IntermediateOutputDirectoryEC)\iomanip.obj; + $(IntermediateOutputDirectoryEC)\ios.obj; + $(IntermediateOutputDirectoryEC)\iosptrs.obj; + $(IntermediateOutputDirectoryEC)\iostream.obj; + $(IntermediateOutputDirectoryEC)\locale.obj; + $(IntermediateOutputDirectoryEC)\locale0.obj; + $(IntermediateOutputDirectoryEC)\multprec.obj; + $(IntermediateOutputDirectoryEC)\raisehan.obj; + $(IntermediateOutputDirectoryEC)\stdhndlr.obj; + $(IntermediateOutputDirectoryEC)\stdthrow.obj; + $(IntermediateOutputDirectoryEC)\syserror.obj; + $(IntermediateOutputDirectoryEC)\cond.obj; + $(IntermediateOutputDirectoryEC)\mutex.obj; + $(IntermediateOutputDirectoryEC)\pplerror.obj; + $(IntermediateOutputDirectoryEC)\ppltasks.obj; + $(IntermediateOutputDirectoryEC)\taskscheduler.obj; + $(IntermediateOutputDirectoryEC)\thread0.obj; + $(IntermediateOutputDirectoryEC)\uncaught_exception.obj; + $(IntermediateOutputDirectoryEC)\uncaught_exceptions.obj; + $(IntermediateOutputDirectoryEC)\ushcerr.obj; + $(IntermediateOutputDirectoryEC)\ushcin.obj; + $(IntermediateOutputDirectoryEC)\ushclog.obj; + $(IntermediateOutputDirectoryEC)\ushcout.obj; + $(IntermediateOutputDirectoryEC)\ushiostr.obj; + $(IntermediateOutputDirectoryEC)\wcerr.obj; + $(IntermediateOutputDirectoryEC)\wcin.obj; + $(IntermediateOutputDirectoryEC)\wclog.obj; + $(IntermediateOutputDirectoryEC)\wcout.obj; + $(IntermediateOutputDirectoryEC)\wiostrea.obj; + $(IntermediateOutputDirectoryEC)\wlocale.obj; + $(IntermediateOutputDirectoryEC)\xalloc.obj; + $(IntermediateOutputDirectoryEC)\xdateord.obj; + $(IntermediateOutputDirectoryEC)\xlgamma.obj; + $(IntermediateOutputDirectoryEC)\xlocale.obj; + $(IntermediateOutputDirectoryEC)\xlock.obj; + $(IntermediateOutputDirectoryEC)\xonce.obj; + $(IntermediateOutputDirectoryEC)\xrngabort.obj; + $(IntermediateOutputDirectoryEC)\xrngdev.obj; + $(IntermediateOutputDirectoryEC)\xthrow.obj; + $(IntermediateOutputDirectoryEC)\winapisupp.obj; + $(IntermediateOutputDirectoryEC)\dllmain.obj; + $(IntermediateOutputDirectoryEC)\instances.obj; + + + + + $(IntermediateOutputDirectoryEC)\filesystem.obj; + $(IntermediateOutputDirectoryEC)\locale0_implib.obj; + $(IntermediateOutputDirectoryEC)\nothrow.obj; + $(IntermediateOutputDirectoryEC)\parallel_algorithms.obj; + $(IntermediateOutputDirectoryEC)\sharedmutex.obj; + $(IntermediateOutputDirectoryEC)\vector_algorithms.obj; + + + + + + + + + + false + true + + + + + + + + + + diff --git a/stl/msbuild/stl_base/mt/libcpmt_kernel32/libcpmt.nativeproj b/stl/msbuild/stl_base/mt/libcpmt_kernel32/libcpmt.nativeproj index 5071e0d8453..e5fda7b500b 100644 --- a/stl/msbuild/stl_base/mt/libcpmt_kernel32/libcpmt.nativeproj +++ b/stl/msbuild/stl_base/mt/libcpmt_kernel32/libcpmt.nativeproj @@ -8,6 +8,7 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception mt kernel32 + true diff --git a/stl/msbuild/stl_base/mt/libcpmt_onecore/libcpmt.nativeproj b/stl/msbuild/stl_base/mt/libcpmt_onecore/libcpmt.nativeproj index b40597da691..f6f1144b9af 100644 --- a/stl/msbuild/stl_base/mt/libcpmt_onecore/libcpmt.nativeproj +++ b/stl/msbuild/stl_base/mt/libcpmt_onecore/libcpmt.nativeproj @@ -8,6 +8,7 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception mt onecore + true diff --git a/stl/msbuild/stl_base/mt1/libcpmt_kernel32/libcpmt.nativeproj b/stl/msbuild/stl_base/mt1/libcpmt_kernel32/libcpmt.nativeproj index 1d22da408f1..1ef7535fc2b 100644 --- a/stl/msbuild/stl_base/mt1/libcpmt_kernel32/libcpmt.nativeproj +++ b/stl/msbuild/stl_base/mt1/libcpmt_kernel32/libcpmt.nativeproj @@ -8,6 +8,7 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception mt1 kernel32 + true diff --git a/stl/msbuild/stl_base/mt1/libcpmt_onecore/libcpmt.nativeproj b/stl/msbuild/stl_base/mt1/libcpmt_onecore/libcpmt.nativeproj index e97431955f0..889fbe794cb 100644 --- a/stl/msbuild/stl_base/mt1/libcpmt_onecore/libcpmt.nativeproj +++ b/stl/msbuild/stl_base/mt1/libcpmt_onecore/libcpmt.nativeproj @@ -8,6 +8,7 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception mt1 onecore + true diff --git a/stl/msbuild/stl_base/xmd/msvcp_app/msvcp.nativeproj b/stl/msbuild/stl_base/xmd/msvcp_app/msvcp.nativeproj index ffa91054e16..e3b55c5e3dc 100644 --- a/stl/msbuild/stl_base/xmd/msvcp_app/msvcp.nativeproj +++ b/stl/msbuild/stl_base/xmd/msvcp_app/msvcp.nativeproj @@ -8,6 +8,7 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception xmd app + true diff --git a/stl/msbuild/stl_base/xmd/msvcp_kernel32/msvcp.nativeproj b/stl/msbuild/stl_base/xmd/msvcp_kernel32/msvcp.nativeproj index d0fb2ae3341..6a31bf3a079 100644 --- a/stl/msbuild/stl_base/xmd/msvcp_kernel32/msvcp.nativeproj +++ b/stl/msbuild/stl_base/xmd/msvcp_kernel32/msvcp.nativeproj @@ -8,6 +8,7 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception xmd kernel32 + true diff --git a/stl/msbuild/stl_base/xmd/msvcp_onecore/msvcp.nativeproj b/stl/msbuild/stl_base/xmd/msvcp_onecore/msvcp.nativeproj index a0a70b0825d..d166a3f4b9d 100644 --- a/stl/msbuild/stl_base/xmd/msvcp_onecore/msvcp.nativeproj +++ b/stl/msbuild/stl_base/xmd/msvcp_onecore/msvcp.nativeproj @@ -8,6 +8,7 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception xmd onecore + true diff --git a/stl/msbuild/stl_base/xmt/libcpmt_kernel32/libcpmt.nativeproj b/stl/msbuild/stl_base/xmt/libcpmt_kernel32/libcpmt.nativeproj index f22c306f367..f7b8117cbeb 100644 --- a/stl/msbuild/stl_base/xmt/libcpmt_kernel32/libcpmt.nativeproj +++ b/stl/msbuild/stl_base/xmt/libcpmt_kernel32/libcpmt.nativeproj @@ -8,6 +8,7 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception xmt kernel32 + true diff --git a/stl/msbuild/stl_base/xmt/libcpmt_onecore/libcpmt.nativeproj b/stl/msbuild/stl_base/xmt/libcpmt_onecore/libcpmt.nativeproj index 0582903f883..86c82dff9c2 100644 --- a/stl/msbuild/stl_base/xmt/libcpmt_onecore/libcpmt.nativeproj +++ b/stl/msbuild/stl_base/xmt/libcpmt_onecore/libcpmt.nativeproj @@ -8,6 +8,7 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception xmt onecore + true diff --git a/stl/msbuild/stl_base/xmt0/libcpmt_kernel32/libcpmt.nativeproj b/stl/msbuild/stl_base/xmt0/libcpmt_kernel32/libcpmt.nativeproj index 8e6d59e9871..d76d2b7cab9 100644 --- a/stl/msbuild/stl_base/xmt0/libcpmt_kernel32/libcpmt.nativeproj +++ b/stl/msbuild/stl_base/xmt0/libcpmt_kernel32/libcpmt.nativeproj @@ -8,6 +8,7 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception xmt0 kernel32 + true diff --git a/stl/msbuild/stl_base/xmt0/libcpmt_onecore/libcpmt.nativeproj b/stl/msbuild/stl_base/xmt0/libcpmt_onecore/libcpmt.nativeproj index c32bd67eec8..d1945603266 100644 --- a/stl/msbuild/stl_base/xmt0/libcpmt_onecore/libcpmt.nativeproj +++ b/stl/msbuild/stl_base/xmt0/libcpmt_onecore/libcpmt.nativeproj @@ -8,6 +8,7 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception xmt0 onecore + true diff --git a/stl/msbuild/stl_base/xmt1/libcpmt_kernel32/libcpmt.nativeproj b/stl/msbuild/stl_base/xmt1/libcpmt_kernel32/libcpmt.nativeproj index 9a86fb7ca53..6266c565a18 100644 --- a/stl/msbuild/stl_base/xmt1/libcpmt_kernel32/libcpmt.nativeproj +++ b/stl/msbuild/stl_base/xmt1/libcpmt_kernel32/libcpmt.nativeproj @@ -8,6 +8,7 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception xmt1 kernel32 + true diff --git a/stl/msbuild/stl_base/xmt1/libcpmt_onecore/libcpmt.nativeproj b/stl/msbuild/stl_base/xmt1/libcpmt_onecore/libcpmt.nativeproj index af945f67d07..db93f3f15a1 100644 --- a/stl/msbuild/stl_base/xmt1/libcpmt_onecore/libcpmt.nativeproj +++ b/stl/msbuild/stl_base/xmt1/libcpmt_onecore/libcpmt.nativeproj @@ -8,6 +8,7 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception xmt1 onecore + true diff --git a/stl/msbuild/stl_codecvt_ids/md/msvcp_codecvt_ids_app/msvcp_codecvt_ids.nativeproj b/stl/msbuild/stl_codecvt_ids/md/msvcp_codecvt_ids_app/msvcp_codecvt_ids.nativeproj index 95df8962f5c..317f7eff453 100644 --- a/stl/msbuild/stl_codecvt_ids/md/msvcp_codecvt_ids_app/msvcp_codecvt_ids.nativeproj +++ b/stl/msbuild/stl_codecvt_ids/md/msvcp_codecvt_ids_app/msvcp_codecvt_ids.nativeproj @@ -8,6 +8,7 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception md app + true diff --git a/stl/msbuild/stl_codecvt_ids/md/msvcp_codecvt_ids_kernel32/msvcp_codecvt_ids.nativeproj b/stl/msbuild/stl_codecvt_ids/md/msvcp_codecvt_ids_kernel32/msvcp_codecvt_ids.nativeproj index 312851c7026..7abf5d633e4 100644 --- a/stl/msbuild/stl_codecvt_ids/md/msvcp_codecvt_ids_kernel32/msvcp_codecvt_ids.nativeproj +++ b/stl/msbuild/stl_codecvt_ids/md/msvcp_codecvt_ids_kernel32/msvcp_codecvt_ids.nativeproj @@ -8,6 +8,7 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception md kernel32 + true diff --git a/stl/msbuild/stl_codecvt_ids/md/msvcp_codecvt_ids_onecore/msvcp_codecvt_ids.nativeproj b/stl/msbuild/stl_codecvt_ids/md/msvcp_codecvt_ids_onecore/msvcp_codecvt_ids.nativeproj index d3956721a0d..71825718ba0 100644 --- a/stl/msbuild/stl_codecvt_ids/md/msvcp_codecvt_ids_onecore/msvcp_codecvt_ids.nativeproj +++ b/stl/msbuild/stl_codecvt_ids/md/msvcp_codecvt_ids_onecore/msvcp_codecvt_ids.nativeproj @@ -8,6 +8,7 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception md onecore + true diff --git a/stl/msbuild/stl_codecvt_ids/msvcp_codecvt_ids.settings.targets b/stl/msbuild/stl_codecvt_ids/msvcp_codecvt_ids.settings.targets index 2116ad9a688..3df5ef40e29 100644 --- a/stl/msbuild/stl_codecvt_ids/msvcp_codecvt_ids.settings.targets +++ b/stl/msbuild/stl_codecvt_ids/msvcp_codecvt_ids.settings.targets @@ -50,6 +50,11 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception true + + $(IntermediateOutputDirectoryEC)\$(DllDefName).def + $(IntermediateOutputDirectory)\$(DllDefName).def + + LIBRARYNAME=$(OutputName.ToUpper());$(DllCppDefines) @@ -70,6 +75,11 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + + + + + - + diff --git a/stl/msbuild/stl_codecvt_ids/xmd/msvcp_codecvt_ids_app/msvcp_codecvt_ids.nativeproj b/stl/msbuild/stl_codecvt_ids/xmd/msvcp_codecvt_ids_app/msvcp_codecvt_ids.nativeproj index 6cb0a78aeeb..a07d3c95ef5 100644 --- a/stl/msbuild/stl_codecvt_ids/xmd/msvcp_codecvt_ids_app/msvcp_codecvt_ids.nativeproj +++ b/stl/msbuild/stl_codecvt_ids/xmd/msvcp_codecvt_ids_app/msvcp_codecvt_ids.nativeproj @@ -8,6 +8,7 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception xmd app + true diff --git a/stl/msbuild/stl_codecvt_ids/xmd/msvcp_codecvt_ids_kernel32/msvcp_codecvt_ids.nativeproj b/stl/msbuild/stl_codecvt_ids/xmd/msvcp_codecvt_ids_kernel32/msvcp_codecvt_ids.nativeproj index 221a4ef9b18..58411828c0d 100644 --- a/stl/msbuild/stl_codecvt_ids/xmd/msvcp_codecvt_ids_kernel32/msvcp_codecvt_ids.nativeproj +++ b/stl/msbuild/stl_codecvt_ids/xmd/msvcp_codecvt_ids_kernel32/msvcp_codecvt_ids.nativeproj @@ -8,6 +8,7 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception xmd kernel32 + true diff --git a/stl/msbuild/stl_codecvt_ids/xmd/msvcp_codecvt_ids_onecore/msvcp_codecvt_ids.nativeproj b/stl/msbuild/stl_codecvt_ids/xmd/msvcp_codecvt_ids_onecore/msvcp_codecvt_ids.nativeproj index 904914f1af7..e603fe84374 100644 --- a/stl/msbuild/stl_codecvt_ids/xmd/msvcp_codecvt_ids_onecore/msvcp_codecvt_ids.nativeproj +++ b/stl/msbuild/stl_codecvt_ids/xmd/msvcp_codecvt_ids_onecore/msvcp_codecvt_ids.nativeproj @@ -8,6 +8,7 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception xmd onecore + true diff --git a/stl/msbuild/stl_post/md/msvcp_post_app/msvcp_post.nativeproj b/stl/msbuild/stl_post/md/msvcp_post_app/msvcp_post.nativeproj index 6cf96cf5791..e5422b71165 100644 --- a/stl/msbuild/stl_post/md/msvcp_post_app/msvcp_post.nativeproj +++ b/stl/msbuild/stl_post/md/msvcp_post_app/msvcp_post.nativeproj @@ -8,6 +8,7 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception md app + true diff --git a/stl/msbuild/stl_post/md/msvcp_post_kernel32/msvcp_post.nativeproj b/stl/msbuild/stl_post/md/msvcp_post_kernel32/msvcp_post.nativeproj index 098b4202e11..25cd54fef6f 100644 --- a/stl/msbuild/stl_post/md/msvcp_post_kernel32/msvcp_post.nativeproj +++ b/stl/msbuild/stl_post/md/msvcp_post_kernel32/msvcp_post.nativeproj @@ -8,6 +8,7 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception md kernel32 + true diff --git a/stl/msbuild/stl_post/md/msvcp_post_netcore/msvcp_post.nativeproj b/stl/msbuild/stl_post/md/msvcp_post_netcore/msvcp_post.nativeproj index 098b4202e11..25cd54fef6f 100644 --- a/stl/msbuild/stl_post/md/msvcp_post_netcore/msvcp_post.nativeproj +++ b/stl/msbuild/stl_post/md/msvcp_post_netcore/msvcp_post.nativeproj @@ -8,6 +8,7 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception md kernel32 + true diff --git a/stl/msbuild/stl_post/md/msvcp_post_onecore/msvcp_post.nativeproj b/stl/msbuild/stl_post/md/msvcp_post_onecore/msvcp_post.nativeproj index 2f33fe6caeb..b9413c6e44c 100644 --- a/stl/msbuild/stl_post/md/msvcp_post_onecore/msvcp_post.nativeproj +++ b/stl/msbuild/stl_post/md/msvcp_post_onecore/msvcp_post.nativeproj @@ -8,6 +8,7 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception md onecore + true diff --git a/stl/msbuild/stl_post/xmd/msvcp_post_app/msvcp_post.nativeproj b/stl/msbuild/stl_post/xmd/msvcp_post_app/msvcp_post.nativeproj index 5ab52321683..c0359f2f7e5 100644 --- a/stl/msbuild/stl_post/xmd/msvcp_post_app/msvcp_post.nativeproj +++ b/stl/msbuild/stl_post/xmd/msvcp_post_app/msvcp_post.nativeproj @@ -8,6 +8,7 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception xmd app + true diff --git a/stl/msbuild/stl_post/xmd/msvcp_post_kernel32/msvcp_post.nativeproj b/stl/msbuild/stl_post/xmd/msvcp_post_kernel32/msvcp_post.nativeproj index 978ebc4f5cc..3656ba523f4 100644 --- a/stl/msbuild/stl_post/xmd/msvcp_post_kernel32/msvcp_post.nativeproj +++ b/stl/msbuild/stl_post/xmd/msvcp_post_kernel32/msvcp_post.nativeproj @@ -8,6 +8,7 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception xmd kernel32 + true diff --git a/stl/msbuild/stl_post/xmd/msvcp_post_netcore/msvcp_post.nativeproj b/stl/msbuild/stl_post/xmd/msvcp_post_netcore/msvcp_post.nativeproj index 978ebc4f5cc..3656ba523f4 100644 --- a/stl/msbuild/stl_post/xmd/msvcp_post_netcore/msvcp_post.nativeproj +++ b/stl/msbuild/stl_post/xmd/msvcp_post_netcore/msvcp_post.nativeproj @@ -8,6 +8,7 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception xmd kernel32 + true diff --git a/stl/msbuild/stl_post/xmd/msvcp_post_onecore/msvcp_post.nativeproj b/stl/msbuild/stl_post/xmd/msvcp_post_onecore/msvcp_post.nativeproj index 452acb060fa..472a8e1f63a 100644 --- a/stl/msbuild/stl_post/xmd/msvcp_post_onecore/msvcp_post.nativeproj +++ b/stl/msbuild/stl_post/xmd/msvcp_post_onecore/msvcp_post.nativeproj @@ -8,6 +8,7 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception xmd onecore + true diff --git a/stl/src/StlCompareStringA.cpp b/stl/src/StlCompareStringA.cpp index 977838a3768..47ffe52bfea 100644 --- a/stl/src/StlCompareStringA.cpp +++ b/stl/src/StlCompareStringA.cpp @@ -2,8 +2,8 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception #include +#include // for __strncnt #include -#include #include @@ -146,5 +146,6 @@ extern "C" int __cdecl __crtCompareStringA(_In_z_ LPCWSTR LocaleName, _In_ DWORD return 0; } - return __crtCompareStringEx(LocaleName, dwCmpFlags, wbuffer1.get(), buff_size1, wbuffer2.get(), buff_size2); + return CompareStringEx( + LocaleName, dwCmpFlags, wbuffer1.get(), buff_size1, wbuffer2.get(), buff_size2, nullptr, nullptr, 0); } diff --git a/stl/src/StlCompareStringW.cpp b/stl/src/StlCompareStringW.cpp index d4c80042608..424593c03a0 100644 --- a/stl/src/StlCompareStringW.cpp +++ b/stl/src/StlCompareStringW.cpp @@ -1,9 +1,7 @@ // Copyright (c) Microsoft Corporation. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -#include -#include -#include +#include // for wcsnlen #include @@ -43,5 +41,5 @@ extern "C" int __cdecl __crtCompareStringW(_In_z_ LPCWSTR LocaleName, _In_ DWORD return (cchCount1 - cchCount2 == 0) ? 2 : (cchCount1 - cchCount2 < 0) ? 1 : 3; } - return __crtCompareStringEx(LocaleName, dwCmpFlags, lpString1, cchCount1, lpString2, cchCount2); + return CompareStringEx(LocaleName, dwCmpFlags, lpString1, cchCount1, lpString2, cchCount2, nullptr, nullptr, 0); } diff --git a/stl/src/StlLCMapStringA.cpp b/stl/src/StlLCMapStringA.cpp index bb5651e3bce..d176fcc4151 100644 --- a/stl/src/StlLCMapStringA.cpp +++ b/stl/src/StlLCMapStringA.cpp @@ -2,7 +2,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception #include -#include #include "awint.hpp" @@ -71,7 +70,7 @@ extern "C" int __cdecl __crtLCMapStringA(_In_opt_z_ LPCWSTR LocaleName, _In_ DWO } // get size required for string mapping - int retval = __crtLCMapStringEx(LocaleName, dwMapFlags, inwbuffer.get(), inbuff_size, nullptr, 0); + int retval = LCMapStringEx(LocaleName, dwMapFlags, inwbuffer.get(), inbuff_size, nullptr, 0, nullptr, nullptr, 0); if (0 == retval) { return 0; } @@ -85,8 +84,8 @@ extern "C" int __cdecl __crtLCMapStringA(_In_opt_z_ LPCWSTR LocaleName, _In_ DWO // do string mapping if (0 - == __crtLCMapStringEx(LocaleName, dwMapFlags, inwbuffer.get(), inbuff_size, - reinterpret_cast(lpDestStr), cchDest)) { + == LCMapStringEx(LocaleName, dwMapFlags, inwbuffer.get(), inbuff_size, + reinterpret_cast(lpDestStr), cchDest, nullptr, nullptr, 0)) { return retval; } } @@ -103,8 +102,8 @@ extern "C" int __cdecl __crtLCMapStringA(_In_opt_z_ LPCWSTR LocaleName, _In_ DWO // do string mapping if (0 - == __crtLCMapStringEx( - LocaleName, dwMapFlags, inwbuffer.get(), inbuff_size, outwbuffer.get(), outbuff_size)) { + == LCMapStringEx(LocaleName, dwMapFlags, inwbuffer.get(), inbuff_size, outwbuffer.get(), outbuff_size, + nullptr, nullptr, 0)) { return retval; } diff --git a/stl/src/StlLCMapStringW.cpp b/stl/src/StlLCMapStringW.cpp index d388a2a7770..625e8f8075c 100644 --- a/stl/src/StlLCMapStringW.cpp +++ b/stl/src/StlLCMapStringW.cpp @@ -1,8 +1,7 @@ // Copyright (c) Microsoft Corporation. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -#include -#include +#include // for wcsnlen #include "awint.hpp" @@ -47,5 +46,6 @@ extern "C" int __cdecl __crtLCMapStringW(_In_opt_z_ LPCWSTR const locale_name, _ } } - return __crtLCMapStringEx(locale_name, map_flags, source, source_count, destination, destination_count); + return LCMapStringEx( + locale_name, map_flags, source, source_count, destination, destination_count, nullptr, nullptr, 0); } diff --git a/stl/src/_tolower.cpp b/stl/src/_tolower.cpp index 21d35f55a10..6d91a498b0f 100644 --- a/stl/src/_tolower.cpp +++ b/stl/src/_tolower.cpp @@ -5,11 +5,10 @@ #include -#include +#include +#include +#include #include -#include -#include -#include #include #include "awint.hpp" diff --git a/stl/src/_toupper.cpp b/stl/src/_toupper.cpp index e0cc01cc5af..78953a811a6 100644 --- a/stl/src/_toupper.cpp +++ b/stl/src/_toupper.cpp @@ -5,9 +5,9 @@ #include -#include -#include -#include +#include +#include +#include #include #include "awint.hpp" diff --git a/stl/src/awint.hpp b/stl/src/awint.hpp index c52f3ce746f..66eed7ab9ca 100644 --- a/stl/src/awint.hpp +++ b/stl/src/awint.hpp @@ -16,194 +16,6 @@ _CRT_BEGIN_C_HEADER _CRTIMP2 BOOL __cdecl __crtIsPackagedApp(); #endif // !defined(_CRT_WINDOWS) && !defined(UNDOCKED_WINDOWS_UCRT) -#if _STL_WIN32_WINNT >= _WIN32_WINNT_WS03 - -#define __crtFlsAlloc(lpCallback) FlsAlloc(lpCallback) - -#define __crtFlsFree(dwFlsIndex) FlsFree(dwFlsIndex) - -#define __crtFlsGetValue(dwFlsIndex) FlsGetValue(dwFlsIndex) - -#define __crtFlsSetValue(dwFlsIndex, lpFlsData) FlsSetValue(dwFlsIndex, lpFlsData) - -#else // _STL_WIN32_WINNT >= _WIN32_WINNT_WS03 - -DWORD __cdecl __crtFlsAlloc(_In_opt_ PFLS_CALLBACK_FUNCTION lpCallback); - -BOOL __cdecl __crtFlsFree(_In_ DWORD dwFlsIndex); - -PVOID __cdecl __crtFlsGetValue(_In_ DWORD dwFlsIndex); - -BOOL __cdecl __crtFlsSetValue(_In_ DWORD dwFlsIndex, _In_opt_ PVOID lpFlsData); - -#endif // _STL_WIN32_WINNT >= _WIN32_WINNT_WS03 - - -#if _STL_WIN32_WINNT >= _WIN32_WINNT_VISTA - -#define __crtInitializeCriticalSectionEx(lpCriticalSection, dwSpinCount, Flags) \ - InitializeCriticalSectionEx(lpCriticalSection, dwSpinCount, Flags) - -#define __crtInitOnceExecuteOnce(InitOnce, InitFn, Parameter, Context) \ - InitOnceExecuteOnce(InitOnce, InitFn, Parameter, Context) - -#define __crtCreateEventExW(lpEventAttributes, lpName, dwFlags, dwDesiredAccess) \ - CreateEventExW(lpEventAttributes, lpName, dwFlags, dwDesiredAccess) - -#define __crtCreateSemaphoreExW(lpSemaphoreAttributes, lInitialCount, lMaximumCount, lpName, dwFlags, dwDesiredAccess) \ - CreateSemaphoreExW(lpSemaphoreAttributes, lInitialCount, lMaximumCount, lpName, dwFlags, dwDesiredAccess) - -#define __crtCreateThreadpoolTimer(pfnti, pv, pcbe) CreateThreadpoolTimer(pfnti, pv, pcbe) - -#define __crtSetThreadpoolTimer(pti, pftDueTime, msPeriod, msWindowLength) \ - SetThreadpoolTimer(pti, pftDueTime, msPeriod, msWindowLength) - -#define __crtWaitForThreadpoolTimerCallbacks(pti, fCancelPendingCallbacks) \ - WaitForThreadpoolTimerCallbacks(pti, fCancelPendingCallbacks) - -#define __crtCloseThreadpoolTimer(pti) CloseThreadpoolTimer(pti) - -#define __crtCreateThreadpoolWait(pfnwa, pv, pcbe) CreateThreadpoolWait(pfnwa, pv, pcbe) - -#define __crtSetThreadpoolWait(pwa, h, pftTimeout) SetThreadpoolWait(pwa, h, pftTimeout) - -#define __crtCloseThreadpoolWait(pwa) CloseThreadpoolWait(pwa) - -#define __crtFlushProcessWriteBuffers() FlushProcessWriteBuffers() - -#define __crtFreeLibraryWhenCallbackReturns(pci, mod) FreeLibraryWhenCallbackReturns(pci, mod) - -#define __crtGetCurrentProcessorNumber() GetCurrentProcessorNumber() - -#define __crtCreateSymbolicLinkW(lpSymlinkFileName, lpTargetFileName, dwFlags) \ - CreateSymbolicLinkW(lpSymlinkFileName, lpTargetFileName, dwFlags) - -#define __crtGetFileInformationByHandleEx(hFile, FileInformationClass, lpFileInformation, dwBufferSize) \ - GetFileInformationByHandleEx(hFile, FileInformationClass, lpFileInformation, dwBufferSize) - -#define __crtSetFileInformationByHandle(hFile, FileInformationClass, lpFileInformation, dwBufferSize) \ - SetFileInformationByHandle(hFile, FileInformationClass, lpFileInformation, dwBufferSize) - -#define __crtGetTickCount64() GetTickCount64() - -#define __crtInitializeConditionVariable(pCond) InitializeConditionVariable(pCond) - -#define __crtWakeConditionVariable(pCond) WakeConditionVariable(pCond) - -#define __crtWakeAllConditionVariable(pCond) WakeAllConditionVariable(pCond) - -#define __crtSleepConditionVariableCS(pCond, pLock, dwMs) SleepConditionVariableCS(pCond, pLock, dwMs) - -#define __crtInitializeSRWLock(pLock) InitializeSRWLock(pLock) - -#define __crtAcquireSRWLockExclusive(pLock) AcquireSRWLockExclusive(pLock) - -#define __crtReleaseSRWLockExclusive(pLock) ReleaseSRWLockExclusive(pLock) - -#define __crtSleepConditionVariableSRW(pCond, pLock, dwMs, flags) SleepConditionVariableSRW(pCond, pLock, dwMs, flags) - -#define __crtCreateThreadpoolWork(pfnwk, pv, pcbe) CreateThreadpoolWork(pfnwk, pv, pcbe) - -#define __crtSubmitThreadpoolWork(pwk) SubmitThreadpoolWork(pwk) - -#define __crtCloseThreadpoolWork(pwk) CloseThreadpoolWork(pwk) - -#define __crtCompareStringEx(lpLocaleName, dwCmpFlags, lpString1, cchCount1, lpString2, cchCount2) \ - CompareStringEx(lpLocaleName, dwCmpFlags, lpString1, cchCount1, lpString2, cchCount2, nullptr, nullptr, 0) - -#define __crtLCMapStringEx(lpLocaleName, dwMapFlags, lpSrcStr, cchStr, lpDestStr, cchDest) \ - LCMapStringEx(lpLocaleName, dwMapFlags, lpSrcStr, cchStr, lpDestStr, cchDest, nullptr, nullptr, 0) - -#define __crtGetLocaleInfoEx(lpLocaleName, LCType, lpLCData, cchData) \ - GetLocaleInfoEx(lpLocaleName, LCType, lpLCData, cchData) - -#else // _STL_WIN32_WINNT >= _WIN32_WINNT_VISTA - -_CRTIMP2 BOOL __cdecl __crtInitializeCriticalSectionEx( - _Out_ LPCRITICAL_SECTION lpCriticalSection, _In_ DWORD dwSpinCount, _In_ DWORD Flags); - -// N.B. Context is not used -_CRTIMP2 BOOL __cdecl __crtInitOnceExecuteOnce( - _Inout_ PINIT_ONCE InitOnce, _In_ PINIT_ONCE_FN InitFn, _Inout_opt_ PVOID Parameter, LPVOID* Context); - -_CRTIMP2 HANDLE __cdecl __crtCreateEventExW(_In_opt_ LPSECURITY_ATTRIBUTES lpEventAttributes, _In_opt_ LPCWSTR lpName, - _In_ DWORD dwFlags, _In_ DWORD dwDesiredAccess); - -_CRTIMP2 HANDLE __cdecl __crtCreateSemaphoreExW(_In_opt_ LPSECURITY_ATTRIBUTES lpSemaphoreAttributes, - _In_ LONG lInitialCount, _In_ LONG lMaximumCount, _In_opt_ LPCWSTR lpName, _Reserved_ DWORD dwFlags, - _In_ DWORD dwDesiredAccess); - -_CRTIMP2 PTP_TIMER __cdecl __crtCreateThreadpoolTimer( - _In_ PTP_TIMER_CALLBACK pfnti, _Inout_opt_ PVOID pv, _In_opt_ PTP_CALLBACK_ENVIRON pcbe); - -_CRTIMP2 VOID __cdecl __crtSetThreadpoolTimer( - _Inout_ PTP_TIMER pti, _In_opt_ PFILETIME pftDueTime, _In_ DWORD msPeriod, _In_opt_ DWORD msWindowLength); - -_CRTIMP2 VOID __cdecl __crtWaitForThreadpoolTimerCallbacks(_Inout_ PTP_TIMER pti, _In_ BOOL fCancelPendingCallbacks); - -_CRTIMP2 VOID __cdecl __crtCloseThreadpoolTimer(_Inout_ PTP_TIMER pti); - -_CRTIMP2 PTP_WAIT __cdecl __crtCreateThreadpoolWait( - _In_ PTP_WAIT_CALLBACK pfnwa, _Inout_opt_ PVOID pv, _In_opt_ PTP_CALLBACK_ENVIRON pcbe); - -_CRTIMP2 VOID __cdecl __crtSetThreadpoolWait(_Inout_ PTP_WAIT pwa, _In_opt_ HANDLE h, _In_opt_ PFILETIME pftTimeout); - -_CRTIMP2 VOID __cdecl __crtCloseThreadpoolWait(_Inout_ PTP_WAIT pwa); - -_CRTIMP2 VOID __cdecl __crtFlushProcessWriteBuffers(); - -_CRTIMP2 VOID __cdecl __crtFreeLibraryWhenCallbackReturns(_Inout_ PTP_CALLBACK_INSTANCE pci, _In_ HMODULE mod); - -_CRTIMP2 DWORD __cdecl __crtGetCurrentProcessorNumber(); - -_CRTIMP2 BOOLEAN __cdecl __crtCreateSymbolicLinkW( - _In_ LPCWSTR lpSymlinkFileName, _In_ LPCWSTR lpTargetFileName, _In_ DWORD dwFlags); - -_CRTIMP2 _Success_(return ) BOOL - __cdecl __crtGetFileInformationByHandleEx(_In_ HANDLE hFile, _In_ FILE_INFO_BY_HANDLE_CLASS FileInformationClass, - _Out_writes_bytes_(dwBufferSize) LPVOID lpFileInformation, _In_ DWORD dwBufferSize); - -_CRTIMP2 BOOL __cdecl __crtSetFileInformationByHandle(_In_ HANDLE hFile, - _In_ FILE_INFO_BY_HANDLE_CLASS FileInformationClass, _In_reads_bytes_(dwBufferSize) LPVOID lpFileInformation, - _In_ DWORD dwBufferSize); - -_CRTIMP2 ULONGLONG __cdecl __crtGetTickCount64(); - -VOID __cdecl __crtInitializeConditionVariable(_Out_ PCONDITION_VARIABLE); - -VOID __cdecl __crtWakeConditionVariable(_Inout_ PCONDITION_VARIABLE); - -VOID __cdecl __crtWakeAllConditionVariable(_Inout_ PCONDITION_VARIABLE); - -BOOL __cdecl __crtSleepConditionVariableCS(_Inout_ PCONDITION_VARIABLE, _Inout_ PCRITICAL_SECTION, _In_ DWORD); - -VOID __cdecl __crtInitializeSRWLock(_Out_ PSRWLOCK); - -VOID __cdecl __crtAcquireSRWLockExclusive(_Inout_ PSRWLOCK); - -VOID __cdecl __crtReleaseSRWLockExclusive(_Inout_ PSRWLOCK); - -BOOL __cdecl __crtSleepConditionVariableSRW(_Inout_ PCONDITION_VARIABLE, _Inout_ PSRWLOCK, _In_ DWORD, _In_ ULONG); - -PTP_WORK __cdecl __crtCreateThreadpoolWork( - _In_ PTP_WORK_CALLBACK pfnwk, _Inout_opt_ PVOID pv, _In_opt_ PTP_CALLBACK_ENVIRON pcbe); - -VOID __cdecl __crtSubmitThreadpoolWork(_Inout_ PTP_WORK pwk); - -VOID __cdecl __crtCloseThreadpoolWork(_Inout_ PTP_WORK pwk); - -_CRTIMP2 int __cdecl __crtCompareStringEx(_In_opt_ LPCWSTR lpLocaleName, _In_ DWORD dwCmpFlags, - _In_NLS_string_(cchCount1) LPCWCH lpString1, _In_ int cchCount1, _In_NLS_string_(cchCount2) LPCWCH lpString2, - _In_ int cchCount2); - -_CRTIMP2 int __cdecl __crtLCMapStringEx(_In_opt_ LPCWSTR lpLocaleName, _In_ DWORD dwMapFlags, - _In_reads_(cchSrc) LPCWSTR lpSrcStr, _In_ int cchSrc, _Out_writes_opt_(cchDest) LPWSTR lpDestStr, _In_ int cchDest); - -_CRTIMP2 int __cdecl __crtGetLocaleInfoEx( - _In_opt_ LPCWSTR lpLocaleName, _In_ LCTYPE LCType, _Out_writes_opt_(cchData) LPWSTR lpLCData, _In_ int cchData); - -#endif // _STL_WIN32_WINNT >= _WIN32_WINNT_VISTA - #if _STL_WIN32_WINNT >= _WIN32_WINNT_WIN7 #define __crtTryAcquireSRWLockExclusive(pLock) TryAcquireSRWLockExclusive(pLock) @@ -225,16 +37,7 @@ _CRTIMP2 void __cdecl __crtGetSystemTimePreciseAsFileTime(_Out_ LPFILETIME lpSys #endif // _STL_WIN32_WINNT >= _WIN32_WINNT_WIN8 -#if _STL_WIN32_WINNT < _WIN32_WINNT_VISTA - -#define __crtQueueUserWorkItem(function, context, flags) QueueUserWorkItem(function, context, flags) - -#else // _STL_WIN32_WINNT < _WIN32_WINNT_VISTA - -BOOL __cdecl __crtQueueUserWorkItem(_In_ LPTHREAD_START_ROUTINE function, _In_opt_ PVOID context, _In_ ULONG flags); - -#endif // _STL_WIN32_WINNT < _WIN32_WINNT_VISTA - +// This enum should not change, even though some functions are no longer imported dynamically enum wrapKERNEL32Functions { eFlsAlloc, eFlsFree, @@ -293,45 +96,8 @@ enum wrapKERNEL32Functions { extern PVOID __KERNEL32Functions[eMaxKernel32Function]; -using PFNFLSALLOC = DWORD(WINAPI*)(PFLS_CALLBACK_FUNCTION); -using PFNFLSFREE = BOOL(WINAPI*)(DWORD); -using PFNFLSGETVALUE = PVOID(WINAPI*)(DWORD); -using PFNFLSSETVALUE = BOOL(WINAPI*)(DWORD, PVOID); -using PFNINITIALIZECRITICALSECTIONEX = BOOL(WINAPI*)(LPCRITICAL_SECTION, DWORD, DWORD); -using PFNINITONCEEXECUTEONCE = BOOL(WINAPI*)(PINIT_ONCE, PINIT_ONCE_FN, PVOID, LPVOID*); -using PFNCREATEEVENTEXW = HANDLE(WINAPI*)(LPSECURITY_ATTRIBUTES, LPCWSTR, DWORD, DWORD); -using PFNCREATESEMAPHOREW = HANDLE(WINAPI*)(LPSECURITY_ATTRIBUTES, LONG, LONG, LPCWSTR); -using PFNCREATESEMAPHOREEXW = HANDLE(WINAPI*)(LPSECURITY_ATTRIBUTES, LONG, LONG, LPCWSTR, DWORD, DWORD); -using PFNCREATETHREADPOOLTIMER = PTP_TIMER(WINAPI*)(PTP_TIMER_CALLBACK, PVOID, PTP_CALLBACK_ENVIRON); -using PFNSETTHREADPOOLTIMER = VOID(WINAPI*)(PTP_TIMER, PFILETIME, DWORD, DWORD); -using PFNWAITFORTHREADPOOLTIMERCALLBACKS = VOID(WINAPI*)(PTP_TIMER, BOOL); -using PFNCLOSETHREADPOOLTIMER = VOID(WINAPI*)(PTP_TIMER); -using PFNCREATETHREADPOOLWAIT = PTP_WAIT(WINAPI*)(PTP_WAIT_CALLBACK, PVOID, PTP_CALLBACK_ENVIRON); -using PFNSETTHREADPOOLWAIT = VOID(WINAPI*)(PTP_WAIT, HANDLE, PFILETIME); -using PFNCLOSETHREADPOOLWAIT = VOID(WINAPI*)(PTP_WAIT); -using PFNFLUSHPROCESSWRITEBUFFERS = VOID(WINAPI*)(); -using PFNFREELIBRARYWHENCALLBACKRETURNS = VOID(WINAPI*)(PTP_CALLBACK_INSTANCE, HMODULE); -using PFNGETCURRENTPROCESSORNUMBER = DWORD(WINAPI*)(); -using PFNCREATESYMBOLICLINKW = BOOLEAN(WINAPI*)(LPCWSTR, LPCWSTR, DWORD); -using PFNGETTICKCOUNT64 = ULONGLONG(WINAPI*)(); -using PFNGETFILEINFORMATIONBYHANDLEEX = BOOL(WINAPI*)(HANDLE, FILE_INFO_BY_HANDLE_CLASS, LPVOID, DWORD); -using PFNSETFILEINFORMATIONBYHANDLE = BOOL(WINAPI*)(HANDLE, FILE_INFO_BY_HANDLE_CLASS, LPVOID, DWORD); -using PFNGETSYSTEMTIMEPRECISEASFILETIME = VOID(WINAPI*)(LPFILETIME); -using PFNINITIALIZECONDITIONVARIABLE = VOID(WINAPI*)(PCONDITION_VARIABLE); -using PFNWAKECONDITIONVARIABLE = VOID(WINAPI*)(PCONDITION_VARIABLE); -using PFNWAKEALLCONDITIONVARIABLE = VOID(WINAPI*)(PCONDITION_VARIABLE); -using PFNSLEEPCONDITIONVARIABLECS = BOOL(WINAPI*)(PCONDITION_VARIABLE, PCRITICAL_SECTION, DWORD); -using PFNINITIALIZESRWLOCK = VOID(WINAPI*)(PSRWLOCK); -using PFNACQUIRESRWLOCKEXCLUSIVE = VOID(WINAPI*)(PSRWLOCK); -using PFNTRYACQUIRESRWLOCKEXCLUSIVE = BOOLEAN(WINAPI*)(PSRWLOCK); -using PFNRELEASESRWLOCKEXCLUSIVE = VOID(WINAPI*)(PSRWLOCK); -using PFNSLEEPCONDITIONVARIABLESRW = BOOL(WINAPI*)(PCONDITION_VARIABLE, PSRWLOCK, DWORD, ULONG); -using PFNCREATETHREADPOOLWORK = PTP_WORK(WINAPI*)(PTP_WORK_CALLBACK, PVOID, PTP_CALLBACK_ENVIRON); -using PFNSUBMITTHREADPOOLWORK = VOID(WINAPI*)(PTP_WORK); -using PFNCLOSETHREADPOOLWORK = VOID(WINAPI*)(PTP_WORK); -using PFNCOMPARESTRINGEX = int(WINAPI*)(LPCWSTR, DWORD, LPCWSTR, int, LPCWSTR, int, LPNLSVERSIONINFO, LPVOID, LPARAM); -using PFNGETLOCALEINFOEX = int(WINAPI*)(LPCWSTR, LCTYPE, LPWSTR, int); -using PFNLCMAPSTRINGEX = int(WINAPI*)(LPCWSTR, DWORD, LPCWSTR, int, LPWSTR, int, LPNLSVERSIONINFO, LPVOID, LPARAM); +using PFNGETSYSTEMTIMEPRECISEASFILETIME = VOID(WINAPI*)(LPFILETIME); +using PFNTRYACQUIRESRWLOCKEXCLUSIVE = BOOLEAN(WINAPI*)(PSRWLOCK); // Use this macro for caching a function pointer from a DLL #define STOREFUNCTIONPOINTER(instance, function_name) \ diff --git a/stl/src/cond.cpp b/stl/src/cond.cpp index 49f79e4633e..c619d264dea 100644 --- a/stl/src/cond.cpp +++ b/stl/src/cond.cpp @@ -3,9 +3,8 @@ // condition variable functions +#include #include -#include -#include #include #include #include diff --git a/stl/src/cthread.cpp b/stl/src/cthread.cpp index 7b144c82151..5a66e009874 100644 --- a/stl/src/cthread.cpp +++ b/stl/src/cthread.cpp @@ -3,11 +3,11 @@ // thread functions +#include +#include +#include +#include #include -#include -#include -#include -#include #include #include diff --git a/stl/src/excptptr.cpp b/stl/src/excptptr.cpp index 6b5879e328b..ed5460df8cd 100644 --- a/stl/src/excptptr.cpp +++ b/stl/src/excptptr.cpp @@ -11,6 +11,8 @@ #endif // _VCRT_ALLOW_INTERNALS #include +#include // for abort +#include // for memcpy #include #include #include @@ -18,9 +20,7 @@ #include #include #include -#include #include -#include #include #include diff --git a/stl/src/filesys.cpp b/stl/src/filesys.cpp index 2ec30bdad0d..02d1fe85a8d 100644 --- a/stl/src/filesys.cpp +++ b/stl/src/filesys.cpp @@ -8,10 +8,10 @@ #include +#include #include #include #include -#include #include @@ -409,7 +409,7 @@ _FS_DLL int __CLRCALL_PURE_OR_CDECL _Symlink(const wchar_t* _Fname1, const wchar (void) _Fname2; return errno = EDOM; // symlinks not supported #else // _CRT_APP - return __crtCreateSymbolicLinkW(_Fname2, _Fname1, 0) != 0 ? 0 : GetLastError(); + return CreateSymbolicLinkW(_Fname2, _Fname1, 0) != 0 ? 0 : GetLastError(); #endif // _CRT_APP } diff --git a/stl/src/filesystem.cpp b/stl/src/filesystem.cpp index cb81206ad2a..a8493ec49ae 100644 --- a/stl/src/filesystem.cpp +++ b/stl/src/filesystem.cpp @@ -9,16 +9,15 @@ // Do not include or define anything else here. // In particular, basic_string must not be included here. +#include #include +#include +#include #include -#include -#include -#include -#include #include #include -#include +#include // We have several switches that do not have case statements for every possible enum value. // Hence, disabling this warning. @@ -29,127 +28,16 @@ static_assert(__std_code_page::_Utf8 == __std_code_page{CP_UTF8}); namespace { -#if !defined(_CRT_APP) - template - [[nodiscard]] _Fn_ptr __stdcall _Runtime_dynamic_link(volatile _STD _Identity_t<_Fn_ptr>* const _Cache, - const wchar_t* const _Module, const char* const _Fn_name, const _Fn_ptr _Fallback) noexcept { - auto _Result = __crt_interlocked_read_pointer(_Cache); - if (_Result) { - return _Result; - } - - const HMODULE _HMod = GetModuleHandleW(_Module); - if (_HMod) { - _Result = reinterpret_cast<_Fn_ptr>(GetProcAddress(_HMod, _Fn_name)); - } - - if (!_Result) { - _Result = _Fallback; - } - - __crt_interlocked_exchange_pointer(_Cache, _Result); - return _Result; - } -#endif // !defined(_CRT_APP) - - // MACRO __vcrt_GetFinalPathNameByHandleW -#if _STL_WIN32_WINNT < _WIN32_WINNT_VISTA - using _GetFinalPathNameByHandleW_t = decltype(&GetFinalPathNameByHandleW); - _GetFinalPathNameByHandleW_t GetFinalPathNameByHandleW_p{}; - - unsigned long __stdcall _Not_supported_GetFinalPathNameByHandleW(HANDLE, wchar_t*, unsigned long, unsigned long) { - SetLastError(ERROR_NOT_SUPPORTED); - return 0; - } - -#define __vcrt_GetFinalPathNameByHandleW \ - (_Runtime_dynamic_link(&GetFinalPathNameByHandleW_p, L"kernel32.dll", "GetFinalPathNameByHandleW", \ - &_Not_supported_GetFinalPathNameByHandleW)) -#else // ^^^ _STL_WIN32_WINNT < _WIN32_WINNT_VISTA ^^^ // vvv _STL_WIN32_WINNT >= _WIN32_WINNT_VISTA vvv -#define __vcrt_GetFinalPathNameByHandleW GetFinalPathNameByHandleW -#endif // _STL_WIN32_WINNT < _WIN32_WINNT_VISTA - - // MACRO __vcrt_GetFileInformationByHandleEx -#if _STL_WIN32_WINNT < _WIN32_WINNT_VISTA - using _GetFileInformationByHandleEx_t = decltype(&GetFileInformationByHandleEx); - _GetFileInformationByHandleEx_t _GetFileInformationByHandleEx_p{}; - - BOOL __stdcall _Not_supported_GetFileInformationByHandleEx( - HANDLE, FILE_INFO_BY_HANDLE_CLASS, void*, unsigned long) { - SetLastError(ERROR_NOT_SUPPORTED); - return 0; - } - -#define __vcrt_GetFileInformationByHandleEx \ - (_Runtime_dynamic_link(&_GetFileInformationByHandleEx_p, L"kernel32.dll", "GetFileInformationByHandleEx", \ - &_Not_supported_GetFileInformationByHandleEx)) - - struct _GetFileInfoByHandleEx { - const _GetFileInformationByHandleEx_t _Fn = __vcrt_GetFileInformationByHandleEx; - - [[nodiscard]] bool _Supported() const noexcept { - return _Fn != _Not_supported_GetFileInformationByHandleEx; - } - - [[nodiscard]] auto operator()(const HANDLE _Handle, const FILE_INFO_BY_HANDLE_CLASS _Class, void* const _Info, - const unsigned long _Size) const noexcept { - return _Fn(_Handle, _Class, _Info, _Size); - } - }; -#else // ^^^ _STL_WIN32_WINNT < _WIN32_WINNT_VISTA ^^^ // vvv _STL_WIN32_WINNT >= _WIN32_WINNT_VISTA vvv -#define __vcrt_GetFileInformationByHandleEx GetFileInformationByHandleEx - - struct _GetFileInfoByHandleEx { - [[nodiscard]] bool _Supported() const noexcept { - return true; - } - - [[nodiscard]] auto operator()(const HANDLE _Handle, const FILE_INFO_BY_HANDLE_CLASS _Class, void* const _Info, - const unsigned long _Size) const noexcept { - return GetFileInformationByHandleEx(_Handle, _Class, _Info, _Size); - } - }; -#endif // _STL_WIN32_WINNT < _WIN32_WINNT_VISTA - - // MACRO __vcrt_SetFileInformationByHandle -#if _STL_WIN32_WINNT < _WIN32_WINNT_VISTA - using _SetFileInformationByHandle_t = decltype(&SetFileInformationByHandle); - _SetFileInformationByHandle_t _SetFileInformationByHandle_p{}; - - BOOL __stdcall _Not_supported_SetFileInformationByHandle(HANDLE, FILE_INFO_BY_HANDLE_CLASS, void*, unsigned long) { - SetLastError(ERROR_NOT_SUPPORTED); - return 0; - } - -#define __vcrt_SetFileInformationByHandle \ - (_Runtime_dynamic_link(&_SetFileInformationByHandle_p, L"kernel32.dll", "SetFileInformationByHandle", \ - &_Not_supported_SetFileInformationByHandle)) -#define _STL_ALWAYS_HAS_SetFileInformationByHandle 0 -#else // ^^^ _STL_WIN32_WINNT < _WIN32_WINNT_VISTA ^^^ // vvv _STL_WIN32_WINNT >= _WIN32_WINNT_VISTA vvv -#define __vcrt_SetFileInformationByHandle SetFileInformationByHandle -#define _STL_ALWAYS_HAS_SetFileInformationByHandle 1 -#endif // _STL_WIN32_WINNT < _WIN32_WINNT_VISTA - // MACRO __vcrt_CreateSymbolicLinkW -#if defined(_CRT_APP) || _STL_WIN32_WINNT < _WIN32_WINNT_VISTA +#ifdef _CRT_APP BOOLEAN __stdcall _Not_supported_CreateSymbolicLinkW(const wchar_t*, const wchar_t*, DWORD) { SetLastError(ERROR_NOT_SUPPORTED); return 0; } -#endif // defined(_CRT_APP) || _STL_WIN32_WINNT < _WIN32_WINNT_VISTA - -#if defined(_CRT_APP) #define __vcrt_CreateSymbolicLinkW _Not_supported_CreateSymbolicLinkW -#elif _STL_WIN32_WINNT < _WIN32_WINNT_VISTA - using _CreateSymbolicLinkW_t = decltype(&CreateSymbolicLinkW); - _CreateSymbolicLinkW_t _CreateSymbolicLinkW_p{}; - -#define __vcrt_CreateSymbolicLinkW \ - (_Runtime_dynamic_link( \ - &_CreateSymbolicLinkW_p, L"kernel32.dll", "CreateSymbolicLinkW", &_Not_supported_CreateSymbolicLinkW)) -#else // !defined(_CRT_APP) && _STL_WIN32_WINNT >= _WIN32_WINNT_VISTA +#else // ^^^ _CRT_APP ^^^ // vvv !_CRT_APP vvv #define __vcrt_CreateSymbolicLinkW CreateSymbolicLinkW -#endif // platform detection for CreateSymbolicLinkW +#endif // _CRT_APP // FUNCTION / MACRO __vcp_CreateFile #ifdef _CRT_APP @@ -233,28 +121,13 @@ namespace { [[nodiscard]] __std_win_error __stdcall _Get_last_write_time_by_handle( const HANDLE _Handle, long long* const _Last_write_filetime) { // read the last write time from _Handle and store it in _Last_write_filetime - __std_win_error _Last_error; FILE_BASIC_INFO _Ex_info; - if (__vcrt_GetFileInformationByHandleEx(_Handle, FileBasicInfo, &_Ex_info, sizeof(_Ex_info)) != 0) { + if (GetFileInformationByHandleEx(_Handle, FileBasicInfo, &_Ex_info, sizeof(_Ex_info)) != 0) { _CSTD memcpy(_Last_write_filetime, &_Ex_info.LastWriteTime, sizeof(*_Last_write_filetime)); return __std_win_error::_Success; } - _Last_error = __std_win_error{GetLastError()}; -#if _STL_WIN32_WINNT < _WIN32_WINNT_VISTA - // note: "maybe Windows XP" test also excludes _CRT_APP - if (_Last_error == __std_win_error::_Not_supported) { - BY_HANDLE_FILE_INFORMATION _Legacy_info; - if (GetFileInformationByHandle(_Handle, &_Legacy_info) != 0) { - _CSTD memcpy(_Last_write_filetime, &_Legacy_info.ftLastWriteTime, sizeof(*_Last_write_filetime)); - return __std_win_error::_Success; - } - - _Last_error = __std_win_error{GetLastError()}; - } -#endif // _STL_WIN32_WINNT < _WIN32_WINNT_VISTA - - return _Last_error; + return __std_win_error{GetLastError()}; } } // unnamed namespace @@ -286,37 +159,22 @@ void __stdcall __std_fs_close_handle(const __std_fs_file_handle _Handle) noexcep __stdcall __std_fs_get_file_attributes_by_handle( _In_ const __std_fs_file_handle _Handle, _Out_ unsigned long* const _File_attributes) noexcept { // read the attributes from _Handle and store it in _File_attributes - __std_win_error _Last_error; const HANDLE _As_plain_handle = reinterpret_cast(_Handle); FILE_BASIC_INFO _Ex_info; - if (__vcrt_GetFileInformationByHandleEx(_As_plain_handle, FileBasicInfo, &_Ex_info, sizeof(_Ex_info)) != 0) { + if (GetFileInformationByHandleEx(_As_plain_handle, FileBasicInfo, &_Ex_info, sizeof(_Ex_info)) != 0) { *_File_attributes = _Ex_info.FileAttributes; return __std_win_error::_Success; } - _Last_error = __std_win_error{GetLastError()}; -#if _STL_WIN32_WINNT < _WIN32_WINNT_VISTA - // note: "maybe Windows XP" test also excludes _CRT_APP - if (_Last_error == __std_win_error::_Not_supported) { - BY_HANDLE_FILE_INFORMATION _Legacy_info; - if (GetFileInformationByHandle(_As_plain_handle, &_Legacy_info) != 0) { - *_File_attributes = _Legacy_info.dwFileAttributes; - return __std_win_error::_Success; - } - - _Last_error = __std_win_error{GetLastError()}; - } -#endif // _STL_WIN32_WINNT < _WIN32_WINNT_VISTA - - return _Last_error; + return __std_win_error{GetLastError()}; } [[nodiscard]] __std_ulong_and_error __stdcall __std_fs_get_final_path_name_by_handle( _In_ const __std_fs_file_handle _Handle, _Out_writes_z_(_Target_size) wchar_t* const _Target, _In_ const unsigned long _Target_size, _In_ const __std_fs_volume_name_kind _Flags) noexcept { // calls GetFinalPathNameByHandleW - const auto _Result = __vcrt_GetFinalPathNameByHandleW( + const auto _Result = GetFinalPathNameByHandleW( reinterpret_cast(_Handle), _Target, _Target_size, static_cast(_Flags)); return {_Result, _Result == 0 ? __std_win_error{GetLastError()} : __std_win_error::_Success}; } @@ -522,8 +380,7 @@ _Success_(return == __std_win_error::_Success) __std_win_error static_assert(sizeof(FILE_ID_INFO) == sizeof(__std_fs_file_id)); static_assert(alignof(FILE_ID_INFO) == alignof(__std_fs_file_id)); - if (__vcrt_GetFileInformationByHandleEx( - _Handle._Get(), FileIdInfo, reinterpret_cast(_Id), sizeof(*_Id)) + if (GetFileInformationByHandleEx(_Handle._Get(), FileIdInfo, reinterpret_cast(_Id), sizeof(*_Id)) != 0) { // if we could get FILE_ID_INFO, use that as the source of truth return __std_win_error::_Success; @@ -632,29 +489,6 @@ _Success_(return == __std_win_error::_Success) __std_win_error [[nodiscard]] __std_fs_remove_result __stdcall __std_fs_remove(_In_z_ const wchar_t* const _Target) noexcept { // remove _Target without caring whether _Target is a file or directory __std_win_error _Last_error; -#if _STL_ALWAYS_HAS_SetFileInformationByHandle -#define _SetFileInformationByHandle SetFileInformationByHandle -#else // ^^^ _STL_ALWAYS_HAS_SetFileInformationByHandle ^^^ // vvv !_STL_ALWAYS_HAS_SetFileInformationByHandle vvv - const auto _SetFileInformationByHandle = __vcrt_SetFileInformationByHandle; - if (_SetFileInformationByHandle == _Not_supported_SetFileInformationByHandle) { // Windows XP - if (RemoveDirectoryW(_Target)) { - // try RemoveDirectoryW first because it gives a specific error code for "the input was a file"; - // DeleteFileW on a directory input returns ERROR_ACCESS_DENIED - return {true, __std_win_error::_Success}; - } - - _Last_error = __std_win_error{GetLastError()}; - if (_Last_error == __std_win_error::_Directory_name_is_invalid) { // input may have been a file - if (DeleteFileW(_Target)) { - return {true, __std_win_error::_Success}; - } - - _Last_error = __std_win_error{GetLastError()}; - } - - return {false, _Translate_not_found_to_success(__std_win_error{GetLastError()})}; - } -#endif // _STL_ALWAYS_HAS_SetFileInformationByHandle constexpr auto _Flags = __std_fs_file_flags::_Backup_semantics | __std_fs_file_flags::_Open_reparse_point; const _STD _Fs_file _Handle(_Target, __std_access_rights::_Delete, _Flags, &_Last_error); @@ -678,7 +512,7 @@ _Success_(return == __std_win_error::_Success) __std_win_error // FileDispositionInfoEx isn't documented in MSDN at the time of this writing, but is present // in minwinbase.h as of at least 10.0.16299.0 constexpr auto _FileDispositionInfoExClass = static_cast(21); - if (_SetFileInformationByHandle(_Handle._Get(), _FileDispositionInfoExClass, &_Info_ex, sizeof(_Info_ex))) { + if (SetFileInformationByHandle(_Handle._Get(), _FileDispositionInfoExClass, &_Info_ex, sizeof(_Info_ex))) { return {true, __std_win_error::_Success}; } @@ -693,7 +527,7 @@ _Success_(return == __std_win_error::_Success) __std_win_error } FILE_DISPOSITION_INFO _Info{/* .Delete= */ TRUE}; - if (_SetFileInformationByHandle(_Handle._Get(), FileDispositionInfo, &_Info, sizeof(_Info))) { + if (SetFileInformationByHandle(_Handle._Get(), FileDispositionInfo, &_Info, sizeof(_Info))) { return {true, __std_win_error::_Success}; } @@ -721,7 +555,7 @@ _Success_(return == __std_win_error::_Success) __std_win_error } FILE_BASIC_INFO _Basic_info; - if (!__vcrt_GetFileInformationByHandleEx(_Handle._Get(), FileBasicInfo, &_Basic_info, sizeof(_Basic_info))) { + if (!GetFileInformationByHandleEx(_Handle._Get(), FileBasicInfo, &_Basic_info, sizeof(_Basic_info))) { return __std_win_error{GetLastError()}; } @@ -730,7 +564,7 @@ _Success_(return == __std_win_error::_Success) __std_win_error } _Basic_info.FileAttributes ^= FILE_ATTRIBUTE_READONLY; - if (__vcrt_SetFileInformationByHandle(_Handle._Get(), FileBasicInfo, &_Basic_info, sizeof(_Basic_info))) { + if (SetFileInformationByHandle(_Handle._Get(), FileBasicInfo, &_Basic_info, sizeof(_Basic_info))) { return __std_win_error::_Success; } @@ -816,7 +650,7 @@ _Success_(return == __std_win_error::_Success) __std_win_error return __std_win_error::_Not_enough_memory; } - _Actual_length = __vcrt_GetFinalPathNameByHandleW(_Handle._Get(), _Buf.get() + _Dos_to_nt_prefix_count, + _Actual_length = GetFinalPathNameByHandleW(_Handle._Get(), _Buf.get() + _Dos_to_nt_prefix_count, _Buf_count - _Dos_to_nt_prefix_count, FILE_NAME_NORMALIZED | VOLUME_NAME_NT); if (_Actual_length == 0) { return __std_win_error{GetLastError()}; @@ -977,83 +811,43 @@ struct alignas(long long) _Aligned_file_attrs { return _Last_error; } - _GetFileInfoByHandleEx _Get_info_fn; - if (_Get_info_fn._Supported()) { - constexpr auto _Basic_info_data = __std_fs_stats_flags::_Attributes | __std_fs_stats_flags::_Last_write_time; - constexpr auto _Attribute_tag_info_data = - __std_fs_stats_flags::_Attributes | __std_fs_stats_flags::_Reparse_tag; - constexpr auto _Standard_info_data = __std_fs_stats_flags::_File_size | __std_fs_stats_flags::_Link_count; - - if (_Flags != _Attribute_tag_info_data && _Bitmask_includes(_Flags, _Basic_info_data)) { - // we have data FileBasicInfo can fill in, that FileAttributeTagInfo wouldn't exactly fill in - FILE_BASIC_INFO _Info; - if (!_Get_info_fn(_Handle._Get(), FileBasicInfo, &_Info, sizeof(_Info))) { - return __std_win_error{GetLastError()}; - } - - _Stats->_Attributes = __std_fs_file_attr{_Info.FileAttributes}; - _Stats->_Last_write_time = _Info.LastWriteTime.QuadPart; - _Flags &= ~_Basic_info_data; - } - - if (_Bitmask_includes(_Flags, _Attribute_tag_info_data)) { - FILE_ATTRIBUTE_TAG_INFO _Info; - if (!_Get_info_fn(_Handle._Get(), FileAttributeTagInfo, &_Info, sizeof(_Info))) { - return __std_win_error{GetLastError()}; - } + constexpr auto _Basic_info_data = __std_fs_stats_flags::_Attributes | __std_fs_stats_flags::_Last_write_time; + constexpr auto _Attribute_tag_info_data = __std_fs_stats_flags::_Attributes | __std_fs_stats_flags::_Reparse_tag; + constexpr auto _Standard_info_data = __std_fs_stats_flags::_File_size | __std_fs_stats_flags::_Link_count; - _Stats->_Attributes = __std_fs_file_attr{_Info.FileAttributes}; - _Stats->_Reparse_point_tag = __std_fs_reparse_tag{_Info.ReparseTag}; - _Flags &= ~_Attribute_tag_info_data; + if (_Flags != _Attribute_tag_info_data && _Bitmask_includes(_Flags, _Basic_info_data)) { + // we have data FileBasicInfo can fill in, that FileAttributeTagInfo wouldn't exactly fill in + FILE_BASIC_INFO _Info; + if (!GetFileInformationByHandleEx(_Handle._Get(), FileBasicInfo, &_Info, sizeof(_Info))) { + return __std_win_error{GetLastError()}; } - if (_Bitmask_includes(_Flags, _Standard_info_data)) { - FILE_STANDARD_INFO _Info; - if (!_Get_info_fn(_Handle._Get(), FileStandardInfo, &_Info, sizeof(_Info))) { - return __std_win_error{GetLastError()}; - } - - _Stats->_File_size = _Info.EndOfFile.QuadPart; - _Stats->_Link_count = _Info.NumberOfLinks; - _Flags &= ~_Standard_info_data; - } + _Stats->_Attributes = __std_fs_file_attr{_Info.FileAttributes}; + _Stats->_Last_write_time = _Info.LastWriteTime.QuadPart; + _Flags &= ~_Basic_info_data; } -#if _STL_WIN32_WINNT < _WIN32_WINNT_VISTA - if (_Flags == __std_fs_stats_flags::_None) { // no more data to get, report success - return __std_win_error::_Success; - } + if (_Bitmask_includes(_Flags, _Attribute_tag_info_data)) { + FILE_ATTRIBUTE_TAG_INFO _Info; + if (!GetFileInformationByHandleEx(_Handle._Get(), FileAttributeTagInfo, &_Info, sizeof(_Info))) { + return __std_win_error{GetLastError()}; + } - BY_HANDLE_FILE_INFORMATION _Legacy_info; - if (!GetFileInformationByHandle(_Handle._Get(), &_Legacy_info)) { - return __std_win_error{GetLastError()}; + _Stats->_Attributes = __std_fs_file_attr{_Info.FileAttributes}; + _Stats->_Reparse_point_tag = __std_fs_reparse_tag{_Info.ReparseTag}; + _Flags &= ~_Attribute_tag_info_data; } - _Stats->_Attributes = __std_fs_file_attr{_Legacy_info.dwFileAttributes}; - _CSTD memcpy(&_Stats->_Last_write_time, &_Legacy_info.ftLastWriteTime, sizeof(_Stats->_Last_write_time)); - _Stats->_File_size = - (static_cast(_Legacy_info.nFileIndexHigh) << 32) + _Legacy_info.nFileIndexLow; - _Stats->_Link_count = _Legacy_info.nNumberOfLinks; - _Flags &= ~(__std_fs_stats_flags::_Attributes | __std_fs_stats_flags::_Last_write_time - | __std_fs_stats_flags::_File_size | __std_fs_stats_flags::_Link_count); - - if (_Bitmask_includes(_Flags, __std_fs_stats_flags::_Reparse_tag)) { - if (_Bitmask_includes(_Stats->_Attributes, __std_fs_file_attr::_Reparse_point)) { - WIN32_FIND_DATAW _Data; - const auto _Dir = FindFirstFileExW(_Path, FindExInfoStandard, &_Data, FindExSearchNameMatch, nullptr, 0); - if (_Dir == INVALID_HANDLE_VALUE) { - return __std_win_error{GetLastError()}; - } - - FindClose(_Dir); - _Stats->_Reparse_point_tag = __std_fs_reparse_tag{_Data.dwReserved0}; - } else { - _Stats->_Reparse_point_tag = __std_fs_reparse_tag::_None; + if (_Bitmask_includes(_Flags, _Standard_info_data)) { + FILE_STANDARD_INFO _Info; + if (!GetFileInformationByHandleEx(_Handle._Get(), FileStandardInfo, &_Info, sizeof(_Info))) { + return __std_win_error{GetLastError()}; } - _Flags &= ~__std_fs_stats_flags::_Reparse_tag; + _Stats->_File_size = _Info.EndOfFile.QuadPart; + _Stats->_Link_count = _Info.NumberOfLinks; + _Flags &= ~_Standard_info_data; } -#endif // _STL_WIN32_WINNT < _WIN32_WINNT_VISTA if (_Flags == __std_fs_stats_flags::_None) { // no more data to get, report success return __std_win_error::_Success; diff --git a/stl/src/future.cpp b/stl/src/future.cpp index 77264b2de59..5ff6f82f924 100644 --- a/stl/src/future.cpp +++ b/stl/src/future.cpp @@ -1,7 +1,6 @@ // Copyright (c) Microsoft Corporation. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -#include #include #include diff --git a/stl/src/ios.cpp b/stl/src/ios.cpp index 9f15c44dc4a..8640a63169b 100644 --- a/stl/src/ios.cpp +++ b/stl/src/ios.cpp @@ -3,7 +3,6 @@ // ios_base basic members -#include #include _STD_BEGIN @@ -26,20 +25,6 @@ __PURE_APPDOMAIN_GLOBAL static ios_base* stdstr[_Nstdstr + 2] = { nullptr}; // [1, _Nstdstr] hold pointers to standard streams __PURE_APPDOMAIN_GLOBAL static char stdopens[_Nstdstr + 2] = {0}; // [1, _Nstdstr] hold open counts for standard streams -// void __CLR_OR_THIS_CALL ios_base::clear(iostate state, bool reraise) { // set state, possibly reraise exception -// _Mystate = (iostate)(state & _Statmask); -// if ((_Mystate & _Except) == 0) -// ; -// else if (reraise) -// _RERAISE; -// else if (_Mystate & _Except & badbit) -// _THROW(failure("ios_base::badbit set")); -// else if (_Mystate & _Except & failbit) -// _THROW(failure("ios_base::failbit set")); -// else -// _THROW(failure("ios_base::eofbit set")); -// } - void __CLRCALL_PURE_OR_CDECL ios_base::_Ios_base_dtor(ios_base* _This) { // destroy the object if (0 < _This->_Stdstr && 0 < --stdopens[_This->_Stdstr]) { return; @@ -49,30 +34,6 @@ void __CLRCALL_PURE_OR_CDECL ios_base::_Ios_base_dtor(ios_base* _This) { // dest delete _This->_Ploc; } -// ios_base::_Iosarray& __CLR_OR_THIS_CALL ios_base::_Findarr(int idx) { // locate or make a variable array element -// static _Iosarray stub(0, 0); -// _Iosarray *p, *q; -// -// if (idx < 0) { // handle bad index -// setstate(badbit); -// return stub; -// } -// -// for (p = _Arr, q = 0; p != 0; p = p->_Next) -// if (p->_Index == idx) -// return *p; // found element, return it -// else if (q == 0 && p->_Lo == 0 && p->_Vp == 0) -// q = p; // found recycling candidate -// -// if (q != 0) { // recycle existing element -// q->_Index = idx; -// return *q; -// } -// -// _Arr = new _Iosarray(idx, _Arr); // make a new element -// return *_Arr; -// } - void __CLRCALL_PURE_OR_CDECL ios_base::_Addstd(ios_base* _This) { // add standard stream to destructor list _BEGIN_LOCK(_LOCK_STREAM) for (_This->_Stdstr = 1; _This->_Stdstr < _Nstdstr; ++_This->_Stdstr) { diff --git a/stl/src/locale0.cpp b/stl/src/locale0.cpp index 46a6f679fe3..acd2fc944a2 100644 --- a/stl/src/locale0.cpp +++ b/stl/src/locale0.cpp @@ -73,8 +73,8 @@ _STD_END #if !STDCPP_IMPLIB || defined(_M_CEE_PURE) +#include #include -#include _EXTERN_C diff --git a/stl/src/mpiostream.cpp b/stl/src/mpiostream.cpp index cbc2b38c93e..a0d1818eafd 100644 --- a/stl/src/mpiostream.cpp +++ b/stl/src/mpiostream.cpp @@ -6,7 +6,6 @@ #error This file must be built with /clr:pure. #endif -#include #include #pragma warning(disable : 4074) diff --git a/stl/src/mutex.cpp b/stl/src/mutex.cpp index 79ca2067e08..8749f4544b9 100644 --- a/stl/src/mutex.cpp +++ b/stl/src/mutex.cpp @@ -3,9 +3,9 @@ // mutex functions +#include +#include #include -#include -#include #include #include #include diff --git a/stl/src/nothrow.cpp b/stl/src/nothrow.cpp index 6e01ef81976..d12dcdcf336 100644 --- a/stl/src/nothrow.cpp +++ b/stl/src/nothrow.cpp @@ -11,8 +11,6 @@ #undef MRTDLL #endif -#include - #include _STD_BEGIN diff --git a/stl/src/ppltasks.cpp b/stl/src/ppltasks.cpp index 95a5a011dbe..b603576f41e 100644 --- a/stl/src/ppltasks.cpp +++ b/stl/src/ppltasks.cpp @@ -1,7 +1,6 @@ // Copyright (c) Microsoft Corporation. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -#include #include #include #include diff --git a/stl/src/primitives.hpp b/stl/src/primitives.hpp index 2f335143af1..a944a5928f5 100644 --- a/stl/src/primitives.hpp +++ b/stl/src/primitives.hpp @@ -2,27 +2,13 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception #pragma once -#pragma warning(push) -#pragma warning(disable : 4201) // nonstandard extension used: nameless struct/union -#pragma warning(disable : 4324) // structure was padded due to alignment specifier -#include +#include // for __max #include #include -#include - -#include #include "awint.hpp" -#ifdef _STL_CONCRT_SUPPORT -#pragma warning(push) -#pragma warning(disable : 6297 6385 6386 6504 28204) -#include -#include -#pragma warning(pop) -#endif - enum class __stl_sync_api_modes_enum { normal, win7, vista, concrt }; extern __stl_sync_api_modes_enum __stl_sync_api_impl_mode; @@ -50,7 +36,7 @@ namespace Concurrency { class stl_critical_section_vista final : public stl_critical_section_interface { public: stl_critical_section_vista() { - __crtInitializeCriticalSectionEx(&_M_critical_section, 4000, 0); + InitializeCriticalSectionEx(&_M_critical_section, 4000, 0); } stl_critical_section_vista(const stl_critical_section_vista&) = delete; @@ -89,7 +75,7 @@ namespace Concurrency { class stl_condition_variable_vista final : public stl_condition_variable_interface { public: stl_condition_variable_vista() { - __crtInitializeConditionVariable(&m_condition_variable); + InitializeConditionVariable(&m_condition_variable); } ~stl_condition_variable_vista() = delete; @@ -105,17 +91,17 @@ namespace Concurrency { } virtual bool wait_for(stl_critical_section_interface* lock, unsigned int timeout) override { - return __crtSleepConditionVariableCS(&m_condition_variable, + return SleepConditionVariableCS(&m_condition_variable, static_cast(lock)->native_handle(), timeout) != 0; } virtual void notify_one() override { - __crtWakeConditionVariable(&m_condition_variable); + WakeConditionVariable(&m_condition_variable); } virtual void notify_all() override { - __crtWakeAllConditionVariable(&m_condition_variable); + WakeAllConditionVariable(&m_condition_variable); } private: @@ -125,7 +111,7 @@ namespace Concurrency { class stl_critical_section_win7 final : public stl_critical_section_interface { public: stl_critical_section_win7() { - __crtInitializeSRWLock(&m_srw_lock); + InitializeSRWLock(&m_srw_lock); } ~stl_critical_section_win7() = delete; @@ -135,7 +121,7 @@ namespace Concurrency { virtual void destroy() override {} virtual void lock() override { - __crtAcquireSRWLockExclusive(&m_srw_lock); + AcquireSRWLockExclusive(&m_srw_lock); } virtual bool try_lock() override { @@ -148,7 +134,7 @@ namespace Concurrency { } virtual void unlock() override { - __crtReleaseSRWLockExclusive(&m_srw_lock); + ReleaseSRWLockExclusive(&m_srw_lock); } PSRWLOCK native_handle() { @@ -162,7 +148,7 @@ namespace Concurrency { class stl_condition_variable_win7 final : public stl_condition_variable_interface { public: stl_condition_variable_win7() { - __crtInitializeConditionVariable(&m_condition_variable); + InitializeConditionVariable(&m_condition_variable); } ~stl_condition_variable_win7() = delete; @@ -178,95 +164,23 @@ namespace Concurrency { } virtual bool wait_for(stl_critical_section_interface* lock, unsigned int timeout) override { - return __crtSleepConditionVariableSRW(&m_condition_variable, + return SleepConditionVariableSRW(&m_condition_variable, static_cast(lock)->native_handle(), timeout, 0) != 0; } virtual void notify_one() override { - __crtWakeConditionVariable(&m_condition_variable); + WakeConditionVariable(&m_condition_variable); } virtual void notify_all() override { - __crtWakeAllConditionVariable(&m_condition_variable); + WakeAllConditionVariable(&m_condition_variable); } private: CONDITION_VARIABLE m_condition_variable; }; -#ifdef _STL_CONCRT_SUPPORT - class stl_critical_section_concrt final : public stl_critical_section_interface { - public: - stl_critical_section_concrt() = default; - ~stl_critical_section_concrt() = delete; - stl_critical_section_concrt(const stl_critical_section_concrt&) = delete; - stl_critical_section_concrt& operator=(const stl_critical_section_concrt&) = delete; - - virtual void lock() override { - m_critical_section.lock(); - } - - virtual bool try_lock() override { - return m_critical_section.try_lock(); - } - - virtual bool try_lock_for(unsigned int duration) override { - return m_critical_section.try_lock_for(duration); - } - - virtual void unlock() override { - m_critical_section.unlock(); - } - - virtual void destroy() override { - // the destructor of stl_critical_section_concrt will never be invoked - m_critical_section.~critical_section(); - } - - critical_section& native_handle() { - return m_critical_section; - } - - private: - critical_section m_critical_section; - }; - - class stl_condition_variable_concrt final : public stl_condition_variable_interface { - public: - stl_condition_variable_concrt() = default; - ~stl_condition_variable_concrt() = delete; - stl_condition_variable_concrt(const stl_condition_variable_concrt&) = delete; - stl_condition_variable_concrt& operator=(const stl_condition_variable_concrt&) = delete; - - virtual void wait(stl_critical_section_interface* lock) override { - m_condition_variable.wait(static_cast(lock)->native_handle()); - } - - virtual bool wait_for(stl_critical_section_interface* lock, unsigned int timeout) override { - return m_condition_variable.wait_for( - static_cast(lock)->native_handle(), timeout); - } - - virtual void notify_one() override { - m_condition_variable.notify_one(); - } - - virtual void notify_all() override { - m_condition_variable.notify_all(); - } - - virtual void destroy() override { - // the destructor of stl_condition_variable_concrt will never be invoked - m_condition_variable.~_Condition_variable(); - } - - private: - _Condition_variable m_condition_variable; - }; - -#endif // _STL_CONCRT_SUPPORT - inline bool are_win7_sync_apis_available() { #if _STL_WIN32_WINNT >= _WIN32_WINNT_WIN7 return true; @@ -278,17 +192,6 @@ namespace Concurrency { #endif } - inline bool are_vista_sync_apis_available() { -#if _STL_WIN32_WINNT >= _WIN32_WINNT_VISTA - return true; -#else - // InitializeConditionVariable ONLY available on Windows Vista+ - DYNAMICGETCACHEDFUNCTION( - PFNINITIALIZECONDITIONVARIABLE, InitializeConditionVariable, pfInitializeConditionVariable); - return pfInitializeConditionVariable != nullptr; -#endif - } - inline void create_stl_critical_section(stl_critical_section_interface* p) { #ifdef _CRT_WINDOWS new (p) stl_critical_section_win7; @@ -302,19 +205,10 @@ namespace Concurrency { } // fall through case __stl_sync_api_modes_enum::vista: - if (are_vista_sync_apis_available()) { - new (p) stl_critical_section_vista; - return; - } - // fall through - case __stl_sync_api_modes_enum::concrt: - default: -#ifdef _STL_CONCRT_SUPPORT - new (p) stl_critical_section_concrt; + new (p) stl_critical_section_vista; return; -#else - std::terminate(); -#endif // _STL_CONCRT_SUPPORT + default: + abort(); } #endif // _CRT_WINDOWS } @@ -332,19 +226,10 @@ namespace Concurrency { } // fall through case __stl_sync_api_modes_enum::vista: - if (are_vista_sync_apis_available()) { - new (p) stl_condition_variable_vista; - return; - } - // fall through - case __stl_sync_api_modes_enum::concrt: - default: -#ifdef _STL_CONCRT_SUPPORT - new (p) stl_condition_variable_concrt; + new (p) stl_condition_variable_vista; return; -#else - std::terminate(); -#endif // _STL_CONCRT_SUPPORT + default: + abort(); } #endif // _CRT_WINDOWS } @@ -355,17 +240,30 @@ namespace Concurrency { const size_t stl_critical_section_max_alignment = alignof(stl_critical_section_win7); const size_t stl_condition_variable_max_alignment = alignof(stl_condition_variable_win7); #elif defined _STL_CONCRT_SUPPORT + +#ifdef _WIN64 + const size_t sizeof_stl_critical_section_concrt = 64; + const size_t sizeof_stl_condition_variable_concrt = 72; + const size_t alignof_stl_critical_section_concrt = 8; + const size_t alignof_stl_condition_variable_concrt = 8; +#else // ^^^ 64-bit / 32-bit vvv + const size_t sizeof_stl_critical_section_concrt = 36; + const size_t sizeof_stl_condition_variable_concrt = 40; + const size_t alignof_stl_critical_section_concrt = 4; + const size_t alignof_stl_condition_variable_concrt = 4; +#endif // ^^^ 32-bit ^^^ + const size_t stl_critical_section_max_size = - __max(__max(sizeof(stl_critical_section_concrt), sizeof(stl_critical_section_vista)), + __max(__max(sizeof_stl_critical_section_concrt, sizeof(stl_critical_section_vista)), sizeof(stl_critical_section_win7)); const size_t stl_condition_variable_max_size = - __max(__max(sizeof(stl_condition_variable_concrt), sizeof(stl_condition_variable_vista)), + __max(__max(sizeof_stl_condition_variable_concrt, sizeof(stl_condition_variable_vista)), sizeof(stl_condition_variable_win7)); const size_t stl_critical_section_max_alignment = - __max(__max(alignof(stl_critical_section_concrt), alignof(stl_critical_section_vista)), + __max(__max(alignof_stl_critical_section_concrt, alignof(stl_critical_section_vista)), alignof(stl_critical_section_win7)); const size_t stl_condition_variable_max_alignment = - __max(__max(alignof(stl_condition_variable_concrt), alignof(stl_condition_variable_vista)), + __max(__max(alignof_stl_condition_variable_concrt, alignof(stl_condition_variable_vista)), alignof(stl_condition_variable_win7)); #else const size_t stl_critical_section_max_size = @@ -379,5 +277,3 @@ namespace Concurrency { #endif } // namespace details } // namespace Concurrency - -#pragma warning(pop) diff --git a/stl/src/special_math.cpp b/stl/src/special_math.cpp index e824c10b2e1..8a4dd5e0836 100644 --- a/stl/src/special_math.cpp +++ b/stl/src/special_math.cpp @@ -19,6 +19,15 @@ #define BOOST_MATH_DOMAIN_ERROR_POLICY errno_on_error #define BOOST_MATH_OVERFLOW_ERROR_POLICY ignore_error +// Avoid SSE intrinsics in EC +#if defined(_M_ARM64EC) +// need to include intrinsics to ensure that x64 definitions in intrin0.h are not lost +#include +#undef _M_AMD64 +#undef _M_X64 +#define _M_ARM64 +#endif // defined(_M_ARM64EC) + // Using headers from Boost.Math #include #include @@ -34,6 +43,13 @@ #include #include +#if defined(_M_ARM64EC) +#undef _M_ARM64 +#define _M_AMD64 +#define _M_X64 +#endif // defined(_M_ARM64EC) + + #pragma warning(pop) namespace { diff --git a/stl/src/taskscheduler.cpp b/stl/src/taskscheduler.cpp index 105a7f05ec8..a4908fe95ad 100644 --- a/stl/src/taskscheduler.cpp +++ b/stl/src/taskscheduler.cpp @@ -2,9 +2,9 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception #include +#include // for size_t #include #include -#include #include @@ -20,15 +20,6 @@ extern "C" IMAGE_DOS_HEADER __ImageBase; namespace Concurrency { namespace details { namespace { - bool _Is_vista_threadpool_supported() { -#if _STL_WIN32_WINNT >= _WIN32_WINNT_VISTA - return true; -#else // ^^^ _STL_WIN32_WINNT >= _WIN32_WINNT_VISTA ^^^ // vvv _STL_WIN32_WINNT < _WIN32_WINNT_VISTA vvv - DYNAMICGETCACHEDFUNCTION(PFNCREATETHREADPOOLWORK, CreateThreadpoolWork, pfCreateThreadpoolWork); - return pfCreateThreadpoolWork != nullptr; -#endif // _STL_WIN32_WINNT >= _WIN32_WINNT_VISTA - } - // When the CRT and STL are statically linked into an EXE, their uninitialization will take place // inside of the call to exit(), before ExitProcess() is called. This means that their // uninitialization occurs before other threads in the process are terminated. We block the exit @@ -134,36 +125,23 @@ namespace Concurrency { reinterpret_cast(_Chore->_M_callback)); if (_Callback_dll != nullptr) { - __crtFreeLibraryWhenCallbackReturns(_Pci, _Callback_dll); + FreeLibraryWhenCallbackReturns(_Pci, _Callback_dll); } } _Chore->_M_callback(_Chore->_M_data); _Decrement_outstanding(); } - - DWORD __stdcall _Task_scheduler_callback_xp(LPVOID _Args) noexcept { - _Increment_outstanding(); - const auto _Chore = static_cast<_Threadpool_chore*>(_Args); - _Chore->_M_callback(_Chore->_M_data); - _Decrement_outstanding(); - return 0; - } } // namespace _CRTIMP2 void __cdecl _Release_chore(_Threadpool_chore* _Chore) { if (_Chore->_M_work != nullptr) { - // Windows XP threadpool doesn't need to release chore - if (_Is_vista_threadpool_supported()) { - __crtCloseThreadpoolWork(static_cast(_Chore->_M_work)); - } + CloseThreadpoolWork(static_cast(_Chore->_M_work)); _Chore->_M_work = nullptr; } } _CRTIMP2 int __cdecl _Reschedule_chore(const _Threadpool_chore* _Chore) { - // reschedule supports only Windows Vista and above - _ASSERT(_Is_vista_threadpool_supported()); _ASSERT(_Chore->_M_work); // Adds a reference to the DLL with the code to execute on async; the callback will @@ -173,7 +151,7 @@ namespace Concurrency { GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, reinterpret_cast(_Chore->_M_callback)); } - __crtSubmitThreadpoolWork(static_cast(_Chore->_M_work)); + SubmitThreadpoolWork(static_cast(_Chore->_M_work)); return 0; } @@ -181,30 +159,12 @@ namespace Concurrency { _ASSERT(_Chore->_M_work == nullptr); _ASSERT(_Chore->_M_callback != nullptr); - if (_Is_vista_threadpool_supported()) { - _Chore->_M_work = __crtCreateThreadpoolWork(_Task_scheduler_callback, _Chore, nullptr); + _Chore->_M_work = CreateThreadpoolWork(_Task_scheduler_callback, _Chore, nullptr); - if (_Chore->_M_work) { - return _Reschedule_chore(_Chore); - } else { - return static_cast(GetLastError()); // LastError won't be 0 when it's in error state - } + if (_Chore->_M_work) { + return _Reschedule_chore(_Chore); } else { - // Windows XP doesn't support FreeLibraryWhenCallbackReturns, - // so we prevent the callback DLL from ever unloading - if (_Get_STL_host_status() != _STL_host_status::_Exe) { - (void) _Call_get_module_handle_ex( - GET_MODULE_HANDLE_EX_FLAG_PIN | GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, - reinterpret_cast(_Chore->_M_callback)); - } - - _Chore->_M_work = _Chore; // give a dummy non-null worker - if (__crtQueueUserWorkItem(_Task_scheduler_callback_xp, _Chore, WT_EXECUTEDEFAULT) == 0) { - _Chore->_M_work = nullptr; - return static_cast(GetLastError()); // LastError won't be 0 when it's in error state - } else { - return 0; - } + return static_cast(GetLastError()); // LastError won't be 0 when it's in error state } } } // namespace details diff --git a/stl/src/thread0.cpp b/stl/src/thread0.cpp index a4067600697..bffe7faf63b 100644 --- a/stl/src/thread0.cpp +++ b/stl/src/thread0.cpp @@ -3,9 +3,7 @@ // thread support functions -#include - -#include +#include #include #include diff --git a/stl/src/vector_algorithms.cpp b/stl/src/vector_algorithms.cpp index 4823e4fdd9d..88a5e5649f9 100644 --- a/stl/src/vector_algorithms.cpp +++ b/stl/src/vector_algorithms.cpp @@ -5,13 +5,17 @@ // injected into the msvcprt.lib and msvcprtd.lib import libraries. // Do not include or define anything else here. // In particular, basic_string must not be included here. -#if (defined(_M_IX86) || defined(_M_X64)) && !defined(_M_CEE_PURE) + +#ifdef _M_CEE_PURE +#error _M_CEE_PURE should not be defined when compiling vector_algorithms.cpp. +#endif + +#if (defined(_M_IX86) || defined(_M_X64)) && !defined(_M_ARM64EC) #include #include #include #include -#include extern "C" long __isa_enabled; @@ -419,4 +423,4 @@ __declspec(noalias) void __cdecl __std_reverse_copy_trivially_copyable_8( } // extern "C" -#endif // (defined(_M_IX86) || defined(_M_X64)) && !defined(_M_CEE_PURE) +#endif // (defined(_M_IX86) || defined(_M_X64)) && !defined(_M_ARM64EC) diff --git a/stl/src/winapinls.cpp b/stl/src/winapinls.cpp index a7a47a51348..44f792e55a4 100644 --- a/stl/src/winapinls.cpp +++ b/stl/src/winapinls.cpp @@ -6,8 +6,8 @@ #if _STL_WIN32_WINNT < _WIN32_WINNT_VISTA #include -#include -#include +#include +#include // for _countof #include namespace { @@ -621,43 +621,24 @@ extern "C" int __cdecl __crtDownlevelLCIDToLocaleName(LCID lcid, LPWSTR outLocal return count + 1; } -// __crtCompareStringEx() - Wrapper for CompareStringEx(). -extern "C" int __cdecl __crtCompareStringEx(_In_opt_ LPCWSTR lpLocaleName, _In_ DWORD dwCmpFlags, +// TRANSITION, ABI: preserved for binary compatibility +extern "C" _CRTIMP2 int __cdecl __crtCompareStringEx(_In_opt_ LPCWSTR lpLocaleName, _In_ DWORD dwCmpFlags, _In_NLS_string_(cchCount1) LPCWSTR lpString1, _In_ int cchCount1, _In_NLS_string_(cchCount2) LPCWSTR lpString2, _In_ int cchCount2) { - // use CompareStringEx if it is available (only on Windows Vista+)... - IFDYNAMICGETCACHEDFUNCTION(PFNCOMPARESTRINGEX, CompareStringEx, pfCompareStringEx) { - return pfCompareStringEx( - lpLocaleName, dwCmpFlags, lpString1, cchCount1, lpString2, cchCount2, nullptr, nullptr, 0); - } - - // ...otherwise fall back to using CompareString. - return CompareStringW( - __crtDownlevelLocaleNameToLCID(lpLocaleName), dwCmpFlags, lpString1, cchCount1, lpString2, cchCount2); + return CompareStringEx(lpLocaleName, dwCmpFlags, lpString1, cchCount1, lpString2, cchCount2, nullptr, nullptr, 0); } -// __crtLCMapStringEx() - Wrapper for LCMapStringEx(). -extern "C" int __cdecl __crtLCMapStringEx(_In_opt_ LPCWSTR lpLocaleName, _In_ DWORD dwMapFlags, +// TRANSITION, ABI: preserved for binary compatibility +extern "C" _CRTIMP2 int __cdecl __crtLCMapStringEx(_In_opt_ LPCWSTR lpLocaleName, _In_ DWORD dwMapFlags, _In_reads_(cchSrc) LPCWSTR lpSrcStr, _In_ int cchSrc, _Out_writes_opt_(cchDest) LPWSTR lpDestStr, _In_ int cchDest) { - // use LCMapStringEx if it is available (only on Windows Vista+)... - IFDYNAMICGETCACHEDFUNCTION(PFNLCMAPSTRINGEX, LCMapStringEx, pfLCMapStringEx) { - return pfLCMapStringEx(lpLocaleName, dwMapFlags, lpSrcStr, cchSrc, lpDestStr, cchDest, nullptr, nullptr, 0); - } - - // ...otherwise fall back to using LCMapString. - return LCMapStringW(__crtDownlevelLocaleNameToLCID(lpLocaleName), dwMapFlags, lpSrcStr, cchSrc, lpDestStr, cchDest); + return LCMapStringEx(lpLocaleName, dwMapFlags, lpSrcStr, cchSrc, lpDestStr, cchDest, nullptr, nullptr, 0); } - -// __crtGetLocaleInfoEx() - Wrapper for GetLocaleInfoEx(). -extern "C" int __cdecl __crtGetLocaleInfoEx(_In_opt_ LPCWSTR const lpLocaleName, _In_ LCTYPE const LCType, +// TRANSITION, ABI: preserved for binary compatibility +extern "C" _CRTIMP2 int __cdecl __crtGetLocaleInfoEx(_In_opt_ LPCWSTR const lpLocaleName, _In_ LCTYPE const LCType, _Out_writes_opt_(cchData) LPWSTR const lpLCData, _In_ int const cchData) { - IFDYNAMICGETCACHEDFUNCTION(PFNGETLOCALEINFOEX, GetLocaleInfoEx, pfGetLocaleInfoEx) { - return pfGetLocaleInfoEx(lpLocaleName, LCType, lpLCData, cchData); - } - - return GetLocaleInfoW(__crtDownlevelLocaleNameToLCID(lpLocaleName), LCType, lpLCData, cchData); + return GetLocaleInfoEx(lpLocaleName, LCType, lpLCData, cchData); } #endif // _STL_WIN32_WINNT < _WIN32_WINNT_VISTA diff --git a/stl/src/winapisupp.cpp b/stl/src/winapisupp.cpp index 9275e307f8c..aa583d138a7 100644 --- a/stl/src/winapisupp.cpp +++ b/stl/src/winapisupp.cpp @@ -4,18 +4,17 @@ // clang-format off // Prevent clang-format from reordering before #include -#include +#include // for APPMODEL_ERROR_NO_PACKAGE #include "awint.hpp" #include -#include +#include // clang-format on #pragma warning(push) #pragma warning(disable : 4265) // non-virtual destructor in base class #include #pragma warning(pop) -#include -#include +#include #if !defined(_CRT_WINDOWS) && !defined(UNDOCKED_WINDOWS_UCRT) // GetCurrentPackageId retrieves the current package id, if the app is deployed via a package. @@ -131,44 +130,24 @@ extern "C" BOOL __cdecl __crtIsPackagedApp() { #if _STL_WIN32_WINNT < _WIN32_WINNT_WS03 +// TRANSITION, ABI: preserved for binary compatibility extern "C" DWORD __cdecl __crtFlsAlloc(_In_opt_ PFLS_CALLBACK_FUNCTION const lpCallback) { - // use FlsAlloc if it is available (only on Windows Server 2003+)... - IFDYNAMICGETCACHEDFUNCTION(PFNFLSALLOC, FlsAlloc, pfFlsAlloc) { - return pfFlsAlloc(lpCallback); - } - - // ...otherwise fall back to using TlsAlloc. - return TlsAlloc(); + return FlsAlloc(lpCallback); } +// TRANSITION, ABI: preserved for binary compatibility extern "C" BOOL __cdecl __crtFlsFree(_In_ DWORD const dwFlsIndex) { - // use FlsFree if it is available (only on Windows Server 2003+)... - IFDYNAMICGETCACHEDFUNCTION(PFNFLSFREE, FlsFree, pfFlsFree) { - return pfFlsFree(dwFlsIndex); - } - - // ...otherwise fall back to using TlsFree. - return TlsFree(dwFlsIndex); + return FlsFree(dwFlsIndex); } +// TRANSITION, ABI: preserved for binary compatibility extern "C" PVOID __cdecl __crtFlsGetValue(_In_ DWORD const dwFlsIndex) { - // use FlsGetValue if it is available (only on Windows Server 2003+)... - IFDYNAMICGETCACHEDFUNCTION(PFNFLSGETVALUE, FlsGetValue, pfFlsGetValue) { - return pfFlsGetValue(dwFlsIndex); - } - - // ...otherwise fall back to using TlsGetValue. - return TlsGetValue(dwFlsIndex); + return FlsGetValue(dwFlsIndex); } +// TRANSITION, ABI: preserved for binary compatibility extern "C" BOOL __cdecl __crtFlsSetValue(_In_ DWORD const dwFlsIndex, _In_opt_ PVOID const lpFlsData) { - // use FlsSetValue if it is available (only on Windows Server 2003+)... - IFDYNAMICGETCACHEDFUNCTION(PFNFLSSETVALUE, FlsSetValue, pfFlsSetValue) { - return pfFlsSetValue(dwFlsIndex, lpFlsData); - } - - // ...otherwise fall back to using TlsSetValue. - return TlsSetValue(dwFlsIndex, lpFlsData); + return FlsSetValue(dwFlsIndex, lpFlsData); } #endif // _STL_WIN32_WINNT < _WIN32_WINNT_WS03 @@ -176,317 +155,180 @@ extern "C" BOOL __cdecl __crtFlsSetValue(_In_ DWORD const dwFlsIndex, _In_opt_ P #if _STL_WIN32_WINNT < _WIN32_WINNT_VISTA -extern "C" ULONGLONG __cdecl __crtGetTickCount64() { - // use GetTickCount64 if it is available (only on Windows Vista+)... - IFDYNAMICGETCACHEDFUNCTION(PFNGETTICKCOUNT64, GetTickCount64, pfGetTickCount64) { - return pfGetTickCount64(); - } - - // ...otherwise fall back to using GetTickCount. -#pragma warning(suppress : 28159) // Consider using 'GetTickCount64' instead of 'GetTickCount'. - return GetTickCount(); +// TRANSITION, ABI: preserved for binary compatibility +extern "C" _CRTIMP2 ULONGLONG __cdecl __crtGetTickCount64() { + return GetTickCount64(); } -extern "C" BOOL __cdecl __crtInitializeCriticalSectionEx( +// TRANSITION, ABI: preserved for binary compatibility +extern "C" _CRTIMP2 BOOL __cdecl __crtInitializeCriticalSectionEx( _Out_ LPCRITICAL_SECTION const lpCriticalSection, _In_ DWORD const dwSpinCount, _In_ DWORD const Flags) { - // use InitializeCriticalSectionEx if it is available (only on Windows Vista+)... - IFDYNAMICGETCACHEDFUNCTION( - PFNINITIALIZECRITICALSECTIONEX, InitializeCriticalSectionEx, pfInitializeCriticalSectionEx) { - return pfInitializeCriticalSectionEx(lpCriticalSection, dwSpinCount, Flags); - } - - // ...otherwise fall back to using InitializeCriticalSectionAndSpinCount. - return InitializeCriticalSectionAndSpinCount(lpCriticalSection, dwSpinCount); + return InitializeCriticalSectionEx(lpCriticalSection, dwSpinCount, Flags); } -extern "C" BOOL __cdecl __crtInitOnceExecuteOnce(_Inout_ PINIT_ONCE const InitOnce, _In_ PINIT_ONCE_FN const InitFn, - _Inout_opt_ PVOID const Parameter, LPVOID* const Context) { - // use InitOnceExecuteOnce if it is available (only on Windows Vista+)... - IFDYNAMICGETCACHEDFUNCTION(PFNINITONCEEXECUTEONCE, InitOnceExecuteOnce, pfInitOnceExecuteOnce) { - return pfInitOnceExecuteOnce(InitOnce, InitFn, Parameter, Context); - } - - // ...otherwise fall back to atomic operations. - void* const PV_INITIAL = reinterpret_cast(static_cast(0)); - void* const PV_WORKING = reinterpret_cast(static_cast(1)); - void* const PV_SUCCESS = reinterpret_cast(static_cast(2)); - - void** const ppv = reinterpret_cast(InitOnce); - - for (;;) { - void* const previous = _InterlockedCompareExchangePointer(ppv, PV_WORKING, PV_INITIAL); - - if (previous == PV_SUCCESS) { - return TRUE; - } else if (previous == PV_INITIAL) { - void* next = PV_SUCCESS; - BOOL ret = TRUE; - - if (InitFn(InitOnce, Parameter, Context) == 0) { - next = PV_INITIAL; - ret = FALSE; - } - - if (_InterlockedExchangePointer(ppv, next) == PV_WORKING) { - return ret; - } else { - SetLastError(ERROR_INVALID_DATA); - return FALSE; - } - } else if (previous == PV_WORKING) { - SwitchToThread(); - } else { - SetLastError(ERROR_INVALID_DATA); - return FALSE; - } - } +// TRANSITION, ABI: preserved for binary compatibility +extern "C" _CRTIMP2 BOOL __cdecl __crtInitOnceExecuteOnce(_Inout_ PINIT_ONCE const InitOnce, + _In_ PINIT_ONCE_FN const InitFn, _Inout_opt_ PVOID const Parameter, LPVOID* const Context) { + return InitOnceExecuteOnce(InitOnce, InitFn, Parameter, Context); } -extern "C" HANDLE __cdecl __crtCreateEventExW(_In_opt_ LPSECURITY_ATTRIBUTES const lpEventAttributes, +// TRANSITION, ABI: preserved for binary compatibility +extern "C" _CRTIMP2 HANDLE __cdecl __crtCreateEventExW(_In_opt_ LPSECURITY_ATTRIBUTES const lpEventAttributes, _In_opt_ LPCWSTR const lpName, _In_ DWORD const dwFlags, _In_ DWORD const dwDesiredAccess) { - // use CreateEventEx if it is available (only on Windows Vista+)... - IFDYNAMICGETCACHEDFUNCTION(PFNCREATEEVENTEXW, CreateEventExW, pfCreateEventExW) { - return pfCreateEventExW(lpEventAttributes, lpName, dwFlags, dwDesiredAccess); - } - - // ...otherwise fall back to using CreateEvent. - return CreateEventW( - lpEventAttributes, dwFlags & CREATE_EVENT_MANUAL_RESET, dwFlags & CREATE_EVENT_INITIAL_SET, lpName); + return CreateEventExW(lpEventAttributes, lpName, dwFlags, dwDesiredAccess); } -extern "C" HANDLE __cdecl __crtCreateSemaphoreExW(_In_opt_ LPSECURITY_ATTRIBUTES const lpSemaphoreAttributes, +// TRANSITION, ABI: preserved for binary compatibility +extern "C" _CRTIMP2 HANDLE __cdecl __crtCreateSemaphoreExW(_In_opt_ LPSECURITY_ATTRIBUTES const lpSemaphoreAttributes, _In_ LONG const lInitialCount, _In_ LONG const lMaximumCount, _In_opt_ LPCWSTR const lpName, _Reserved_ DWORD const dwFlags, _In_ DWORD const dwDesiredAccess) { - // use CreateSemaphoreEx if it is available (only on Windows Vista+)... - IFDYNAMICGETCACHEDFUNCTION(PFNCREATESEMAPHOREEXW, CreateSemaphoreExW, pfCreateSemaphoreExW) { - return pfCreateSemaphoreExW( - lpSemaphoreAttributes, lInitialCount, lMaximumCount, lpName, dwFlags, dwDesiredAccess); - } - - // ...otherwise fall back to using CreateSemaphore on Windows XP (API is not present on OneCore)... - IFDYNAMICGETCACHEDFUNCTION(PFNCREATESEMAPHOREW, CreateSemaphoreW, pfCreateSemaphoreW) { - return pfCreateSemaphoreW(lpSemaphoreAttributes, lInitialCount, lMaximumCount, lpName); - } - - // ... otherwise return failure because there is no fall back. - return nullptr; + return CreateSemaphoreExW(lpSemaphoreAttributes, lInitialCount, lMaximumCount, lpName, dwFlags, dwDesiredAccess); } -extern "C" PTP_TIMER __cdecl __crtCreateThreadpoolTimer( +// TRANSITION, ABI: preserved for binary compatibility +extern "C" _CRTIMP2 PTP_TIMER __cdecl __crtCreateThreadpoolTimer( _In_ PTP_TIMER_CALLBACK const pfnti, _Inout_opt_ PVOID const pv, _In_opt_ PTP_CALLBACK_ENVIRON const pcbe) { - // use CreateThreadpoolTimer if it is available (only on Windows Vista+)... - IFDYNAMICGETCACHEDFUNCTION(PFNCREATETHREADPOOLTIMER, CreateThreadpoolTimer, pfCreateThreadpoolTimer) { - return pfCreateThreadpoolTimer(pfnti, pv, pcbe); - } - - // ...otherwise return failure because there is no fall back. - return nullptr; + return CreateThreadpoolTimer(pfnti, pv, pcbe); } -extern "C" VOID __cdecl __crtSetThreadpoolTimer(_Inout_ PTP_TIMER const pti, _In_opt_ PFILETIME const pftDueTime, - _In_ DWORD const msPeriod, _In_opt_ DWORD const msWindowLength) { - // use SetThreadpoolTimer if it is available (only on Windows Vista+)... - IFDYNAMICGETCACHEDFUNCTION(PFNSETTHREADPOOLTIMER, SetThreadpoolTimer, pfSetThreadpoolTimer) { - pfSetThreadpoolTimer(pti, pftDueTime, msPeriod, msWindowLength); - } - - // ...otherwise there is no fall back. - return; +// TRANSITION, ABI: preserved for binary compatibility +extern "C" _CRTIMP2 VOID __cdecl __crtSetThreadpoolTimer(_Inout_ PTP_TIMER const pti, + _In_opt_ PFILETIME const pftDueTime, _In_ DWORD const msPeriod, _In_opt_ DWORD const msWindowLength) { + SetThreadpoolTimer(pti, pftDueTime, msPeriod, msWindowLength); } -extern "C" VOID __cdecl __crtWaitForThreadpoolTimerCallbacks( +// TRANSITION, ABI: preserved for binary compatibility +extern "C" _CRTIMP2 VOID __cdecl __crtWaitForThreadpoolTimerCallbacks( _Inout_ PTP_TIMER const pti, _In_ BOOL const fCancelPendingCallbacks) { - // use WaitForThreadpoolTimerCallbacks if it is available (only on Windows Vista+)... - IFDYNAMICGETCACHEDFUNCTION( - PFNWAITFORTHREADPOOLTIMERCALLBACKS, WaitForThreadpoolTimerCallbacks, pfWaitForThreadpoolTimerCallbacks) { - pfWaitForThreadpoolTimerCallbacks(pti, fCancelPendingCallbacks); - } - - // ...otherwise there is no fall back. - return; + WaitForThreadpoolTimerCallbacks(pti, fCancelPendingCallbacks); } -extern "C" VOID __cdecl __crtCloseThreadpoolTimer(_Inout_ PTP_TIMER const pti) { - // use CloseThreadpoolTimer if it is available (only on Windows Vista+)... - IFDYNAMICGETCACHEDFUNCTION(PFNCLOSETHREADPOOLTIMER, CloseThreadpoolTimer, pfCloseThreadpoolTimer) { - pfCloseThreadpoolTimer(pti); - } - - // ...otherwise there is no fall back. - return; +// TRANSITION, ABI: preserved for binary compatibility +extern "C" _CRTIMP2 VOID __cdecl __crtCloseThreadpoolTimer(_Inout_ PTP_TIMER const pti) { + CloseThreadpoolTimer(pti); } -extern "C" PTP_WAIT __cdecl __crtCreateThreadpoolWait( +// TRANSITION, ABI: preserved for binary compatibility +extern "C" _CRTIMP2 PTP_WAIT __cdecl __crtCreateThreadpoolWait( _In_ PTP_WAIT_CALLBACK const pfnwa, _Inout_opt_ PVOID const pv, _In_opt_ PTP_CALLBACK_ENVIRON const pcbe) { - // use CreateThreadpoolWait if it is available (only on Windows Vista+)... - IFDYNAMICGETCACHEDFUNCTION(PFNCREATETHREADPOOLWAIT, CreateThreadpoolWait, pfCreateThreadpoolWait) { - return pfCreateThreadpoolWait(pfnwa, pv, pcbe); - } - - // ...otherwise return failure because there is no fall back. - return nullptr; + return CreateThreadpoolWait(pfnwa, pv, pcbe); } -extern "C" VOID __cdecl __crtSetThreadpoolWait( +// TRANSITION, ABI: preserved for binary compatibility +extern "C" _CRTIMP2 VOID __cdecl __crtSetThreadpoolWait( _Inout_ PTP_WAIT const pwa, _In_opt_ HANDLE const h, _In_opt_ PFILETIME const pftTimeout) { - // use SetThreadpoolWait if it is available (only on Windows Vista+)... - IFDYNAMICGETCACHEDFUNCTION(PFNSETTHREADPOOLWAIT, SetThreadpoolWait, pfSetThreadpoolWait) { - pfSetThreadpoolWait(pwa, h, pftTimeout); - } - - // ...otherwise there is no fall back. + SetThreadpoolWait(pwa, h, pftTimeout); } -extern "C" VOID __cdecl __crtCloseThreadpoolWait(_Inout_ PTP_WAIT const pwa) { - // use CloseThreadpoolWait if it is available (only on Windows Vista+)... - IFDYNAMICGETCACHEDFUNCTION(PFNCLOSETHREADPOOLWAIT, CloseThreadpoolWait, pfCloseThreadpoolWait) { - pfCloseThreadpoolWait(pwa); - } - - // ...otherwise there is no fall back. +// TRANSITION, ABI: preserved for binary compatibility +extern "C" _CRTIMP2 VOID __cdecl __crtCloseThreadpoolWait(_Inout_ PTP_WAIT const pwa) { + CloseThreadpoolWait(pwa); } -extern "C" VOID __cdecl __crtFlushProcessWriteBuffers() { - // use FlushProcessWriteBuffers if it is available (only on Windows Vista+)... - IFDYNAMICGETCACHEDFUNCTION(PFNFLUSHPROCESSWRITEBUFFERS, FlushProcessWriteBuffers, pfFlushProcessWriteBuffers) { - pfFlushProcessWriteBuffers(); - } - - // ...otherwise there is no fall back. +// TRANSITION, ABI: preserved for binary compatibility +extern "C" _CRTIMP2 VOID __cdecl __crtFlushProcessWriteBuffers() { + FlushProcessWriteBuffers(); } -extern "C" VOID __cdecl __crtFreeLibraryWhenCallbackReturns( +// TRANSITION, ABI: preserved for binary compatibility +extern "C" _CRTIMP2 VOID __cdecl __crtFreeLibraryWhenCallbackReturns( _Inout_ PTP_CALLBACK_INSTANCE const pci, _In_ HMODULE const mod) { - // use FreeLibraryWhenCallbackReturns if it is available (only on Windows Vista+)... - IFDYNAMICGETCACHEDFUNCTION( - PFNFREELIBRARYWHENCALLBACKRETURNS, FreeLibraryWhenCallbackReturns, pfFreeLibraryWhenCallbackReturns) { - pfFreeLibraryWhenCallbackReturns(pci, mod); - } - - // ...otherwise there is no fall back. + FreeLibraryWhenCallbackReturns(pci, mod); } -extern "C" DWORD __cdecl __crtGetCurrentProcessorNumber() { - // use GetCurrentProcessorNumber if it is available (only on Windows Vista+)... - IFDYNAMICGETCACHEDFUNCTION(PFNGETCURRENTPROCESSORNUMBER, GetCurrentProcessorNumber, pfGetCurrentProcessorNumber) { - return pfGetCurrentProcessorNumber(); - } - - // ...otherwise return 0 because there is no fall back. - return 0; +// TRANSITION, ABI: preserved for binary compatibility +extern "C" _CRTIMP2 DWORD __cdecl __crtGetCurrentProcessorNumber() { + return GetCurrentProcessorNumber(); } -extern "C" BOOLEAN __cdecl __crtCreateSymbolicLinkW( +// TRANSITION, ABI: preserved for binary compatibility +extern "C" _CRTIMP2 BOOLEAN __cdecl __crtCreateSymbolicLinkW( _In_ LPCWSTR const lpSymlinkFileName, _In_ LPCWSTR const lpTargetFileName, _In_ DWORD const dwFlags) { - // use CreateSymbolicLink if it is available (only on Windows Vista+)... - IFDYNAMICGETCACHEDFUNCTION(PFNCREATESYMBOLICLINKW, CreateSymbolicLinkW, pfCreateSymbolicLink) { - return pfCreateSymbolicLink(lpSymlinkFileName, lpTargetFileName, dwFlags); - } - - // ...otherwise return 0 and set error code because there is no fall back. - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); +#ifdef _CRT_APP + (void) lpSymlinkFileName; + (void) lpTargetFileName; + (void) dwFlags; + SetLastError(ERROR_NOT_SUPPORTED); return 0; +#else // _CRT_APP + return CreateSymbolicLinkW(lpSymlinkFileName, lpTargetFileName, dwFlags); +#endif // _CRT_APP } -extern "C" _Success_(return ) BOOL __cdecl __crtGetFileInformationByHandleEx(_In_ HANDLE const hFile, +// TRANSITION, ABI: preserved for binary compatibility +extern "C" _CRTIMP2 _Success_(return ) BOOL __cdecl __crtGetFileInformationByHandleEx(_In_ HANDLE const hFile, _In_ FILE_INFO_BY_HANDLE_CLASS const FileInformationClass, _Out_writes_bytes_(dwBufferSize) LPVOID const lpFileInformation, _In_ DWORD const dwBufferSize) { - // use GetFileInformationByHandleEx if it is available (only on Windows Vista+)... - IFDYNAMICGETCACHEDFUNCTION( - PFNGETFILEINFORMATIONBYHANDLEEX, GetFileInformationByHandleEx, pfGetFileInformationByHandleEx) { - return pfGetFileInformationByHandleEx(hFile, FileInformationClass, lpFileInformation, dwBufferSize); - } - - // ...otherwise return 0 and set error code because there is no fall back. - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return 0; + return GetFileInformationByHandleEx(hFile, FileInformationClass, lpFileInformation, dwBufferSize); } -extern "C" BOOL __cdecl __crtSetFileInformationByHandle(_In_ HANDLE const hFile, +// TRANSITION, ABI: preserved for binary compatibility +extern "C" _CRTIMP2 BOOL __cdecl __crtSetFileInformationByHandle(_In_ HANDLE const hFile, _In_ FILE_INFO_BY_HANDLE_CLASS const FileInformationClass, _In_reads_bytes_(dwBufferSize) LPVOID const lpFileInformation, _In_ DWORD const dwBufferSize) { - // use SetFileInformationByHandle if it is available (only on Windows Vista+)... - IFDYNAMICGETCACHEDFUNCTION( - PFNSETFILEINFORMATIONBYHANDLE, SetFileInformationByHandle, pfSetFileInformationByHandle) { - return pfSetFileInformationByHandle(hFile, FileInformationClass, lpFileInformation, dwBufferSize); - } - - // ...otherwise return 0 and set error code because there is no fall back. - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return 0; + return SetFileInformationByHandle(hFile, FileInformationClass, lpFileInformation, dwBufferSize); } +// TRANSITION, ABI: preserved for binary compatibility extern "C" VOID __cdecl __crtInitializeConditionVariable(_Out_ PCONDITION_VARIABLE const pCond) { - DYNAMICGETCACHEDFUNCTION( - PFNINITIALIZECONDITIONVARIABLE, InitializeConditionVariable, pfInitializeConditionVariable); - pfInitializeConditionVariable(pCond); - // Don't have fallbacks because the only caller (in primitives.hpp) will check the existence before calling + InitializeConditionVariable(pCond); } +// TRANSITION, ABI: preserved for binary compatibility extern "C" VOID __cdecl __crtWakeConditionVariable(_Inout_ PCONDITION_VARIABLE const pCond) { - DYNAMICGETCACHEDFUNCTION(PFNWAKECONDITIONVARIABLE, WakeConditionVariable, pfWakeConditionVariable); - pfWakeConditionVariable(pCond); - // Don't have fallbacks because the only caller (in primitives.hpp) will check the existence before calling + WakeConditionVariable(pCond); } +// TRANSITION, ABI: preserved for binary compatibility extern "C" VOID __cdecl __crtWakeAllConditionVariable(_Inout_ PCONDITION_VARIABLE const pCond) { - DYNAMICGETCACHEDFUNCTION(PFNWAKEALLCONDITIONVARIABLE, WakeAllConditionVariable, pfWakeAllConditionVariable); - pfWakeAllConditionVariable(pCond); - // Don't have fallbacks because the only caller (in primitives.hpp) will check the existence before calling + WakeAllConditionVariable(pCond); } +// TRANSITION, ABI: preserved for binary compatibility extern "C" BOOL __cdecl __crtSleepConditionVariableCS( _Inout_ PCONDITION_VARIABLE const pCond, _Inout_ PCRITICAL_SECTION const pLock, _In_ DWORD const dwMs) { - DYNAMICGETCACHEDFUNCTION(PFNSLEEPCONDITIONVARIABLECS, SleepConditionVariableCS, pfSleepConditionVariableCS); - return pfSleepConditionVariableCS(pCond, pLock, dwMs); - // Don't have fallbacks because the only caller (in primitives.hpp) will check the existence before calling + return SleepConditionVariableCS(pCond, pLock, dwMs); } +// TRANSITION, ABI: preserved for binary compatibility extern "C" VOID __cdecl __crtInitializeSRWLock(_Out_ PSRWLOCK const pLock) { - DYNAMICGETCACHEDFUNCTION(PFNINITIALIZESRWLOCK, InitializeSRWLock, pfInitializeSRWLock); - pfInitializeSRWLock(pLock); - // Don't have fallbacks because the only caller (in primitives.hpp) will check the existence before calling + InitializeSRWLock(pLock); } +// TRANSITION, ABI: preserved for binary compatibility extern "C" VOID __cdecl __crtAcquireSRWLockExclusive(_Inout_ PSRWLOCK const pLock) { - DYNAMICGETCACHEDFUNCTION(PFNACQUIRESRWLOCKEXCLUSIVE, AcquireSRWLockExclusive, pfAcquireSRWLockExclusive); - pfAcquireSRWLockExclusive(pLock); - // Don't have fallbacks because the only caller (in primitives.hpp) will check the existence before calling + AcquireSRWLockExclusive(pLock); } +// TRANSITION, ABI: preserved for binary compatibility extern "C" VOID __cdecl __crtReleaseSRWLockExclusive(_Inout_ PSRWLOCK const pLock) { - DYNAMICGETCACHEDFUNCTION(PFNRELEASESRWLOCKEXCLUSIVE, ReleaseSRWLockExclusive, pfReleaseSRWLockExclusive); - pfReleaseSRWLockExclusive(pLock); - // Don't have fallbacks because the only caller (in primitives.hpp) will check the existence before calling + ReleaseSRWLockExclusive(pLock); } +// TRANSITION, ABI: preserved for binary compatibility extern "C" BOOL __cdecl __crtSleepConditionVariableSRW(_Inout_ PCONDITION_VARIABLE const pCond, _Inout_ PSRWLOCK const pLock, _In_ DWORD const dwMs, _In_ ULONG const flags) { - DYNAMICGETCACHEDFUNCTION(PFNSLEEPCONDITIONVARIABLESRW, SleepConditionVariableSRW, pfSleepConditionVariableSRW); - return pfSleepConditionVariableSRW(pCond, pLock, dwMs, flags); - // Don't have fallbacks because the only caller (in primitives.hpp) will check the existence before calling + return SleepConditionVariableSRW(pCond, pLock, dwMs, flags); } +// TRANSITION, ABI: preserved for binary compatibility extern "C" PTP_WORK __cdecl __crtCreateThreadpoolWork( _In_ PTP_WORK_CALLBACK const pfnwk, _Inout_opt_ PVOID const pv, _In_opt_ PTP_CALLBACK_ENVIRON const pcbe) { - DYNAMICGETCACHEDFUNCTION(PFNCREATETHREADPOOLWORK, CreateThreadpoolWork, pfCreateThreadpoolWork); - return pfCreateThreadpoolWork(pfnwk, pv, pcbe); - // Don't have fallbacks because the only caller (in taskscheduler.cpp) will check the existence before calling + return CreateThreadpoolWork(pfnwk, pv, pcbe); } +// TRANSITION, ABI: preserved for binary compatibility extern "C" VOID __cdecl __crtSubmitThreadpoolWork(_Inout_ PTP_WORK const pwk) { - DYNAMICGETCACHEDFUNCTION(PFNSUBMITTHREADPOOLWORK, SubmitThreadpoolWork, pfSubmitThreadpoolWork); - return pfSubmitThreadpoolWork(pwk); - // Don't have fallbacks because the only caller (in taskscheduler.cpp) will check the existence before calling + SubmitThreadpoolWork(pwk); } +// TRANSITION, ABI: preserved for binary compatibility extern "C" VOID __cdecl __crtCloseThreadpoolWork(_Inout_ PTP_WORK const pwk) { - DYNAMICGETCACHEDFUNCTION(PFNCLOSETHREADPOOLWORK, CloseThreadpoolWork, pfCloseThreadpoolWork); - return pfCloseThreadpoolWork(pwk); - // Don't have fallbacks because the only caller (in taskscheduler.cpp) will check the existence before calling + CloseThreadpoolWork(pwk); } #else // _STL_WIN32_WINNT < _WIN32_WINNT_VISTA +// TRANSITION, ABI: preserved for binary compatibility extern "C" BOOL __cdecl __crtQueueUserWorkItem(_In_ LPTHREAD_START_ROUTINE, _In_opt_ PVOID, _In_ ULONG) { // This function doesn't have an implementation as it is only used on Windows XP return 0; diff --git a/stl/src/xalloc.cpp b/stl/src/xalloc.cpp index 78bc3c5b157..379f506e888 100644 --- a/stl/src/xalloc.cpp +++ b/stl/src/xalloc.cpp @@ -14,7 +14,7 @@ namespace stdext { _CRTIMP2_PURE void __CLRCALL_PURE_OR_CDECL _Mtx_new(void*& _Ptr) { _Ptr = new CRITICAL_SECTION; - __crtInitializeCriticalSectionEx(static_cast(_Ptr), 4000, 0); + InitializeCriticalSectionEx(static_cast(_Ptr), 4000, 0); } _CRTIMP2_PURE void __CLRCALL_PURE_OR_CDECL _Mtx_delete(void* _Ptr) { diff --git a/stl/src/xdateord.cpp b/stl/src/xdateord.cpp index bcd1951dbfb..4bef192fdee 100644 --- a/stl/src/xdateord.cpp +++ b/stl/src/xdateord.cpp @@ -11,7 +11,7 @@ _EXTERN_C_UNLESS_PURE int __CLRCALL_PURE_OR_CDECL _Getdateorder() { // return date order for current locale wchar_t buf[2] = {0}; - __crtGetLocaleInfoEx(___lc_locale_name_func()[LC_TIME], LOCALE_ILDATE, buf, sizeof(buf) / sizeof(buf[0])); + GetLocaleInfoEx(___lc_locale_name_func()[LC_TIME], LOCALE_ILDATE, buf, sizeof(buf) / sizeof(buf[0])); switch (buf[0]) { case L'0': diff --git a/stl/src/xferaise.cpp b/stl/src/xferaise.cpp index b1683d6e194..a36a55a98b4 100644 --- a/stl/src/xferaise.cpp +++ b/stl/src/xferaise.cpp @@ -3,10 +3,7 @@ // _Feraise function -#include - -#include -#include +#include "xmath.hpp" _EXTERN_C_UNLESS_PURE diff --git a/stl/src/xfprec.cpp b/stl/src/xfprec.cpp index 31ca4b8aad1..4c4e438e406 100644 --- a/stl/src/xfprec.cpp +++ b/stl/src/xfprec.cpp @@ -3,6 +3,5 @@ // _FXp* functions -#include "xmath.hpp" #include "xxfftype.hpp" #include "xxxprec.hpp" diff --git a/stl/src/xgetwctype.cpp b/stl/src/xgetwctype.cpp index b3e444a2376..2063e0cfded 100644 --- a/stl/src/xgetwctype.cpp +++ b/stl/src/xgetwctype.cpp @@ -5,7 +5,7 @@ #include -#include +#include #include #include "awint.hpp" diff --git a/stl/src/xlock.cpp b/stl/src/xlock.cpp index 1ffa80e9362..e6274ddd3e5 100644 --- a/stl/src/xlock.cpp +++ b/stl/src/xlock.cpp @@ -5,8 +5,8 @@ #include -#include -#include +#include +#include #include "xmtx.hpp" diff --git a/stl/src/xlprec.cpp b/stl/src/xlprec.cpp index 3061c43c846..34963b7bee6 100644 --- a/stl/src/xlprec.cpp +++ b/stl/src/xlprec.cpp @@ -3,6 +3,5 @@ // _LXp* functions -#include "xmath.hpp" #include "xxlftype.hpp" #include "xxxprec.hpp" diff --git a/stl/src/xmath.hpp b/stl/src/xmath.hpp index 200d7a9d981..a11a8230bbf 100644 --- a/stl/src/xmath.hpp +++ b/stl/src/xmath.hpp @@ -3,11 +3,17 @@ #ifndef _XMATH #define _XMATH -#include -#include -#include +#include +#include #include +// MACROS FOR _Feraise ARGUMENT +#define _FE_DIVBYZERO 0x04 +#define _FE_INEXACT 0x20 +#define _FE_INVALID 0x01 +#define _FE_OVERFLOW 0x08 +#define _FE_UNDERFLOW 0x10 + // FLOAT PROPERTIES #define _D0 3 // little-endian, small long doubles #define _D1 2 diff --git a/stl/src/xmbtowc.cpp b/stl/src/xmbtowc.cpp index 5bc58a872cf..d415eeb8c5a 100644 --- a/stl/src/xmbtowc.cpp +++ b/stl/src/xmbtowc.cpp @@ -3,14 +3,11 @@ // Convert multibyte char to wide char. +#include +#include +#include // for INT_MAX #include -#include -#include #include -#include // for INT_MAX -#include -#include // for EOF -#include #include // for _Cvtvec, _Mbrtowc _EXTERN_C_UNLESS_PURE diff --git a/stl/src/xmtx.cpp b/stl/src/xmtx.cpp index 3cdc59dc5ea..a28195af92b 100644 --- a/stl/src/xmtx.cpp +++ b/stl/src/xmtx.cpp @@ -12,7 +12,7 @@ _EXTERN_C_UNLESS_PURE // Win32 critical sections are recursive void __CLRCALL_PURE_OR_CDECL _Mtxinit(_Rmtx* _Mtx) noexcept { // initialize mutex - __crtInitializeCriticalSectionEx(_Mtx, 4000, 0); + InitializeCriticalSectionEx(_Mtx, 4000, 0); } void __CLRCALL_PURE_OR_CDECL _Mtxdst(_Rmtx* _Mtx) noexcept { // delete mutex diff --git a/stl/src/xmtx.hpp b/stl/src/xmtx.hpp index f891af3175f..9380716a3c0 100644 --- a/stl/src/xmtx.hpp +++ b/stl/src/xmtx.hpp @@ -6,7 +6,7 @@ #define _XMTX #include -#include +#include #include diff --git a/stl/src/xnotify.cpp b/stl/src/xnotify.cpp index bf362c717ea..64a513855d9 100644 --- a/stl/src/xnotify.cpp +++ b/stl/src/xnotify.cpp @@ -3,8 +3,7 @@ // thread exit notification functions -#include -#include +#include #include #include diff --git a/stl/src/xonce.cpp b/stl/src/xonce.cpp index 5c6a5f9c2f9..b36f0a53b41 100644 --- a/stl/src/xonce.cpp +++ b/stl/src/xonce.cpp @@ -8,13 +8,30 @@ #include "awint.hpp" _STD_BEGIN + +struct _Xfg_trampoline_parameter { + void* _Pv; + _Execute_once_fp_t _Callback; +}; + // TRANSITION, ABI _CRTIMP2_PURE int __CLRCALL_PURE_OR_CDECL _Execute_once( once_flag& _Flag, _Execute_once_fp_t _Callback, void* _Pv) noexcept { // wrap Win32 InitOnceExecuteOnce() static_assert(sizeof(_Flag._Opaque) == sizeof(INIT_ONCE), "invalid size"); - return __crtInitOnceExecuteOnce( - reinterpret_cast(&_Flag._Opaque), reinterpret_cast(_Callback), _Pv, nullptr); + // _Execute_once_fp_t and PINIT_ONCE_FN differ in type signature, therefore + // we introduce _Xfg_trampoline which has PINIT_ONCE_FN's type signature and + // calls into _Callback as an _Execute_once_fp_t for XFG compatibility. + + _Xfg_trampoline_parameter _Trampoline_parameter = {_Pv, _Callback}; + + PINIT_ONCE_FN _Xfg_trampoline = [](PINIT_ONCE _InitOnce, PVOID _Parameter, PVOID* _Context) { + const auto _Trampoline_parameter = static_cast<_Xfg_trampoline_parameter*>(_Parameter); + return static_cast(_Trampoline_parameter->_Callback(_InitOnce, _Trampoline_parameter->_Pv, _Context)); + }; + + return InitOnceExecuteOnce( + reinterpret_cast(&_Flag._Opaque), _Xfg_trampoline, &_Trampoline_parameter, nullptr); } [[noreturn]] _CRTIMP2_PURE void __CLRCALL_PURE_OR_CDECL diff --git a/stl/src/xprec.cpp b/stl/src/xprec.cpp index 4097ba6a9fa..cb7eaa21f20 100644 --- a/stl/src/xprec.cpp +++ b/stl/src/xprec.cpp @@ -3,6 +3,5 @@ // _Xp* functions -#include "xmath.hpp" #include "xxdftype.hpp" #include "xxxprec.hpp" diff --git a/stl/src/xrngabort.cpp b/stl/src/xrngabort.cpp index b221d651871..87642321b95 100644 --- a/stl/src/xrngabort.cpp +++ b/stl/src/xrngabort.cpp @@ -5,8 +5,8 @@ #include -#include -#include +#include +#include // clang-format off _STD_BEGIN diff --git a/stl/src/xstod.cpp b/stl/src/xstod.cpp index 821cd15fb8a..34425729a3c 100644 --- a/stl/src/xstod.cpp +++ b/stl/src/xstod.cpp @@ -5,7 +5,7 @@ #include // include first, for native shared -#include +#include #include "xmath.hpp" #include "xxcctype.hpp" diff --git a/stl/src/xstof.cpp b/stl/src/xstof.cpp index 0c98e1a855f..1f0107573d3 100644 --- a/stl/src/xstof.cpp +++ b/stl/src/xstof.cpp @@ -5,7 +5,7 @@ #include // include first, for native shared -#include +#include #include "xmath.hpp" #include "xxcctype.hpp" diff --git a/stl/src/xstoflt.cpp b/stl/src/xstoflt.cpp index 57dfdaf5707..3a9b6adf214 100644 --- a/stl/src/xstoflt.cpp +++ b/stl/src/xstoflt.cpp @@ -3,9 +3,9 @@ // _Stoflt function -#include -#include -#include +#include +#include +#include #include "xmath.hpp" diff --git a/stl/src/xstol.cpp b/stl/src/xstol.cpp index 35a9e052fee..3cd73becd64 100644 --- a/stl/src/xstol.cpp +++ b/stl/src/xstol.cpp @@ -5,10 +5,10 @@ #include -#include -#include -#include -#include +#include +#include +#include +#include #include "xmath.hpp" diff --git a/stl/src/xstold.cpp b/stl/src/xstold.cpp index f8a66cb8827..cea4090ffc4 100644 --- a/stl/src/xstold.cpp +++ b/stl/src/xstold.cpp @@ -5,7 +5,7 @@ #include // include first, for native shared -#include +#include #include "xmath.hpp" #include "xxcctype.hpp" diff --git a/stl/src/xstoll.cpp b/stl/src/xstoll.cpp index af01eeb597c..63ad80e1493 100644 --- a/stl/src/xstoll.cpp +++ b/stl/src/xstoll.cpp @@ -3,10 +3,10 @@ // _Stoll function -#include -#include -#include -#include +#include +#include +#include +#include #include "xmath.hpp" diff --git a/stl/src/xstopfx.cpp b/stl/src/xstopfx.cpp index b9d44fe14b6..207b4cd7c61 100644 --- a/stl/src/xstopfx.cpp +++ b/stl/src/xstopfx.cpp @@ -3,7 +3,7 @@ // _Stopfx function -#include +#include #include "xmath.hpp" diff --git a/stl/src/xstoul.cpp b/stl/src/xstoul.cpp index c9a3214ed5b..48f48489b22 100644 --- a/stl/src/xstoul.cpp +++ b/stl/src/xstoul.cpp @@ -3,14 +3,13 @@ // _Stoul function -#include -#include -#include -#include -#include -#include - -#include "xmath.hpp" +#include +#include +#include +#include +#include +#include + _EXTERN_C_UNLESS_PURE diff --git a/stl/src/xstoull.cpp b/stl/src/xstoull.cpp index 2d04d149ee8..8a29d7ab260 100644 --- a/stl/src/xstoull.cpp +++ b/stl/src/xstoull.cpp @@ -3,14 +3,12 @@ // _Stoull function -#include -#include -#include -#include -#include -#include - -#include "xmath.hpp" +#include +#include +#include +#include +#include +#include _EXTERN_C_UNLESS_PURE diff --git a/stl/src/xstoxflt.cpp b/stl/src/xstoxflt.cpp index a4e33a6a6e7..d8b2c590574 100644 --- a/stl/src/xstoxflt.cpp +++ b/stl/src/xstoxflt.cpp @@ -3,10 +3,10 @@ // _Stoxflt function -#include -#include -#include -#include +#include +#include +#include +#include #include "xmath.hpp" diff --git a/stl/src/xstrcoll.cpp b/stl/src/xstrcoll.cpp index 2def872bf86..752999db66e 100644 --- a/stl/src/xstrcoll.cpp +++ b/stl/src/xstrcoll.cpp @@ -3,12 +3,12 @@ // Compare two strings using the locale LC_COLLATE information. +#include +#include #include -#include -#include +#include +#include #include -#include -#include #include // for _Collvec, _Strcoll #include "awint.hpp" diff --git a/stl/src/xstrxfrm.cpp b/stl/src/xstrxfrm.cpp index e7988a747ab..e814ecfe618 100644 --- a/stl/src/xstrxfrm.cpp +++ b/stl/src/xstrxfrm.cpp @@ -3,11 +3,10 @@ // Transform a string using the locale information as set by LC_COLLATE. -#include -#include +#include +#include +#include #include -#include -#include #include // for _Collvec #include diff --git a/stl/src/xtime.cpp b/stl/src/xtime.cpp index 0de318718d8..6d4bb94dc6c 100644 --- a/stl/src/xtime.cpp +++ b/stl/src/xtime.cpp @@ -4,8 +4,6 @@ // xtime functions #include -#include -#include #include #include "awint.hpp" diff --git a/stl/src/xtowlower.cpp b/stl/src/xtowlower.cpp index 630f148bc69..b7417de4a96 100644 --- a/stl/src/xtowlower.cpp +++ b/stl/src/xtowlower.cpp @@ -3,7 +3,7 @@ // _Towlower -- convert wchar_t to lower case -#include +#include #include #include "awint.hpp" diff --git a/stl/src/xtowupper.cpp b/stl/src/xtowupper.cpp index 84901eae6ef..943b160ffcb 100644 --- a/stl/src/xtowupper.cpp +++ b/stl/src/xtowupper.cpp @@ -3,7 +3,7 @@ // _Towupper -- convert wchar_t to upper case -#include +#include #include #include "awint.hpp" diff --git a/stl/src/xwcscoll.cpp b/stl/src/xwcscoll.cpp index 9bf62598030..c8a105d94cf 100644 --- a/stl/src/xwcscoll.cpp +++ b/stl/src/xwcscoll.cpp @@ -3,10 +3,10 @@ // Compare two wchar_t strings using the locale LC_COLLATE information. -#include -#include -#include -#include +#include +#include +#include +#include // for wmemcmp #include // for _Collvec, _Wcscoll #include "awint.hpp" diff --git a/stl/src/xwcsxfrm.cpp b/stl/src/xwcsxfrm.cpp index ab3692be410..9c283e289b7 100644 --- a/stl/src/xwcsxfrm.cpp +++ b/stl/src/xwcsxfrm.cpp @@ -3,11 +3,11 @@ // Transform a wide-character string using the locale information as set by LC_COLLATE. +#include +#include +#include +#include #include -#include -#include -#include -#include #include // for _Collvec, _Wcsxfrm #include "awint.hpp" diff --git a/stl/src/xwctomb.cpp b/stl/src/xwctomb.cpp index d82f8a5bdaa..80ce47e3abe 100644 --- a/stl/src/xwctomb.cpp +++ b/stl/src/xwctomb.cpp @@ -3,13 +3,11 @@ // Convert wide character to multibyte character, with locale. -#include -#include // for MB_LEN_MAX -#include +#include +#include // for MB_LEN_MAX +#include +#include #include -#include // for EOF -#include -#include // for memcpy #include // for _Cvtvec, _Wcrtomb #include diff --git a/stl/src/xwstod.cpp b/stl/src/xwstod.cpp index 499d19e2852..a2a4c927158 100644 --- a/stl/src/xwstod.cpp +++ b/stl/src/xwstod.cpp @@ -3,8 +3,8 @@ // _WStod function -#include -#include +#include +#include #include "xmath.hpp" #include "xxdftype.hpp" diff --git a/stl/src/xwstof.cpp b/stl/src/xwstof.cpp index cbe81b4f3f0..8419e7f4974 100644 --- a/stl/src/xwstof.cpp +++ b/stl/src/xwstof.cpp @@ -3,7 +3,7 @@ // _WStof function -#include +#include #include "xmath.hpp" #include "xxfftype.hpp" diff --git a/stl/src/xwstoflt.cpp b/stl/src/xwstoflt.cpp index 0631679e5d2..0da23a067de 100644 --- a/stl/src/xwstoflt.cpp +++ b/stl/src/xwstoflt.cpp @@ -3,9 +3,9 @@ // _WStoflt function -#include -#include -#include +#include +#include +#include #include "xmath.hpp" diff --git a/stl/src/xwstold.cpp b/stl/src/xwstold.cpp index e00bb8194aa..ff8bbe800fa 100644 --- a/stl/src/xwstold.cpp +++ b/stl/src/xwstold.cpp @@ -3,7 +3,7 @@ // _WStold function -#include +#include #include "xmath.hpp" #include "xxlftype.hpp" diff --git a/stl/src/xwstopfx.cpp b/stl/src/xwstopfx.cpp index b3d74711b4d..a9447bca098 100644 --- a/stl/src/xwstopfx.cpp +++ b/stl/src/xwstopfx.cpp @@ -3,7 +3,7 @@ // _WStopfx function -#include +#include #include "xmath.hpp" diff --git a/stl/src/xwstoxfl.cpp b/stl/src/xwstoxfl.cpp index 871501031e3..174ab1cf351 100644 --- a/stl/src/xwstoxfl.cpp +++ b/stl/src/xwstoxfl.cpp @@ -3,10 +3,10 @@ // _WStoxflt function -#include -#include -#include -#include +#include +#include +#include +#include #include "xmath.hpp" diff --git a/stl/src/xxdftype.hpp b/stl/src/xxdftype.hpp index ecf8baff491..db33883c974 100644 --- a/stl/src/xxdftype.hpp +++ b/stl/src/xxdftype.hpp @@ -5,7 +5,7 @@ #include -#include +#include #define FTYPE double #define FBITS DBL_MANT_DIG diff --git a/stl/src/xxfftype.hpp b/stl/src/xxfftype.hpp index 387570dbb66..cd2e1ad4d80 100644 --- a/stl/src/xxfftype.hpp +++ b/stl/src/xxfftype.hpp @@ -5,7 +5,7 @@ #include -#include +#include #define FTYPE float #define FBITS FLT_MANT_DIG diff --git a/stl/src/xxlftype.hpp b/stl/src/xxlftype.hpp index 09b46c0c42c..8657da52ed6 100644 --- a/stl/src/xxlftype.hpp +++ b/stl/src/xxlftype.hpp @@ -5,7 +5,7 @@ #include -#include +#include #define FTYPE long double #define FBITS LDBL_MANT_DIG diff --git a/stl/src/xxxprec.hpp b/stl/src/xxxprec.hpp index 7f63882fa38..7eea90d532a 100644 --- a/stl/src/xxxprec.hpp +++ b/stl/src/xxxprec.hpp @@ -3,7 +3,7 @@ // common extended precision functionality -#include +#include #include "xmath.hpp" diff --git a/tests/libcxx/expected_results.txt b/tests/libcxx/expected_results.txt index 3e4254debc4..33115b7aed8 100644 --- a/tests/libcxx/expected_results.txt +++ b/tests/libcxx/expected_results.txt @@ -66,6 +66,7 @@ std/numerics/bit/bit.pow.two/log2p1.pass.cpp FAIL # test emits warning C4310: cast truncates constant value std/numerics/bit/bitops.rot/rotl.pass.cpp:0 FAIL + # *** INTERACTIONS WITH CONTEST / C1XX THAT UPSTREAM LIKELY WON'T FIX *** # Tracked by VSO-593630 " Enable libcxx filesystem tests" # rapid-cxx-test.hpp uses pragma system_header @@ -486,10 +487,10 @@ std/thread/futures/futures.task/futures.task.members/make_ready_at_thread_exit.p # *** C1XX COMPILER BUGS *** -# Compiler bug: DevCom-409222 "Constructing rvalue reference from non-reference-related lvalue reference" +# DevCom-409222 "Constructing rvalue reference from non-reference-related lvalue reference" std/utilities/meta/meta.unary/meta.unary.prop/is_constructible.pass.cpp:0 FAIL -# Compiler bug: DevCom-876860 "conditional operator errors" blocks readable. +# DevCom-876860 "conditional operator errors" blocks readable. std/containers/views/span.cons/ptr_len.pass.cpp:0 FAIL std/containers/views/span.cons/ptr_ptr.pass.cpp:0 FAIL @@ -504,7 +505,7 @@ std/depr/depr.c.headers/tgmath_h.pass.cpp:1 FAIL # *** CLANG FEATURES NOT YET IMPLEMENTED *** # P0960R3 "Allow initializing aggregates from a parenthesized list of values" -std/utilities/tuple/tuple.tuple/tuple.creation/tuple_cat.pass.cpp SKIPPED # TRANSITION, VS 2019 16.8 p3 +std/utilities/tuple/tuple.tuple/tuple.creation/tuple_cat.pass.cpp:0 FAIL # *** CLANG ISSUES, NOT YET ANALYZED *** @@ -519,49 +520,42 @@ std/language.support/support.limits/limits/numeric.limits.members/traps.pass.cpp # *** STL BUGS *** -# STL bug: VSO-121977 ": the enum value of std::money_base is not correct[libcxx]" +# GH-1112 : the enum value of std::money_base is not correct std/localization/locale.categories/category.monetary/locale.moneypunct/money_base.pass.cpp FAIL -# STL Bug: VSO-595631 basic_filebuf doesn't comply with setbuf(0,0) requirement in the standard +# GH-1113 : basic_filebuf doesn't comply with setbuf(0,0) requirement in the standard std/input.output/file.streams/fstreams/filebuf.virtuals/overflow.pass.cpp FAIL std/input.output/file.streams/fstreams/filebuf.virtuals/underflow.pass.cpp FAIL -# STL bug: Our inheritance implementation is allowing this to compile when it shouldn't. -std/numerics/complex.number/complex.special/double_long_double_implicit.compile.fail.cpp FAIL -std/numerics/complex.number/complex.special/float_double_implicit.compile.fail.cpp FAIL -std/numerics/complex.number/complex.special/float_long_double_implicit.compile.fail.cpp FAIL - -# STL bug: regex_traits::transform() isn't following the Standard. +# GH-1004 : Error C2664 in std::regex_traits::transform std/re/re.traits/transform.pass.cpp FAIL -# STL bug: Incorrect return types. -std/numerics/complex.number/cmplx.over/pow.pass.cpp FAIL - -# STL bug: We allow fill() and swap() for array. +# GH-1295 : array allows fill() and swap() std/containers/sequences/array/array.fill/fill.fail.cpp FAIL std/containers/sequences/array/array.swap/swap.fail.cpp FAIL -# STL bug: VSO-207715 We reject array. +# GH-942 : std::array doesn't compile - when type is not default constructible std/containers/sequences/array/array.cons/implicit_copy.pass.cpp FAIL std/containers/sequences/array/array.cons/initialization.pass.cpp FAIL std/containers/sequences/array/array.data/data_const.pass.cpp FAIL std/containers/sequences/array/array.data/data.pass.cpp FAIL std/containers/sequences/array/iterators.pass.cpp FAIL -# Predicate count assertions - IDL2 is slightly bending the Standard's rules here. +# GH-1006 : debug checks for predicates are observable std/algorithms/alg.sorting/alg.heap.operations/make.heap/make_heap_comp.pass.cpp FAIL std/algorithms/alg.sorting/alg.merge/inplace_merge_comp.pass.cpp FAIL std/algorithms/alg.sorting/alg.min.max/minmax_init_list_comp.pass.cpp FAIL -# STL bug: We don't match strtod / strtof when doing field extraction for hexfloats, or special cases like inf +# GH-1259 : wrong field extraction for hexfloats, or special cases like inf std/localization/locale.categories/category.numeric/locale.num.get/facet.num.get.members/get_double.pass.cpp FAIL std/localization/locale.categories/category.numeric/locale.num.get/facet.num.get.members/get_float.pass.cpp FAIL std/localization/locale.categories/category.numeric/locale.num.get/facet.num.get.members/get_long_double.pass.cpp FAIL -# STL bug: We don't match numpunct groups correctly in do_get +# GH-1277 : We don't match numpunct groups correctly in do_get std/localization/locale.categories/category.numeric/locale.num.get/facet.num.get.members/get_long.pass.cpp FAIL -# STL test bug: We don't have the locale names libcxx wants specialized in platform_support.hpp +# GH-1275 : missing some locale names +# We don't have the locale names libcxx wants specialized in platform_support.hpp # More bugs may be uncovered when the locale names are present. # move.pass.cpp can crash. std/input.output/iostreams.base/ios/basic.ios.members/move.pass.cpp SKIPPED @@ -593,22 +587,26 @@ std/localization/locale.categories/category.time/locale.time.put.byname/put1.pas std/localization/locale.categories/facet.numpunct/locale.numpunct.byname/grouping.pass.cpp FAIL std/localization/locale.categories/facet.numpunct/locale.numpunct.byname/thousands_sep.pass.cpp FAIL -# STL Bug? Our wbuffer_convert does not implement seek. [depr.conversions.buffer] is completely underspecified. +# GH-1264 : wbuffer_convert does not implement seek std/localization/locales/locale.convenience/conversions/conversions.buffer/seekoff.pass.cpp FAIL -# STL Bug: error_category's default ctor isn't constexpr. (Should be fixed in vNext.) +# GH-1116 : error_category's default ctor isn't constexpr. std/diagnostics/syserr/syserr.errcat/syserr.errcat.nonvirtuals/default_ctor.pass.cpp:1 FAIL -# STL Bug: future incorrectly uses copy assignment instead of copy construction in set_value. (Should be fixed in vNext.) +# GH-1190 : incorrectly used copy assignment instead of copy construction in set_value std/thread/futures/futures.promise/set_value_const.pass.cpp FAIL -# STL bug: GH-757 : Too many enabled hash specializations +# GH-757 : Too many enabled hash specializations std/strings/basic.string.hash/char_type_hash.fail.cpp FAIL std/strings/string.view/string.view.hash/char_type.hash.fail.cpp FAIL -# STL bug: GH-784 : aligned_storage has incorrect alignment defaults +# GH-784 : aligned_storage has incorrect alignment defaults std/utilities/meta/meta.trans/meta.trans.other/aligned_storage.pass.cpp FAIL +# GH-519 : signbit() misses overloads for integer types +std/depr/depr.c.headers/math_h.pass.cpp FAIL +std/numerics/c.math/cmath.pass.cpp FAIL + # *** CRT BUGS *** # We're permanently missing aligned_alloc(). @@ -634,10 +632,6 @@ std/thread/thread.semaphore/try_acquire.pass.cpp FAIL std/thread/thread.barrier/completion.pass.cpp FAIL std/thread/thread.barrier/max.pass.cpp FAIL -# Test bug/LEWG issue or STL bug. See GH-519 ": signbit() misses overloads for integer types". -std/depr/depr.c.headers/math_h.pass.cpp FAIL -std/numerics/c.math/cmath.pass.cpp FAIL - # Test bug after LWG-2899 "is_(nothrow_)move_constructible and tuple, optional and unique_ptr" was accepted. std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.asgn/move_convert.pass.cpp FAIL std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.asgn/move_convert.runtime.pass.cpp FAIL @@ -748,13 +742,16 @@ std/language.support/cmp/cmp.weakord/weakord.pass.cpp FAIL # error C4576: a parenthesized type followed by an initializer list is a non-standard explicit type conversion syntax std/containers/sequences/array/array.creation/to_array.pass.cpp:0 FAIL -# Tests that need to learn that insert iterators have non-void difference type in C++20 +# Tests that need to learn that iterators have non-void difference types in C++20 std/iterators/predef.iterators/insert.iterators/back.insert.iterator/types.pass.cpp FAIL std/iterators/predef.iterators/insert.iterators/front.insert.iterator/types.pass.cpp FAIL std/iterators/predef.iterators/insert.iterators/insert.iterator/types.pass.cpp FAIL +std/iterators/stream.iterators/ostream.iterator/types.pass.cpp FAIL +std/iterators/stream.iterators/ostreambuf.iterator/types.pass.cpp FAIL # Tests emit warning C4244: 'argument': conversion from 'T' to 'const std::complex::_Ty', possible loss of data std/numerics/complex.number/cmplx.over/conj.pass.cpp:0 FAIL +std/numerics/complex.number/cmplx.over/pow.pass.cpp:0 FAIL std/numerics/complex.number/cmplx.over/proj.pass.cpp:0 FAIL # Assertion failed: std::abs(skew - x_skew) < 0.01 diff --git a/tests/libcxx/skipped_tests.txt b/tests/libcxx/skipped_tests.txt index bc5a21bba1f..4239de46b5b 100644 --- a/tests/libcxx/skipped_tests.txt +++ b/tests/libcxx/skipped_tests.txt @@ -66,6 +66,7 @@ numerics\bit\bit.pow.two\log2p1.pass.cpp # test emits warning C4310: cast truncates constant value numerics\bit\bitops.rot\rotl.pass.cpp + # *** INTERACTIONS WITH CONTEST / C1XX THAT UPSTREAM LIKELY WON'T FIX *** # Tracked by VSO-593630 " Enable libcxx filesystem tests" # rapid-cxx-test.hpp uses pragma system_header @@ -486,10 +487,10 @@ thread\futures\futures.task\futures.task.members\make_ready_at_thread_exit.pass. # *** C1XX COMPILER BUGS *** -# Compiler bug: DevCom-409222 "Constructing rvalue reference from non-reference-related lvalue reference" +# DevCom-409222 "Constructing rvalue reference from non-reference-related lvalue reference" utilities\meta\meta.unary\meta.unary.prop\is_constructible.pass.cpp -# Compiler bug: DevCom-876860 "conditional operator errors" blocks readable. +# DevCom-876860 "conditional operator errors" blocks readable. containers\views\span.cons\ptr_len.pass.cpp containers\views\span.cons\ptr_ptr.pass.cpp @@ -519,49 +520,42 @@ language.support\support.limits\limits\numeric.limits.members\traps.pass.cpp # *** STL BUGS *** -# STL bug: VSO-121977 ": the enum value of std::money_base is not correct[libcxx]" +# GH-1112 : the enum value of std::money_base is not correct localization\locale.categories\category.monetary\locale.moneypunct\money_base.pass.cpp -# STL Bug: VSO-595631 basic_filebuf doesn't comply with setbuf(0,0) requirement in the standard +# GH-1113 : basic_filebuf doesn't comply with setbuf(0,0) requirement in the standard input.output\file.streams\fstreams\filebuf.virtuals\overflow.pass.cpp input.output\file.streams\fstreams\filebuf.virtuals\underflow.pass.cpp -# STL bug: Our inheritance implementation is allowing this to compile when it shouldn't. -numerics\complex.number\complex.special\double_long_double_implicit.compile.fail.cpp -numerics\complex.number\complex.special\float_double_implicit.compile.fail.cpp -numerics\complex.number\complex.special\float_long_double_implicit.compile.fail.cpp - -# STL bug: regex_traits::transform() isn't following the Standard. +# GH-1004 : Error C2664 in std::regex_traits::transform re\re.traits\transform.pass.cpp -# STL bug: Incorrect return types. -numerics\complex.number\cmplx.over\pow.pass.cpp - -# STL bug: We allow fill() and swap() for array. +# GH-1295 : array allows fill() and swap() containers\sequences\array\array.fill\fill.fail.cpp containers\sequences\array\array.swap\swap.fail.cpp -# STL bug: VSO-207715 We reject array. +# GH-942 : std::array doesn't compile - when type is not default constructible containers\sequences\array\array.cons\implicit_copy.pass.cpp containers\sequences\array\array.cons\initialization.pass.cpp containers\sequences\array\array.data\data_const.pass.cpp containers\sequences\array\array.data\data.pass.cpp containers\sequences\array\iterators.pass.cpp -# Predicate count assertions - IDL2 is slightly bending the Standard's rules here. +# GH-1006 : debug checks for predicates are observable algorithms\alg.sorting\alg.heap.operations\make.heap\make_heap_comp.pass.cpp algorithms\alg.sorting\alg.merge\inplace_merge_comp.pass.cpp algorithms\alg.sorting\alg.min.max\minmax_init_list_comp.pass.cpp -# STL bug: We don't match strtod / strtof when doing field extraction for hexfloats, or special cases like inf +# GH-1259 : wrong field extraction for hexfloats, or special cases like inf localization\locale.categories\category.numeric\locale.num.get\facet.num.get.members\get_double.pass.cpp localization\locale.categories\category.numeric\locale.num.get\facet.num.get.members\get_float.pass.cpp localization\locale.categories\category.numeric\locale.num.get\facet.num.get.members\get_long_double.pass.cpp -# STL bug: We don't match numpunct groups correctly in do_get +# GH-1277 : We don't match numpunct groups correctly in do_get localization\locale.categories\category.numeric\locale.num.get\facet.num.get.members\get_long.pass.cpp -# STL test bug: We don't have the locale names libcxx wants specialized in platform_support.hpp +# GH-1275 : missing some locale names +# We don't have the locale names libcxx wants specialized in platform_support.hpp # More bugs may be uncovered when the locale names are present. # move.pass.cpp can crash. input.output\iostreams.base\ios\basic.ios.members\move.pass.cpp @@ -593,22 +587,26 @@ localization\locale.categories\category.time\locale.time.put.byname\put1.pass.cp localization\locale.categories\facet.numpunct\locale.numpunct.byname\grouping.pass.cpp localization\locale.categories\facet.numpunct\locale.numpunct.byname\thousands_sep.pass.cpp -# STL Bug? Our wbuffer_convert does not implement seek. [depr.conversions.buffer] is completely underspecified. +# GH-1264 : wbuffer_convert does not implement seek localization\locales\locale.convenience\conversions\conversions.buffer\seekoff.pass.cpp -# STL Bug: error_category's default ctor isn't constexpr. (Should be fixed in vNext.) +# GH-1116 : error_category's default ctor isn't constexpr. diagnostics\syserr\syserr.errcat\syserr.errcat.nonvirtuals\default_ctor.pass.cpp -# STL Bug: future incorrectly uses copy assignment instead of copy construction in set_value. (Should be fixed in vNext.) +# GH-1190 : incorrectly used copy assignment instead of copy construction in set_value thread\futures\futures.promise\set_value_const.pass.cpp -# STL bug: GH-757 : Too many enabled hash specializations +# GH-757 : Too many enabled hash specializations strings\basic.string.hash\char_type_hash.fail.cpp strings\string.view\string.view.hash\char_type.hash.fail.cpp -# STL bug: GH-784 : aligned_storage has incorrect alignment defaults +# GH-784 : aligned_storage has incorrect alignment defaults utilities\meta\meta.trans\meta.trans.other\aligned_storage.pass.cpp +# GH-519 : signbit() misses overloads for integer types +depr\depr.c.headers\math_h.pass.cpp +numerics\c.math\cmath.pass.cpp + # *** CRT BUGS *** # We're permanently missing aligned_alloc(). @@ -634,10 +632,6 @@ thread\thread.semaphore\try_acquire.pass.cpp thread\thread.barrier\completion.pass.cpp thread\thread.barrier\max.pass.cpp -# Test bug/LEWG issue or STL bug. See GH-519 ": signbit() misses overloads for integer types". -depr\depr.c.headers\math_h.pass.cpp -numerics\c.math\cmath.pass.cpp - # Test bug after LWG-2899 "is_(nothrow_)move_constructible and tuple, optional and unique_ptr" was accepted. utilities\smartptr\unique.ptr\unique.ptr.class\unique.ptr.asgn\move_convert.pass.cpp utilities\smartptr\unique.ptr\unique.ptr.class\unique.ptr.asgn\move_convert.runtime.pass.cpp @@ -748,13 +742,16 @@ language.support\cmp\cmp.weakord\weakord.pass.cpp # error C4576: a parenthesized type followed by an initializer list is a non-standard explicit type conversion syntax containers\sequences\array\array.creation\to_array.pass.cpp -# Tests that need to learn that insert iterators have non-void difference type in C++20 +# Tests that need to learn that iterators have non-void difference types in C++20 iterators\predef.iterators\insert.iterators\back.insert.iterator\types.pass.cpp iterators\predef.iterators\insert.iterators\front.insert.iterator\types.pass.cpp iterators\predef.iterators\insert.iterators\insert.iterator\types.pass.cpp +iterators\stream.iterators\ostream.iterator\types.pass.cpp +iterators\stream.iterators\ostreambuf.iterator\types.pass.cpp # Tests emit warning C4244: 'argument': conversion from 'T' to 'const std::complex::_Ty', possible loss of data numerics\complex.number\cmplx.over\conj.pass.cpp +numerics\complex.number\cmplx.over\pow.pass.cpp numerics\complex.number\cmplx.over\proj.pass.cpp # Assertion failed: std::abs(skew - x_skew) < 0.01 diff --git a/tests/std/include/new_counter.hpp b/tests/std/include/new_counter.hpp new file mode 100644 index 00000000000..9ecb27607a5 --- /dev/null +++ b/tests/std/include/new_counter.hpp @@ -0,0 +1,120 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include + +#pragma once +#pragma warning(push) +#pragma warning(disable : 28251) // Inconsistent annotation for 'new': this instance has no annotations. + +namespace std_testing { + size_t g_total_news = 0; + size_t g_total_deletes = 0; + size_t g_maximum_news = 0; + + void reset_new_counters(size_t new_maximum_news) { + assert(g_total_news == g_total_deletes); + g_total_news = 0; + g_total_deletes = 0; + g_maximum_news = new_maximum_news; + } +} // namespace std_testing + +void* operator new(size_t size) { + void* const p = ::operator new(size, std::nothrow); + if (p == nullptr) { + throw std::bad_alloc{}; + } + + return p; +} + +void* operator new(size_t, std::align_val_t) { + abort(); +} + +void* operator new(size_t size, const std::nothrow_t&) noexcept { + if (std_testing::g_total_news == std_testing::g_maximum_news) { + return nullptr; + } + + if (size == 0) { + ++size; + } + + ++std_testing::g_total_news; + return malloc(size); +} + +void* operator new(size_t, std::align_val_t, const std::nothrow_t&) noexcept { + abort(); +} + +void operator delete(void* ptr) noexcept { + ::operator delete(ptr, std::nothrow); +} + +void operator delete(void* ptr, size_t) noexcept { + ::operator delete(ptr, std::nothrow); +} + +void operator delete(void*, std::align_val_t) noexcept { + abort(); +} + +void operator delete(void* ptr, const std::nothrow_t&) noexcept { + if (ptr) { + ++std_testing::g_total_deletes; + assert(std_testing::g_total_deletes <= std_testing::g_total_news); + free(ptr); + } +} + +void operator delete(void*, std::align_val_t, const std::nothrow_t&) noexcept { + abort(); +} + +void* operator new[](size_t size) { + return ::operator new(size); +} + +void* operator new[](size_t, std::align_val_t) { + abort(); +} + +void* operator new[](size_t size, const std::nothrow_t&) noexcept { + return ::operator new(size, std::nothrow); +} + +void* operator new[](size_t, std::align_val_t, const std::nothrow_t&) noexcept { + abort(); +} + +void operator delete[](void* ptr) noexcept { + ::operator delete(ptr); +} + +void operator delete[](void* ptr, size_t size) noexcept { + ::operator delete(ptr, size); +} + +void operator delete[](void*, std::align_val_t) noexcept { + abort(); +} + +void operator delete[](void*, size_t, std::align_val_t) noexcept { + abort(); +} + +void operator delete[](void* ptr, const std::nothrow_t&) noexcept { + ::operator delete(ptr, std::nothrow); +} + +void operator delete[](void*, std::align_val_t, const std::nothrow_t&) noexcept { + abort(); +} + +#pragma warning(pop) diff --git a/tests/std/test.lst b/tests/std/test.lst index 2585db8b27f..3855902a344 100644 --- a/tests/std/test.lst +++ b/tests/std/test.lst @@ -162,11 +162,13 @@ tests\GH_000685_condition_variable_any tests\GH_000690_overaligned_function tests\GH_000890_pow_template tests\GH_000940_missing_valarray_copy +tests\GH_001001_random_rejection_rounding tests\GH_001010_filesystem_error_encoding tests\GH_001017_discrete_distribution_out_of_range tests\GH_001059_hyperbolic_truncation tests\GH_001086_partial_sort_copy tests\GH_001103_countl_zero_correctness +tests\GH_001123_random_cast_out_of_range tests\LWG2597_complex_branch_cut tests\LWG3018_shared_ptr_function tests\P0019R8_atomic_ref @@ -218,6 +220,7 @@ tests\P0220R1_sample tests\P0220R1_searchers tests\P0220R1_string_view tests\P0325R4_to_array +tests\P0339R6_polymorphic_allocator tests\P0356R5_bind_front tests\P0357R3_supporting_incomplete_types_in_reference_wrapper tests\P0414R2_shared_ptr_for_arrays @@ -235,6 +238,9 @@ tests\P0595R2_is_constant_evaluated tests\P0607R0_inline_variables tests\P0616R0_using_move_in_numeric tests\P0631R8_numbers_math_constants +tests\P0660R10_jthread_and_cv_any +tests\P0660R10_stop_token +tests\P0660R10_stop_token_death tests\P0674R1_make_shared_for_arrays tests\P0718R2_atomic_smart_ptrs tests\P0758R1_is_nothrow_convertible @@ -311,7 +317,16 @@ tests\P0896R4_ranges_alg_sort tests\P0896R4_ranges_alg_swap_ranges tests\P0896R4_ranges_alg_transform_binary tests\P0896R4_ranges_alg_transform_unary +tests\P0896R4_ranges_alg_uninitialized_copy +tests\P0896R4_ranges_alg_uninitialized_copy_n +tests\P0896R4_ranges_alg_uninitialized_default_construct +tests\P0896R4_ranges_alg_uninitialized_default_construct_n +tests\P0896R4_ranges_alg_uninitialized_fill +tests\P0896R4_ranges_alg_uninitialized_fill_n tests\P0896R4_ranges_alg_uninitialized_move +tests\P0896R4_ranges_alg_uninitialized_move_n +tests\P0896R4_ranges_alg_uninitialized_value_construct +tests\P0896R4_ranges_alg_uninitialized_value_construct_n tests\P0896R4_ranges_alg_unique tests\P0896R4_ranges_alg_unique_copy tests\P0896R4_ranges_algorithm_machinery @@ -321,6 +336,7 @@ tests\P0896R4_ranges_ref_view tests\P0896R4_ranges_subrange tests\P0896R4_ranges_test_machinery tests\P0896R4_ranges_to_address +tests\P0896R4_stream_iterators tests\P0896R4_views_all tests\P0896R4_views_drop tests\P0896R4_views_empty @@ -336,6 +352,7 @@ tests\P0898R3_identity tests\P0912R5_coroutine tests\P0919R3_heterogeneous_unordered_lookup tests\P0966R1_string_reserve_should_not_shrink +tests\P1007R3_assume_aligned tests\P1023R0_constexpr_for_array_comparisons tests\P1032R1_miscellaneous_constexpr tests\P1135R6_atomic_flag_test diff --git a/tests/std/tests/Dev10_722102_shared_ptr_nullptr/test.cpp b/tests/std/tests/Dev10_722102_shared_ptr_nullptr/test.cpp index 0c753db3ddd..75eca42e39d 100644 --- a/tests/std/tests/Dev10_722102_shared_ptr_nullptr/test.cpp +++ b/tests/std/tests/Dev10_722102_shared_ptr_nullptr/test.cpp @@ -4,12 +4,12 @@ // Dev10-722102 "STL: Get nullptr overloads" // DevDiv-520681 "Faulty implementation of shared_ptr(nullptr_t) constructor" -#include +#include +#include +#include #include #include #include -#include -#include #include #include @@ -159,11 +159,43 @@ namespace unique_ptr_ { template struct fancy_pointer { - T* ptr_; + T* ptr_{nullptr}; fancy_pointer() = default; + explicit fancy_pointer(secret_tag, T* ptr) : ptr_{ptr} {} + fancy_pointer(nullptr_t) {} + + fancy_pointer& operator=(nullptr_t) { + ptr_ = nullptr; + return *this; + } + + friend bool operator==(const fancy_pointer& left, const fancy_pointer& right) { + return left.ptr_ == right.ptr_; + } + + friend bool operator!=(const fancy_pointer& left, const fancy_pointer& right) { + return left.ptr_ != right.ptr_; + } + + friend bool operator==(const fancy_pointer& left, nullptr_t) { + return left.ptr_ == nullptr; + } + + friend bool operator!=(const fancy_pointer& left, nullptr_t) { + return left.ptr_ != nullptr; + } + + friend bool operator==(nullptr_t, const fancy_pointer& right) { + return nullptr == right.ptr_; + } + + friend bool operator!=(nullptr_t, const fancy_pointer& right) { + return nullptr != right.ptr_; + } + operator T*() const { return ptr_; } diff --git a/tests/std/tests/Dev11_0836436_get_time/test.cpp b/tests/std/tests/Dev11_0836436_get_time/test.cpp index 79d2dde40a9..d6279cde33d 100644 --- a/tests/std/tests/Dev11_0836436_get_time/test.cpp +++ b/tests/std/tests/Dev11_0836436_get_time/test.cpp @@ -309,6 +309,46 @@ void test_990695() { iss >> get_time(&t, fmt.c_str()); assert(iss.fail()); } + + { + // GH-1071 should not fail when format is longer than the stream + istringstream iss("2020"); + ios_base::iostate err = Bit; + tm t{}; + const string fmt("%Y%m%d"); + use_facet>(iss.getloc()) + .get(Iter(iss.rdbuf()), Iter(), iss, err, &t, fmt.c_str(), fmt.c_str() + fmt.size()); + assert(err == ios_base::eofbit); + assert(t.tm_mon == 0); + assert(t.tm_mday == 0); + assert(t.tm_year == 120); + } + + { + // GH-1071 should not fail when format is longer than the stream + istringstream iss("2020-sep"); + tm t = {}; + const string fmt("%Y-%b-%d"); + iss >> get_time(&t, fmt.c_str()); + assert(!iss.fail()); + assert(iss.eof()); + assert(t.tm_mon == 8); + assert(t.tm_mday == 0); + assert(t.tm_year == 120); + } + + { + // GH-1071 should not fail when format is longer than the stream + istringstream iss("Current time is 3:8"); + tm t = {}; + const string fmt("Current time is %H:%M:%S"); + iss >> get_time(&t, fmt.c_str()); + assert(!iss.fail()); + assert(iss.eof()); + assert(t.tm_hour == 3); + assert(t.tm_min == 8); + assert(t.tm_sec == 0); + } } } diff --git a/tests/std/tests/GH_001001_random_rejection_rounding/env.lst b/tests/std/tests/GH_001001_random_rejection_rounding/env.lst new file mode 100644 index 00000000000..19f025bd0e6 --- /dev/null +++ b/tests/std/tests/GH_001001_random_rejection_rounding/env.lst @@ -0,0 +1,4 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\usual_matrix.lst diff --git a/tests/std/tests/GH_001001_random_rejection_rounding/test.cpp b/tests/std/tests/GH_001001_random_rejection_rounding/test.cpp new file mode 100644 index 00000000000..fc0c792b13b --- /dev/null +++ b/tests/std/tests/GH_001001_random_rejection_rounding/test.cpp @@ -0,0 +1,43 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include +#include + +void Test_GH1001() { + constexpr int N{1000}; + constexpr double p{.001238}; + constexpr int seed{12345}; + constexpr int iters{1'000'000}; + std::map frequency; + + std::mt19937 mt_rand(seed); + + std::binomial_distribution distribution(N, p); + + for (int i = 0; i < iters; ++i) { + ++frequency[distribution(mt_rand)]; + } + + double mean_x{0.0}; + for (const auto& valueCountPair : frequency) { + mean_x += valueCountPair.first * static_cast(valueCountPair.second) / iters; + } + const double p0_x{static_cast(frequency[0]) / iters}; + const double p1_x{static_cast(frequency[1]) / iters}; + + const double p0{std::pow(1.0 - p, static_cast(N))}; + const double p1{1000.0 * p * std::pow(1.0 - p, static_cast(N - 1))}; + const double mean{p * N}; + + assert(std::abs(mean_x / mean - 1.0) < 0.01); + assert(std::abs(p0_x / p0 - 1.0) < 0.01); + assert(std::abs(p1_x / p1 - 1.0) < 0.01); +} + +int main() { + Test_GH1001(); +} diff --git a/tests/std/tests/GH_001017_discrete_distribution_out_of_range/test.cpp b/tests/std/tests/GH_001017_discrete_distribution_out_of_range/test.cpp index 5a43af9b4df..d4ded00b997 100644 --- a/tests/std/tests/GH_001017_discrete_distribution_out_of_range/test.cpp +++ b/tests/std/tests/GH_001017_discrete_distribution_out_of_range/test.cpp @@ -6,6 +6,23 @@ #include "bad_random_engine.hpp" +template +void Test_for_NaN_Inf(Distribution&& distribution) { + for (bad_random_generator rng; !rng.has_cycled_through();) { + const auto rand_value = distribution(rng); + assert(!isnan(rand_value) && !isinf(rand_value)); + } +} + +template +void Test_distributions() { + // Additionally test GH-1174 ": Some random number distributions could return NaN" + Test_for_NaN_Inf(std::normal_distribution{}); + Test_for_NaN_Inf(std::lognormal_distribution{}); + Test_for_NaN_Inf(std::fisher_f_distribution{}); + Test_for_NaN_Inf(std::student_t_distribution{}); +} + int main() { std::discrete_distribution dist{1, 1, 1, 1, 1, 1}; bad_random_generator rng; @@ -14,4 +31,8 @@ int main() { const auto rand_value = dist(rng); assert(0 <= rand_value && rand_value < 6); } + + Test_distributions(); + Test_distributions(); + Test_distributions(); } diff --git a/tests/std/tests/GH_001123_random_cast_out_of_range/env.lst b/tests/std/tests/GH_001123_random_cast_out_of_range/env.lst new file mode 100644 index 00000000000..19f025bd0e6 --- /dev/null +++ b/tests/std/tests/GH_001123_random_cast_out_of_range/env.lst @@ -0,0 +1,4 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\usual_matrix.lst diff --git a/tests/std/tests/GH_001123_random_cast_out_of_range/test.cpp b/tests/std/tests/GH_001123_random_cast_out_of_range/test.cpp new file mode 100644 index 00000000000..b2a9cbb6e2a --- /dev/null +++ b/tests/std/tests/GH_001123_random_cast_out_of_range/test.cpp @@ -0,0 +1,86 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include +#include + +#pragma warning(disable : 4984) // if constexpr is a C++17 language extension +#ifdef __clang__ +#pragma clang diagnostic ignored "-Wc++17-extensions" +#endif // __clang__ + +template +using lim = std::numeric_limits; + +template +void CheckUpperBound(IntType i, FltType fmax) { + const auto x{std::_Float_upper_bound(i)}; + const auto y{std::nextafter(x, FltType{0})}; // lower bound, <= i + + assert(y < fmax); + assert(static_cast(y) <= i); + assert(x <= fmax); + if (x < fmax) { + assert(static_cast(x) > i); + } +} + +template +void TestUpperBoundExhaustive() { + const auto fmax{exp2(static_cast(lim::digits))}; + IntType i{0}; + do { + CheckUpperBound(i, fmax); + } while (++i != IntType{0}); +} + +template +constexpr T FillLsb(int n) { + if (n <= 0) { + return 0; + } + T x{T{1} << (n - 1)}; + return (x - 1) ^ x; +} + +template +void TestUpperBoundSelective() { + const auto fmax{exp2(static_cast(lim::digits))}; + CheckUpperBound(IntType{0}, fmax); + CheckUpperBound(IntType{1}, fmax); + CheckUpperBound(lim::max(), fmax); + + constexpr int diff{lim::digits - lim::digits}; + if constexpr (diff > 0) { + // crossover from ulp < 1 to ulp = 1 + constexpr auto a{FillLsb(lim::digits - 1)}; + CheckUpperBound(a - 1, fmax); + CheckUpperBound(a, fmax); + + // crossover from ulp = 1 to ulp > 1 + constexpr auto b{FillLsb(lim::digits)}; + CheckUpperBound(b, fmax); + CheckUpperBound(b + 1, fmax); + CheckUpperBound(b + 2, fmax); + + // saturation at the largest representable IntType + constexpr auto c{FillLsb(lim::digits) << diff}; + CheckUpperBound(c - 1, fmax); + CheckUpperBound(c, fmax); + CheckUpperBound(c + 1, fmax); + } +} + +int main() { + TestUpperBoundExhaustive(); + TestUpperBoundExhaustive(); + TestUpperBoundSelective(); + + TestUpperBoundExhaustive(); + TestUpperBoundSelective(); + TestUpperBoundSelective(); + TestUpperBoundSelective(); +} diff --git a/tests/std/tests/P0019R8_atomic_ref/test.cpp b/tests/std/tests/P0019R8_atomic_ref/test.cpp index 15151a2fe19..1813049d209 100644 --- a/tests/std/tests/P0019R8_atomic_ref/test.cpp +++ b/tests/std/tests/P0019R8_atomic_ref/test.cpp @@ -94,40 +94,72 @@ void test_int_ops() { const std::atomic_ref rx(v); const std::atomic_ref ry(v); - vx.fetch_add(0x10); - rx.fetch_add(0x10); + assert(vx.fetch_add(0x10) == 0x40); + assert(rx.fetch_add(0x10) == 0x40); assert(vx.load() == 0x50); assert(vy.load() == 0x40); assert(rx.load() == 0x50); assert(ry.load() == 0x50); - vx.fetch_sub(0x8); - rx.fetch_sub(0x8); + assert(vx.fetch_sub(0x8) == 0x50); + assert(rx.fetch_sub(0x8) == 0x50); assert(vx.load() == 0x48); assert(vy.load() == 0x40); assert(rx.load() == 0x48); assert(ry.load() == 0x48); - vx.fetch_or(0xF); - rx.fetch_or(0xF); + assert(vx.fetch_or(0xF) == 0x48); + assert(rx.fetch_or(0xF) == 0x48); assert(vx.load() == 0x4F); assert(vy.load() == 0x40); assert(rx.load() == 0x4F); assert(ry.load() == 0x4F); - vx.fetch_and(0x3C); - rx.fetch_and(0x3C); + assert(vx.fetch_and(0x3C) == 0x4F); + assert(rx.fetch_and(0x3C) == 0x4F); assert(vx.load() == 0xC); assert(vy.load() == 0x40); assert(rx.load() == 0xC); assert(ry.load() == 0xC); - vx.fetch_xor(0x3F); - rx.fetch_xor(0x3F); + assert(vx.fetch_xor(0x3F) == 0xC); + assert(rx.fetch_xor(0x3F) == 0xC); + + assert(vx.load() == 0x33); + assert(vy.load() == 0x40); + assert(rx.load() == 0x33); + assert(ry.load() == 0x33); + + assert(vx-- == 0x33); + assert(rx-- == 0x33); + + assert(vx.load() == 0x32); + assert(vy.load() == 0x40); + assert(rx.load() == 0x32); + assert(ry.load() == 0x32); + + assert(--vx == 0x31); + assert(--rx == 0x31); + + assert(vx.load() == 0x31); + assert(vy.load() == 0x40); + assert(rx.load() == 0x31); + assert(ry.load() == 0x31); + + assert(vx++ == 0x31); + assert(rx++ == 0x31); + + assert(vx.load() == 0x32); + assert(vy.load() == 0x40); + assert(rx.load() == 0x32); + assert(ry.load() == 0x32); + + assert(++vx == 0x33); + assert(++rx == 0x33); assert(vx.load() == 0x33); assert(vy.load() == 0x40); @@ -145,16 +177,16 @@ void test_float_ops() { const std::atomic_ref rx(v); const std::atomic_ref ry(v); - vx.fetch_add(0x10); - rx.fetch_add(0x10); + assert(vx.fetch_add(0x10) == 0x40); + assert(rx.fetch_add(0x10) == 0x40); assert(vx.load() == 0x50); assert(vy.load() == 0x40); assert(rx.load() == 0x50); assert(ry.load() == 0x50); - vx.fetch_sub(0x8); - rx.fetch_sub(0x8); + assert(vx.fetch_sub(0x8) == 0x50); + assert(rx.fetch_sub(0x8) == 0x50); assert(vx.load() == 0x48); assert(vy.load() == 0x40); @@ -180,16 +212,16 @@ void test_ptr_ops() { const std::atomic_ref rx(v); const std::atomic_ref ry(v); - vx.fetch_add(0x10); - rx.fetch_add(0x10); + assert(vx.fetch_add(0x10) == a); + assert(rx.fetch_add(0x10) == a); assert(vx.load() == a + 0x10); assert(vy.load() == a); assert(rx.load() == a + 0x10); assert(ry.load() == a + 0x10); - vx.fetch_sub(0x8); - rx.fetch_sub(0x8); + assert(vx.fetch_sub(0x8) == a + 0x10); + assert(rx.fetch_sub(0x8) == a + 0x10); assert(vx.load() == a + 0x8); assert(vy.load() == a); @@ -203,6 +235,38 @@ void test_ptr_ops() { assert(vy.load() == a); assert(rx.load() == a + 0x10); assert(ry.load() == a + 0x10); + + assert(vx-- == a + 0x10); + assert(rx-- == a + 0x10); + + assert(vx.load() == a + 0xF); + assert(vy.load() == a); + assert(rx.load() == a + 0xF); + assert(ry.load() == a + 0xF); + + assert(--vx == a + 0xE); + assert(--rx == a + 0xE); + + assert(vx.load() == a + 0xE); + assert(vy.load() == a); + assert(rx.load() == a + 0xE); + assert(ry.load() == a + 0xE); + + assert(vx++ == a + 0xE); + assert(rx++ == a + 0xE); + + assert(vx.load() == a + 0xF); + assert(vy.load() == a); + assert(rx.load() == a + 0xF); + assert(ry.load() == a + 0xF); + + assert(++vx == a + 0x10); + assert(++rx == a + 0x10); + + assert(vx.load() == a + 0x10); + assert(vy.load() == a); + assert(rx.load() == a + 0x10); + assert(ry.load() == a + 0x10); } int main() { diff --git a/tests/std/tests/P0067R5_charconv/double_general_precision_to_chars_test_cases.hpp b/tests/std/tests/P0067R5_charconv/double_general_precision_to_chars_test_cases.hpp index 5158ae7b374..94961b13853 100644 --- a/tests/std/tests/P0067R5_charconv/double_general_precision_to_chars_test_cases.hpp +++ b/tests/std/tests/P0067R5_charconv/double_general_precision_to_chars_test_cases.hpp @@ -5049,4 +5049,12 @@ inline constexpr DoublePrecisionToCharsTestCase double_general_precision_to_char {0x1.88e2d605edc3dp+345, chars_format::general, 3, "1.1e+104"}, {0x1.88e2d605edc3dp+345, chars_format::general, 2, "1.1e+104"}, {0x1.88e2d605edc3dp+345, chars_format::general, 1, "1e+104"}, + + // More cases that the UCRT had trouble with (e.g. DevCom-1093399). + {0x1.8p+62, chars_format::general, 17, "6.9175290276410819e+18"}, + {0x1.0a2742p+17, chars_format::general, 6, "136271"}, + {0x1.f8b0f962cdffbp+205, chars_format::general, 14, "1.0137595739223e+62"}, + {0x1.f8b0f962cdffbp+205, chars_format::general, 17, "1.0137595739222531e+62"}, + {0x1.f8b0f962cdffbp+205, chars_format::general, 51, "1.01375957392225305727423222620636224221808910954041e+62"}, + {0x1.f8b0f962cdffbp+205, chars_format::general, 55, "1.013759573922253057274232226206362242218089109540405973e+62"}, }; diff --git a/tests/std/tests/P0067R5_charconv/double_scientific_precision_to_chars_test_cases_1.hpp b/tests/std/tests/P0067R5_charconv/double_scientific_precision_to_chars_test_cases_1.hpp index 835111d6ac4..eb25bbf2c81 100644 --- a/tests/std/tests/P0067R5_charconv/double_scientific_precision_to_chars_test_cases_1.hpp +++ b/tests/std/tests/P0067R5_charconv/double_scientific_precision_to_chars_test_cases_1.hpp @@ -312,4 +312,13 @@ inline constexpr DoublePrecisionToCharsTestCase double_scientific_precision_to_c {0x1.88e2d605edc3dp+345, chars_format::scientific, 2, "1.10e+104"}, {0x1.88e2d605edc3dp+345, chars_format::scientific, 1, "1.1e+104"}, {0x1.88e2d605edc3dp+345, chars_format::scientific, 0, "1e+104"}, + + // More cases that the UCRT had trouble with (e.g. DevCom-1093399). + {0x1.8p+62, chars_format::scientific, 16, "6.9175290276410819e+18"}, + {0x1.0a2742p+17, chars_format::scientific, 5, "1.36271e+05"}, + {0x1.f8b0f962cdffbp+205, chars_format::scientific, 13, "1.0137595739223e+62"}, + {0x1.f8b0f962cdffbp+205, chars_format::scientific, 16, "1.0137595739222531e+62"}, + {0x1.f8b0f962cdffbp+205, chars_format::scientific, 50, "1.01375957392225305727423222620636224221808910954041e+62"}, + {0x1.f8b0f962cdffbp+205, chars_format::scientific, 54, + "1.013759573922253057274232226206362242218089109540405973e+62"}, }; diff --git a/tests/std/tests/P0067R5_charconv/test.cpp b/tests/std/tests/P0067R5_charconv/test.cpp index 5e8e804bc09..fcb20bc270d 100644 --- a/tests/std/tests/P0067R5_charconv/test.cpp +++ b/tests/std/tests/P0067R5_charconv/test.cpp @@ -1059,6 +1059,24 @@ void all_floating_tests(mt19937_64& mt64) { } } +void test_right_shift_64_bits_with_rounding() { + // Directly test _Right_shift_with_rounding for the case of _Shift == 64 && _Value >= 2^63. + // We were unable to actually exercise this codepath with the public interface of from_chars, + // but were equally unable to prove that it can never ever be executed. + assert(_Right_shift_with_rounding(0x0000'0000'0000'0000ULL, 64, true) == 0); + assert(_Right_shift_with_rounding(0x0000'0000'0000'0000ULL, 64, false) == 0); + assert(_Right_shift_with_rounding(0x0000'0000'0000'0001ULL, 64, true) == 0); + assert(_Right_shift_with_rounding(0x0000'0000'0000'0001ULL, 64, false) == 0); + assert(_Right_shift_with_rounding(0x7fff'ffff'ffff'ffffULL, 64, true) == 0); + assert(_Right_shift_with_rounding(0x7fff'ffff'ffff'ffffULL, 64, false) == 0); + assert(_Right_shift_with_rounding(0x8000'0000'0000'0000ULL, 64, true) == 0); + assert(_Right_shift_with_rounding(0x8000'0000'0000'0000ULL, 64, false) == 1); + assert(_Right_shift_with_rounding(0x8000'0000'0000'0001ULL, 64, true) == 1); + assert(_Right_shift_with_rounding(0x8000'0000'0000'0001ULL, 64, false) == 1); + assert(_Right_shift_with_rounding(0xffff'ffff'ffff'ffffULL, 64, true) == 1); + assert(_Right_shift_with_rounding(0xffff'ffff'ffff'ffffULL, 64, false) == 1); +} + int main(int argc, char** argv) { const auto start = chrono::steady_clock::now(); @@ -1070,6 +1088,8 @@ int main(int argc, char** argv) { all_floating_tests(mt64); + test_right_shift_64_bits_with_rounding(); + const auto finish = chrono::steady_clock::now(); const long long ms = chrono::duration_cast(finish - start).count(); diff --git a/tests/std/tests/P0083R3_splicing_maps_and_sets/test.cpp b/tests/std/tests/P0083R3_splicing_maps_and_sets/test.cpp index f6eef6d8d92..95cbc6c9f58 100644 --- a/tests/std/tests/P0083R3_splicing_maps_and_sets/test.cpp +++ b/tests/std/tests/P0083R3_splicing_maps_and_sets/test.cpp @@ -59,6 +59,8 @@ struct allocation_guard { } }; +bool construct_destroy_exact = false; + template struct tracked_allocator { using value_type = T; @@ -80,6 +82,26 @@ struct tracked_allocator { --allocation_count; } + template + void construct(U* ptr, Args&&... args) { + if constexpr (!std::is_same_v) { + assert(!construct_destroy_exact); + printf("construct\n"); + } + std::allocator alloc; + std::allocator_traits>::construct(alloc, ptr, std::forward(args)...); + } + + template + void destroy(U* ptr) { + if constexpr (!std::is_same_v) { + assert(!construct_destroy_exact); + printf("destroy\n"); + } + std::allocator alloc; + std::allocator_traits>::destroy(alloc, ptr); + } + template bool operator==(tracked_allocator const&) const noexcept { return true; @@ -131,9 +153,11 @@ void test_node_handle(NodeHandle& nh1, NodeHandle& nh2, Validator1 v1, Validator // Nothrow/constexpr default construction static_assert(std::is_nothrow_default_constructible_v); CHECK_EMPTY(NodeHandle{}); -#ifdef __clang__ +#if defined(__cpp_constinit) + { static constinit NodeHandle static_handle{}; } +#elif defined(__clang__) { [[clang::require_constant_initialization]] static NodeHandle static_handle{}; } -#endif // __clang__ +#endif // ^^^ __clang__ ^^^ // No copies! static_assert(!std::is_copy_constructible_v); @@ -478,7 +502,7 @@ void test_set() { { using S = Set, tracked_allocator>; allocation_guard guard{true}; - S s{{0, 1}}; + S s{0, 1}; allocation_allowed = false; auto nh1 = test_extract(s, 42, 0); @@ -587,7 +611,7 @@ void test_unordered_set() { { using S = Set, std::equal_to<>, tracked_allocator>; allocation_guard guard{true}; - S s{{0, 1}}; + S s{0, 1}; allocation_allowed = false; auto nh1 = test_extract(s, 42, 0); @@ -634,6 +658,137 @@ void test_unordered_set() { test_merge(); } +void test_gh1309() { + // Guard against regression of GH-1309, in which node handles were incorrectly destroying the user value with a node + // allocator rather than a value_type allocator as the Standard requires. + + allocation_guard guard{true}; + + { + using A = tracked_allocator>; + using M = std::map, A>; + using NH = M::node_type; + NH nh1; + NH nh2; + { + M m{{0, 'x'}, {1, 'y'}}; + nh1 = m.extract(0); + nh2 = m.extract(1); + } + construct_destroy_exact = true; + nh1 = std::move(nh2); + } + construct_destroy_exact = false; + + { + using A = tracked_allocator>; + using M = std::multimap, A>; + using NH = M::node_type; + NH nh1; + NH nh2; + { + M m{{0, 'x'}, {0, 'y'}}; + nh1 = m.extract(0); + nh2 = m.extract(0); + } + construct_destroy_exact = true; + nh1 = std::move(nh2); + } + construct_destroy_exact = false; + + { + using S = std::set, tracked_allocator>; + using NH = S::node_type; + NH nh1; + NH nh2; + { + S s{0, 1}; + nh1 = s.extract(0); + nh2 = s.extract(s.begin()); + } + construct_destroy_exact = true; + nh1 = std::move(nh2); + } + construct_destroy_exact = false; + + { + using S = std::multiset, tracked_allocator>; + using NH = S::node_type; + NH nh1; + NH nh2; + { + S s{0, 0}; + nh1 = s.extract(0); + nh2 = s.extract(s.begin()); + } + construct_destroy_exact = true; + nh1 = std::move(nh2); + } + construct_destroy_exact = false; + + { + using A = tracked_allocator>; + using M = std::unordered_map, std::equal_to<>, A>; + using NH = M::node_type; + NH nh1; + NH nh2; + { + M m{{0, 'x'}, {1, 'y'}}; + nh1 = m.extract(0); + nh2 = m.extract(m.begin()); + } + construct_destroy_exact = true; + nh1 = std::move(nh2); + } + construct_destroy_exact = false; + + { + using A = tracked_allocator>; + using M = std::unordered_multimap, std::equal_to<>, A>; + using NH = M::node_type; + NH nh1; + NH nh2; + { + M m{{0, 'x'}, {0, 'y'}}; + nh1 = m.extract(0); + nh2 = m.extract(m.begin()); + } + construct_destroy_exact = true; + nh1 = std::move(nh2); + } + construct_destroy_exact = false; + + { + using S = std::unordered_set, std::equal_to<>, tracked_allocator>; + using NH = S::node_type; + NH nh1; + NH nh2; + { + S s{0, 1}; + nh1 = s.extract(0); + nh2 = s.extract(s.begin()); + } + construct_destroy_exact = true; + nh1 = std::move(nh2); + } + construct_destroy_exact = false; + + { + using S = std::unordered_multiset, std::equal_to<>, tracked_allocator>; + using NH = S::node_type; + NH nh1; + NH nh2; + { + S s{0, 0}; + nh1 = s.extract(0); + nh2 = s.extract(s.begin()); + } + construct_destroy_exact = true; + nh1 = std::move(nh2); + } + construct_destroy_exact = false; +} + int main() { test_map(); test_map(); @@ -646,4 +801,6 @@ int main() { test_unordered_set(); test_unordered_set(); + + test_gh1309(); } diff --git a/tests/std/tests/P0088R3_variant/test.cpp b/tests/std/tests/P0088R3_variant/test.cpp index 3a96506be06..2857e561b3a 100644 --- a/tests/std/tests/P0088R3_variant/test.cpp +++ b/tests/std/tests/P0088R3_variant/test.cpp @@ -6485,7 +6485,6 @@ namespace msvc { namespace derived_variant { void run_test() { -#ifndef __EDG__ // TRANSITION, VSO-1178211 // Extension: std::visit accepts types derived from a specialization of variant. { struct my_variant : std::variant { @@ -6538,7 +6537,6 @@ namespace msvc { } catch (std::bad_variant_access&) { } } -#endif // TRANSITION, VSO-1178211 } } // namespace derived_variant diff --git a/tests/std/tests/P0218R1_filesystem/test.cpp b/tests/std/tests/P0218R1_filesystem/test.cpp index df813ffa2a1..0ff4f084c32 100644 --- a/tests/std/tests/P0218R1_filesystem/test.cpp +++ b/tests/std/tests/P0218R1_filesystem/test.cpp @@ -3669,6 +3669,11 @@ void test_create_dirs_and_remove_all() { remove_all(badPath, ec); EXPECT(good(ec)); + // test GH-1283 create_directories() should throw for empty paths + EXPECT(throws_filesystem_error([] { create_directories(path{}); }, "create_directories", path{})); + EXPECT(create_directories(path{}, ec) == false); + EXPECT(bad(ec)); + // test that normalization isn't done first auto dots = r / L"a/../b/../c"sv; EXPECT(create_directories(dots)); diff --git a/tests/std/tests/P0339R6_polymorphic_allocator/env.lst b/tests/std/tests/P0339R6_polymorphic_allocator/env.lst new file mode 100644 index 00000000000..642f530ffad --- /dev/null +++ b/tests/std/tests/P0339R6_polymorphic_allocator/env.lst @@ -0,0 +1,4 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\usual_latest_matrix.lst diff --git a/tests/std/tests/P0339R6_polymorphic_allocator/test.cpp b/tests/std/tests/P0339R6_polymorphic_allocator/test.cpp new file mode 100644 index 00000000000..374ec7d0b4e --- /dev/null +++ b/tests/std/tests/P0339R6_polymorphic_allocator/test.cpp @@ -0,0 +1,106 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include +#include +#include +#include + +using std::pmr::polymorphic_allocator; + +void allocate_bytes_test() { + constexpr int N = 5; + + polymorphic_allocator<> alloc{}; + + void* vp = alloc.allocate_bytes(sizeof(int) * N, alignof(int)); + + int* arr = static_cast(vp); + + for (int i = 0; i < N; ++i) { + alloc.construct(arr + i, i); + } + + for (int i = 0; i < N; ++i) { + assert(arr[i] == i); + } + + std::destroy(arr, arr + N); + + alloc.deallocate_bytes(vp, sizeof(int) * N, alignof(int)); + + void* vp2 = alloc.allocate_bytes(sizeof(int)); + assert(reinterpret_cast(vp2) % alignof(std::max_align_t) == 0); + alloc.deallocate_bytes(vp2, sizeof(int)); +} + +void allocate_object_test() { + constexpr int N = 10; + + polymorphic_allocator<> alloc{}; + + int* arr = alloc.allocate_object(N); + + for (int i = 0; i < N; ++i) { + alloc.construct(arr + i, i); + } + + for (int i = 0; i < N; ++i) { + assert(arr[i] == i); + } + + std::destroy(arr, arr + N); + + alloc.deallocate_object(arr, N); + + // N = 1 + int* p = alloc.allocate_object(); + alloc.construct(p, 20); + assert(*p == 20); + std::destroy_at(p); + alloc.deallocate_object(p); +} + +void allocate_object_overflow_test() { + constexpr auto threshold = std::numeric_limits::max() / sizeof(int); + + polymorphic_allocator<> alloc{}; + + try { + int* vp = alloc.allocate_object(threshold); + alloc.deallocate_object(vp, threshold); + } catch (const std::bad_alloc&) { + } catch (...) { + assert(false); + } + + try { + [[maybe_unused]] int* vp = alloc.allocate_object(threshold + 1); + } catch (const std::bad_array_new_length&) { + return; + } catch (...) { + assert(false); + } + assert(false); +} + +void new_object_test() { + polymorphic_allocator<> alloc{}; + + int* p = alloc.new_object(20); + + assert(*p == 20); + + alloc.delete_object(p); +} + + +int main() { + allocate_bytes_test(); + allocate_object_test(); + allocate_object_overflow_test(); + new_object_test(); +} diff --git a/tests/std/tests/P0356R5_bind_front/test.cpp b/tests/std/tests/P0356R5_bind_front/test.cpp index 804997e3b42..804c9c3bb6f 100644 --- a/tests/std/tests/P0356R5_bind_front/test.cpp +++ b/tests/std/tests/P0356R5_bind_front/test.cpp @@ -164,4 +164,65 @@ int main() { auto bound7 = move(bound6); assert(*move(bound6)() == -9000); assert(*move(bound7)() == 1234); + + // Also test GH-1292 "bind_front violates [func.require]p8" in which the return type of bind_front inadvertently + // depends on the value category and/or cv-qualification of its arguments. + { + struct S { + int i = 42; + }; + S s; + auto lambda = [](S x) { return x.i; }; + auto returns_lambda = [=] { return lambda; }; + auto returns_const_lambda = [=]() -> const decltype(lambda) { return lambda; }; + auto returns_const_S = []() -> const S { return {}; }; + + using T = decltype(bind_front(lambda, s)); + static_assert(is_same_v); + static_assert(is_same_v); + + static_assert(is_same_v); + static_assert(is_same_v); + static_assert(is_same_v); + + static_assert(is_same_v); + static_assert(is_same_v); + static_assert(is_same_v); + + static_assert(is_same_v); + static_assert(is_same_v); + static_assert(is_same_v); + + static_assert(is_same_v); + static_assert(is_same_v); + static_assert(is_same_v); + + static_assert(is_same_v); + static_assert(is_same_v); + static_assert(is_same_v); + + static_assert(is_same_v); + static_assert(is_same_v); + static_assert(is_same_v); + + static_assert(is_same_v); + static_assert(is_same_v); + static_assert(is_same_v); + + static_assert(is_same_v); + static_assert(is_same_v); + static_assert(is_same_v); + + static_assert(is_same_v); + static_assert(is_same_v); + static_assert(is_same_v); + + static_assert(is_same_v); + static_assert(is_same_v); + static_assert(is_same_v); + + static_assert(is_same_v); + static_assert(is_same_v); + static_assert(is_same_v); + } } diff --git a/tests/std/tests/P0660R10_jthread_and_cv_any/env.lst b/tests/std/tests/P0660R10_jthread_and_cv_any/env.lst new file mode 100644 index 00000000000..642f530ffad --- /dev/null +++ b/tests/std/tests/P0660R10_jthread_and_cv_any/env.lst @@ -0,0 +1,4 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\usual_latest_matrix.lst diff --git a/tests/std/tests/P0660R10_jthread_and_cv_any/test.cpp b/tests/std/tests/P0660R10_jthread_and_cv_any/test.cpp new file mode 100644 index 00000000000..1495227aacd --- /dev/null +++ b/tests/std/tests/P0660R10_jthread_and_cv_any/test.cpp @@ -0,0 +1,245 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include +#include +#include +#include + +#define STATIC_ASSERT(...) static_assert(__VA_ARGS__, #__VA_ARGS__) + +#ifdef __clang__ +#pragma clang diagnostic ignored "-Wself-move" +#endif // __clang__ + +using namespace std; + +STATIC_ASSERT(is_same_v); +STATIC_ASSERT(is_same_v); + +int main() { + // dtor tested in lots of places here so no explicit tests for it + + { // default ctor + jthread default_constructed; + assert(default_constructed.get_id() == thread::id{}); + assert(!default_constructed.get_stop_source().stop_possible()); + } + + { // initializing ctor, traditional functor + jthread worker{[] {}}; + assert(worker.get_id() != thread::id{}); + assert(worker.joinable()); + assert(worker.get_stop_source().stop_possible()); + } + + { // also make sure that we don't delegate to std::thread's constructor which would try to move assign over the + // std::thread inside jthread rather than passing it to the functor + jthread worker{[](thread t) { t.join(); }, thread{[] {}}}; + assert(worker.get_id() != thread::id{}); + assert(worker.joinable()); + assert(worker.get_stop_source().stop_possible()); + } + + { // initializing ctor, token functor + bool called = false; + struct overload_detector { + bool* p_called; + void operator()(stop_token, int i) const { + assert(i == 1729); + *p_called = true; + } + void operator()(int) const { + assert(false); + } + }; + + { + jthread worker{overload_detector{&called}, 1729}; + (void) worker; + } + + assert(called); + } + + { // move ctor + jthread worker{[] {}}; + auto worker_source = worker.get_stop_source(); + { + jthread moved{move(worker)}; + assert(moved.get_stop_source() == worker_source); + assert(moved.joinable()); + assert(worker.get_stop_source() != worker_source); + assert(!worker.joinable()); + } + } + + { // move assign + jthread worker_a{[] {}}; + auto source_a = worker_a.get_stop_source(); + jthread worker_b{[] {}}; + auto id_b = worker_b.get_id(); + auto source_b = worker_b.get_stop_source(); + worker_a = move(worker_b); + assert(source_a.stop_requested()); + assert(id_b == worker_a.get_id()); + assert(!source_b.stop_requested()); + assert(worker_a.get_stop_source() == source_b); + assert(!worker_b.joinable()); + } + + { // self move assign, as of N4861 specified to try to cancel and join [thread.jthread.cons]/13 + jthread worker{[] {}}; + auto source = worker.get_stop_source(); + worker = move(worker); + assert(!worker.joinable()); + assert(source.stop_requested()); + } + + { // swaps + jthread worker_a{[] {}}; + auto id_a = worker_a.get_id(); + auto source_a = worker_a.get_stop_source(); + auto token_a = worker_a.get_stop_token(); + jthread worker_b{[] {}}; + auto id_b = worker_b.get_id(); + auto source_b = worker_b.get_stop_source(); + auto token_b = worker_b.get_stop_token(); + + assert(id_a != id_b); + assert(source_a != source_b); + assert(token_a != token_b); + + worker_a.swap(worker_b); + assert(worker_a.get_id() == id_b); + assert(worker_a.get_stop_source() == source_b); + assert(worker_b.get_id() == id_a); + assert(worker_b.get_stop_source() == source_a); + swap(worker_a, worker_b); + assert(worker_a.get_id() == id_a); + assert(worker_a.get_stop_source() == source_a); + assert(worker_b.get_id() == id_b); + assert(worker_b.get_stop_source() == source_b); + } + + { // join + jthread worker{[] {}}; + auto source = worker.get_stop_source(); + worker.join(); + assert(!worker.joinable()); + assert(worker.get_stop_source() == source); + assert(!source.stop_requested()); + assert(source.stop_possible()); + } + + // TRANSITION, OS-11107628 "_Exit allows cleanup in other DLLs" + // detach() is intentionally not tested + + // get_id, get_stop_source, get_stop_token tested above + + assert(jthread::hardware_concurrency() == thread::hardware_concurrency()); + + { // first wait_until overload; without the cancellation this would deadlock + jthread worker([](stop_token token) { + mutex m; + condition_variable_any cv; + unique_lock lck{m}; + assert(cv.wait(lck, move(token), [] { return false; }) == false); + }); + } + + static constexpr auto forever = chrono::steady_clock::duration::max(); + static constexpr auto infinity = chrono::steady_clock::time_point::max(); + + { // ditto without the cancellation this would deadlock + jthread worker([](stop_token token) { + mutex m; + condition_variable_any cv; + unique_lock lck{m}; + assert(cv.wait_until(lck, move(token), infinity, [] { return false; }) == false); + }); + } + + { // ditto without the cancellation this would deadlock + jthread worker([](stop_token token) { + mutex m; + condition_variable_any cv; + unique_lock lck{m}; + assert(cv.wait_for(lck, move(token), forever, [] { return false; }) == false); + }); + } + + // smoke test true-returning versions of the above + { + mutex m; + condition_variable_any cv; + bool b = false; + jthread worker([&](stop_token token) { + unique_lock lck{m}; + assert(cv.wait(lck, move(token), [] { return true; }) == true); + assert(cv.wait(lck, move(token), [&] { return b; }) == true); + }); + + { + lock_guard lck{m}; + b = true; + } + + cv.notify_all(); + } + + { + mutex m; + condition_variable_any cv; + bool b = false; + jthread worker([&](stop_token token) { + unique_lock lck{m}; + assert(cv.wait_until(lck, move(token), infinity, [] { return true; }) == true); + assert(cv.wait_until(lck, move(token), infinity, [&] { return b; }) == true); + }); + + { + lock_guard lck{m}; + b = true; + } + + cv.notify_all(); + } + + { + mutex m; + condition_variable_any cv; + bool b = false; + jthread worker([&](stop_token token) { + unique_lock lck{m}; + assert(cv.wait_for(lck, move(token), forever, [] { return true; }) == true); + assert(cv.wait_for(lck, move(token), forever, [&] { return b; }) == true); + }); + + { + lock_guard lck{m}; + b = true; + } + + cv.notify_all(); + } + + // smoke test a timeout case: + { + jthread worker([] { + stop_source never_stopped; + mutex m; + condition_variable_any cv; + unique_lock lck{m}; + auto started_at = chrono::steady_clock::now(); + assert(cv.wait_for(lck, never_stopped.get_token(), 100ms, [] { return false; }) == false); + // not a timing assumption: the wait_for must wait at least that long + assert(started_at + 100ms <= chrono::steady_clock::now()); + }); + } + + puts("pass"); +} diff --git a/tests/std/tests/P0660R10_stop_token/env.lst b/tests/std/tests/P0660R10_stop_token/env.lst new file mode 100644 index 00000000000..642f530ffad --- /dev/null +++ b/tests/std/tests/P0660R10_stop_token/env.lst @@ -0,0 +1,4 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\usual_latest_matrix.lst diff --git a/tests/std/tests/P0660R10_stop_token/test.cpp b/tests/std/tests/P0660R10_stop_token/test.cpp new file mode 100644 index 00000000000..eaf5cdc24e0 --- /dev/null +++ b/tests/std/tests/P0660R10_stop_token/test.cpp @@ -0,0 +1,418 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace std; +using namespace std_testing; + +#ifdef __clang__ +#pragma clang diagnostic ignored "-Wself-move" +#endif // __clang__ + +struct throwing_construction_functor { + throwing_construction_functor(int x) { + throw x; + } + + void operator()() const { + assert(false); + } +}; + +struct call_counting_functor { + atomic* state; + + call_counting_functor(atomic* state_) : state(state_) {} + + call_counting_functor(const call_counting_functor&) = delete; + call_counting_functor& operator=(const call_counting_functor&) = delete; + + void operator()() && { + ++*state; + } +}; + +struct cb_destroying_functor { + optional>& owner; + cb_destroying_functor(optional>& owner_) : owner(owner_) {} + + cb_destroying_functor(const cb_destroying_functor&) = delete; + cb_destroying_functor& operator=(const cb_destroying_functor&) = delete; + + void operator()() && { + owner.reset(); + } +}; + +int main() noexcept { + reset_new_counters(0); + { // all the following must not allocate, and must work with a nostopstate source; in rough synopsis order + stop_token token; + stop_token token_copy{token}; + stop_token token_moved{move(token)}; + token_copy = token; + token_moved = move(token); + token.swap(token_copy); + assert(!token.stop_requested()); + assert(!token.stop_possible()); + assert(token == token_copy); + swap(token, token_copy); + + stop_source source{nostopstate}; + stop_source copied_source{source}; + stop_source moved_source{move(source)}; + copied_source = source; + moved_source = move(source); + copied_source.swap(source); + + assert(!source.get_token().stop_possible()); + assert(!source.get_token().stop_requested()); + assert(!source.stop_possible()); + assert(!source.stop_requested()); + assert(!source.request_stop()); + + assert(source == copied_source); + assert(source == moved_source); + + swap(source, copied_source); + + stop_callback cb{token, [] { assert(false); }}; + stop_callback cb_moved{move(token), [] { assert(false); }}; + } + + // normal reference counted things state management; in rough synopsis order + reset_new_counters(2); + { // stop_source + stop_source empty{nostopstate}; + + // default ctor + stop_source source_a; + assert(source_a.stop_possible()); + assert(!source_a.stop_requested()); + stop_source source_b; + assert(source_b.stop_possible()); + assert(!source_b.stop_requested()); + assert(source_a != empty); + assert(source_a != source_b); + + // copy ctor + stop_source copied_source{source_a}; + assert(copied_source == source_a); + source_a.swap(source_b); + assert(copied_source == source_b); + swap(source_a, source_b); + assert(copied_source == source_a); + + // move ctor + stop_source moved_source{move(source_a)}; + assert(!source_a.stop_possible()); + assert(empty == source_a); + assert(moved_source != source_a); + moved_source = move(moved_source); + swap(moved_source, source_a); + + // copy assignment + copied_source = source_b; + assert(copied_source == source_b); + + // move assignment + moved_source = move(source_a); + assert(!source_a.stop_possible()); + assert(moved_source.stop_possible()); + + // swap member + moved_source.swap(source_a); + assert(source_a.stop_possible()); + assert(!moved_source.stop_possible()); + + // get_token tested with tokens below + // stop_possible tested above + // stop_requested tested below + assert(!empty.request_stop()); + assert(source_a.request_stop()); + assert(source_a.stop_requested()); + assert(!source_a.request_stop()); + assert(source_a.stop_requested()); + + assert(!source_b.stop_requested()); + assert(!copied_source.stop_requested()); + assert(copied_source.request_stop()); + assert(source_b.stop_requested()); + assert(copied_source.stop_requested()); + assert(!source_b.request_stop()); + } + + reset_new_counters(2); + { // stop_token + stop_source source_a; + stop_token token_a = source_a.get_token(); + assert(token_a.stop_possible()); + assert(!token_a.stop_requested()); + + stop_source source_b; + stop_token token_b = source_b.get_token(); + assert(token_a != token_b); + + stop_token empty; + + // default ctor tested above in the no-alloc block + + // copy ctor + stop_token copied_token{token_a}; + assert(copied_token == token_a); + + // move ctor + stop_token moved_token{move(token_a)}; + assert(moved_token == copied_token); + assert(moved_token != token_a); + assert(!token_a.stop_possible()); + assert(!token_a.stop_requested()); + moved_token.swap(token_a); + + // copy assign + copied_token = token_b; + assert(copied_token == token_b); + + // move assign + moved_token = move(token_b); + assert(moved_token == copied_token); + moved_token = move(moved_token); + assert(moved_token == copied_token); + assert(moved_token != token_a); + assert(!token_b.stop_possible()); + assert(!token_b.stop_requested()); + swap(token_b, moved_token); + + // stop_possible tested above and 1 special case below + + // stop_requested + assert(!copied_token.stop_requested()); + assert(source_b.request_stop()); + assert(!token_a.stop_requested()); + assert(token_b.stop_requested()); + assert(copied_token.stop_requested()); + + // equals and swap tested above + } + + // the stop_possible special cases + reset_new_counters(1); + { // all sources are gone + stop_token token; + { + stop_source source; + token = source.get_token(); + assert(token.stop_possible()); + assert(!token.stop_requested()); + } // destroy source + + assert(!token.stop_possible()); + assert(!token.stop_requested()); + stop_callback cb{token, [] { assert(false); }}; + (void) cb; + } + + reset_new_counters(1); + { // all sources are gone but stop happened first + stop_token token; + { + stop_source source; + token = source.get_token(); + assert(token.stop_possible()); + assert(!token.stop_requested()); + assert(source.request_stop()); + assert(token.stop_possible()); + assert(token.stop_requested()); + } // destroy source + + assert(token.stop_possible()); + assert(token.stop_requested()); + } + + // empty assign special cases + reset_new_counters(1); + { + stop_source source; + stop_source empty{nostopstate}; + source = empty; // lvalue + assert(!source.stop_possible()); + } + + reset_new_counters(1); + { + stop_source source; + source = stop_source{nostopstate}; // rvalue + assert(!source.stop_possible()); + } + + reset_new_counters(1); + { + stop_source source; + auto token = source.get_token(); + stop_token empty; + token = empty; // lvalue + assert(!token.stop_possible()); + } + + reset_new_counters(1); + { + stop_source source; + auto token = source.get_token(); + token = stop_token{}; // rvalue + assert(!token.stop_possible()); + } + + // callback calling in the ctor + reset_new_counters(1); + { + atomic calls{0}; + stop_source source; + source.request_stop(); + assert(calls.load() == 0); + stop_callback cb{source.get_token(), &calls}; + (void) cb; + assert(calls.load() == 1); + } + + reset_new_counters(1); + { + atomic calls{0}; + stop_token token; + + { + stop_source source; + token = source.get_token(); + source.request_stop(); + } // destroy source + + assert(calls.load() == 0); + stop_callback cb{token, &calls}; + (void) cb; + assert(calls.load() == 1); + } + + // callback calling on cancel + reset_new_counters(1); + { + atomic calls{0}; + stop_source source; + assert(calls.load() == 0); + stop_callback cb{source.get_token(), &calls}; + assert(calls.load() == 0); + source.request_stop(); + assert(calls.load() == 1); + } + + // if the callback is executing on the current thread it does not block for the callback to finish executing + reset_new_counters(1); + { + stop_source source; + auto token = source.get_token(); + optional> cb; + cb.emplace(token, cb); + source.request_stop(); // if we don't do what the standard says, this will deadlock + } + + // if the callback is executing on another thread it blocks for the callback to finish executing + reset_new_counters(2); // nonstandard assumption that our std::thread allocates exactly once + { + static constexpr chrono::milliseconds callback_wait_length = 5s; + static constexpr chrono::milliseconds request_wait_length = 500ms; + stop_source source; + atomic block_request_stop{false}; + // block_destroy makes it more likely that the timing assumption above is correct because the timer doesn't + // start until we know the worker thread is actively running trying to request_stop + atomic block_destroy{false}; + thread worker{[&] { + // run the callbacks in the worker thread + block_request_stop.wait(false); + block_destroy.store(true); + block_destroy.notify_one(); + assert("request_wait_length TIMING ASSUMPTION" && source.request_stop()); + }}; + + + auto worker_id = worker.get_id(); + chrono::steady_clock::time_point started_at; + { + // timing assumption that the main thread will try to destroy cb within request_wait_length + stop_callback cb{source.get_token(), [&] { + this_thread::sleep_for(callback_wait_length); + assert("request_wait_length TIMING ASSUMPTION" && this_thread::get_id() == worker_id); + }}; + started_at = chrono::steady_clock::now(); + block_request_stop.store(true); + block_request_stop.notify_one(); + block_destroy.wait(false); // wait for the other thread to start stopping + // timing assumption that worker enters request_stop before we try to destroy cb here; + // if that assumption is wrong then we merely don't test the case in which we're interested (because cb will + // run on this thread so we won't have to block for destruction) + this_thread::sleep_for(request_wait_length); + assert("request_wait_length TIMING ASSUMPTION" && !source.request_stop()); + } // destroy cb + + worker.join(); + + // not a timing assumption: we must have waited at least as long as the sleep_for in the cancellation callback + // (that's the point of this test) + auto stopped_at = chrono::steady_clock::now(); + assert(started_at + callback_wait_length <= stopped_at); + } + + // more than one callback in the list and the first callback unregisters one of the others + // (this tests edge cases in the callback linked list management) + for (int idx = 0; idx < 5; ++idx) { + reset_new_counters(1); + stop_source source; + auto token = source.get_token(); + optional> cbs[5]; + cbs[0].emplace(token, cbs[idx]); + cbs[1].emplace(token, cbs[1]); + cbs[2].emplace(token, cbs[2]); + cbs[3].emplace(token, cbs[3]); + cbs[4].emplace(token, cbs[4]); + cbs[2].reset(); + source.request_stop(); + } + + // exception safety cases + reset_new_counters(0); + try { + stop_source source; + (void) source; + assert(false); + } catch (const bad_alloc&) { + // expected + } + + reset_new_counters(1); + try { + stop_source source; + stop_callback cb{source.get_token(), 42}; + } catch (int i) { + assert(i == 42); + } + + reset_new_counters(1); + try { + stop_source source; + auto token_lvalue = source.get_token(); + stop_callback cb{token_lvalue, 43}; + } catch (int i) { + assert(i == 43); + } + + reset_new_counters(0); + + puts("pass"); +} diff --git a/tests/std/tests/P0660R10_stop_token_death/env.lst b/tests/std/tests/P0660R10_stop_token_death/env.lst new file mode 100644 index 00000000000..e5b00aee0d4 --- /dev/null +++ b/tests/std/tests/P0660R10_stop_token_death/env.lst @@ -0,0 +1,4 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\usual_latest_winsdk_matrix.lst diff --git a/tests/std/tests/P0660R10_stop_token_death/test.cpp b/tests/std/tests/P0660R10_stop_token_death/test.cpp new file mode 100644 index 00000000000..e9075218b7a --- /dev/null +++ b/tests/std/tests/P0660R10_stop_token_death/test.cpp @@ -0,0 +1,48 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include + +#include + +using namespace std; + +struct throwing_functor { + void operator()() { + throw 42; + } +}; + +void test_case_throw_during_callback_ctor() { + stop_source source; + source.request_stop(); + stop_callback cb{source.get_token(), throwing_functor{}}; + (void) cb; +} + +void test_case_throw_during_callback_lvalue_ctor() { + stop_source source; + source.request_stop(); + auto lvalue_token = source.get_token(); + stop_callback cb{lvalue_token, throwing_functor{}}; + (void) cb; +} + +void test_case_throw_during_request_stop() { + stop_source source; + stop_callback cb{source.get_token(), throwing_functor{}}; + (void) cb; + source.request_stop(); +} + +int main(int argc, char* argv[]) { + std_testing::death_test_executive exec([] {}); + + exec.add_death_tests({ + test_case_throw_during_request_stop, + test_case_throw_during_callback_lvalue_ctor, + test_case_throw_during_request_stop, + }); + + return exec.run(argc, argv); +} diff --git a/tests/std/tests/P0784R7_library_support_for_more_constexpr_containers/test.cpp b/tests/std/tests/P0784R7_library_support_for_more_constexpr_containers/test.cpp index 733265ddd20..7cf1685a980 100644 --- a/tests/std/tests/P0784R7_library_support_for_more_constexpr_containers/test.cpp +++ b/tests/std/tests/P0784R7_library_support_for_more_constexpr_containers/test.cpp @@ -9,8 +9,50 @@ #include #include +#pragma warning(disable : 4582) // '%s': constructor is not implicitly called +#pragma warning(disable : 4583) // '%s': destructor is not implicitly called + using namespace std; +#ifdef __cpp_lib_concepts +template +concept can_std_construct_at = requires(Ty* ptr, Types&&... args) { + construct_at(ptr, forward(args)...); +}; + +template +concept can_ranges_construct_at = requires(Ty* ptr, Types&&... args) { + ranges::construct_at(ptr, forward(args)...); +}; + +template +concept can_ranges_destroy_at = requires(Ty* ptr) { + ranges::destroy_at(ptr); +}; + +template +inline constexpr bool can_construct_at = [] { + constexpr bool result = can_std_construct_at; + static_assert(can_ranges_construct_at == result); + return result; +}(); + +template +constexpr bool construct_at_noexcept() { + constexpr bool result = noexcept(construct_at(declval(), declval()...)); + static_assert(noexcept(ranges::construct_at(declval(), declval()...)) == result); + return result; +} + +template +constexpr bool destroy_at_noexcept() { + static_assert(noexcept(destroy_at(declval()))); + if constexpr (can_ranges_destroy_at) { + static_assert(noexcept(ranges::destroy_at(declval()))); + } + return true; +} +#else // ^^^ Concepts and Ranges / No Concepts or Ranges vvv template inline constexpr bool can_construct_at_impl = false; @@ -21,6 +63,17 @@ inline constexpr bool template inline constexpr bool can_construct_at = can_construct_at_impl; +template +constexpr bool construct_at_noexcept() { + return noexcept(construct_at(declval(), declval()...)); +} + +template +constexpr bool destroy_at_noexcept() { + return noexcept(destroy_at(declval())); +} +#endif // __cpp_lib_concepts + static_assert(can_construct_at); static_assert(can_construct_at); static_assert(can_construct_at); @@ -70,53 +123,157 @@ static_assert(!can_construct_at); // The following static_asserts test our strengthening of noexcept #ifndef __EDG__ // TRANSITION, VSO-1075296 -static_assert(noexcept(construct_at(declval(), 42))); -static_assert(noexcept(construct_at(declval(), 42))); -static_assert(noexcept(construct_at(declval(), 42))); -static_assert(noexcept(construct_at(declval(), 42))); +static_assert(construct_at_noexcept()); +static_assert(construct_at_noexcept()); +static_assert(construct_at_noexcept()); +static_assert(construct_at_noexcept()); #endif // __EDG__ -static_assert(!noexcept(construct_at(declval(), "hello"))); -static_assert(!noexcept(construct_at(declval(), "hello"))); -static_assert(!noexcept(construct_at(declval(), "hello"))); -static_assert(!noexcept(construct_at(declval(), "hello"))); +static_assert(!construct_at_noexcept()); +static_assert(!construct_at_noexcept()); +static_assert(!construct_at_noexcept()); +static_assert(!construct_at_noexcept()); + +static_assert(destroy_at_noexcept()); +static_assert(destroy_at_noexcept()); +static_assert(destroy_at_noexcept()); +static_assert(destroy_at_noexcept()); +static_assert(destroy_at_noexcept()); +static_assert(destroy_at_noexcept()); +static_assert(destroy_at_noexcept()); +static_assert(destroy_at_noexcept()); -static_assert(noexcept(destroy_at(declval()))); -static_assert(noexcept(destroy_at(declval()))); -static_assert(noexcept(destroy_at(declval()))); -static_assert(noexcept(destroy_at(declval()))); -static_assert(noexcept(destroy_at(declval()))); -static_assert(noexcept(destroy_at(declval()))); -static_assert(noexcept(destroy_at(declval()))); -static_assert(noexcept(destroy_at(declval()))); +#if _HAS_CXX20 +static_assert(destroy_at_noexcept()); +static_assert(destroy_at_noexcept()); +static_assert(destroy_at_noexcept()); +static_assert(destroy_at_noexcept()); +static_assert(destroy_at_noexcept()); +static_assert(destroy_at_noexcept()); +static_assert(destroy_at_noexcept()); +static_assert(destroy_at_noexcept()); +#endif // _HAS_CXX20 struct throwing_dtor { ~throwing_dtor() noexcept(false) {} }; -static_assert(noexcept(destroy_at(declval()))); +static_assert(destroy_at_noexcept()); +#if _HAS_CXX20 +static_assert(destroy_at_noexcept()); +#endif // _HAS_CXX20 + +#ifdef __cpp_lib_concepts +static_assert(!can_ranges_destroy_at); +static_assert(!can_ranges_destroy_at); +#endif // __cpp_lib_concepts template void test_runtime(const Ty& val) { alignas(Ty) unsigned char storage[sizeof(Ty)]; - memset(storage, 42, sizeof(Ty)); const auto asPtrTy = reinterpret_cast(&storage); + memset(storage, 42, sizeof(Ty)); assert(asPtrTy == construct_at(asPtrTy, val)); assert(*asPtrTy == val); destroy_at(asPtrTy); +#ifdef __cpp_lib_concepts // test ranges: + memset(storage, 42, sizeof(Ty)); assert(asPtrTy == ranges::construct_at(asPtrTy, val)); assert(*asPtrTy == val); - destroy_at(asPtrTy); + ranges::destroy_at(asPtrTy); +#endif // __cpp_lib_concepts // test voidify: const auto asCv = static_cast(asPtrTy); + memset(storage, 42, sizeof(Ty)); assert(asPtrTy == construct_at(asCv, val)); assert(const_cast(*asCv) == val); destroy_at(asCv); + +#ifdef __cpp_lib_concepts + memset(storage, 42, sizeof(Ty)); + assert(asPtrTy == ranges::construct_at(asCv, val)); + assert(const_cast(*asCv) == val); + ranges::destroy_at(asCv); +#endif // __cpp_lib_concepts } +template +void test_array(const T& val) { + constexpr int N = 42; + (void) val; + +#if _HAS_CXX20 + alignas(T) unsigned char storage[sizeof(T) * N]; + using U = conditional_t, const volatile T, T>; + const auto ptr = reinterpret_cast(storage); + + for (auto i = 0; i < N; ++i) { + construct_at(ptr + i, val); + } + + destroy_at(reinterpret_cast(ptr)); + +#ifdef __cpp_lib_concepts + for (auto i = 0; i < N; ++i) { + ranges::construct_at(ptr + i, val); + } + +#if defined(__clang__) || defined(__EDG__) // TRANSITION, VSO-1049320 + ranges::destroy_at(reinterpret_cast(ptr)); +#else // ^^^ no workaround / workaround vvv + ranges::destroy_at(reinterpret_cast(const_cast(ptr))); +#endif // TRANSITION, VSO-1049320 +#endif // __cpp_lib_concepts +#endif // _HAS_CXX20 +} + +#if _HAS_CXX20 && defined(__cpp_constexpr_dynamic_alloc) +template +struct storage_for { + union { + T object; + }; + + constexpr storage_for() noexcept {} + constexpr ~storage_for() {} +}; + +constexpr void test_compiletime() { + { + storage_for s; + construct_at(&s.object, 42); + assert(s.object == 42); + destroy_at(&s.object); + + ranges::construct_at(&s.object, 1729); + assert(s.object == 1729); + ranges::destroy_at(&s.object); + } + + struct nontrivial { + constexpr nontrivial(int i = 42) noexcept : x{i} {} + constexpr ~nontrivial() {} + + int x = 42; + }; + + { + storage_for s; + construct_at(&s.object, 42); + assert(s.object.x == 42); + destroy_at(&s.object); + + ranges::construct_at(&s.object, 1729); + assert(s.object.x == 1729); + ranges::destroy_at(&s.object); + } +} +static_assert((test_compiletime(), true)); +#endif // _HAS_CXX20 && defined(__cpp_constexpr_dynamic_alloc) + int main() { test_runtime(1234); test_runtime(string("hello world")); @@ -127,5 +284,14 @@ int main() { const auto ptr = reinterpret_cast(storage); construct_at(ptr); ptr->destroy(); + +#ifdef __cpp_lib_concepts + ranges::construct_at(ptr); + ptr->destroy(); +#endif // __cpp_lib_concepts } + + test_array(1234); + test_array(string("hello world")); + test_array(string("hello to some really long world that certainly doesn't fit in SSO")); } diff --git a/tests/std/tests/P0896R4_P1614R2_comparisons/test.cpp b/tests/std/tests/P0896R4_P1614R2_comparisons/test.cpp index d590d917b7a..4f100192065 100644 --- a/tests/std/tests/P0896R4_P1614R2_comparisons/test.cpp +++ b/tests/std/tests/P0896R4_P1614R2_comparisons/test.cpp @@ -260,9 +260,7 @@ STATIC_ASSERT(test_compare_three_way()); STATIC_ASSERT(test_compare_three_way()); STATIC_ASSERT(test_compare_three_way()); STATIC_ASSERT(test_compare_three_way()); -#if defined(__clang__) || defined(__EDG__) // TRANSITION, DevCom-1044530 STATIC_ASSERT(test_compare_three_way()); -#endif // TRANSITION, DevCom-1044530 STATIC_ASSERT(test_compare_three_way()); STATIC_ASSERT(test_compare_three_way()); @@ -419,9 +417,7 @@ constexpr void ordering_test_cases() { test_strongly_ordered(13U, u8'x'); #endif // __cpp_char8_t test_strongly_ordered(13U, u'x'); -#if defined(__clang__) || defined(__EDG__) // TRANSITION, VSO-1062618 test_strongly_ordered(13U, U'x'); -#endif // TRANSITION, VSO-1062618 test_strongly_ordered(scoped{13}, scoped{42}); test_strongly_ordered(unscoped{13}, unscoped{42}); diff --git a/tests/std/tests/P0896R4_ranges_alg_heap/test.cpp b/tests/std/tests/P0896R4_ranges_alg_heap/test.cpp index d938ff02434..ac24c5645f2 100644 --- a/tests/std/tests/P0896R4_ranges_alg_heap/test.cpp +++ b/tests/std/tests/P0896R4_ranges_alg_heap/test.cpp @@ -108,16 +108,11 @@ struct make_and_sort_heap_test { ASSERT(!is_heap(wrapped, less{}, get_first)); -#if !defined(__clang__) && !defined(__EDG__) // TRANSITION, VSO-938163 - if constexpr (!ranges::contiguous_range) -#endif // TRANSITION, VSO-938163 - { - make_heap(wrapped, less{}, get_first); - ASSERT(is_heap(wrapped, less{}, get_first)); - - sort_heap(wrapped, less{}, get_first); - ASSERT(is_sorted(wrapped, less{}, get_first)); - } + make_heap(wrapped, less{}, get_first); + ASSERT(is_heap(wrapped, less{}, get_first)); + + sort_heap(wrapped, less{}, get_first); + ASSERT(is_sorted(wrapped, less{}, get_first)); } { @@ -126,16 +121,11 @@ struct make_and_sort_heap_test { ASSERT(!is_heap(wrapped.begin(), wrapped.end(), less{}, get_first)); -#if !defined(__clang__) && !defined(__EDG__) // TRANSITION, VSO-938163 - if constexpr (!ranges::contiguous_range) -#endif // TRANSITION, VSO-938163 - { - make_heap(wrapped.begin(), wrapped.end(), less{}, get_first); - ASSERT(is_heap(wrapped.begin(), wrapped.end(), less{}, get_first)); + make_heap(wrapped.begin(), wrapped.end(), less{}, get_first); + ASSERT(is_heap(wrapped.begin(), wrapped.end(), less{}, get_first)); - sort_heap(wrapped.begin(), wrapped.end(), less{}, get_first); - ASSERT(is_sorted(wrapped.begin(), wrapped.end(), less{}, get_first)); - } + sort_heap(wrapped.begin(), wrapped.end(), less{}, get_first); + ASSERT(is_sorted(wrapped.begin(), wrapped.end(), less{}, get_first)); } } }; @@ -192,34 +182,24 @@ struct push_and_pop_heap_test { auto buff = initial_values; const Range wrapped{buff}; -#if !defined(__clang__) && !defined(__EDG__) // TRANSITION, VSO-938163 - if constexpr (!ranges::contiguous_range) -#endif // TRANSITION, VSO-938163 - { - pop_heap(wrapped, less{}, get_first); - ASSERT(equal(wrapped, expectedPopped)); + pop_heap(wrapped, less{}, get_first); + ASSERT(equal(wrapped, expectedPopped)); - push_heap(wrapped, less{}, get_first); - ASSERT(equal(wrapped, expectedPushed)); - } + push_heap(wrapped, less{}, get_first); + ASSERT(equal(wrapped, expectedPushed)); } { auto buff = initial_values; const Range wrapped{buff}; -#if !defined(__clang__) && !defined(__EDG__) // TRANSITION, VSO-938163 - if constexpr (!ranges::contiguous_range) -#endif // TRANSITION, VSO-938163 - { - pop_heap(wrapped.begin(), wrapped.end(), less{}, get_first); - ASSERT(is_heap(expectedPopped.begin(), expectedPopped.end() - 1, less{}, get_first)); - ASSERT(equal(wrapped.begin(), wrapped.end(), expectedPopped.begin(), expectedPopped.end())); - - push_heap(wrapped.begin(), wrapped.end(), less{}, get_first); - ASSERT(is_heap(expectedPushed, less{}, get_first)); - ASSERT(equal(wrapped.begin(), wrapped.end(), expectedPushed.begin(), expectedPushed.end())); - } + pop_heap(wrapped.begin(), wrapped.end(), less{}, get_first); + ASSERT(is_heap(expectedPopped.begin(), expectedPopped.end() - 1, less{}, get_first)); + ASSERT(equal(wrapped.begin(), wrapped.end(), expectedPopped.begin(), expectedPopped.end())); + + push_heap(wrapped.begin(), wrapped.end(), less{}, get_first); + ASSERT(is_heap(expectedPushed, less{}, get_first)); + ASSERT(equal(wrapped.begin(), wrapped.end(), expectedPushed.begin(), expectedPushed.end())); } } }; diff --git a/tests/std/tests/P0896R4_ranges_alg_move/test.cpp b/tests/std/tests/P0896R4_ranges_alg_move/test.cpp index dbd4e70a55f..9bf09c04d34 100644 --- a/tests/std/tests/P0896R4_ranges_alg_move/test.cpp +++ b/tests/std/tests/P0896R4_ranges_alg_move/test.cpp @@ -37,36 +37,30 @@ struct instantiator { template > Write> static constexpr void call() { -#if !defined(__clang__) && !defined(__EDG__) // TRANSITION, VSO-938163 -#pragma warning(suppress : 4127) // conditional expression is constant - if (!ranges::contiguous_range || !is_constant_evaluated()) -#endif // TRANSITION, VSO-938163 + using ranges::move, ranges::move_result, ranges::equal, ranges::iterator_t; { - using ranges::move, ranges::move_result, ranges::equal, ranges::iterator_t; - { - int_wrapper input[3] = {13, 55, 12345}; - int_wrapper output[3] = {-2, -2, -2}; - Read wrapped_input{input}; + int_wrapper input[3] = {13, 55, 12345}; + int_wrapper output[3] = {-2, -2, -2}; + Read wrapped_input{input}; - auto result = move(wrapped_input, Write{output}); - STATIC_ASSERT(same_as, Write>>); - assert(result.in == wrapped_input.end()); - assert(result.out.peek() == output + 3); - assert(equal(output, expected_output)); - assert(equal(input, expected_input)); - } - { - int_wrapper input[3] = {13, 55, 12345}; - int_wrapper output[3] = {-2, -2, -2}; - Read wrapped_input{input}; + auto result = move(wrapped_input, Write{output}); + STATIC_ASSERT(same_as, Write>>); + assert(result.in == wrapped_input.end()); + assert(result.out.peek() == output + 3); + assert(equal(output, expected_output)); + assert(equal(input, expected_input)); + } + { + int_wrapper input[3] = {13, 55, 12345}; + int_wrapper output[3] = {-2, -2, -2}; + Read wrapped_input{input}; - auto result = move(wrapped_input.begin(), wrapped_input.end(), Write{output}); - STATIC_ASSERT(same_as, Write>>); - assert(result.in == wrapped_input.end()); - assert(result.out.peek() == output + 3); - assert(equal(output, expected_output)); - assert(equal(input, expected_input)); - } + auto result = move(wrapped_input.begin(), wrapped_input.end(), Write{output}); + STATIC_ASSERT(same_as, Write>>); + assert(result.in == wrapped_input.end()); + assert(result.out.peek() == output + 3); + assert(equal(output, expected_output)); + assert(equal(input, expected_input)); } } }; diff --git a/tests/std/tests/P0896R4_ranges_alg_move_backward/test.cpp b/tests/std/tests/P0896R4_ranges_alg_move_backward/test.cpp index 06c17f7953f..30ccd3d19e4 100644 --- a/tests/std/tests/P0896R4_ranges_alg_move_backward/test.cpp +++ b/tests/std/tests/P0896R4_ranges_alg_move_backward/test.cpp @@ -42,50 +42,44 @@ struct instantiator { template static constexpr void call() { -#if !defined(__clang__) && !defined(__EDG__) // TRANSITION, VSO-938163 -#pragma warning(suppress : 4127) // conditional expression is constant - if (!ranges::contiguous_range || !is_constant_evaluated()) -#endif // TRANSITION, VSO-938163 - { - // For the second range, we need an iterator to the end; it's expedient to simply ignore ranges with - // differing iterator and sentinel types (i.e., ranges that don't satisfy common_range). - if constexpr (ranges::common_range) { - using ranges::move_backward, ranges::move_backward_result, ranges::equal, ranges::iterator_t; - - { // Validate range overload - int_wrapper input[] = {13, 42, 1729}; - int_wrapper output[] = {-2, -2, -2}; - R1 wrapped_input{input}; - R2 wrapped_output{output}; - same_as, iterator_t>> auto result = - move_backward(wrapped_input, wrapped_output.end()); - assert(result.in == wrapped_input.end()); - assert(result.out == wrapped_output.begin()); - assert(equal(output, expected_output, ranges::equal_to{}, &int_wrapper::val)); - assert(equal(input, expected_input, ranges::equal_to{}, &int_wrapper::val)); - } - { // Validate iterator + sentinel overload - int_wrapper input[] = {13, 42, 1729}; - int_wrapper output[] = {-2, -2, -2}; - R1 wrapped_input{input}; - R2 wrapped_output{output}; - same_as, iterator_t>> auto result = - move_backward(wrapped_input.begin(), wrapped_input.end(), wrapped_output.end()); - assert(result.in == wrapped_input.end()); - assert(result.out == wrapped_output.begin()); - assert(equal(output, expected_output, ranges::equal_to{}, &int_wrapper::val)); - assert(equal(input, expected_input, ranges::equal_to{}, &int_wrapper::val)); - } - { // Validate overlapping ranges - int_wrapper io[] = {0, 1, 2, 42}; - R1 wrapped_input{span{io}.first<3>()}; - R2 wrapped_output{span{io}.last<3>()}; - same_as, iterator_t>> auto result = - move_backward(wrapped_input, wrapped_output.end()); - assert(result.in == wrapped_input.end()); - assert(result.out == wrapped_output.begin()); - assert(equal(io, expected_overlapping, ranges::equal_to{}, &int_wrapper::val)); - } + // For the second range, we need an iterator to the end; it's expedient to simply ignore ranges with + // differing iterator and sentinel types (i.e., ranges that don't satisfy common_range). + if constexpr (ranges::common_range) { + using ranges::move_backward, ranges::move_backward_result, ranges::equal, ranges::iterator_t; + + { // Validate range overload + int_wrapper input[] = {13, 42, 1729}; + int_wrapper output[] = {-2, -2, -2}; + R1 wrapped_input{input}; + R2 wrapped_output{output}; + same_as, iterator_t>> auto result = + move_backward(wrapped_input, wrapped_output.end()); + assert(result.in == wrapped_input.end()); + assert(result.out == wrapped_output.begin()); + assert(equal(output, expected_output, ranges::equal_to{}, &int_wrapper::val)); + assert(equal(input, expected_input, ranges::equal_to{}, &int_wrapper::val)); + } + { // Validate iterator + sentinel overload + int_wrapper input[] = {13, 42, 1729}; + int_wrapper output[] = {-2, -2, -2}; + R1 wrapped_input{input}; + R2 wrapped_output{output}; + same_as, iterator_t>> auto result = + move_backward(wrapped_input.begin(), wrapped_input.end(), wrapped_output.end()); + assert(result.in == wrapped_input.end()); + assert(result.out == wrapped_output.begin()); + assert(equal(output, expected_output, ranges::equal_to{}, &int_wrapper::val)); + assert(equal(input, expected_input, ranges::equal_to{}, &int_wrapper::val)); + } + { // Validate overlapping ranges + int_wrapper io[] = {0, 1, 2, 42}; + R1 wrapped_input{span{io}.first<3>()}; + R2 wrapped_output{span{io}.last<3>()}; + same_as, iterator_t>> auto result = + move_backward(wrapped_input, wrapped_output.end()); + assert(result.in == wrapped_input.end()); + assert(result.out == wrapped_output.begin()); + assert(equal(io, expected_overlapping, ranges::equal_to{}, &int_wrapper::val)); } } } diff --git a/tests/std/tests/P0896R4_ranges_alg_nth_element/test.cpp b/tests/std/tests/P0896R4_ranges_alg_nth_element/test.cpp index 36b3f936650..8d34d35fc8f 100644 --- a/tests/std/tests/P0896R4_ranges_alg_nth_element/test.cpp +++ b/tests/std/tests/P0896R4_ranges_alg_nth_element/test.cpp @@ -22,57 +22,51 @@ struct instantiator { template static constexpr void call() { -#if !defined(__clang__) && !defined(__EDG__) // TRANSITION, VSO-938163 -#pragma warning(suppress : 4127) // conditional expression is constant - if (!ranges::contiguous_range || !is_constant_evaluated()) -#endif // TRANSITION, VSO-938163 - { - using ranges::nth_element, ranges::all_of, ranges::find, ranges::iterator_t, ranges::less, ranges::none_of, - ranges::size; - - P input[size(keys)]; - const auto init = [&] { - for (size_t j = 0; j < size(keys); ++j) { - input[j] = P{keys[j], static_cast(10 + j)}; - } - }; + using ranges::nth_element, ranges::all_of, ranges::find, ranges::iterator_t, ranges::less, ranges::none_of, + ranges::size; - // Validate range overload - for (int i = 0; i < int{size(keys)}; ++i) { - init(); - const R wrapped{input}; - const auto nth = wrapped.begin() + i; - const same_as> auto result = nth_element(wrapped, nth, less{}, get_first); - assert(result == wrapped.end()); - assert((*nth == P{i, static_cast(10 + (find(keys, i) - keys))})); - if (nth != wrapped.end()) { - assert(all_of(wrapped.begin(), nth, [&](auto&& x) { return get_first(x) <= get_first(*nth); })); - assert(all_of(nth, wrapped.end(), [&](auto&& x) { return get_first(*nth) <= get_first(x); })); - } + P input[size(keys)]; + const auto init = [&] { + for (size_t j = 0; j < size(keys); ++j) { + input[j] = P{keys[j], static_cast(10 + j)}; } + }; - // Validate iterator overload - for (int i = 0; i < int{size(keys)}; ++i) { - init(); - const R wrapped{input}; - const auto nth = wrapped.begin() + i; - const same_as> auto result = - nth_element(wrapped.begin(), nth, wrapped.end(), less{}, get_first); - assert(result == wrapped.end()); - assert((input[i] == P{i, static_cast(10 + (find(keys, i) - keys))})); - if (nth != wrapped.end()) { - assert(all_of(wrapped.begin(), nth, [&](auto&& x) { return get_first(x) <= get_first(*nth); })); - assert(all_of(nth, wrapped.end(), [&](auto&& x) { return get_first(*nth) <= get_first(x); })); - } + // Validate range overload + for (int i = 0; i < int{size(keys)}; ++i) { + init(); + const R wrapped{input}; + const auto nth = wrapped.begin() + i; + const same_as> auto result = nth_element(wrapped, nth, less{}, get_first); + assert(result == wrapped.end()); + assert((*nth == P{i, static_cast(10 + (find(keys, i) - keys))})); + if (nth != wrapped.end()) { + assert(all_of(wrapped.begin(), nth, [&](auto&& x) { return get_first(x) <= get_first(*nth); })); + assert(all_of(nth, wrapped.end(), [&](auto&& x) { return get_first(*nth) <= get_first(x); })); } + } - { - // Validate empty range - const R range{}; - const same_as> auto result = nth_element(range, range.begin(), less{}, get_first); - assert(result == range.end()); + // Validate iterator overload + for (int i = 0; i < int{size(keys)}; ++i) { + init(); + const R wrapped{input}; + const auto nth = wrapped.begin() + i; + const same_as> auto result = + nth_element(wrapped.begin(), nth, wrapped.end(), less{}, get_first); + assert(result == wrapped.end()); + assert((input[i] == P{i, static_cast(10 + (find(keys, i) - keys))})); + if (nth != wrapped.end()) { + assert(all_of(wrapped.begin(), nth, [&](auto&& x) { return get_first(x) <= get_first(*nth); })); + assert(all_of(nth, wrapped.end(), [&](auto&& x) { return get_first(*nth) <= get_first(x); })); } } + + { + // Validate empty range + const R range{}; + const same_as> auto result = nth_element(range, range.begin(), less{}, get_first); + assert(result == range.end()); + } } }; diff --git a/tests/std/tests/P0896R4_ranges_alg_partial_sort/test.cpp b/tests/std/tests/P0896R4_ranges_alg_partial_sort/test.cpp index 3023ee38e28..cd414cad286 100644 --- a/tests/std/tests/P0896R4_ranges_alg_partial_sort/test.cpp +++ b/tests/std/tests/P0896R4_ranges_alg_partial_sort/test.cpp @@ -21,34 +21,28 @@ struct instantiator { template static constexpr void call() { -#if !defined(__clang__) && !defined(__EDG__) // TRANSITION, VSO-938163 -#pragma warning(suppress : 4127) // conditional expression is constant - if (!ranges::contiguous_range || !is_constant_evaluated()) -#endif // TRANSITION, VSO-938163 - { - using ranges::partial_sort, ranges::equal, ranges::iterator_t, ranges::less, ranges::next, ranges::size; - - { // Validate range overload - for (size_t i = 0; i <= size(sorted); ++i) { - P elements[] = {{7, 10}, {5, 11}, {1, 12}, {3, 13}, {6, 14}, {4, 15}, {0, 16}, {2, 17}}; - const R range{elements}; - const auto middle = next(range.begin(), static_cast(i)); - const same_as> auto result = partial_sort(range, middle, less{}, get_first); - assert(result == range.end()); - assert(equal(range.begin(), middle, sorted + 0, sorted + i)); - } + using ranges::partial_sort, ranges::equal, ranges::iterator_t, ranges::less, ranges::next, ranges::size; + + { // Validate range overload + for (size_t i = 0; i <= size(sorted); ++i) { + P elements[] = {{7, 10}, {5, 11}, {1, 12}, {3, 13}, {6, 14}, {4, 15}, {0, 16}, {2, 17}}; + const R range{elements}; + const auto middle = next(range.begin(), static_cast(i)); + const same_as> auto result = partial_sort(range, middle, less{}, get_first); + assert(result == range.end()); + assert(equal(range.begin(), middle, sorted + 0, sorted + i)); } + } - { // Validate iterator overload - for (size_t i = 0; i <= size(sorted); ++i) { - P elements[] = {{7, 10}, {5, 11}, {1, 12}, {3, 13}, {6, 14}, {4, 15}, {0, 16}, {2, 17}}; - const R range{elements}; - const auto middle = next(range.begin(), static_cast(i)); - const same_as> auto result = - partial_sort(range.begin(), middle, range.end(), less{}, get_first); - assert(result == range.end()); - assert(equal(range.begin(), middle, sorted + 0, sorted + i)); - } + { // Validate iterator overload + for (size_t i = 0; i <= size(sorted); ++i) { + P elements[] = {{7, 10}, {5, 11}, {1, 12}, {3, 13}, {6, 14}, {4, 15}, {0, 16}, {2, 17}}; + const R range{elements}; + const auto middle = next(range.begin(), static_cast(i)); + const same_as> auto result = + partial_sort(range.begin(), middle, range.end(), less{}, get_first); + assert(result == range.end()); + assert(equal(range.begin(), middle, sorted + 0, sorted + i)); } } } diff --git a/tests/std/tests/P0896R4_ranges_alg_partial_sort_copy/test.cpp b/tests/std/tests/P0896R4_ranges_alg_partial_sort_copy/test.cpp index c757fa93519..e7ba82b960a 100644 --- a/tests/std/tests/P0896R4_ranges_alg_partial_sort_copy/test.cpp +++ b/tests/std/tests/P0896R4_ranges_alg_partial_sort_copy/test.cpp @@ -33,37 +33,31 @@ constexpr P expected[] = {{0, 16}, {1, 12}, {2, 17}, {3, 13}, {4, 15}, {5, 11}}; struct instantiator1 { template static constexpr void call() { -#if !defined(__clang__) && !defined(__EDG__) // TRANSITION, VSO-938163 -#pragma warning(suppress : 4127) // conditional expression is constant - if ((!ranges::contiguous_range && !ranges::contiguous_range) || !is_constant_evaluated()) -#endif // TRANSITION, VSO-938163 - { - using ranges::partial_sort_copy, ranges::partial_sort_copy_result, ranges::equal, ranges::iterator_t, - ranges::less, ranges::min, ranges::next, ranges::size; - - P output[2 * size(source)]; - constexpr int sizes[] = {0, int{size(source) / 2}, int{size(source)}, int{2 * size(source)}}; - - { // Validate range overload - for (const int& i : sizes) { - In range1{source}; - Out range2{span{output}.first(static_cast(i))}; - const same_as, iterator_t>> auto result = - partial_sort_copy(range1, range2, less{}, get_first, get_first); - assert(result.in == range1.end()); - const auto n = min(i, int{size(source)}); - assert(result.out == range2.begin() + n); - assert(equal(range2.begin(), range2.begin() + n, expected, expected + n)); - } - - // also with empty input - In range1{}; - Out range2{output}; + using ranges::partial_sort_copy, ranges::partial_sort_copy_result, ranges::equal, ranges::iterator_t, + ranges::less, ranges::min, ranges::next, ranges::size; + + P output[2 * size(source)]; + constexpr int sizes[] = {0, int{size(source) / 2}, int{size(source)}, int{2 * size(source)}}; + + { // Validate range overload + for (const int& i : sizes) { + In range1{source}; + Out range2{span{output}.first(static_cast(i))}; const same_as, iterator_t>> auto result = partial_sort_copy(range1, range2, less{}, get_first, get_first); assert(result.in == range1.end()); - assert(result.out == range2.begin()); + const auto n = min(i, int{size(source)}); + assert(result.out == range2.begin() + n); + assert(equal(range2.begin(), range2.begin() + n, expected, expected + n)); } + + // also with empty input + In range1{}; + Out range2{output}; + const same_as, iterator_t>> auto result = + partial_sort_copy(range1, range2, less{}, get_first, get_first); + assert(result.in == range1.end()); + assert(result.out == range2.begin()); } } }; @@ -71,39 +65,32 @@ struct instantiator1 { struct instantiator2 { template static constexpr void call() { -#if !defined(__clang__) && !defined(__EDG__) // TRANSITION, VSO-938163 -#pragma warning(suppress : 4127) // conditional expression is constant - if ((!ranges::contiguous_range && !ranges::contiguous_range) || !is_constant_evaluated()) -#endif // TRANSITION, VSO-938163 - { - using ranges::partial_sort_copy, ranges::partial_sort_copy_result, ranges::equal, ranges::iterator_t, - ranges::less, ranges::min, ranges::next, ranges::size; - - P output[2 * size(source)]; - constexpr int sizes[] = {0, int{size(source) / 2}, int{size(source)}, int{2 * size(source)}}; - - { // Validate iterator overload - for (const int& i : sizes) { - In range1{source}; - Out range2{span{output}.first(static_cast(i))}; - const same_as, iterator_t>> auto result = - partial_sort_copy( - range1.begin(), range1.end(), range2.begin(), range2.end(), less{}, get_first, get_first); - assert(result.in == range1.end()); - const auto n = min(i, int{size(source)}); - assert(result.out == range2.begin() + n); - assert(equal(range2.begin(), range2.begin() + n, expected, expected + n)); - } - - // also with empty input - In range1{}; - Out range2{output}; + using ranges::partial_sort_copy, ranges::partial_sort_copy_result, ranges::equal, ranges::iterator_t, + ranges::less, ranges::min, ranges::next, ranges::size; + + P output[2 * size(source)]; + constexpr int sizes[] = {0, int{size(source) / 2}, int{size(source)}, int{2 * size(source)}}; + + { // Validate iterator overload + for (const int& i : sizes) { + In range1{source}; + Out range2{span{output}.first(static_cast(i))}; const same_as, iterator_t>> auto result = partial_sort_copy( range1.begin(), range1.end(), range2.begin(), range2.end(), less{}, get_first, get_first); assert(result.in == range1.end()); - assert(result.out == range2.begin()); + const auto n = min(i, int{size(source)}); + assert(result.out == range2.begin() + n); + assert(equal(range2.begin(), range2.begin() + n, expected, expected + n)); } + + // also with empty input + In range1{}; + Out range2{output}; + const same_as, iterator_t>> auto result = partial_sort_copy( + range1.begin(), range1.end(), range2.begin(), range2.end(), less{}, get_first, get_first); + assert(result.in == range1.end()); + assert(result.out == range2.begin()); } } }; diff --git a/tests/std/tests/P0896R4_ranges_alg_partition/test.cpp b/tests/std/tests/P0896R4_ranges_alg_partition/test.cpp index c7807e78c3d..01bff413f27 100644 --- a/tests/std/tests/P0896R4_ranges_alg_partition/test.cpp +++ b/tests/std/tests/P0896R4_ranges_alg_partition/test.cpp @@ -76,42 +76,35 @@ struct partition_test { } } -#if !defined(__clang__) && !defined(__EDG__) // TRANSITION, VSO-938163 - if (!is_constant_evaluated()) -#endif // TRANSITION, VSO-938163 - { - if constexpr (ranges::forward_range) { - { // Validate range overloads of partition, is_partitioned, partition_point - auto pairs = elements; - const Range range{pairs}; - const auto mid = ranges::next(range.begin(), 4); - - { - auto result = partition(range, is_even, get_first); - ASSERT(result.begin() == mid); - ASSERT(result.end() == range.end()); - } - ASSERT( - is_permutation(subrange{range.begin(), mid}, array{0, 2, 4, 6}, ranges::equal_to{}, get_first)); - ASSERT(is_partitioned(range, is_even, get_first)); - ASSERT(partition_point(range, is_even, get_first) == mid); + if constexpr (ranges::forward_range) { + { // Validate range overloads of partition, is_partitioned, partition_point + auto pairs = elements; + const Range range{pairs}; + const auto mid = ranges::next(range.begin(), 4); + + { + auto result = partition(range, is_even, get_first); + ASSERT(result.begin() == mid); + ASSERT(result.end() == range.end()); } + ASSERT(is_permutation(subrange{range.begin(), mid}, array{0, 2, 4, 6}, ranges::equal_to{}, get_first)); + ASSERT(is_partitioned(range, is_even, get_first)); + ASSERT(partition_point(range, is_even, get_first) == mid); + } + + { // Validate iterator overloads of partition, is_partitioned, partition_point + auto pairs = elements; + const Range range{pairs}; + const auto mid = ranges::next(range.begin(), 4); - { // Validate iterator overloads of partition, is_partitioned, partition_point - auto pairs = elements; - const Range range{pairs}; - const auto mid = ranges::next(range.begin(), 4); - - { - auto result = partition(range.begin(), range.end(), is_even, get_first); - ASSERT(result.begin() == mid); - ASSERT(result.end() == range.end()); - } - ASSERT( - is_permutation(subrange{range.begin(), mid}, array{0, 2, 4, 6}, ranges::equal_to{}, get_first)); - ASSERT(is_partitioned(range.begin(), range.end(), is_even, get_first)); - ASSERT(partition_point(range.begin(), range.end(), is_even, get_first) == mid); + { + auto result = partition(range.begin(), range.end(), is_even, get_first); + ASSERT(result.begin() == mid); + ASSERT(result.end() == range.end()); } + ASSERT(is_permutation(subrange{range.begin(), mid}, array{0, 2, 4, 6}, ranges::equal_to{}, get_first)); + ASSERT(is_partitioned(range.begin(), range.end(), is_even, get_first)); + ASSERT(partition_point(range.begin(), range.end(), is_even, get_first) == mid); } } } diff --git a/tests/std/tests/P0896R4_ranges_alg_permutations/test.cpp b/tests/std/tests/P0896R4_ranges_alg_permutations/test.cpp index 6b8cd0037e5..c169e8212fa 100644 --- a/tests/std/tests/P0896R4_ranges_alg_permutations/test.cpp +++ b/tests/std/tests/P0896R4_ranges_alg_permutations/test.cpp @@ -236,26 +236,21 @@ struct empty_range_test { }; int main() { -#if defined(__clang__) || defined(__EDG__) // TRANSITION, VSO-938163 STATIC_ASSERT((test_bidi(), true)); + test_bidi(); STATIC_ASSERT((test_bidi, int_wrapper>(), true)); STATIC_ASSERT((test_bidi, int_wrapper>(), true)); STATIC_ASSERT((test_bidi, int_wrapper>(), true)); - - STATIC_ASSERT((test_bidi, int_wrapper>(), true)); - STATIC_ASSERT((test_bidi, int_wrapper>(), true)); - STATIC_ASSERT((test_bidi, int_wrapper>(), true)); -#endif // TRANSITION, VSO-938163 - - test_bidi(); - test_bidi, int_wrapper>(); test_bidi, int_wrapper>(); test_bidi, int_wrapper>(); test_bidi, int_wrapper>(); test_bidi, int_wrapper>(); + STATIC_ASSERT((test_bidi, int_wrapper>(), true)); + STATIC_ASSERT((test_bidi, int_wrapper>(), true)); + STATIC_ASSERT((test_bidi, int_wrapper>(), true)); test_bidi, int_wrapper>(); test_bidi, int_wrapper>(); test_bidi, int_wrapper>(); diff --git a/tests/std/tests/P0896R4_ranges_alg_remove/test.cpp b/tests/std/tests/P0896R4_ranges_alg_remove/test.cpp index 3ddb3c33703..769c64d6ab4 100644 --- a/tests/std/tests/P0896R4_ranges_alg_remove/test.cpp +++ b/tests/std/tests/P0896R4_ranges_alg_remove/test.cpp @@ -21,44 +21,38 @@ struct instantiator { template static constexpr void call() { -#if !defined(__clang__) && !defined(__EDG__) // TRANSITION, VSO-938163 -#pragma warning(suppress : 4127) // conditional expression is constant - if (!ranges::contiguous_range || !is_constant_evaluated()) -#endif // TRANSITION, VSO-938163 - { - using ranges::remove, ranges::subrange, ranges::equal, ranges::iterator_t; - - size_t projectionCounter = 0; - auto projection = [&projectionCounter](const P& val) { - ++projectionCounter; - return val.second; - }; - - { // Validate iterator + sentinel overload - P input[5] = {{0, 99}, {1, 47}, {2, 99}, {3, 47}, {4, 99}}; - Read wrapped_input{input}; - - auto result = remove(wrapped_input.begin(), wrapped_input.end(), 47, projection); - STATIC_ASSERT(same_as>>); - assert(result.begin() == next(wrapped_input.begin(), 3)); - assert(result.end() == wrapped_input.end()); - assert(equal(expected, span{input}.first<3>())); - assert(projectionCounter == ranges::size(input)); - } + using ranges::remove, ranges::subrange, ranges::equal, ranges::iterator_t; + + size_t projectionCounter = 0; + auto projection = [&projectionCounter](const P& val) { + ++projectionCounter; + return val.second; + }; + + { // Validate iterator + sentinel overload + P input[5] = {{0, 99}, {1, 47}, {2, 99}, {3, 47}, {4, 99}}; + Read wrapped_input{input}; + + auto result = remove(wrapped_input.begin(), wrapped_input.end(), 47, projection); + STATIC_ASSERT(same_as>>); + assert(result.begin() == next(wrapped_input.begin(), 3)); + assert(result.end() == wrapped_input.end()); + assert(equal(expected, span{input}.first<3>())); + assert(projectionCounter == ranges::size(input)); + } - projectionCounter = 0; + projectionCounter = 0; - { // Validate range overload - P input[5] = {{0, 99}, {1, 47}, {2, 99}, {3, 47}, {4, 99}}; - Read wrapped_input{input}; + { // Validate range overload + P input[5] = {{0, 99}, {1, 47}, {2, 99}, {3, 47}, {4, 99}}; + Read wrapped_input{input}; - auto result = remove(wrapped_input, 47, projection); - STATIC_ASSERT(same_as>>); - assert(result.begin() == next(wrapped_input.begin(), 3)); - assert(result.end() == wrapped_input.end()); - assert(equal(expected, span{input}.first<3>())); - assert(projectionCounter == ranges::size(input)); - } + auto result = remove(wrapped_input, 47, projection); + STATIC_ASSERT(same_as>>); + assert(result.begin() == next(wrapped_input.begin(), 3)); + assert(result.end() == wrapped_input.end()); + assert(equal(expected, span{input}.first<3>())); + assert(projectionCounter == ranges::size(input)); } } }; diff --git a/tests/std/tests/P0896R4_ranges_alg_remove_if/test.cpp b/tests/std/tests/P0896R4_ranges_alg_remove_if/test.cpp index 863a0e28917..386f93e0dfa 100644 --- a/tests/std/tests/P0896R4_ranges_alg_remove_if/test.cpp +++ b/tests/std/tests/P0896R4_ranges_alg_remove_if/test.cpp @@ -23,44 +23,38 @@ struct instantiator { template static constexpr void call() { -#if !defined(__clang__) && !defined(__EDG__) // TRANSITION, VSO-938163 -#pragma warning(suppress : 4127) // conditional expression is constant - if (!ranges::contiguous_range || !is_constant_evaluated()) -#endif // TRANSITION, VSO-938163 - { - using ranges::remove_if, ranges::subrange, ranges::equal, ranges::iterator_t; + using ranges::remove_if, ranges::subrange, ranges::equal, ranges::iterator_t; - size_t projectionCounter = 0; - auto projection = [&projectionCounter](const P& val) { - ++projectionCounter; - return val.second; - }; + size_t projectionCounter = 0; + auto projection = [&projectionCounter](const P& val) { + ++projectionCounter; + return val.second; + }; - { // Validate iterator + sentinel overload - P input[5] = {{0, 99}, {1, 47}, {2, 99}, {3, 47}, {4, 99}}; - Read wrapped_input{input}; + { // Validate iterator + sentinel overload + P input[5] = {{0, 99}, {1, 47}, {2, 99}, {3, 47}, {4, 99}}; + Read wrapped_input{input}; - auto result = remove_if(wrapped_input.begin(), wrapped_input.end(), matches, projection); - STATIC_ASSERT(same_as>>); - assert(result.begin() == next(wrapped_input.begin(), 3)); - assert(result.end() == wrapped_input.end()); - assert(equal(expected, span{input}.first<3>())); - assert(projectionCounter == ranges::size(input)); - } + auto result = remove_if(wrapped_input.begin(), wrapped_input.end(), matches, projection); + STATIC_ASSERT(same_as>>); + assert(result.begin() == next(wrapped_input.begin(), 3)); + assert(result.end() == wrapped_input.end()); + assert(equal(expected, span{input}.first<3>())); + assert(projectionCounter == ranges::size(input)); + } - projectionCounter = 0; + projectionCounter = 0; - { // Validate range overload - P input[5] = {{0, 99}, {1, 47}, {2, 99}, {3, 47}, {4, 99}}; - Read wrapped_input{input}; + { // Validate range overload + P input[5] = {{0, 99}, {1, 47}, {2, 99}, {3, 47}, {4, 99}}; + Read wrapped_input{input}; - auto result = remove_if(wrapped_input, matches, projection); - STATIC_ASSERT(same_as>>); - assert(result.begin() == next(wrapped_input.begin(), 3)); - assert(result.end() == wrapped_input.end()); - assert(equal(expected, span{input}.first<3>())); - assert(projectionCounter == ranges::size(input)); - } + auto result = remove_if(wrapped_input, matches, projection); + STATIC_ASSERT(same_as>>); + assert(result.begin() == next(wrapped_input.begin(), 3)); + assert(result.end() == wrapped_input.end()); + assert(equal(expected, span{input}.first<3>())); + assert(projectionCounter == ranges::size(input)); } } }; diff --git a/tests/std/tests/P0896R4_ranges_alg_reverse/test.cpp b/tests/std/tests/P0896R4_ranges_alg_reverse/test.cpp index 53d0251a472..11b78e69cc6 100644 --- a/tests/std/tests/P0896R4_ranges_alg_reverse/test.cpp +++ b/tests/std/tests/P0896R4_ranges_alg_reverse/test.cpp @@ -151,33 +151,21 @@ struct test_vector { }; int main() { -#if defined(__clang__) || defined(__EDG__) // TRANSITION, VSO-938163 STATIC_ASSERT((test_bidi(), true)); -#endif // TRANSITION, VSO-938163 test_bidi(); -#if defined(__clang__) || defined(__EDG__) // TRANSITION, VSO-938163 STATIC_ASSERT((test_contiguous>(), true)); -#endif // TRANSITION, VSO-938163 test_contiguous>(); -#if defined(__clang__) || defined(__EDG__) // TRANSITION, VSO-938163 STATIC_ASSERT((test_contiguous>(), true)); -#endif // TRANSITION, VSO-938163 test_contiguous>(); -#if defined(__clang__) || defined(__EDG__) // TRANSITION, VSO-938163 STATIC_ASSERT((test_contiguous>(), true)); -#endif // TRANSITION, VSO-938163 test_contiguous>(); -#if defined(__clang__) || defined(__EDG__) // TRANSITION, VSO-938163 STATIC_ASSERT((test_contiguous>(), true)); -#endif // TRANSITION, VSO-938163 test_contiguous>(); -#if defined(__clang__) || defined(__EDG__) // TRANSITION, VSO-938163 STATIC_ASSERT((test_contiguous>(), true)); -#endif // TRANSITION, VSO-938163 test_contiguous>(); } diff --git a/tests/std/tests/P0896R4_ranges_alg_rotate/test.cpp b/tests/std/tests/P0896R4_ranges_alg_rotate/test.cpp index 511a83c0b98..8337cef3f5b 100644 --- a/tests/std/tests/P0896R4_ranges_alg_rotate/test.cpp +++ b/tests/std/tests/P0896R4_ranges_alg_rotate/test.cpp @@ -45,8 +45,6 @@ struct instantiator { }; int main() { -#if defined(__clang__) || defined(__EDG__) // TRANSITION, VSO-938163 STATIC_ASSERT((test_fwd(), true)); -#endif // TRANSITION, VSO-938163 test_fwd(); } diff --git a/tests/std/tests/P0896R4_ranges_alg_sort/test.cpp b/tests/std/tests/P0896R4_ranges_alg_sort/test.cpp index 88c838a4eba..8c01b10ec60 100644 --- a/tests/std/tests/P0896R4_ranges_alg_sort/test.cpp +++ b/tests/std/tests/P0896R4_ranges_alg_sort/test.cpp @@ -23,34 +23,29 @@ struct instantiator { template static constexpr void call() { -#if !defined(__clang__) && !defined(__EDG__) // TRANSITION, VSO-938163 - if constexpr (!ranges::contiguous_range) -#endif // TRANSITION, VSO-938163 - { - using ranges::sort, ranges::is_sorted, ranges::iterator_t, ranges::less; - - { // Validate range overload - auto buff = input; - const R range{buff}; - const same_as> auto result = sort(range, less{}, get_first); - assert(result == range.end()); - assert(is_sorted(range, less{}, get_first)); - } - - { // Validate iterator overload - auto buff = input; - const R range{buff}; - const same_as> auto result = sort(range.begin(), range.end(), less{}, get_first); - assert(result == range.end()); - assert(is_sorted(range.begin(), range.end(), less{}, get_first)); - } - - { // Validate empty range - const R range{}; - const same_as> auto result = sort(range, less{}, get_first); - assert(result == range.end()); - assert(is_sorted(range, less{}, get_first)); - } + using ranges::sort, ranges::is_sorted, ranges::iterator_t, ranges::less; + + { // Validate range overload + auto buff = input; + const R range{buff}; + const same_as> auto result = sort(range, less{}, get_first); + assert(result == range.end()); + assert(is_sorted(range, less{}, get_first)); + } + + { // Validate iterator overload + auto buff = input; + const R range{buff}; + const same_as> auto result = sort(range.begin(), range.end(), less{}, get_first); + assert(result == range.end()); + assert(is_sorted(range.begin(), range.end(), less{}, get_first)); + } + + { // Validate empty range + const R range{}; + const same_as> auto result = sort(range, less{}, get_first); + assert(result == range.end()); + assert(is_sorted(range, less{}, get_first)); } } }; diff --git a/tests/std/tests/P0896R4_ranges_alg_swap_ranges/test.cpp b/tests/std/tests/P0896R4_ranges_alg_swap_ranges/test.cpp index 534280d29d1..17aea1f6ce2 100644 --- a/tests/std/tests/P0896R4_ranges_alg_swap_ranges/test.cpp +++ b/tests/std/tests/P0896R4_ranges_alg_swap_ranges/test.cpp @@ -98,9 +98,7 @@ constexpr void run_tests() { } int main() { -#if defined(__clang__) || defined(__EDG__) // TRANSITION, VSO-938163 STATIC_ASSERT((run_tests(), true)); -#endif // TRANSITION, VSO-938163 run_tests(); } #endif // TEST_EVERYTHING diff --git a/tests/std/tests/P0896R4_ranges_alg_uninitialized_copy/env.lst b/tests/std/tests/P0896R4_ranges_alg_uninitialized_copy/env.lst new file mode 100644 index 00000000000..f3ccc8613c6 --- /dev/null +++ b/tests/std/tests/P0896R4_ranges_alg_uninitialized_copy/env.lst @@ -0,0 +1,4 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\concepts_matrix.lst diff --git a/tests/std/tests/P0896R4_ranges_alg_uninitialized_copy/test.cpp b/tests/std/tests/P0896R4_ranges_alg_uninitialized_copy/test.cpp new file mode 100644 index 00000000000..f2c607162fe --- /dev/null +++ b/tests/std/tests/P0896R4_ranges_alg_uninitialized_copy/test.cpp @@ -0,0 +1,177 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace std; + +// Validate that uninitialized_copy_result aliases in_out_result +STATIC_ASSERT(same_as, ranges::in_out_result>); + +// Validate dangling story +STATIC_ASSERT(same_as{}, borrowed{})), + ranges::uninitialized_copy_result>); +STATIC_ASSERT(same_as{}, borrowed{})), + ranges::uninitialized_copy_result>); +STATIC_ASSERT(same_as{}, borrowed{})), + ranges::uninitialized_copy_result>); +STATIC_ASSERT(same_as{}, borrowed{})), + ranges::uninitialized_copy_result>); + +struct int_wrapper { + inline static int constructions = 0; + inline static int destructions = 0; + + static void clear_counts() { + constructions = 0; + destructions = 0; + } + + static constexpr int magic_throwing_val = 29; + int val = 10; + + int_wrapper() { + ++constructions; + } + int_wrapper(int x) : val{x} { + ++constructions; + } + + int_wrapper(const int_wrapper& that) { + if (that.val == magic_throwing_val) { + throw magic_throwing_val; + } + + val = that.val; + ++constructions; + } + + ~int_wrapper() { + ++destructions; + } + + int_wrapper& operator=(const int_wrapper&) { + abort(); + } + + auto operator<=>(const int_wrapper&) const = default; +}; + +template +struct holder { + STATIC_ASSERT(N < ~size_t{0} / sizeof(T)); + alignas(T) unsigned char space[N * sizeof(T)]; + + auto as_span() { + return span{reinterpret_cast(space + 0), N}; + } +}; + +template +void not_ranges_destroy(R&& r) { // TRANSITION, ranges::destroy + for (auto& e : r) { + destroy_at(&e); + } +} + +struct instantiator { + static constexpr int expected_output[] = {13, 55, 12345}; + static constexpr int expected_input[] = {13, 55, 12345}; + + template + static void call() { + using ranges::uninitialized_copy, ranges::uninitialized_copy_result, ranges::equal, ranges::equal_to, + ranges::iterator_t; + + { // Validate range overload + int_wrapper input[3] = {13, 55, 12345}; + R wrapped_input{input}; + holder mem; + W wrapped_output{mem.as_span()}; + + int_wrapper::clear_counts(); + const same_as, iterator_t>> auto result = + uninitialized_copy(wrapped_input, wrapped_output); + assert(int_wrapper::constructions == 3); + assert(int_wrapper::destructions == 0); + assert(result.in == wrapped_input.end()); + assert(result.out == wrapped_output.end()); + assert(equal(wrapped_output, expected_output, equal_to{}, &int_wrapper::val)); + assert(equal(input, expected_input, equal_to{}, &int_wrapper::val)); + not_ranges_destroy(wrapped_output); + assert(int_wrapper::constructions == 3); + assert(int_wrapper::destructions == 3); + } + + { // Validate iterator overload + int_wrapper input[3] = {13, 55, 12345}; + R wrapped_input{input}; + holder mem; + W wrapped_output{mem.as_span()}; + + int_wrapper::clear_counts(); + const same_as, iterator_t>> auto result = uninitialized_copy( + wrapped_input.begin(), wrapped_input.end(), wrapped_output.begin(), wrapped_output.end()); + assert(int_wrapper::constructions == 3); + assert(int_wrapper::destructions == 0); + assert(result.in == wrapped_input.end()); + assert(result.out == wrapped_output.end()); + assert(equal(wrapped_output, expected_output, equal_to{}, &int_wrapper::val)); + assert(equal(input, expected_input, equal_to{}, &int_wrapper::val)); + not_ranges_destroy(wrapped_output); + assert(int_wrapper::constructions == 3); + assert(int_wrapper::destructions == 3); + } + } +}; + +struct throwing_test { + static constexpr int expected_input[] = {13, 55, int_wrapper::magic_throwing_val, 12345}; + + template + static void call() { + // Validate only range overload (one is plenty since they both use the same backend) + int_wrapper input[] = {13, 55, int_wrapper::magic_throwing_val, 12345}; + R wrapped_input{input}; + holder mem; + W wrapped_output{mem.as_span()}; + + int_wrapper::clear_counts(); + try { + (void) ranges::uninitialized_copy(wrapped_input, wrapped_output); + assert(false); + } catch (int i) { + assert(i == int_wrapper::magic_throwing_val); + } catch (...) { + assert(false); + } + assert(int_wrapper::constructions == 2); + assert(int_wrapper::destructions == 2); + assert(ranges::equal(input, expected_input, ranges::equal_to{}, &int_wrapper::val)); + } +}; + +template +using test_input = test::range; +using test_output = test::range; + +int main() { + // The algorithm is oblivious to non-required category, size, difference, and "proxyness" of the input range. It + // _is_ sensitive to proxyness in that it requires non-proxy references for the output range. + + instantiator::call, test_output>(); + instantiator::call, test_output>(); + throwing_test::call, test_output>(); + throwing_test::call, test_output>(); +} 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 new file mode 100644 index 00000000000..f3ccc8613c6 --- /dev/null +++ b/tests/std/tests/P0896R4_ranges_alg_uninitialized_copy_n/env.lst @@ -0,0 +1,4 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\concepts_matrix.lst diff --git a/tests/std/tests/P0896R4_ranges_alg_uninitialized_copy_n/test.cpp b/tests/std/tests/P0896R4_ranges_alg_uninitialized_copy_n/test.cpp new file mode 100644 index 00000000000..9e86c952d8d --- /dev/null +++ b/tests/std/tests/P0896R4_ranges_alg_uninitialized_copy_n/test.cpp @@ -0,0 +1,143 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace std; + +// Validate that uninitialized_copy_n_result aliases in_out_result +STATIC_ASSERT(same_as, ranges::in_out_result>); + +struct int_wrapper { + inline static int constructions = 0; + inline static int destructions = 0; + + static void clear_counts() { + constructions = 0; + destructions = 0; + } + + static constexpr int magic_throwing_val = 29; + int val = 10; + + int_wrapper() { + ++constructions; + } + int_wrapper(int x) : val{x} { + ++constructions; + } + + int_wrapper(const int_wrapper& that) { + if (that.val == magic_throwing_val) { + throw magic_throwing_val; + } + + val = that.val; + ++constructions; + } + + ~int_wrapper() { + ++destructions; + } + + int_wrapper& operator=(const int_wrapper&) { + abort(); + } + + auto operator<=>(const int_wrapper&) const = default; +}; + +template +struct holder { + STATIC_ASSERT(N < ~size_t{0} / sizeof(T)); + alignas(T) unsigned char space[N * sizeof(T)]; + + auto as_span() { + return span{reinterpret_cast(space + 0), N}; + } +}; + +template +void not_ranges_destroy(R&& r) { // TRANSITION, ranges::destroy + for (auto& e : r) { + destroy_at(&e); + } +} + +struct instantiator { + static constexpr int expected_output[] = {13, 55, 12345}; + static constexpr int expected_input[] = {13, 55, 12345}; + + template + static void call() { + using ranges::uninitialized_copy_n, ranges::uninitialized_copy_n_result, ranges::equal, ranges::equal_to, + ranges::iterator_t; + + int_wrapper input[3] = {13, 55, 12345}; + Read wrapped_input{input}; + holder mem; + Write wrapped_output{mem.as_span()}; + + int_wrapper::clear_counts(); + const same_as, iterator_t>> auto result = + uninitialized_copy_n(wrapped_input.begin(), 3, wrapped_output.begin(), wrapped_output.end()); + assert(int_wrapper::constructions == 3); + assert(int_wrapper::destructions == 0); + assert(result.in == wrapped_input.end()); + assert(result.out == wrapped_output.end()); + assert(equal(wrapped_output, expected_output, equal_to{}, &int_wrapper::val)); + assert(equal(input, expected_input, equal_to{}, &int_wrapper::val)); + not_ranges_destroy(wrapped_output); + assert(int_wrapper::constructions == 3); + assert(int_wrapper::destructions == 3); + } +}; + +struct throwing_test { + static constexpr int expected_input[] = {13, 55, int_wrapper::magic_throwing_val, 12345}; + + template + static void call() { + int_wrapper input[] = {13, 55, int_wrapper::magic_throwing_val, 12345}; + Read wrapped_input{input}; + holder mem; + Write wrapped_output{mem.as_span()}; + + int_wrapper::clear_counts(); + try { + (void) ranges::uninitialized_copy_n(wrapped_input.begin(), 4, wrapped_output.begin(), wrapped_output.end()); + assert(false); + } catch (int i) { + assert(i == int_wrapper::magic_throwing_val); + } catch (...) { + assert(false); + } + assert(int_wrapper::constructions == 2); + assert(int_wrapper::destructions == 2); + } +}; + +template +using test_input = test::range; +using test_output = test::range; + +int main() { + // The algorithm is oblivious to non-required category, size, difference, and "proxyness" of the input range. It + // _is_ sensitive to proxyness in that it requires non-proxy references for the output range. + + instantiator::call, test_output>(); + instantiator::call, test_output>(); + throwing_test::call, test_output>(); + throwing_test::call, test_output>(); +} diff --git a/tests/std/tests/P0896R4_ranges_alg_uninitialized_default_construct/env.lst b/tests/std/tests/P0896R4_ranges_alg_uninitialized_default_construct/env.lst new file mode 100644 index 00000000000..f3ccc8613c6 --- /dev/null +++ b/tests/std/tests/P0896R4_ranges_alg_uninitialized_default_construct/env.lst @@ -0,0 +1,4 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\concepts_matrix.lst diff --git a/tests/std/tests/P0896R4_ranges_alg_uninitialized_default_construct/test.cpp b/tests/std/tests/P0896R4_ranges_alg_uninitialized_default_construct/test.cpp new file mode 100644 index 00000000000..2f99b0aef75 --- /dev/null +++ b/tests/std/tests/P0896R4_ranges_alg_uninitialized_default_construct/test.cpp @@ -0,0 +1,129 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace std; + +// Validate dangling story +STATIC_ASSERT(same_as{})), int*>); +STATIC_ASSERT(same_as{})), ranges::dangling>); + +struct int_wrapper { + inline static int constructions = 0; + inline static int destructions = 0; + + static void clear_counts() { + constructions = 0; + destructions = 0; + } + + static constexpr int magic_throwing_val = 4; + int val; + + int_wrapper() { + if (++constructions == magic_throwing_val) { + throw magic_throwing_val; + } + } + + ~int_wrapper() { + ++destructions; + } + + auto operator<=>(const int_wrapper&) const = default; +}; +STATIC_ASSERT(default_initializable); + +template +struct holder { + STATIC_ASSERT(N < ~size_t{0} / sizeof(T)); + alignas(T) unsigned char space[N * sizeof(T)]; + + auto as_span() { + return span{reinterpret_cast(space + 0), N}; + } +}; + +template +void not_ranges_destroy(R&& r) { // TRANSITION, ranges::destroy + for (auto& e : r) { + destroy_at(&e); + } +} + +struct instantiator { + template + static void call() { + using ranges::uninitialized_default_construct, ranges::equal, ranges::equal_to, ranges::iterator_t; + + { // Validate range overload + holder mem; + Write wrapped_input{mem.as_span()}; + + int_wrapper::clear_counts(); + const same_as> auto result = uninitialized_default_construct(wrapped_input); + assert(int_wrapper::constructions == 3); + assert(int_wrapper::destructions == 0); + assert(result == wrapped_input.end()); + not_ranges_destroy(wrapped_input); + assert(int_wrapper::constructions == 3); + assert(int_wrapper::destructions == 3); + } + + { // Validate iterator overload + holder mem; + Write wrapped_input{mem.as_span()}; + + int_wrapper::clear_counts(); + const same_as> auto result = + uninitialized_default_construct(wrapped_input.begin(), wrapped_input.end()); + assert(int_wrapper::constructions == 3); + assert(int_wrapper::destructions == 0); + assert(result == wrapped_input.end()); + not_ranges_destroy(wrapped_input); + assert(int_wrapper::constructions == 3); + assert(int_wrapper::destructions == 3); + } + } +}; + +struct throwing_test { + template + static void call() { + // Validate only range overload (one is plenty since they both use the same backend) + holder mem; + Write wrapped_input{mem.as_span()}; + + int_wrapper::clear_counts(); + try { + (void) ranges::uninitialized_default_construct(wrapped_input); + assert(false); + } catch (int i) { + assert(i == int_wrapper::magic_throwing_val); + } catch (...) { + assert(false); + } + assert(int_wrapper::constructions == int_wrapper::magic_throwing_val); + assert(int_wrapper::destructions == int_wrapper::magic_throwing_val - 1); + } +}; + +using test_range = test::range; + +int main() { + // The algorithm is oblivious to non-required category, size, difference. It _is_ sensitive to proxyness in that it + // requires non-proxy references for the input range. + + instantiator::call(); + throwing_test::call(); +} diff --git a/tests/std/tests/P0896R4_ranges_alg_uninitialized_default_construct_n/env.lst b/tests/std/tests/P0896R4_ranges_alg_uninitialized_default_construct_n/env.lst new file mode 100644 index 00000000000..f3ccc8613c6 --- /dev/null +++ b/tests/std/tests/P0896R4_ranges_alg_uninitialized_default_construct_n/env.lst @@ -0,0 +1,4 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\concepts_matrix.lst diff --git a/tests/std/tests/P0896R4_ranges_alg_uninitialized_default_construct_n/test.cpp b/tests/std/tests/P0896R4_ranges_alg_uninitialized_default_construct_n/test.cpp new file mode 100644 index 00000000000..d28eefede3c --- /dev/null +++ b/tests/std/tests/P0896R4_ranges_alg_uninitialized_default_construct_n/test.cpp @@ -0,0 +1,107 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace std; + +struct int_wrapper { + inline static int constructions = 0; + inline static int destructions = 0; + + static void clear_counts() { + constructions = 0; + destructions = 0; + } + + static constexpr int magic_throwing_val = 4; + int val; + + int_wrapper() { + if (++constructions == magic_throwing_val) { + throw magic_throwing_val; + } + } + + ~int_wrapper() { + ++destructions; + } + + auto operator<=>(const int_wrapper&) const = default; +}; +STATIC_ASSERT(default_initializable); + +template +struct holder { + STATIC_ASSERT(N < ~size_t{0} / sizeof(T)); + alignas(T) unsigned char space[N * sizeof(T)]; + + auto as_span() { + return span{reinterpret_cast(space + 0), N}; + } +}; + +template +void not_ranges_destroy(R&& r) { // TRANSITION, ranges::destroy + for (auto& e : r) { + destroy_at(&e); + } +} + +struct instantiator { + template + static void call() { + using ranges::uninitialized_default_construct_n, ranges::equal, ranges::equal_to, ranges::iterator_t; + + holder mem; + Write wrapped_input{mem.as_span()}; + + int_wrapper::clear_counts(); + const same_as> auto result = uninitialized_default_construct_n(wrapped_input.begin(), 3); + assert(int_wrapper::constructions == 3); + assert(int_wrapper::destructions == 0); + assert(result == wrapped_input.end()); + not_ranges_destroy(wrapped_input); + assert(int_wrapper::constructions == 3); + assert(int_wrapper::destructions == 3); + } +}; + +struct throwing_test { + template + static void call() { + holder mem; + Write wrapped_input{mem.as_span()}; + + int_wrapper::clear_counts(); + try { + (void) ranges::uninitialized_default_construct_n(wrapped_input.begin(), int_wrapper::magic_throwing_val); + assert(false); + } catch (int i) { + assert(i == int_wrapper::magic_throwing_val); + } catch (...) { + assert(false); + } + assert(int_wrapper::constructions == int_wrapper::magic_throwing_val); + assert(int_wrapper::destructions == int_wrapper::magic_throwing_val - 1); + } +}; + +using test_range = test::range; + +int main() { + // The algorithm is oblivious to non-required category, size, difference. It _is_ sensitive to proxyness in that it + // requires non-proxy references for the input range. + + instantiator::call(); + throwing_test::call(); +} diff --git a/tests/std/tests/P0896R4_ranges_alg_uninitialized_fill/env.lst b/tests/std/tests/P0896R4_ranges_alg_uninitialized_fill/env.lst new file mode 100644 index 00000000000..f3ccc8613c6 --- /dev/null +++ b/tests/std/tests/P0896R4_ranges_alg_uninitialized_fill/env.lst @@ -0,0 +1,4 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\concepts_matrix.lst diff --git a/tests/std/tests/P0896R4_ranges_alg_uninitialized_fill/test.cpp b/tests/std/tests/P0896R4_ranges_alg_uninitialized_fill/test.cpp new file mode 100644 index 00000000000..1defdd193d2 --- /dev/null +++ b/tests/std/tests/P0896R4_ranges_alg_uninitialized_fill/test.cpp @@ -0,0 +1,136 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace std; + +// Validate dangling story +STATIC_ASSERT(same_as{}, 42)), int*>); +STATIC_ASSERT(same_as{}, 42)), ranges::dangling>); + +struct int_wrapper { + inline static int constructions = 0; + inline static int destructions = 0; + + static void clear_counts() { + constructions = 0; + destructions = 0; + } + + static constexpr int magic_throwing_val = 4; + int val; + + int_wrapper() = default; + + int_wrapper(const int v) { + if (++constructions == magic_throwing_val) { + throw magic_throwing_val; + } + val = v; + } + + ~int_wrapper() { + ++destructions; + } + + auto operator<=>(const int_wrapper&) const = default; +}; +STATIC_ASSERT(default_initializable); + +template +struct holder { + STATIC_ASSERT(N < ~size_t{0} / sizeof(T)); + alignas(T) unsigned char space[N * sizeof(T)]; + + auto as_span() { + return span{reinterpret_cast(space + 0), N}; + } +}; + +template +void not_ranges_destroy(R&& r) { // TRANSITION, ranges::destroy + for (auto& e : r) { + destroy_at(&e); + } +} + +struct instantiator { + static constexpr int expected[3] = {42, 42, 42}; + + template + static void call() { + using ranges::uninitialized_fill, ranges::equal, ranges::equal_to, ranges::iterator_t; + + { // Validate range overload + holder mem; + Write wrapped_input{mem.as_span()}; + + int_wrapper::clear_counts(); + const same_as> auto result = uninitialized_fill(wrapped_input, 42); + assert(int_wrapper::constructions == 3); + assert(int_wrapper::destructions == 0); + assert(result == wrapped_input.end()); + assert(equal(wrapped_input, expected, equal_to{}, &int_wrapper::val)); + not_ranges_destroy(wrapped_input); + assert(int_wrapper::constructions == 3); + assert(int_wrapper::destructions == 3); + } + + { // Validate iterator overload + holder mem; + Write wrapped_input{mem.as_span()}; + + int_wrapper::clear_counts(); + const same_as> auto result = + uninitialized_fill(wrapped_input.begin(), wrapped_input.end(), 42); + assert(int_wrapper::constructions == 3); + assert(int_wrapper::destructions == 0); + assert(result == wrapped_input.end()); + assert(equal(wrapped_input, expected, equal_to{}, &int_wrapper::val)); + not_ranges_destroy(wrapped_input); + assert(int_wrapper::constructions == 3); + assert(int_wrapper::destructions == 3); + } + } +}; + +struct throwing_test { + template + static void call() { + // Validate only range overload (one is plenty since they both use the same backend) + holder mem; + Write wrapped_input{mem.as_span()}; + + int_wrapper::clear_counts(); + try { + (void) ranges::uninitialized_fill(wrapped_input, 42); + assert(false); + } catch (int i) { + assert(i == int_wrapper::magic_throwing_val); + } catch (...) { + assert(false); + } + assert(int_wrapper::constructions == int_wrapper::magic_throwing_val); + assert(int_wrapper::destructions == int_wrapper::magic_throwing_val - 1); + } +}; + +using test_range = test::range; + +int main() { + // The algorithm is oblivious to non-required category, size, difference. It _is_ sensitive to proxyness in that it + // requires non-proxy references for the input range. + + instantiator::call(); + throwing_test::call(); +} diff --git a/tests/std/tests/P0896R4_ranges_alg_uninitialized_fill_n/env.lst b/tests/std/tests/P0896R4_ranges_alg_uninitialized_fill_n/env.lst new file mode 100644 index 00000000000..f3ccc8613c6 --- /dev/null +++ b/tests/std/tests/P0896R4_ranges_alg_uninitialized_fill_n/env.lst @@ -0,0 +1,4 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\concepts_matrix.lst diff --git a/tests/std/tests/P0896R4_ranges_alg_uninitialized_fill_n/test.cpp b/tests/std/tests/P0896R4_ranges_alg_uninitialized_fill_n/test.cpp new file mode 100644 index 00000000000..97da0b88fd1 --- /dev/null +++ b/tests/std/tests/P0896R4_ranges_alg_uninitialized_fill_n/test.cpp @@ -0,0 +1,113 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace std; + +struct int_wrapper { + inline static int constructions = 0; + inline static int destructions = 0; + + static void clear_counts() { + constructions = 0; + destructions = 0; + } + + static constexpr int magic_throwing_val = 4; + int val; + + int_wrapper() = default; + + int_wrapper(const int v) { + if (++constructions == magic_throwing_val) { + throw magic_throwing_val; + } + val = v; + } + + ~int_wrapper() { + ++destructions; + } + + auto operator<=>(const int_wrapper&) const = default; +}; +STATIC_ASSERT(default_initializable); + +template +struct holder { + STATIC_ASSERT(N < ~size_t{0} / sizeof(T)); + alignas(T) unsigned char space[N * sizeof(T)]; + + auto as_span() { + return span{reinterpret_cast(space + 0), N}; + } +}; + +template +void not_ranges_destroy(R&& r) { // TRANSITION, ranges::destroy + for (auto& e : r) { + destroy_at(&e); + } +} + +struct instantiator { + static constexpr int expected[3] = {42, 42, 42}; + + template + static void call() { + using ranges::uninitialized_fill_n, ranges::equal, ranges::equal_to, ranges::iterator_t; + + holder mem; + Write wrapped_input{mem.as_span()}; + + int_wrapper::clear_counts(); + const same_as> auto result = uninitialized_fill_n(wrapped_input.begin(), 3, 42); + assert(int_wrapper::constructions == 3); + assert(int_wrapper::destructions == 0); + assert(result == wrapped_input.end()); + assert(equal(wrapped_input, expected, equal_to{}, &int_wrapper::val)); + not_ranges_destroy(wrapped_input); + assert(int_wrapper::constructions == 3); + assert(int_wrapper::destructions == 3); + } +}; + +struct throwing_test { + template + static void call() { + holder mem; + Write wrapped_input{mem.as_span()}; + + int_wrapper::clear_counts(); + try { + (void) ranges::uninitialized_fill_n(wrapped_input.begin(), int_wrapper::magic_throwing_val, 42); + assert(false); + } catch (int i) { + assert(i == int_wrapper::magic_throwing_val); + } catch (...) { + assert(false); + } + assert(int_wrapper::constructions == int_wrapper::magic_throwing_val); + assert(int_wrapper::destructions == int_wrapper::magic_throwing_val - 1); + } +}; + +using test_range = test::range; + +int main() { + // The algorithm is oblivious to non-required category, size, difference. It _is_ sensitive to proxyness in that it + // requires non-proxy references for the input range. + + instantiator::call(); + throwing_test::call(); +} diff --git a/tests/std/tests/P0896R4_ranges_alg_uninitialized_move/test.cpp b/tests/std/tests/P0896R4_ranges_alg_uninitialized_move/test.cpp index 773378f42f4..8be0b1e8de3 100644 --- a/tests/std/tests/P0896R4_ranges_alg_uninitialized_move/test.cpp +++ b/tests/std/tests/P0896R4_ranges_alg_uninitialized_move/test.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -58,12 +59,8 @@ struct int_wrapper { ++destructions; } - int_wrapper& operator=(int_wrapper&& that) { - if (that.val == magic_throwing_val) { - throw magic_throwing_val; - } - val = exchange(that.val, -1); - return *this; + int_wrapper& operator=(int_wrapper&&) { + abort(); } auto operator<=>(const int_wrapper&) const = default; @@ -80,21 +77,14 @@ struct holder { } }; -template -void not_ranges_destroy(R&& r) { // TRANSITION, ranges::destroy - for (auto& e : r) { - destroy_at(&e); - } -} - struct instantiator { static constexpr int expected_output[] = {13, 55, 12345}; static constexpr int expected_input[] = {-1, -1, -1}; template static void call() { - using ranges::uninitialized_move, ranges::uninitialized_move_result, ranges::equal, ranges::equal_to, - ranges::iterator_t; + using ranges::uninitialized_move, ranges::uninitialized_move_result, ranges::destroy, ranges::equal, + ranges::equal_to, ranges::iterator_t; { // Validate range overload int_wrapper input[3] = {13, 55, 12345}; @@ -111,7 +101,7 @@ struct instantiator { assert(result.out == wrapped_output.end()); assert(equal(wrapped_output, expected_output, equal_to{}, &int_wrapper::val)); assert(equal(input, expected_input, equal_to{}, &int_wrapper::val)); - not_ranges_destroy(wrapped_output); + destroy(wrapped_output); assert(int_wrapper::constructions == 3); assert(int_wrapper::destructions == 3); } @@ -131,7 +121,7 @@ struct instantiator { assert(result.out == wrapped_output.end()); assert(equal(wrapped_output, expected_output, equal_to{}, &int_wrapper::val)); assert(equal(input, expected_input, equal_to{}, &int_wrapper::val)); - not_ranges_destroy(wrapped_output); + destroy(wrapped_output); assert(int_wrapper::constructions == 3); assert(int_wrapper::destructions == 3); } 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 new file mode 100644 index 00000000000..f3ccc8613c6 --- /dev/null +++ b/tests/std/tests/P0896R4_ranges_alg_uninitialized_move_n/env.lst @@ -0,0 +1,4 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\concepts_matrix.lst diff --git a/tests/std/tests/P0896R4_ranges_alg_uninitialized_move_n/test.cpp b/tests/std/tests/P0896R4_ranges_alg_uninitialized_move_n/test.cpp new file mode 100644 index 00000000000..eef82b952c4 --- /dev/null +++ b/tests/std/tests/P0896R4_ranges_alg_uninitialized_move_n/test.cpp @@ -0,0 +1,145 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace std; + +// Validate that uninitialized_move_n_result aliases in_out_result +STATIC_ASSERT(same_as, ranges::in_out_result>); + +struct int_wrapper { + inline static int constructions = 0; + inline static int destructions = 0; + + static void clear_counts() { + constructions = 0; + destructions = 0; + } + + static constexpr int magic_throwing_val = 29; + int val = 10; + + int_wrapper() { + ++constructions; + } + int_wrapper(int x) : val{x} { + ++constructions; + } + + int_wrapper(int_wrapper&& that) { + if (that.val == magic_throwing_val) { + throw magic_throwing_val; + } + + val = exchange(that.val, -1); + ++constructions; + } + + ~int_wrapper() { + ++destructions; + } + + int_wrapper& operator=(int_wrapper&&) { + abort(); + } + + auto operator<=>(const int_wrapper&) const = default; +}; +STATIC_ASSERT(movable && !copyable); + +template +struct holder { + STATIC_ASSERT(N < ~size_t{0} / sizeof(T)); + alignas(T) unsigned char space[N * sizeof(T)]; + + auto as_span() { + return span{reinterpret_cast(space + 0), N}; + } +}; + +template +void not_ranges_destroy(R&& r) { // TRANSITION, ranges::destroy + for (auto& e : r) { + destroy_at(&e); + } +} + +struct instantiator { + static constexpr int expected_output[] = {13, 55, 12345}; + static constexpr int expected_input[] = {-1, -1, -1}; + + template + static void call() { + using ranges::uninitialized_move_n, ranges::uninitialized_move_n_result, ranges::equal, ranges::equal_to, + ranges::iterator_t; + + int_wrapper input[3] = {13, 55, 12345}; + Read wrapped_input{input}; + holder mem; + Write wrapped_output{mem.as_span()}; + + int_wrapper::clear_counts(); + const same_as, iterator_t>> auto result = + uninitialized_move_n(wrapped_input.begin(), 3, wrapped_output.begin(), wrapped_output.end()); + assert(int_wrapper::constructions == 3); + assert(int_wrapper::destructions == 0); + assert(result.in == wrapped_input.end()); + assert(result.out == wrapped_output.end()); + assert(equal(wrapped_output, expected_output, equal_to{}, &int_wrapper::val)); + assert(equal(input, expected_input, equal_to{}, &int_wrapper::val)); + not_ranges_destroy(wrapped_output); + assert(int_wrapper::constructions == 3); + assert(int_wrapper::destructions == 3); + } +}; + +struct throwing_test { + static constexpr int expected_input[] = {-1, -1, int_wrapper::magic_throwing_val, 12345}; + + template + static void call() { + int_wrapper input[] = {13, 55, int_wrapper::magic_throwing_val, 12345}; + Read wrapped_input{input}; + holder mem; + Write wrapped_output{mem.as_span()}; + + int_wrapper::clear_counts(); + try { + (void) ranges::uninitialized_move_n(wrapped_input.begin(), 4, wrapped_output.begin(), wrapped_output.end()); + assert(false); + } catch (int i) { + assert(i == int_wrapper::magic_throwing_val); + } catch (...) { + assert(false); + } + assert(int_wrapper::constructions == 2); + assert(int_wrapper::destructions == 2); + assert(ranges::equal(input, expected_input, ranges::equal_to{}, &int_wrapper::val)); + } +}; + +template +using test_input = test::range; +using test_output = test::range; + +int main() { + // The algorithm is oblivious to non-required category, size, difference, and "proxyness" of the input range. It + // _is_ sensitive to proxyness in that it requires non-proxy references for the output range. + + instantiator::call, test_output>(); + instantiator::call, test_output>(); + throwing_test::call, test_output>(); + throwing_test::call, test_output>(); +} diff --git a/tests/std/tests/P0896R4_ranges_alg_uninitialized_value_construct/env.lst b/tests/std/tests/P0896R4_ranges_alg_uninitialized_value_construct/env.lst new file mode 100644 index 00000000000..f3ccc8613c6 --- /dev/null +++ b/tests/std/tests/P0896R4_ranges_alg_uninitialized_value_construct/env.lst @@ -0,0 +1,4 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\concepts_matrix.lst diff --git a/tests/std/tests/P0896R4_ranges_alg_uninitialized_value_construct/test.cpp b/tests/std/tests/P0896R4_ranges_alg_uninitialized_value_construct/test.cpp new file mode 100644 index 00000000000..a17ede367c5 --- /dev/null +++ b/tests/std/tests/P0896R4_ranges_alg_uninitialized_value_construct/test.cpp @@ -0,0 +1,133 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace std; + +// Validate dangling story +STATIC_ASSERT(same_as{})), int*>); +STATIC_ASSERT(same_as{})), ranges::dangling>); + +struct int_wrapper { + inline static int constructions = 0; + inline static int destructions = 0; + + static void clear_counts() { + constructions = 0; + destructions = 0; + } + + static constexpr int magic_throwing_val = 4; + int val = 10; + + int_wrapper() { + if (++constructions == magic_throwing_val) { + throw magic_throwing_val; + } + } + + ~int_wrapper() { + ++destructions; + } + + auto operator<=>(const int_wrapper&) const = default; +}; +STATIC_ASSERT(default_initializable); + +template +struct holder { + STATIC_ASSERT(N < ~size_t{0} / sizeof(T)); + alignas(T) unsigned char space[N * sizeof(T)]; + + auto as_span() { + return span{reinterpret_cast(space + 0), N}; + } +}; + +template +void not_ranges_destroy(R&& r) { // TRANSITION, ranges::destroy + for (auto& e : r) { + destroy_at(&e); + } +} + +struct instantiator { + static constexpr int expected[3] = {10, 10, 10}; + + template + static void call() { + using ranges::uninitialized_value_construct, ranges::equal, ranges::equal_to, ranges::iterator_t; + + { // Validate range overload + holder mem; + Write wrapped_input{mem.as_span()}; + + int_wrapper::clear_counts(); + const same_as> auto result = uninitialized_value_construct(wrapped_input); + assert(int_wrapper::constructions == 3); + assert(int_wrapper::destructions == 0); + assert(result == wrapped_input.end()); + assert(equal(wrapped_input, expected, equal_to{}, &int_wrapper::val)); + not_ranges_destroy(wrapped_input); + assert(int_wrapper::constructions == 3); + assert(int_wrapper::destructions == 3); + } + + { // Validate iterator overload + holder mem; + Write wrapped_input{mem.as_span()}; + + int_wrapper::clear_counts(); + const same_as> auto result = + uninitialized_value_construct(wrapped_input.begin(), wrapped_input.end()); + assert(int_wrapper::constructions == 3); + assert(int_wrapper::destructions == 0); + assert(result == wrapped_input.end()); + assert(equal(wrapped_input, expected, equal_to{}, &int_wrapper::val)); + not_ranges_destroy(wrapped_input); + assert(int_wrapper::constructions == 3); + assert(int_wrapper::destructions == 3); + } + } +}; + +struct throwing_test { + template + static void call() { + // Validate only range overload (one is plenty since they both use the same backend) + holder mem; + Write wrapped_input{mem.as_span()}; + + int_wrapper::clear_counts(); + try { + (void) ranges::uninitialized_value_construct(wrapped_input); + assert(false); + } catch (int i) { + assert(i == int_wrapper::magic_throwing_val); + } catch (...) { + assert(false); + } + assert(int_wrapper::constructions == int_wrapper::magic_throwing_val); + assert(int_wrapper::destructions == int_wrapper::magic_throwing_val - 1); + } +}; + +using test_range = test::range; + +int main() { + // The algorithm is oblivious to non-required category, size, difference. It _is_ sensitive to proxyness in that it + // requires non-proxy references for the input range. + + instantiator::call(); + throwing_test::call(); +} diff --git a/tests/std/tests/P0896R4_ranges_alg_uninitialized_value_construct_n/env.lst b/tests/std/tests/P0896R4_ranges_alg_uninitialized_value_construct_n/env.lst new file mode 100644 index 00000000000..f3ccc8613c6 --- /dev/null +++ b/tests/std/tests/P0896R4_ranges_alg_uninitialized_value_construct_n/env.lst @@ -0,0 +1,4 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\concepts_matrix.lst diff --git a/tests/std/tests/P0896R4_ranges_alg_uninitialized_value_construct_n/test.cpp b/tests/std/tests/P0896R4_ranges_alg_uninitialized_value_construct_n/test.cpp new file mode 100644 index 00000000000..6a9f08449d8 --- /dev/null +++ b/tests/std/tests/P0896R4_ranges_alg_uninitialized_value_construct_n/test.cpp @@ -0,0 +1,112 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace std; + +struct int_wrapper { + inline static int constructions = 0; + inline static int destructions = 0; + + static void clear_counts() { + constructions = 0; + destructions = 0; + } + + static constexpr int magic_throwing_val = 4; + int val = 10; + + int_wrapper() { + if (++constructions == magic_throwing_val) { + throw magic_throwing_val; + } + } + + ~int_wrapper() { + ++destructions; + } + + auto operator<=>(const int_wrapper&) const = default; +}; +STATIC_ASSERT(default_initializable); + +template +struct holder { + STATIC_ASSERT(N < ~size_t{0} / sizeof(T)); + alignas(T) unsigned char space[N * sizeof(T)]; + + auto as_span() { + return span{reinterpret_cast(space + 0), N}; + } +}; + +template +void not_ranges_destroy(R&& r) { // TRANSITION, ranges::destroy + for (auto& e : r) { + destroy_at(&e); + } +} + +struct instantiator { + static constexpr int expected[3] = {10, 10, 10}; + + template + static void call() { + using ranges::uninitialized_value_construct_n, ranges::equal, ranges::equal_to, ranges::iterator_t; + + { // Validate iterator overload + holder mem; + Write wrapped_input{mem.as_span()}; + + int_wrapper::clear_counts(); + const same_as> auto result = uninitialized_value_construct_n(wrapped_input.begin(), 3); + assert(int_wrapper::constructions == 3); + assert(int_wrapper::destructions == 0); + assert(result == wrapped_input.end()); + assert(equal(wrapped_input, expected, equal_to{}, &int_wrapper::val)); + not_ranges_destroy(wrapped_input); + assert(int_wrapper::constructions == 3); + assert(int_wrapper::destructions == 3); + } + } +}; + +struct throwing_test { + template + static void call() { + holder mem; + Write wrapped_input{mem.as_span()}; + + int_wrapper::clear_counts(); + try { + (void) ranges::uninitialized_value_construct_n(wrapped_input.begin(), int_wrapper::magic_throwing_val); + assert(false); + } catch (int i) { + assert(i == int_wrapper::magic_throwing_val); + } catch (...) { + assert(false); + } + assert(int_wrapper::constructions == int_wrapper::magic_throwing_val); + assert(int_wrapper::destructions == int_wrapper::magic_throwing_val - 1); + } +}; + +using test_range = test::range; + +int main() { + // The algorithm is oblivious to non-required category, size, difference. It _is_ sensitive to proxyness in that it + // requires non-proxy references for the input range. + + instantiator::call(); + throwing_test::call(); +} diff --git a/tests/std/tests/P0896R4_ranges_alg_unique/test.cpp b/tests/std/tests/P0896R4_ranges_alg_unique/test.cpp index 3da1a4923e9..8e1ab7324c0 100644 --- a/tests/std/tests/P0896R4_ranges_alg_unique/test.cpp +++ b/tests/std/tests/P0896R4_ranges_alg_unique/test.cpp @@ -28,40 +28,35 @@ struct instantiator { template static constexpr void call() { -#if !defined(__clang__) && !defined(__EDG__) // TRANSITION, VSO-938163 - if constexpr (!ranges::contiguous_range) -#endif // TRANSITION, VSO-938163 - { - using ranges::unique, ranges::subrange, ranges::equal, ranges::size, ranges::iterator_t; + using ranges::unique, ranges::subrange, ranges::equal, ranges::size, ranges::iterator_t; - size_t comparisonCounter = 0; - const auto countedEq = make_counter(comparisonCounter); + size_t comparisonCounter = 0; + const auto countedEq = make_counter(comparisonCounter); - { // Validate iterator + sentinel overload - P input[6] = {{0, 99}, {1, 47}, {2, 47}, {3, 99}, {4, 47}, {5, 47}}; - ReadWrite wrapped_input{input}; + { // Validate iterator + sentinel overload + P input[6] = {{0, 99}, {1, 47}, {2, 47}, {3, 99}, {4, 47}, {5, 47}}; + ReadWrite wrapped_input{input}; - auto result = unique(wrapped_input.begin(), wrapped_input.end(), countedEq, get_second); - STATIC_ASSERT(same_as>>); - assert(result.begin() == next(wrapped_input.begin(), 4)); - assert(result.end() == wrapped_input.end()); - assert(equal(expected, span{input}.first<4>())); - assert(comparisonCounter == size(input) - 1); - } + auto result = unique(wrapped_input.begin(), wrapped_input.end(), countedEq, get_second); + STATIC_ASSERT(same_as>>); + assert(result.begin() == next(wrapped_input.begin(), 4)); + assert(result.end() == wrapped_input.end()); + assert(equal(expected, span{input}.first<4>())); + assert(comparisonCounter == size(input) - 1); + } - comparisonCounter = 0; + comparisonCounter = 0; - { // Validate range overload - P input[6] = {{0, 99}, {1, 47}, {2, 47}, {3, 99}, {4, 47}, {5, 47}}; - ReadWrite wrapped_input{input}; + { // Validate range overload + P input[6] = {{0, 99}, {1, 47}, {2, 47}, {3, 99}, {4, 47}, {5, 47}}; + ReadWrite wrapped_input{input}; - auto result = unique(wrapped_input, countedEq, get_second); - STATIC_ASSERT(same_as>>); - assert(result.begin() == next(wrapped_input.begin(), 4)); - assert(result.end() == wrapped_input.end()); - assert(equal(expected, span{input}.first<4>())); - assert(comparisonCounter == size(input) - 1); - } + auto result = unique(wrapped_input, countedEq, get_second); + STATIC_ASSERT(same_as>>); + assert(result.begin() == next(wrapped_input.begin(), 4)); + assert(result.end() == wrapped_input.end()); + assert(equal(expected, span{input}.first<4>())); + assert(comparisonCounter == size(input) - 1); } } }; diff --git a/tests/std/tests/P0896R4_ranges_iterator_machinery/test.cpp b/tests/std/tests/P0896R4_ranges_iterator_machinery/test.cpp index f748c811daf..3ad80d1b8fa 100644 --- a/tests/std/tests/P0896R4_ranges_iterator_machinery/test.cpp +++ b/tests/std/tests/P0896R4_ranges_iterator_machinery/test.cpp @@ -1173,9 +1173,7 @@ namespace iterator_cust_swap_test { STATIC_ASSERT(noexcept(ranges::iter_swap(&i0, &i1))); return true; } -#if defined(__clang__) || defined(__EDG__) // TRANSITION, VSO-938163 STATIC_ASSERT(test()); -#endif // TRANSITION, VSO-938163 template struct swap_proxy_ref { @@ -1277,9 +1275,6 @@ namespace iterator_cust_swap_test { assert(i1 == 42); } -#if !defined(__clang__) && !defined(__EDG__) // TRANSITION, VSO-938163 - if (!std::is_constant_evaluated()) -#endif // TRANSITION, VSO-938163 { // Validate iter_swap bullet 3 to defend against regression of GH-1067 "ranges::iter_swap is broken" int i = 42; diff --git a/tests/std/tests/P0896R4_stream_iterators/env.lst b/tests/std/tests/P0896R4_stream_iterators/env.lst new file mode 100644 index 00000000000..19f025bd0e6 --- /dev/null +++ b/tests/std/tests/P0896R4_stream_iterators/env.lst @@ -0,0 +1,4 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\usual_matrix.lst diff --git a/tests/std/tests/P0896R4_stream_iterators/test.cpp b/tests/std/tests/P0896R4_stream_iterators/test.cpp new file mode 100644 index 00000000000..e41a74fdb1d --- /dev/null +++ b/tests/std/tests/P0896R4_stream_iterators/test.cpp @@ -0,0 +1,126 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +// Covers Ranges changes to istream_iterator, ostream_iterator, istreambuf_iterator, and ostreambuf_iterator + +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +#define STATIC_ASSERT(...) static_assert(__VA_ARGS__, #__VA_ARGS__) + +template , class Diff = ptrdiff_t> +void test_istream_iterator() { + using I = istream_iterator; + + // Also test strengthened noexcept on some pre-existing operations + const I i{}; + STATIC_ASSERT(is_nothrow_default_constructible_v == is_nothrow_default_constructible_v); + STATIC_ASSERT(noexcept(*i)); + STATIC_ASSERT(noexcept(i.operator->())); + + STATIC_ASSERT(noexcept(i == i)); + STATIC_ASSERT(noexcept(i != i)); + +#ifdef __cpp_lib_concepts + STATIC_ASSERT(input_iterator); + + if constexpr (is_scalar_v) { + constexpr I fromDefaultSentinel{default_sentinel}; + assert(fromDefaultSentinel == I{}); + assert(!(fromDefaultSentinel != I{})); + STATIC_ASSERT(is_nothrow_constructible_v); + } + + assert(i == default_sentinel); + STATIC_ASSERT(noexcept(i == default_sentinel)); + assert(default_sentinel == i); + STATIC_ASSERT(noexcept(default_sentinel == i)); + assert(!(i != default_sentinel)); + STATIC_ASSERT(noexcept(!(i != default_sentinel))); + assert(!(default_sentinel != i)); + STATIC_ASSERT(noexcept(!(default_sentinel != i))); +#endif // __cpp_lib_concepts +} + +template > +void test_ostream_iterator(basic_ostream& os) { + using I = ostream_iterator; + + // Also tests strengthened noexcept on some pre-existing operations + I i{os}; + STATIC_ASSERT(is_nothrow_constructible_v&>); + STATIC_ASSERT(is_nothrow_constructible_v&, const CharT*>); + STATIC_ASSERT(noexcept(*i)); + STATIC_ASSERT(noexcept(++i)); + STATIC_ASSERT(noexcept(i++)); + +#ifdef __cpp_lib_concepts + STATIC_ASSERT(output_iterator); + + STATIC_ASSERT(is_same_v); + { [[maybe_unused]] constexpr I constexprConstructed{}; } + STATIC_ASSERT(is_nothrow_default_constructible_v); +#endif // __cpp_lib_concepts +} + +template > +void test_istreambuf_iterator() { +#ifdef __cpp_lib_concepts + using I = istreambuf_iterator; + STATIC_ASSERT(input_iterator); + + constexpr I i{default_sentinel}; + assert(i == I{}); + assert(!(i != I{})); + STATIC_ASSERT(is_nothrow_constructible_v); + + assert(i == default_sentinel); + assert(default_sentinel == i); + assert(!(i != default_sentinel)); + assert(!(default_sentinel != i)); +#endif // __cpp_lib_concepts +} + +template > +void test_ostreambuf_iterator(basic_ostream& os) { + using I = ostreambuf_iterator; + + // Also tests strengthened noexcept on some pre-existing operations + I i{os}; + STATIC_ASSERT(noexcept(*i)); + STATIC_ASSERT(noexcept(++i)); + STATIC_ASSERT(noexcept(i++)); + +#ifdef __cpp_lib_concepts + STATIC_ASSERT(output_iterator); + + STATIC_ASSERT(is_same_v); + { [[maybe_unused]] constexpr I constexprConstructed{}; } + STATIC_ASSERT(is_nothrow_default_constructible_v); +#endif // __cpp_lib_concepts +} + +int main() { + test_istream_iterator(); + test_istream_iterator(); + test_istream_iterator(); + test_istream_iterator(); + + test_ostream_iterator(cout); + test_ostream_iterator(cout); + test_ostream_iterator(wcout); + test_ostream_iterator(wcout); + + test_istreambuf_iterator(); + test_istreambuf_iterator(); + + test_ostreambuf_iterator(cout); + test_ostreambuf_iterator(wcout); +} diff --git a/tests/std/tests/P0896R4_views_drop/test.cpp b/tests/std/tests/P0896R4_views_drop/test.cpp index aae2ce6f41b..d2795e28e09 100644 --- a/tests/std/tests/P0896R4_views_drop/test.cpp +++ b/tests/std/tests/P0896R4_views_drop/test.cpp @@ -184,9 +184,6 @@ constexpr bool test_one(Rng&& rng, Expected&& expected) { const bool is_empty = ranges::empty(expected); // Validate deduction guide -#if !defined(__clang__) && !defined(__EDG__) // TRANSITION, DevCom-1159442 - (void) 42; -#endif // TRANSITION, DevCom-1159442 same_as> auto r = drop_view{forward(rng), 4}; using R = decltype(r); STATIC_ASSERT(ranges::view); @@ -442,17 +439,16 @@ constexpr void move_only_test() { } constexpr void output_range_test() { -#if !defined(__clang__) && !defined(__EDG__) // TRANSITION, VSO-938163 - if (!is_constant_evaluated()) -#endif // TRANSITION, VSO-938163 - { - using R = test::range; - int some_writable_ints[] = {0, 1, 2, 3}; - STATIC_ASSERT(same_as>); - ranges::fill(R{some_writable_ints} | views::drop(2), 42); - assert(ranges::equal(some_writable_ints, initializer_list{0, 1, 42, 42})); - } + using R = test::range; + int some_writable_ints[] = {0, 1, 2, 3}; + STATIC_ASSERT(same_as>); +#if !defined(__clang__) && !defined(__EDG__) // TRANSITION, VSO-1217687 + ranges::fill(views::drop(R{some_writable_ints}, 2), 42); +#else // ^^^ workaround / no workaround vvv + ranges::fill(R{some_writable_ints} | views::drop(2), 42); +#endif // TRANSITION, VSO-1217687 + assert(ranges::equal(some_writable_ints, initializer_list{0, 1, 42, 42})); } int main() { diff --git a/tests/std/tests/P0896R4_views_take/test.cpp b/tests/std/tests/P0896R4_views_take/test.cpp index b0d35fc3900..cb18fa20929 100644 --- a/tests/std/tests/P0896R4_views_take/test.cpp +++ b/tests/std/tests/P0896R4_views_take/test.cpp @@ -183,9 +183,6 @@ constexpr bool test_one(Rng&& rng, Expected&& expected) { const bool is_empty = ranges::empty(expected); // Validate deduction guide -#if !defined(__clang__) && !defined(__EDG__) // TRANSITION, DevCom-1159442 - (void) 42; -#endif // TRANSITION, DevCom-1159442 same_as> auto r = take_view{forward(rng), 4}; using R = decltype(r); STATIC_ASSERT(ranges::view); @@ -460,9 +457,9 @@ constexpr void move_only_test() { } constexpr void output_range_test() { -#if !defined(__clang__) && !defined(__EDG__) // TRANSITION, VSO-938163 +#if !defined(__clang__) && !defined(__EDG__) // TRANSITION, VSO-1132704 if (!is_constant_evaluated()) -#endif // TRANSITION, VSO-938163 +#endif // TRANSITION, VSO-1132704 { using R = test::range; @@ -470,10 +467,18 @@ constexpr void output_range_test() { STATIC_ASSERT(same_as>); // How do I implement "Fill up to n elements in {output range} with {value}"? +#if !defined(__clang__) && !defined(__EDG__) // TRANSITION, VSO-1217687 + ranges::fill(views::take(R{some_writable_ints}, 99999), 42); +#else // ^^^ workaround / no workaround vvv ranges::fill(R{some_writable_ints} | views::take(99999), 42); +#endif // TRANSITION, VSO-1217687 assert(ranges::equal(some_writable_ints, initializer_list{42, 42, 42, 42})); +#if !defined(__clang__) && !defined(__EDG__) // TRANSITION, VSO-1217687 + ranges::fill(views::take(R{some_writable_ints}, 3), 13); +#else // ^^^ workaround / no workaround vvv ranges::fill(R{some_writable_ints} | views::take(3), 13); +#endif // TRANSITION, VSO-1217687 assert(ranges::equal(some_writable_ints, initializer_list{13, 13, 13, 42})); } } diff --git a/tests/std/tests/P0896R4_views_transform/test.cpp b/tests/std/tests/P0896R4_views_transform/test.cpp index fb03a17c0f0..a683ba68583 100644 --- a/tests/std/tests/P0896R4_views_transform/test.cpp +++ b/tests/std/tests/P0896R4_views_transform/test.cpp @@ -159,9 +159,6 @@ constexpr bool test_one(Rng&& rng, Expected&& expected) { const bool is_empty = ranges::empty(expected); // Validate deduction guide -#if !defined(__clang__) && !defined(__EDG__) // TRANSITION, DevCom-1159442 - (void) 42; -#endif // TRANSITION, DevCom-1159442 same_as auto r = transform_view{forward(rng), add8}; using R = decltype(r); STATIC_ASSERT(ranges::view); diff --git a/tests/std/tests/P1007R3_assume_aligned/env.lst b/tests/std/tests/P1007R3_assume_aligned/env.lst new file mode 100644 index 00000000000..642f530ffad --- /dev/null +++ b/tests/std/tests/P1007R3_assume_aligned/env.lst @@ -0,0 +1,4 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\usual_latest_matrix.lst diff --git a/tests/std/tests/P1007R3_assume_aligned/test.cpp b/tests/std/tests/P1007R3_assume_aligned/test.cpp new file mode 100644 index 00000000000..a878589d1fb --- /dev/null +++ b/tests/std/tests/P1007R3_assume_aligned/test.cpp @@ -0,0 +1,43 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include + +constexpr void can_change_value_via_assume_aligned(int* p) { + int* p1 = std::assume_aligned<256>(p); + p1[0] = 10; + p1[1] = -15; +} + +constexpr int can_read_value_via_assume_aligned_and_sum_it(int const* p, size_t size) { + int const* p1 = std::assume_aligned<256>(p); + int result = 0; + for (size_t i = 0; i < size; ++i) { + result += p1[i]; + } + return result; +} + +constexpr bool assume_aligned_can_change_value() { + alignas(256) int arr[2] = {0, 0}; + can_change_value_via_assume_aligned(&arr[0]); + assert(arr[0] == 10); + assert(arr[1] == -15); + return true; +} + +constexpr bool assume_aligned_can_read_value() { + alignas(256) constexpr int arr[3] = {10, 11, 9}; + assert(can_read_value_via_assume_aligned_and_sum_it(arr, 3) == 30); + return true; +} + +int main() { + assume_aligned_can_change_value(); + static_assert(assume_aligned_can_change_value()); + + assume_aligned_can_read_value(); + static_assert(assume_aligned_can_read_value()); +} diff --git a/tests/std/tests/VSO_0105317_expression_sfinae/test.cpp b/tests/std/tests/VSO_0105317_expression_sfinae/test.cpp index e65467d1dd5..2884e162cbf 100644 --- a/tests/std/tests/VSO_0105317_expression_sfinae/test.cpp +++ b/tests/std/tests/VSO_0105317_expression_sfinae/test.cpp @@ -19,14 +19,16 @@ using namespace std; #if _HAS_CXX17 template struct HasInvokeResultT : false_type { - STATIC_ASSERT(!is_invocable_v); + STATIC_ASSERT(!is_nothrow_invocable_v); + STATIC_ASSERT(!is_invocable_r_v); + STATIC_ASSERT(!is_nothrow_invocable_r_v); }; template struct HasInvokeResultT>, Callable, Args...> : true_type { - STATIC_ASSERT(is_invocable_v); + STATIC_ASSERT(is_invocable_r_v); }; template @@ -584,6 +586,12 @@ STATIC_ASSERT(is_nothrow_invocable_r_v); STATIC_ASSERT(is_invocable_r_v); STATIC_ASSERT(!is_nothrow_invocable_r_v); +// When the return type is void, does the invocation throw? +STATIC_ASSERT(is_invocable_r_v); +STATIC_ASSERT(is_nothrow_invocable_r_v); +STATIC_ASSERT(is_invocable_r_v); +STATIC_ASSERT(!is_nothrow_invocable_r_v); + struct Puppy { explicit Puppy(int); Puppy(long) noexcept; @@ -605,6 +613,38 @@ STATIC_ASSERT(is_nothrow_invocable_r_v); STATIC_ASSERT(is_invocable_r_v); STATIC_ASSERT(!is_nothrow_invocable_r_v); +#if defined(__clang__) || defined(__EDG__) // TRANSITION, VSO-1026729 +// Defend against regression of VSO-963790, in which is_invocable_r mishandles non-movable return types +struct NonMovable { + NonMovable(NonMovable&&) = delete; + NonMovable(const NonMovable&) = delete; +}; + +template +NonMovable getNonMovable() noexcept(Nothrow); + +STATIC_ASSERT(is_invocable_r_v)>); +STATIC_ASSERT(is_invocable_r_v)>); +STATIC_ASSERT(!is_nothrow_invocable_r_v)>); +STATIC_ASSERT(is_nothrow_invocable_r_v)>); + +template +struct ConvertsToNonMovable { + operator NonMovable() const noexcept(Nothrow); +}; + +template +ConvertsToNonMovable getConvertsToNonMovable() noexcept(Nothrow); + +STATIC_ASSERT(is_invocable_r_v)>); +STATIC_ASSERT(is_invocable_r_v)>); +STATIC_ASSERT(is_invocable_r_v)>); +STATIC_ASSERT(is_invocable_r_v)>); +STATIC_ASSERT(!is_nothrow_invocable_r_v)>); +STATIC_ASSERT(!is_nothrow_invocable_r_v)>); +STATIC_ASSERT(!is_nothrow_invocable_r_v)>); +STATIC_ASSERT(is_nothrow_invocable_r_v)>); +#endif // TRANSITION, VSO-1026729 #endif // _HAS_CXX17 diff --git a/tests/std/tests/VSO_0157762_feature_test_macros/test.cpp b/tests/std/tests/VSO_0157762_feature_test_macros/test.cpp index 455494fdd26..153a5e821fc 100644 --- a/tests/std/tests/VSO_0157762_feature_test_macros/test.cpp +++ b/tests/std/tests/VSO_0157762_feature_test_macros/test.cpp @@ -83,6 +83,20 @@ STATIC_ASSERT(__cpp_lib_array_constexpr == 201803L); STATIC_ASSERT(__cpp_lib_as_const == 201510L); #endif +#if _HAS_CXX20 +#ifndef __cpp_lib_assume_aligned +#error __cpp_lib_assume_aligned is not defined +#elif __cpp_lib_assume_aligned != 201811L +#error __cpp_lib_assume_aligned is not 201811L +#else +STATIC_ASSERT(__cpp_lib_assume_aligned == 201811L); +#endif +#else +#ifdef __cpp_lib_assume_aligned +#error __cpp_lib_assume_aligned is defined +#endif +#endif + #if _HAS_CXX20 #ifndef __cpp_lib_atomic_flag_test #error __cpp_lib_atomic_flag_test is not defined @@ -862,6 +876,20 @@ STATIC_ASSERT(__cpp_lib_is_swappable == 201603L); #endif #endif +#if _HAS_CXX20 +#ifndef __cpp_lib_jthread +#error __cpp_lib_jthread is not defined +#elif __cpp_lib_jthread != 201911L +#error __cpp_lib_jthread is not 201911L +#else +STATIC_ASSERT(__cpp_lib_jthread == 201911L); +#endif +#else +#ifdef __cpp_lib_jthread +#error __cpp_lib_jthread is defined +#endif +#endif + #if _HAS_CXX20 #ifndef __cpp_lib_latch #error __cpp_lib_latch is not defined @@ -1064,6 +1092,20 @@ STATIC_ASSERT(__cpp_lib_parallel_algorithm == 201603L); #endif #endif +#if _HAS_CXX20 +#ifndef __cpp_lib_polymorphic_allocator +#error __cpp_lib_polymorphic_allocator is not defined +#elif __cpp_lib_polymorphic_allocator != 201902L +#error __cpp_lib_polymorphic_allocator is not 201902L +#else +STATIC_ASSERT(__cpp_lib_polymorphic_allocator == 201902L); +#endif +#else +#ifdef __cpp_lib_polymorphic_allocator +#error __cpp_lib_polymorphic_allocator is defined +#endif +#endif + #ifndef __cpp_lib_quoted_string_io #error __cpp_lib_quoted_string_io is not defined #elif __cpp_lib_quoted_string_io != 201304L diff --git a/tests/std/tests/include_each_header_alone_matrix.lst b/tests/std/tests/include_each_header_alone_matrix.lst index 71cb23f8d3d..6728e9f7124 100644 --- a/tests/std/tests/include_each_header_alone_matrix.lst +++ b/tests/std/tests/include_each_header_alone_matrix.lst @@ -62,6 +62,7 @@ PM_CL="/DMEOW_HEADER=span" PM_CL="/DMEOW_HEADER=sstream" PM_CL="/DMEOW_HEADER=stack" PM_CL="/DMEOW_HEADER=stdexcept" +PM_CL="/DMEOW_HEADER=stop_token" PM_CL="/DMEOW_HEADER=streambuf" PM_CL="/DMEOW_HEADER=string" PM_CL="/DMEOW_HEADER=string_view" diff --git a/tests/utils/stl/compiler.py b/tests/utils/stl/compiler.py index 6a638046938..ff5d4ef3bdd 100644 --- a/tests/utils/stl/compiler.py +++ b/tests/utils/stl/compiler.py @@ -22,7 +22,7 @@ class CXXCompiler: CM_Analyze = 4 def __init__(self, path, flags=None, compile_flags=None, - link_flags=None, compile_env=None): + link_flags=None, compile_env=None, edg_drop=None): self.path = path if path is not None: self.name = os.path.basename(path).split('.')[0] @@ -34,6 +34,7 @@ def __init__(self, path, flags=None, compile_flags=None, self.link_flags = link_flags or [] self.compile_env = compile_env + self.edg_drop = edg_drop def _basicCmd(self, source_files: List[Path], out: Path, mode=CM_Default, flags=[], compile_flags=[], link_flags=[], diff --git a/tests/utils/stl/test/config.py b/tests/utils/stl/test/config.py index d9a6c040352..e8f1fd773c4 100644 --- a/tests/utils/stl/test/config.py +++ b/tests/utils/stl/test/config.py @@ -298,6 +298,10 @@ def configure_default_compiler(self): self.default_compiler.compile_env = self.config.environment + env_var = 'STL_EDG_DROP' + if env_var in os.environ and os.environ[env_var] is not None: + self.default_compiler.edg_drop = os.environ[env_var] + # TRANSITION: Investigate using SSHExecutor for ARM def configure_executors(self): self.build_executor = LocalExecutor() diff --git a/tests/utils/stl/test/format.py b/tests/utils/stl/test/format.py index 8132ba29b3f..d82a1fa9180 100644 --- a/tests/utils/stl/test/format.py +++ b/tests/utils/stl/test/format.py @@ -244,14 +244,44 @@ def getBuildSteps(self, test, lit_config, shared): output_dir = test.getOutputDir() source_path = Path(test.getSourcePath()) + flags = [] + isense_rsp_path = None + if test.cxx.edg_drop is not None: + isense_rsp_path = output_dir / (output_base + '.isense.rsp') + flags.extend(['/dE--write-isense-rsp', '/dE' + str(isense_rsp_path)]) + cmd, out_files, shared.exec_file = \ test.cxx.executeBasedOnFlagsCmd([source_path], output_dir, shared.exec_dir, output_base, - [], [], []) + flags, [], []) yield TestStep(cmd, shared.exec_dir, [source_path], test.cxx.compile_env) + if isense_rsp_path is not None: + with open(isense_rsp_path) as f: + cmd = [line.strip() for line in f] + cmd[0] = test.cxx.edg_drop + + # cpfecl translates /Fo into --import_dir, but that is not + # used in the same way by upstream EDG. + try: + index = cmd.index('--import_dir') + cmd.pop(index) + cmd.pop(index) + except ValueError: + pass + + # --print_diagnostics is not recognized by upstream EDG. + try: + index = cmd.index('--print_diagnostics') + cmd.pop(index) + except ValueError: + pass + + yield TestStep(cmd, shared.exec_dir, [source_path], + test.cxx.compile_env) + def getTestSteps(self, test, lit_config, shared): if shared.exec_file is not None: exec_env = test.cxx.compile_env diff --git a/tests/utils/stl/test/tests.py b/tests/utils/stl/test/tests.py index 6728132870a..0dce11f5afe 100644 --- a/tests/utils/stl/test/tests.py +++ b/tests/utils/stl/test/tests.py @@ -34,6 +34,7 @@ def __init__(self, suite, path_in_suite, lit_config, test_config, self._configure_cxx(lit_config, envlst_entry, default_cxx) + use_edg = False for flag in chain(self.cxx.flags, self.cxx.compile_flags): if flag[1:] == 'clr:pure': self.requires.append('clr_pure') # TRANSITION, GH-798 @@ -41,6 +42,10 @@ def __init__(self, suite, path_in_suite, lit_config, test_config, self.requires.append('clr') # TRANSITION, GH-797 elif flag[1:] == 'BE': self.requires.append('edg') # available for x86, see config.py + use_edg = True + + if not use_edg and self.cxx.edg_drop is not None: + self.skipped = True def getOutputDir(self): return Path(os.path.join( @@ -142,7 +147,7 @@ def _configure_cxx(self, lit_config, envlst_entry, default_cxx): compile_flags.append('-m32') self.cxx = CXXCompiler(cxx, flags, compile_flags, link_flags, - default_cxx.compile_env) + default_cxx.compile_env, default_cxx.edg_drop) # This is partially lifted from lit's Test class. The changes here are to # handle skipped tests, our env.lst format, and different naming schemes. diff --git a/tools/parallelize/parallelize.cpp b/tools/parallelize/parallelize.cpp index 59a8173d62e..8fa82216ce1 100644 --- a/tools/parallelize/parallelize.cpp +++ b/tools/parallelize/parallelize.cpp @@ -158,8 +158,7 @@ extern "C" int wmain(int argc, wchar_t* argv[]) { L".hpp"sv, }; - // TRANSITION, P0202R3, use constexpr is_sorted() - assert(std::is_sorted(accepted_extensions.begin(), accepted_extensions.end())); + static_assert(std::is_sorted(accepted_extensions.begin(), accepted_extensions.end())); if (argc < 3) { puts("Usage: parallelize.exe commandPrefix pathRoot0 [... pathRootN]\n"