diff --git a/CMakeLists.txt b/CMakeLists.txt index 5eb09a74e84..f85527c87f1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,7 @@ # Copyright (c) Microsoft Corporation. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -cmake_minimum_required(VERSION 3.28.0) +cmake_minimum_required(VERSION 3.29.0) set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY) project(msvc_standard_libraries LANGUAGES CXX) @@ -58,7 +58,6 @@ if("${VCLIBS_TARGET_ARCHITECTURE}" STREQUAL "x86") # Note that we set _WIN32_WINNT to a high level to make declarations available, but still engage downlevel # runtime dynamic linking by setting our own _STL_WIN32_WINNT back to Windows XP. add_compile_definitions(_X86_ _VCRT_WIN32_WINNT=0x0501 _STL_WIN32_WINNT=0x0501) - add_compile_options($<$:/arch:IA32>) elseif(VCLIBS_TARGET_ARCHITECTURE STREQUAL "x64") set(VCLIBS_TARGET_ARCHITECTURE "x64") set(VCLIBS_I386_OR_AMD64 "amd64") diff --git a/README.md b/README.md index 92a1d1062b9..56cd3ab20b1 100644 --- a/README.md +++ b/README.md @@ -141,11 +141,11 @@ Just try to follow these rules, so we can spend more time fixing bugs and implem # How To Build With The Visual Studio IDE -1. Install Visual Studio 2022 17.11 Preview 2 or later. +1. Install Visual Studio 2022 17.11 Preview 3 or later. * Select "Windows 11 SDK (10.0.22621.0)" in the VS Installer. * We recommend selecting "C++ CMake tools for Windows" in the VS Installer. This will ensure that you're using supported versions of CMake and Ninja. - * Otherwise, install [CMake][] 3.28.0 or later, and [Ninja][] 1.11.0 or later. + * Otherwise, install [CMake][] 3.29.0 or later, and [Ninja][] 1.11.0 or later. * Make sure [Python][] 3.12 or later is available to CMake. 2. Open Visual Studio, and choose the "Clone or check out code" option. Enter the URL of this repository, `https://github.com/microsoft/STL`. @@ -156,11 +156,11 @@ Just try to follow these rules, so we can spend more time fixing bugs and implem # How To Build With A Native Tools Command Prompt -1. Install Visual Studio 2022 17.11 Preview 2 or later. +1. Install Visual Studio 2022 17.11 Preview 3 or later. * Select "Windows 11 SDK (10.0.22621.0)" in the VS Installer. * We recommend selecting "C++ CMake tools for Windows" in the VS Installer. This will ensure that you're using supported versions of CMake and Ninja. - * Otherwise, install [CMake][] 3.28.0 or later, and [Ninja][] 1.11.0 or later. + * Otherwise, install [CMake][] 3.29.0 or later, and [Ninja][] 1.11.0 or later. * Make sure [Python][] 3.12 or later is available to CMake. 2. Open a command prompt. 3. Change directories to a location where you'd like a clone of this STL repository. diff --git a/azure-devops/config.yml b/azure-devops/config.yml index 43ac66c6059..a7da64abd9c 100644 --- a/azure-devops/config.yml +++ b/azure-devops/config.yml @@ -5,7 +5,7 @@ variables: - name: poolName - value: 'StlBuild-2024-06-11T1315-Pool' + value: 'StlBuild-2024-07-09T1614-Pool' readonly: true - name: poolDemands value: 'EnableSpotVM -equals false' diff --git a/azure-devops/create-1es-hosted-pool.ps1 b/azure-devops/create-1es-hosted-pool.ps1 index c996e8d74ba..307c511a7c8 100644 --- a/azure-devops/create-1es-hosted-pool.ps1 +++ b/azure-devops/create-1es-hosted-pool.ps1 @@ -13,7 +13,7 @@ $ErrorActionPreference = 'Stop' $CurrentDate = Get-Date -$Location = 'eastus' +$Location = 'eastus2' $VMSize = 'Standard_D32ads_v5' $ProtoVMName = 'PROTOTYPE' $ImagePublisher = 'MicrosoftWindowsServer' diff --git a/azure-devops/provision-image.ps1 b/azure-devops/provision-image.ps1 index 826fa4bfea5..097bc2fd53a 100644 --- a/azure-devops/provision-image.ps1 +++ b/azure-devops/provision-image.ps1 @@ -40,7 +40,7 @@ foreach ($workload in $VisualStudioWorkloads) { } # https://github.com/PowerShell/PowerShell/releases/latest -$PowerShellUrl = 'https://github.com/PowerShell/PowerShell/releases/download/v7.4.2/PowerShell-7.4.2-win-x64.msi' +$PowerShellUrl = 'https://github.com/PowerShell/PowerShell/releases/download/v7.4.3/PowerShell-7.4.3-win-x64.msi' $PowerShellArgs = @('/quiet', '/norestart') $PythonUrl = 'https://www.python.org/ftp/python/3.12.4/python-3.12.4-amd64.exe' diff --git a/benchmarks/CMakeLists.txt b/benchmarks/CMakeLists.txt index bb6ebbf4030..32c6e1925fa 100644 --- a/benchmarks/CMakeLists.txt +++ b/benchmarks/CMakeLists.txt @@ -1,7 +1,7 @@ # Copyright (c) Microsoft Corporation. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -cmake_minimum_required(VERSION 3.28.0) +cmake_minimum_required(VERSION 3.29.0) project(msvc_standard_libraries_benchmarks LANGUAGES CXX) if(DEFINED STL_BINARY_DIR) diff --git a/benchmarks/src/bitset_to_string.cpp b/benchmarks/src/bitset_to_string.cpp index c5f012c6a18..5fc88147839 100644 --- a/benchmarks/src/bitset_to_string.cpp +++ b/benchmarks/src/bitset_to_string.cpp @@ -13,29 +13,40 @@ using namespace std; namespace { - const auto random_bits = [] { + template + auto random_bits_init() { mt19937_64 rnd{}; - array arr; + array arr; for (auto& d : arr) { d = rnd(); } return arr; - }(); + } + + template + const auto random_bits = random_bits_init(); template void BM_bitset_to_string(benchmark::State& state) { + static_assert(N <= 64); + for (auto _ : state) { - for (const auto& bits : random_bits) { + for (const auto& bits : random_bits<>) { + benchmark::DoNotOptimize(bits); bitset bs{bits}; benchmark::DoNotOptimize(bs.to_string()); } } } - template + template void BM_bitset_to_string_large_single(benchmark::State& state) { - const auto large_bitset = bit_cast>(random_bits); + static_assert(N % 64 == 0 && N >= 64); + const auto& bitset_data = random_bits; + + const auto large_bitset = bit_cast>(bitset_data); for (auto _ : state) { + benchmark::DoNotOptimize(large_bitset); benchmark::DoNotOptimize(large_bitset.to_string()); } } @@ -43,11 +54,11 @@ namespace { BENCHMARK(BM_bitset_to_string<15, char>); BENCHMARK(BM_bitset_to_string<64, char>); -BENCHMARK(BM_bitset_to_string<512, char>); -BENCHMARK(BM_bitset_to_string_large_single); +BENCHMARK(BM_bitset_to_string_large_single<512, char>); +BENCHMARK(BM_bitset_to_string_large_single<2048, char>); BENCHMARK(BM_bitset_to_string<7, wchar_t>); BENCHMARK(BM_bitset_to_string<64, wchar_t>); -BENCHMARK(BM_bitset_to_string<512, wchar_t>); -BENCHMARK(BM_bitset_to_string_large_single); +BENCHMARK(BM_bitset_to_string_large_single<512, wchar_t>); +BENCHMARK(BM_bitset_to_string_large_single<2048, wchar_t>); BENCHMARK_MAIN(); diff --git a/stl/CMakeLists.txt b/stl/CMakeLists.txt index 9c9157623e0..ad8fecd9862 100644 --- a/stl/CMakeLists.txt +++ b/stl/CMakeLists.txt @@ -557,7 +557,7 @@ function(add_stl_dlls D_SUFFIX REL_OR_DBG) generate_satellite_def("atomic_wait" "${D_SUFFIX}") add_library(msvcp${D_SUFFIX}_atomic_wait SHARED "${CMAKE_BINARY_DIR}/msvcp_atomic_wait${D_SUFFIX}.def") - target_link_libraries(msvcp${D_SUFFIX}_atomic_wait PRIVATE msvcp${D_SUFFIX}_atomic_wait_objects msvcp${D_SUFFIX}_satellite_objects msvcp${D_SUFFIX}_implib_objects "msvcp${D_SUFFIX}" "${TOOLSET_LIB}/vcruntime${D_SUFFIX}.lib" "${TOOLSET_LIB}/msvcrt${D_SUFFIX}.lib" "ucrt${D_SUFFIX}.lib" "advapi32.lib") + target_link_libraries(msvcp${D_SUFFIX}_atomic_wait PRIVATE msvcp${D_SUFFIX}_atomic_wait_objects msvcp${D_SUFFIX}_satellite_objects msvcp${D_SUFFIX}_implib_objects "msvcp${D_SUFFIX}" "${TOOLSET_LIB}/vcruntime${D_SUFFIX}.lib" "${TOOLSET_LIB}/msvcrt${D_SUFFIX}.lib" "ucrt${D_SUFFIX}.lib" "advapi32.lib" "synchronization.lib") set_target_properties(msvcp${D_SUFFIX}_atomic_wait PROPERTIES ARCHIVE_OUTPUT_NAME "msvcp140_atomic_wait${D_SUFFIX}${VCLIBS_SUFFIX}") set_target_properties(msvcp${D_SUFFIX}_atomic_wait PROPERTIES ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}") set_target_properties(msvcp${D_SUFFIX}_atomic_wait PROPERTIES OUTPUT_NAME "msvcp140${D_SUFFIX}_atomic_wait${VCLIBS_SUFFIX}") diff --git a/stl/inc/__msvc_bit_utils.hpp b/stl/inc/__msvc_bit_utils.hpp index 7537edb3ef3..eb86c43d0f4 100644 --- a/stl/inc/__msvc_bit_utils.hpp +++ b/stl/inc/__msvc_bit_utils.hpp @@ -300,9 +300,8 @@ _NODISCARD int _Checked_x86_x64_countr_zero(const _Ty _Val) noexcept { #endif // _HAS_TZCNT_BSF_INTRINSICS -// TRANSITION, remove `_MSC_VER > 1940` check after MSVC-internal toolset update -#if (defined(_M_IX86) || defined(_M_X64) || (defined(_M_ARM64) && _MSC_VER > 1940)) && !defined(_M_CEE_PURE) \ - && !defined(__CUDACC__) && !defined(__INTEL_COMPILER) +#if (defined(_M_IX86) || defined(_M_X64) || defined(_M_ARM64)) && !defined(_M_CEE_PURE) && !defined(__CUDACC__) \ + && !defined(__INTEL_COMPILER) #define _HAS_POPCNT_INTRINSICS 1 #if defined(__AVX__) || defined(_M_ARM64) || defined(_M_ARM64EC) #define _POPCNT_INTRINSICS_ALWAYS_AVAILABLE 1 diff --git a/stl/inc/__msvc_chrono.hpp b/stl/inc/__msvc_chrono.hpp index cad459cf814..08268b83b84 100644 --- a/stl/inc/__msvc_chrono.hpp +++ b/stl/inc/__msvc_chrono.hpp @@ -640,7 +640,7 @@ namespace chrono { return time_point<_Clock, _To>(_CHRONO round<_To>(_Time.time_since_epoch())); } - _EXPORT_STD struct system_clock { // wraps GetSystemTimePreciseAsFileTime/GetSystemTimeAsFileTime + _EXPORT_STD struct system_clock { // wraps GetSystemTimePreciseAsFileTime using rep = long long; using period = ratio<1, 10'000'000>; // 100 nanoseconds using duration = _CHRONO duration; diff --git a/stl/inc/__msvc_formatter.hpp b/stl/inc/__msvc_formatter.hpp index a27138106bb..5ff1bea2f4b 100644 --- a/stl/inc/__msvc_formatter.hpp +++ b/stl/inc/__msvc_formatter.hpp @@ -47,6 +47,9 @@ #include #include #include +#if _HAS_CXX23 +#include +#endif // _HAS_CXX23 #pragma pack(push, _CRT_PACKING) #pragma warning(push, _STL_WARNING_LEVEL) @@ -268,17 +271,91 @@ struct formatter, _CharT> }; #if _HAS_CXX23 -_EXPORT_STD template -struct pair; +template <> +struct formatter { + formatter() = delete; + formatter(const formatter&) = delete; + formatter& operator=(const formatter&) = delete; +}; + +template <> +struct formatter { + formatter() = delete; + formatter(const formatter&) = delete; + formatter& operator=(const formatter&) = delete; +}; + +template +struct formatter { + formatter() = delete; + formatter(const formatter&) = delete; + formatter& operator=(const formatter&) = delete; +}; -_EXPORT_STD template -class tuple; +template +struct formatter, wchar_t> { + formatter() = delete; + formatter(const formatter&) = delete; + formatter& operator=(const formatter&) = delete; +}; -// Specializations for pairs and tuples are forward-declared to avoid any risk of using the disabled primary template. +template +struct formatter, wchar_t> { + formatter() = delete; + formatter(const formatter&) = delete; + formatter& operator=(const formatter&) = delete; +}; + +_EXPORT_STD enum class range_format { disabled, map, set, sequence, string, debug_string }; + +template +struct _Invalid_format_kind { + static_assert(_Always_false<_Ty>, "A program that instantiates the primary template of format_kind is ill-formed. " + "(N4981 [format.range.fmtkind]/1)"); +}; + +_EXPORT_STD template +constexpr _Invalid_format_kind<_Ty> format_kind; + +template +constexpr bool _Is_two_tuple = false; + +template +constexpr bool _Is_two_tuple> = true; + +template +constexpr bool _Is_two_tuple> = true; + +template <_RANGES input_range _Rng> + requires same_as<_Rng, remove_cvref_t<_Rng>> +constexpr range_format format_kind<_Rng> = []() consteval { + using _Ref_value_t = remove_cvref_t<_RANGES range_reference_t<_Rng>>; + if constexpr (same_as<_Ref_value_t, _Rng>) { + return range_format::disabled; + } else if constexpr (requires { typename _Rng::key_type; }) { + if constexpr (requires { typename _Rng::mapped_type; } && _Is_two_tuple<_Ref_value_t>) { + return range_format::map; + } else { + return range_format::set; + } + } else { + return range_format::sequence; + } +}(); + +// Specializations for pairs, tuples, and ranges are forward-declared to avoid any risk of using the disabled primary +// template. // Per LWG-3997, `_CharT` in library-provided `formatter` specializations is // constrained to character types supported by `format`. +template +concept _Formatting_enabled_range = format_kind<_Rng> != range_format::disabled; + +template <_RANGES input_range _Rng, _Format_supported_charT _CharT> + requires _Formatting_enabled_range<_Rng> +struct formatter<_Rng, _CharT>; + template <_Format_supported_charT _CharT, class _Ty1, class _Ty2> struct formatter, _CharT>; diff --git a/stl/inc/__msvc_int128.hpp b/stl/inc/__msvc_int128.hpp index 306bb9e8b03..cef5bd87c0a 100644 --- a/stl/inc/__msvc_int128.hpp +++ b/stl/inc/__msvc_int128.hpp @@ -328,18 +328,18 @@ struct } #if _HAS_CXX20 - _NODISCARD_FRIEND constexpr bool operator==(const _Base128&, const _Base128&) noexcept = default; + _NODISCARD friend constexpr bool operator==(const _Base128&, const _Base128&) noexcept = default; #else // ^^^ _HAS_CXX20 / !_HAS_CXX20 vvv - _NODISCARD_FRIEND constexpr bool operator==(const _Base128& _Left, const _Base128& _Right) noexcept { + _NODISCARD friend constexpr bool operator==(const _Base128& _Left, const _Base128& _Right) noexcept { return _Left._Word[0] == _Right._Word[0] && _Left._Word[1] == _Right._Word[1]; } - _NODISCARD_FRIEND constexpr bool operator!=(const _Base128& _Left, const _Base128& _Right) noexcept { + _NODISCARD friend constexpr bool operator!=(const _Base128& _Left, const _Base128& _Right) noexcept { return !(_Left == _Right); } #endif // ^^^ !_HAS_CXX20 ^^^ - _NODISCARD_FRIEND constexpr bool operator<(const _Base128& _Left, const _Base128& _Right) noexcept { + _NODISCARD friend constexpr bool operator<(const _Base128& _Left, const _Base128& _Right) noexcept { if (_Left._Word[1] < _Right._Word[1]) { return true; } @@ -349,23 +349,23 @@ struct } return _Left._Word[0] < _Right._Word[0]; } - _NODISCARD_FRIEND constexpr bool operator>(const _Base128& _Left, const _Base128& _Right) noexcept { + _NODISCARD friend constexpr bool operator>(const _Base128& _Left, const _Base128& _Right) noexcept { return _Right < _Left; } - _NODISCARD_FRIEND constexpr bool operator<=(const _Base128& _Left, const _Base128& _Right) noexcept { + _NODISCARD friend constexpr bool operator<=(const _Base128& _Left, const _Base128& _Right) noexcept { return !(_Right < _Left); } - _NODISCARD_FRIEND constexpr bool operator>=(const _Base128& _Left, const _Base128& _Right) noexcept { + _NODISCARD friend constexpr bool operator>=(const _Base128& _Left, const _Base128& _Right) noexcept { return !(_Left < _Right); } _TEMPLATE_CLASS_INTEGRAL(_Ty) - _NODISCARD_FRIEND constexpr _Ty operator<<(const _Ty _Left, const _Base128& _Right) noexcept { + _NODISCARD friend constexpr _Ty operator<<(const _Ty _Left, const _Base128& _Right) noexcept { return _Left << _Right._Word[0]; } _TEMPLATE_CLASS_INTEGRAL(_Ty) - _NODISCARD_FRIEND constexpr _Ty operator>>(const _Ty _Left, const _Base128& _Right) noexcept { + _NODISCARD friend constexpr _Ty operator>>(const _Ty _Left, const _Base128& _Right) noexcept { return _Left >> _Right._Word[0]; } @@ -720,7 +720,7 @@ struct _Unsigned128 : _Base128 { } #if _HAS_CXX20 - _NODISCARD_FRIEND constexpr strong_ordering operator<=>( + _NODISCARD friend constexpr strong_ordering operator<=>( const _Unsigned128& _Left, const _Unsigned128& _Right) noexcept { strong_ordering _Ord = _Left._Word[1] <=> _Right._Word[1]; if (_Ord == strong_ordering::equal) { @@ -729,7 +729,7 @@ struct _Unsigned128 : _Base128 { return _Ord; } #else // ^^^ _HAS_CXX20 / !_HAS_CXX20 vvv - _NODISCARD_FRIEND constexpr bool operator<(const _Unsigned128& _Left, const _Unsigned128& _Right) noexcept { + _NODISCARD friend constexpr bool operator<(const _Unsigned128& _Left, const _Unsigned128& _Right) noexcept { if (_Left._Word[1] < _Right._Word[1]) { return true; } @@ -741,20 +741,20 @@ struct _Unsigned128 : _Base128 { return _Left._Word[0] < _Right._Word[0]; } - _NODISCARD_FRIEND constexpr bool operator>(const _Unsigned128& _Left, const _Unsigned128& _Right) noexcept { + _NODISCARD friend constexpr bool operator>(const _Unsigned128& _Left, const _Unsigned128& _Right) noexcept { return _Right < _Left; } - _NODISCARD_FRIEND constexpr bool operator<=(const _Unsigned128& _Left, const _Unsigned128& _Right) noexcept { + _NODISCARD friend constexpr bool operator<=(const _Unsigned128& _Left, const _Unsigned128& _Right) noexcept { return !(_Right < _Left); } - _NODISCARD_FRIEND constexpr bool operator>=(const _Unsigned128& _Left, const _Unsigned128& _Right) noexcept { + _NODISCARD friend constexpr bool operator>=(const _Unsigned128& _Left, const _Unsigned128& _Right) noexcept { return !(_Left < _Right); } #endif // ^^^ !_HAS_CXX20 ^^^ - _NODISCARD_FRIEND constexpr _Unsigned128 operator<<(const _Unsigned128& _Left, const _Base128& _Right) noexcept { + _NODISCARD friend constexpr _Unsigned128 operator<<(const _Unsigned128& _Left, const _Base128& _Right) noexcept { auto _Tmp{_Left}; _Tmp._Left_shift(static_cast(_Right._Word[0])); return _Tmp; @@ -770,7 +770,7 @@ struct _Unsigned128 : _Base128 { return *this; } - _NODISCARD_FRIEND constexpr _Unsigned128 operator>>(const _Unsigned128& _Left, const _Base128& _Right) noexcept { + _NODISCARD friend constexpr _Unsigned128 operator>>(const _Unsigned128& _Left, const _Base128& _Right) noexcept { auto _Tmp{_Left}; _Tmp._Unsigned_right_shift(static_cast(_Right._Word[0])); return _Tmp; @@ -822,7 +822,7 @@ struct _Unsigned128 : _Base128 { return _Unsigned128{~_Word[0], ~_Word[1]}; } - _NODISCARD_FRIEND constexpr _Unsigned128 operator+(const _Base128& _Left, const _Base128& _Right) noexcept { + _NODISCARD friend constexpr _Unsigned128 operator+(const _Base128& _Left, const _Base128& _Right) noexcept { _Unsigned128 _Result; const auto _Carry = _AddCarry64(0, _Left._Word[0], _Right._Word[0], _Result._Word[0]); _AddCarry64(_Carry, _Left._Word[1], _Right._Word[1], _Result._Word[1]); @@ -840,7 +840,7 @@ struct _Unsigned128 : _Base128 { return _Left; } - _NODISCARD_FRIEND constexpr _Unsigned128 operator-(const _Base128& _Left, const _Base128& _Right) noexcept { + _NODISCARD friend constexpr _Unsigned128 operator-(const _Base128& _Left, const _Base128& _Right) noexcept { _Unsigned128 _Result; const auto _Borrow = _SubBorrow64(0, _Left._Word[0], _Right._Word[0], _Result._Word[0]); _SubBorrow64(_Borrow, _Left._Word[1], _Right._Word[1], _Result._Word[1]); @@ -858,7 +858,7 @@ struct _Unsigned128 : _Base128 { return _Left; } - _NODISCARD_FRIEND constexpr _Unsigned128 operator*(const _Base128& _Left, const _Base128& _Right) noexcept { + _NODISCARD friend constexpr _Unsigned128 operator*(const _Base128& _Left, const _Base128& _Right) noexcept { return _Unsigned128{_Base128::_Multiply(_Left, _Right)}; } @@ -873,7 +873,7 @@ struct _Unsigned128 : _Base128 { } _TEMPLATE_CLASS_INTEGRAL(_Ty) - _NODISCARD_FRIEND constexpr _Unsigned128 operator/(const _Unsigned128& _Num, const _Ty _Den) noexcept { + _NODISCARD friend constexpr _Unsigned128 operator/(const _Unsigned128& _Num, const _Ty _Den) noexcept { #if !_STL_128_DIV_INTRINSICS if constexpr (sizeof(_Ty) <= 4) { return _Unsigned128{_Base128::_Divide(_Num, static_cast(_Den))}; @@ -883,7 +883,7 @@ struct _Unsigned128 : _Base128 { return _Unsigned128{_Base128::_Divide(_Num, static_cast(_Den))}; } } - _NODISCARD_FRIEND constexpr _Unsigned128 operator/(const _Base128& _Num, const _Base128& _Den) noexcept { + _NODISCARD friend constexpr _Unsigned128 operator/(const _Base128& _Num, const _Base128& _Den) noexcept { return _Unsigned128{_Base128::_Divide(_Num, _Den)}; } @@ -914,7 +914,7 @@ struct _Unsigned128 : _Base128 { } _TEMPLATE_CLASS_INTEGRAL(_Ty) - _NODISCARD_FRIEND constexpr _Unsigned128 operator%(const _Base128& _Num, const _Ty _Den) noexcept { + _NODISCARD friend constexpr _Unsigned128 operator%(const _Base128& _Num, const _Ty _Den) noexcept { #if !_STL_128_DIV_INTRINSICS if constexpr (sizeof(_Ty) <= 4) { return _Unsigned128{_Base128::_Modulo(_Num, static_cast(_Den))}; @@ -924,7 +924,7 @@ struct _Unsigned128 : _Base128 { return _Unsigned128{_Base128::_Modulo(_Num, static_cast(_Den))}; } } - _NODISCARD_FRIEND constexpr _Unsigned128 operator%(const _Base128& _Num, const _Base128& _Den) noexcept { + _NODISCARD friend constexpr _Unsigned128 operator%(const _Base128& _Num, const _Base128& _Den) noexcept { return _Unsigned128{_Base128::_Modulo(_Num, _Den)}; } @@ -945,7 +945,7 @@ struct _Unsigned128 : _Base128 { return _Left; } - _NODISCARD_FRIEND constexpr _Unsigned128 operator&(const _Base128& _Left, const _Base128& _Right) noexcept { + _NODISCARD friend constexpr _Unsigned128 operator&(const _Base128& _Left, const _Base128& _Right) noexcept { return _Unsigned128{_Left._Word[0] & _Right._Word[0], _Left._Word[1] & _Right._Word[1]}; } @@ -955,7 +955,7 @@ struct _Unsigned128 : _Base128 { return *this; } - _NODISCARD_FRIEND constexpr _Unsigned128 operator^(const _Base128& _Left, const _Base128& _Right) noexcept { + _NODISCARD friend constexpr _Unsigned128 operator^(const _Base128& _Left, const _Base128& _Right) noexcept { return _Unsigned128{_Left._Word[0] ^ _Right._Word[0], _Left._Word[1] ^ _Right._Word[1]}; } @@ -965,7 +965,7 @@ struct _Unsigned128 : _Base128 { return *this; } - _NODISCARD_FRIEND constexpr _Unsigned128 operator|(const _Base128& _Left, const _Base128& _Right) noexcept { + _NODISCARD friend constexpr _Unsigned128 operator|(const _Base128& _Left, const _Base128& _Right) noexcept { return _Unsigned128{_Left._Word[0] | _Right._Word[0], _Left._Word[1] | _Right._Word[1]}; } @@ -1037,7 +1037,7 @@ struct _Signed128 : _Base128 { } #if _HAS_CXX20 - _NODISCARD_FRIEND constexpr strong_ordering operator<=>( + _NODISCARD friend constexpr strong_ordering operator<=>( const _Signed128& _Left, const _Signed128& _Right) noexcept { strong_ordering _Ord = static_cast(_Left._Word[1]) <=> static_cast(_Right._Word[1]); if (_Ord == strong_ordering::equal) { @@ -1046,7 +1046,7 @@ struct _Signed128 : _Base128 { return _Ord; } #else // ^^^ _HAS_CXX20 / !_HAS_CXX20 vvv - _NODISCARD_FRIEND constexpr bool operator<(const _Signed128& _Left, const _Signed128& _Right) noexcept { + _NODISCARD friend constexpr bool operator<(const _Signed128& _Left, const _Signed128& _Right) noexcept { if (static_cast(_Left._Word[1]) < static_cast(_Right._Word[1])) { return true; } @@ -1058,20 +1058,20 @@ struct _Signed128 : _Base128 { return _Left._Word[0] < _Right._Word[0]; } - _NODISCARD_FRIEND constexpr bool operator>(const _Signed128& _Left, const _Signed128& _Right) noexcept { + _NODISCARD friend constexpr bool operator>(const _Signed128& _Left, const _Signed128& _Right) noexcept { return _Right < _Left; } - _NODISCARD_FRIEND constexpr bool operator<=(const _Signed128& _Left, const _Signed128& _Right) noexcept { + _NODISCARD friend constexpr bool operator<=(const _Signed128& _Left, const _Signed128& _Right) noexcept { return !(_Right < _Left); } - _NODISCARD_FRIEND constexpr bool operator>=(const _Signed128& _Left, const _Signed128& _Right) noexcept { + _NODISCARD friend constexpr bool operator>=(const _Signed128& _Left, const _Signed128& _Right) noexcept { return !(_Left < _Right); } #endif // ^^^ !_HAS_CXX20 ^^^ - _NODISCARD_FRIEND constexpr _Signed128 operator<<(const _Signed128& _Left, const _Base128& _Right) noexcept { + _NODISCARD friend constexpr _Signed128 operator<<(const _Signed128& _Left, const _Base128& _Right) noexcept { auto _Tmp{_Left}; _Tmp._Left_shift(static_cast(_Right._Word[0])); return _Tmp; @@ -1110,7 +1110,7 @@ struct _Signed128 : _Base128 { _Word[1] = static_cast(static_cast(_Word[1]) >> _Count); } - _NODISCARD_FRIEND constexpr _Signed128 operator>>(const _Signed128& _Left, const _Base128& _Right) noexcept { + _NODISCARD friend constexpr _Signed128 operator>>(const _Signed128& _Left, const _Base128& _Right) noexcept { auto _Tmp{_Left}; _Tmp._Signed_right_shift(static_cast(_Right._Word[0])); return _Tmp; @@ -1162,7 +1162,7 @@ struct _Signed128 : _Base128 { return _Signed128{~_Word[0], ~_Word[1]}; } - _NODISCARD_FRIEND constexpr _Signed128 operator+(const _Signed128& _Left, const _Signed128& _Right) noexcept { + _NODISCARD friend constexpr _Signed128 operator+(const _Signed128& _Left, const _Signed128& _Right) noexcept { _Signed128 _Result; const auto _Carry = _AddCarry64(0, _Left._Word[0], _Right._Word[0], _Result._Word[0]); _AddCarry64(_Carry, _Left._Word[1], _Right._Word[1], _Result._Word[1]); @@ -1180,7 +1180,7 @@ struct _Signed128 : _Base128 { return _Left; } - _NODISCARD_FRIEND constexpr _Signed128 operator-(const _Signed128& _Left, const _Signed128& _Right) noexcept { + _NODISCARD friend constexpr _Signed128 operator-(const _Signed128& _Left, const _Signed128& _Right) noexcept { _Signed128 _Result; const auto _Borrow = _SubBorrow64(0, _Left._Word[0], _Right._Word[0], _Result._Word[0]); _SubBorrow64(_Borrow, _Left._Word[1], _Right._Word[1], _Result._Word[1]); @@ -1205,7 +1205,7 @@ struct _Signed128 : _Base128 { } } - _NODISCARD_FRIEND constexpr _Signed128 operator*(_Signed128 _Left, _Signed128 _Right) noexcept { + _NODISCARD friend constexpr _Signed128 operator*(_Signed128 _Left, _Signed128 _Right) noexcept { bool _Negative = false; _Left._Strip_negative(_Negative); _Right._Strip_negative(_Negative); @@ -1236,7 +1236,7 @@ struct _Signed128 : _Base128 { } _TEMPLATE_CLASS_INTEGRAL(_Ty) - _NODISCARD_FRIEND constexpr _Signed128 operator/(_Signed128 _Num, _Ty _Den) noexcept { + _NODISCARD friend constexpr _Signed128 operator/(_Signed128 _Num, _Ty _Den) noexcept { bool _Negative = false; _Num._Strip_negative(_Negative); if constexpr (is_signed_v<_Ty>) { @@ -1261,7 +1261,7 @@ struct _Signed128 : _Base128 { } return _Result; } - _NODISCARD_FRIEND constexpr _Signed128 operator/(_Signed128 _Num, _Signed128 _Den) noexcept { + _NODISCARD friend constexpr _Signed128 operator/(_Signed128 _Num, _Signed128 _Den) noexcept { bool _Negative = false; _Num._Strip_negative(_Negative); _Den._Strip_negative(_Negative); @@ -1291,7 +1291,7 @@ struct _Signed128 : _Base128 { return _Left; } - _NODISCARD_FRIEND constexpr _Signed128 operator%(_Signed128 _Left, _Signed128 _Right) noexcept { + _NODISCARD friend constexpr _Signed128 operator%(_Signed128 _Left, _Signed128 _Right) noexcept { bool _Negative = false; _Left._Strip_negative(_Negative); @@ -1308,7 +1308,7 @@ struct _Signed128 : _Base128 { } _TEMPLATE_CLASS_INTEGRAL(_Ty) - _NODISCARD_FRIEND constexpr _Signed128 operator%(_Signed128 _Left, const _Ty _Right) noexcept { + _NODISCARD friend constexpr _Signed128 operator%(_Signed128 _Left, const _Ty _Right) noexcept { return _Left % _Signed128{_Right}; } @@ -1331,7 +1331,7 @@ struct _Signed128 : _Base128 { return _Left; } - _NODISCARD_FRIEND constexpr _Signed128 operator&(const _Signed128& _Left, const _Signed128& _Right) noexcept { + _NODISCARD friend constexpr _Signed128 operator&(const _Signed128& _Left, const _Signed128& _Right) noexcept { return _Signed128{_Left._Word[0] & _Right._Word[0], _Left._Word[1] & _Right._Word[1]}; } @@ -1341,7 +1341,7 @@ struct _Signed128 : _Base128 { return *this; } - _NODISCARD_FRIEND constexpr _Signed128 operator^(const _Signed128& _Left, const _Signed128& _Right) noexcept { + _NODISCARD friend constexpr _Signed128 operator^(const _Signed128& _Left, const _Signed128& _Right) noexcept { return _Signed128{_Left._Word[0] ^ _Right._Word[0], _Left._Word[1] ^ _Right._Word[1]}; } @@ -1351,7 +1351,7 @@ struct _Signed128 : _Base128 { return *this; } - _NODISCARD_FRIEND constexpr _Signed128 operator|(const _Signed128& _Left, const _Signed128& _Right) noexcept { + _NODISCARD friend constexpr _Signed128 operator|(const _Signed128& _Left, const _Signed128& _Right) noexcept { return _Signed128{_Left._Word[0] | _Right._Word[0], _Left._Word[1] | _Right._Word[1]}; } diff --git a/stl/inc/__msvc_ranges_to.hpp b/stl/inc/__msvc_ranges_to.hpp index bd4cfaea563..5477a7347e9 100644 --- a/stl/inc/__msvc_ranges_to.hpp +++ b/stl/inc/__msvc_ranges_to.hpp @@ -827,7 +827,7 @@ namespace ranges { return _STD invoke(*_Parent->_Fun, _Current[_Idx]); } - _NODISCARD_FRIEND constexpr bool operator==(const _Iterator& _Left, const _Iterator& _Right) noexcept( + _NODISCARD friend constexpr bool operator==(const _Iterator& _Left, const _Iterator& _Right) noexcept( noexcept(_Left._Current == _Right._Current)) /* strengthened */ requires equality_comparable> { @@ -837,7 +837,7 @@ namespace ranges { return _Left._Current == _Right._Current; } - _NODISCARD_FRIEND constexpr bool operator<(const _Iterator& _Left, const _Iterator& _Right) noexcept( + _NODISCARD friend constexpr bool operator<(const _Iterator& _Left, const _Iterator& _Right) noexcept( noexcept(_Left._Current < _Right._Current)) /* strengthened */ requires random_access_range<_Base> { @@ -846,25 +846,25 @@ namespace ranges { #endif // _ITERATOR_DEBUG_LEVEL != 0 return _Left._Current < _Right._Current; } - _NODISCARD_FRIEND constexpr bool operator>(const _Iterator& _Left, const _Iterator& _Right) noexcept( + _NODISCARD friend constexpr bool operator>(const _Iterator& _Left, const _Iterator& _Right) noexcept( noexcept(_Left._Current < _Right._Current)) /* strengthened */ requires random_access_range<_Base> { return _Right < _Left; } - _NODISCARD_FRIEND constexpr bool operator<=(const _Iterator& _Left, const _Iterator& _Right) noexcept( + _NODISCARD friend constexpr bool operator<=(const _Iterator& _Left, const _Iterator& _Right) noexcept( noexcept(_Left._Current < _Right._Current)) /* strengthened */ requires random_access_range<_Base> { return !(_Right < _Left); } - _NODISCARD_FRIEND constexpr bool operator>=(const _Iterator& _Left, const _Iterator& _Right) noexcept( + _NODISCARD friend constexpr bool operator>=(const _Iterator& _Left, const _Iterator& _Right) noexcept( noexcept(_Left._Current < _Right._Current)) /* strengthened */ requires random_access_range<_Base> { return !(_Left < _Right); } - _NODISCARD_FRIEND constexpr auto operator<=>(const _Iterator& _Left, const _Iterator& _Right) noexcept( + _NODISCARD friend constexpr auto operator<=>(const _Iterator& _Left, const _Iterator& _Right) noexcept( noexcept(_Left._Current <=> _Right._Current)) /* strengthened */ requires random_access_range<_Base> && three_way_comparable> { @@ -874,7 +874,7 @@ namespace ranges { return _Left._Current <=> _Right._Current; } - _NODISCARD_FRIEND constexpr _Iterator operator+(_Iterator _It, const difference_type _Off) noexcept( + _NODISCARD friend constexpr _Iterator operator+(_Iterator _It, const difference_type _Off) noexcept( noexcept(_It._Current += _Off)) /* strengthened */ requires random_access_range<_Base> { @@ -884,7 +884,7 @@ namespace ranges { _It._Current += _Off; return _It; } - _NODISCARD_FRIEND constexpr _Iterator operator+(const difference_type _Off, _Iterator _It) noexcept( + _NODISCARD friend constexpr _Iterator operator+(const difference_type _Off, _Iterator _It) noexcept( noexcept(_It._Current += _Off)) /* strengthened */ requires random_access_range<_Base> { @@ -895,7 +895,7 @@ namespace ranges { return _It; } - _NODISCARD_FRIEND constexpr _Iterator operator-(_Iterator _It, const difference_type _Off) noexcept( + _NODISCARD friend constexpr _Iterator operator-(_Iterator _It, const difference_type _Off) noexcept( noexcept(_It._Current -= _Off)) /* strengthened */ requires random_access_range<_Base> { @@ -907,7 +907,7 @@ namespace ranges { return _It; } - _NODISCARD_FRIEND constexpr difference_type operator-(const _Iterator& _Left, + _NODISCARD friend constexpr difference_type operator-(const _Iterator& _Left, const _Iterator& _Right) noexcept(noexcept(_Left._Current - _Right._Current)) /* strengthened */ requires sized_sentinel_for, iterator_t<_Base>> { @@ -958,14 +958,14 @@ namespace ranges { template requires sentinel_for, _Maybe_const_iter<_OtherConst>> - _NODISCARD_FRIEND constexpr bool operator==(const _Iterator<_OtherConst>& _Left, + _NODISCARD friend constexpr bool operator==(const _Iterator<_OtherConst>& _Left, const _Sentinel& _Right) noexcept(noexcept(_Get_current(_Left) == _Right._Last)) /* strengthened */ { return _Get_current(_Left) == _Right._Last; } template requires sized_sentinel_for, _Maybe_const_iter<_OtherConst>> - _NODISCARD_FRIEND constexpr range_difference_t<_Maybe_const<_OtherConst, _Vw>> operator-( + _NODISCARD friend constexpr range_difference_t<_Maybe_const<_OtherConst, _Vw>> operator-( const _Iterator<_OtherConst>& _Left, const _Sentinel& _Right) noexcept(noexcept(_Get_current(_Left) - _Right._Last)) /* strengthened */ { return _Get_current(_Left) - _Right._Last; @@ -973,7 +973,7 @@ namespace ranges { template requires sized_sentinel_for, _Maybe_const_iter<_OtherConst>> - _NODISCARD_FRIEND constexpr range_difference_t<_Maybe_const<_OtherConst, _Vw>> + _NODISCARD friend constexpr range_difference_t<_Maybe_const<_OtherConst, _Vw>> operator-(const _Sentinel& _Left, const _Iterator<_OtherConst>& _Right) noexcept( noexcept(_Left._Last - _Get_current(_Right))) /* strengthened */ { return _Left._Last - _Get_current(_Right); diff --git a/stl/inc/__msvc_string_view.hpp b/stl/inc/__msvc_string_view.hpp index 52daaedbaf5..5ef55aded17 100644 --- a/stl/inc/__msvc_string_view.hpp +++ b/stl/inc/__msvc_string_view.hpp @@ -990,7 +990,7 @@ class _String_view_iterator { return _Tmp; } - _NODISCARD_FRIEND constexpr _String_view_iterator operator+( + _NODISCARD friend constexpr _String_view_iterator operator+( const difference_type _Off, _String_view_iterator _Right) noexcept { _Right += _Off; return _Right; diff --git a/stl/inc/algorithm b/stl/inc/algorithm index 5510edb3d97..af08dfa626b 100644 --- a/stl/inc/algorithm +++ b/stl/inc/algorithm @@ -10274,7 +10274,7 @@ namespace ranges { auto _ULast = _RANGES _Uend(_Range); _STL_ASSERT( _UFirst != _ULast, "A range passed to std::ranges::minmax must not be empty. (N4971 [alg.min.max]/21)"); - if constexpr (forward_range<_Rng> && _Prefer_iterator_copies>) { + if constexpr (forward_range<_Rng> && _Prefer_iterator_copies) { return _Minmax_fwd_unchecked( _STD move(_UFirst), _STD move(_ULast), _STD _Pass_fn(_Pred), _STD _Pass_fn(_Proj)); } else { diff --git a/stl/inc/array b/stl/inc/array index 6c9ee17926f..8f9b575f8ba 100644 --- a/stl/inc/array +++ b/stl/inc/array @@ -252,7 +252,7 @@ public: return _Tmp; } - _NODISCARD_FRIEND _CONSTEXPR17 _Array_const_iterator operator+( + _NODISCARD friend _CONSTEXPR17 _Array_const_iterator operator+( const ptrdiff_t _Off, _Array_const_iterator _Next) noexcept { _Next += _Off; return _Next; @@ -360,7 +360,7 @@ public: return _Tmp; } - _NODISCARD_FRIEND _CONSTEXPR17 _Array_iterator operator+(const ptrdiff_t _Off, _Array_iterator _Next) noexcept { + _NODISCARD friend _CONSTEXPR17 _Array_iterator operator+(const ptrdiff_t _Off, _Array_iterator _Next) noexcept { _Next += _Off; return _Next; } diff --git a/stl/inc/atomic b/stl/inc/atomic index 5f7e7300499..69bb22d98a7 100644 --- a/stl/inc/atomic +++ b/stl/inc/atomic @@ -28,29 +28,10 @@ _STL_DISABLE_CLANG_WARNINGS #pragma push_macro("new") #undef new -#ifdef _WIN64 -#if _STD_ATOMIC_ALWAYS_USE_CMPXCHG16B == 1 -#define _STD_COMPARE_EXCHANGE_128 _InterlockedCompareExchange128 -#else // ^^^ _STD_ATOMIC_ALWAYS_USE_CMPXCHG16B == 1 / _STD_ATOMIC_ALWAYS_USE_CMPXCHG16B == 0 vvv -// 16-byte atomics are separately compiled for x64, as not all x64 hardware has the cmpxchg16b -// instruction; in the event this instruction is not available, the fallback is a global -// synchronization object shared by all 16-byte atomics. -// (Note: machines without this instruction typically have 2 cores or fewer, so this isn't too bad) -// All pointer parameters must be 16-byte aligned. -extern "C" _NODISCARD unsigned char __stdcall __std_atomic_compare_exchange_128( - _Inout_bytecount_(16) long long* _Destination, _In_ long long _ExchangeHigh, _In_ long long _ExchangeLow, - _Inout_bytecount_(16) long long* _ComparandResult) noexcept; -extern "C" _NODISCARD char __stdcall __std_atomic_has_cmpxchg16b() noexcept; -#define _STD_COMPARE_EXCHANGE_128 __std_atomic_compare_exchange_128 -#endif // ^^^ _STD_ATOMIC_ALWAYS_USE_CMPXCHG16B == 0 ^^^ -#endif // defined(_WIN64) - -// 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) || 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 // ^^^ We only sometimes have DCAS ^^^ +// Allow _InterlockedCompareExchange128 to be used: +#if defined(__clang__) && defined(_M_X64) +#pragma clang attribute _STD_ATOMIC_HEADER.push([[gnu::target("cx16")]], apply_to = function) +#endif // ^^^ defined(__clang__) && defined(_M_X64) ^^^ // Controls whether ARM64 ldar/ldapr/stlr should be used #ifndef _STD_ATOMIC_USE_ARM64_LDAR_STLR @@ -603,7 +584,7 @@ inline bool __stdcall _Atomic_wait_compare_16_bytes(const void* _Storage, void* const auto _Cmp = static_cast(_Comparand); alignas(16) long long _Tmp[2] = {_Cmp[0], _Cmp[1]}; #if defined(_M_X64) && !defined(_M_ARM64EC) - return _STD_COMPARE_EXCHANGE_128(_Dest, _Tmp[1], _Tmp[0], _Tmp) != 0; + return _InterlockedCompareExchange128(_Dest, _Tmp[1], _Tmp[0], _Tmp) != 0; #else // ^^^ _M_X64 / ARM64, _M_ARM64EC vvv return _InterlockedCompareExchange128_nf(_Dest, _Tmp[1], _Tmp[0], _Tmp) != 0; #endif // ^^^ ARM64, _M_ARM64EC ^^^ @@ -1199,7 +1180,7 @@ struct _Atomic_storage<_Ty&, 16> { // lock-free using 16-byte intrinsics _NODISCARD _TVal load() const noexcept { // load with sequential consistency long long* const _Storage_ptr = const_cast(_STD _Atomic_address_as(_Storage)); _Int128 _Result{}; // atomic CAS 0 with 0 - (void) _STD_COMPARE_EXCHANGE_128(_Storage_ptr, 0, 0, &_Result._Low); + (void) _InterlockedCompareExchange128(_Storage_ptr, 0, 0, &_Result._Low); return reinterpret_cast<_TVal&>(_Result); } @@ -1270,7 +1251,7 @@ struct _Atomic_storage<_Ty&, 16> { // lock-free using 16-byte intrinsics &_Expected_temp._Low); #else // ^^^ _M_ARM64, _M_ARM64EC / _M_X64 vvv (void) _Order; - _Result = _STD_COMPARE_EXCHANGE_128(&reinterpret_cast(_Storage), _Desired_bytes._High, + _Result = _InterlockedCompareExchange128(&reinterpret_cast(_Storage), _Desired_bytes._High, _Desired_bytes._Low, &_Expected_temp._Low); #endif // ^^^ _M_X64 ^^^ if (_Result) { @@ -1296,7 +1277,7 @@ struct _Atomic_storage<_Ty&, 16> { // lock-free using 16-byte intrinsics &_Expected_temp._Low); #else // ^^^ _M_ARM64, _M_ARM64EC / _M_X64 vvv (void) _Order; - _Result = _STD_COMPARE_EXCHANGE_128( + _Result = _InterlockedCompareExchange128( &reinterpret_cast(_Storage), _Desired_bytes._High, _Desired_bytes._Low, &_Expected_temp._Low); #endif // ^^^ _M_X64 ^^^ if (_Result == 0) { @@ -1649,13 +1630,8 @@ struct _Atomic_integral<_Ty, 8> : _Atomic_storage<_Ty> { // atomic integral oper template constexpr bool _Is_always_lock_free = _TypeSize <= 8 && (_TypeSize & (_TypeSize - 1)) == 0; #else // ^^^ don't break ABI / break ABI vvv -#if _ATOMIC_HAS_DCAS template constexpr bool _Is_always_lock_free = _TypeSize <= 2 * sizeof(void*); -#else // ^^^ _ATOMIC_HAS_DCAS / !_ATOMIC_HAS_DCAS vvv -template -constexpr bool _Is_always_lock_free = _TypeSize <= sizeof(void*); -#endif // ^^^ !_ATOMIC_HAS_DCAS ^^^ #endif // ^^^ break ABI ^^^ template > @@ -2175,23 +2151,10 @@ public: static constexpr bool is_always_lock_free = _Is_always_lock_free; #endif // _HAS_CXX17 -#if 1 // TRANSITION, ABI _NODISCARD bool is_lock_free() const volatile noexcept { - constexpr bool _Result = sizeof(_Ty) <= 8 && (sizeof(_Ty) & sizeof(_Ty) - 1) == 0; - return _Result; + return _Is_always_lock_free; } -#else // ^^^ don't break ABI / break ABI vvv - - _NODISCARD bool is_lock_free() const volatile noexcept { -#if _ATOMIC_HAS_DCAS - return sizeof(_Ty) <= 2 * sizeof(void*); -#else // ^^^ _ATOMIC_HAS_DCAS / !_ATOMIC_HAS_DCAS vvv - return sizeof(_Ty) <= sizeof(void*) || (sizeof(_Ty) <= 2 * sizeof(void*) && __std_atomic_has_cmpxchg16b()); -#endif // ^^^ !_ATOMIC_HAS_DCAS ^^^ - } -#endif // ^^^ break ABI ^^^ - _NODISCARD bool is_lock_free() const noexcept { return static_cast(this)->is_lock_free(); } @@ -2341,7 +2304,7 @@ public: using value_type = _Ty; explicit atomic_ref(_Ty& _Value) noexcept /* strengthened */ : _Base(_Value) { - if constexpr (_Is_potentially_lock_free) { + if constexpr (is_always_lock_free) { _Check_alignment(_Value); } else { this->_Init_spinlock_for_ref(); @@ -2352,28 +2315,13 @@ public: atomic_ref& operator=(const atomic_ref&) = delete; - static constexpr bool _Is_potentially_lock_free = - sizeof(_Ty) <= 2 * sizeof(void*) && (sizeof(_Ty) & (sizeof(_Ty) - 1)) == 0; - static constexpr bool is_always_lock_free = -#if _ATOMIC_HAS_DCAS - _Is_potentially_lock_free; -#else // ^^^ _ATOMIC_HAS_DCAS / !_ATOMIC_HAS_DCAS vvv - _Is_potentially_lock_free && sizeof(_Ty) <= sizeof(void*); -#endif // ^^^ !_ATOMIC_HAS_DCAS ^^^ + sizeof(_Ty) <= 2 * sizeof(void*) && (sizeof(_Ty) & (sizeof(_Ty) - 1)) == 0; - static constexpr size_t required_alignment = _Is_potentially_lock_free ? sizeof(_Ty) : alignof(_Ty); + static constexpr size_t required_alignment = is_always_lock_free ? sizeof(_Ty) : alignof(_Ty); _NODISCARD bool is_lock_free() const noexcept { -#if _ATOMIC_HAS_DCAS return is_always_lock_free; -#else // ^^^ _ATOMIC_HAS_DCAS / !_ATOMIC_HAS_DCAS vvv - if constexpr (is_always_lock_free) { - return true; - } else { - return __std_atomic_has_cmpxchg16b() != 0; - } -#endif // ^^^ !_ATOMIC_HAS_DCAS ^^^ } void store(const _Ty _Value) const noexcept { @@ -3047,16 +2995,18 @@ _STD_END #undef _ATOMIC_STORE_32_SEQ_CST #undef _ATOMIC_STORE_64_SEQ_CST #undef _ATOMIC_STORE_64_SEQ_CST_IX86 -#undef _ATOMIC_HAS_DCAS #undef _ATOMIC_STORE_SEQ_CST_ARM64 #undef __LOAD_ACQUIRE_ARM64 #undef _ATOMIC_LOAD_ARM64 #undef __STORE_RELEASE #undef _STD_ATOMIC_USE_ARM64_LDAR_STLR -#undef _STD_COMPARE_EXCHANGE_128 #undef _INVALID_MEMORY_ORDER +#if defined(__clang__) && defined(_M_X64) +#pragma clang attribute _STD_ATOMIC_HEADER.pop +#endif // ^^^ defined(__clang__) && defined(_M_X64) ^^^ + #pragma pop_macro("new") _STL_RESTORE_CLANG_WARNINGS #pragma warning(pop) diff --git a/stl/inc/bitset b/stl/inc/bitset index 66ec4c06c4b..f7eba3f7c7a 100644 --- a/stl/inc/bitset +++ b/stl/inc/bitset @@ -18,6 +18,10 @@ _STL_DISABLE_CLANG_WARNINGS #pragma push_macro("new") #undef new +#ifndef _STD_BITSET_TO_STREAM_STACK_RESERVATION +#define _STD_BITSET_TO_STREAM_STACK_RESERVATION 128 +#endif // !defined(_STD_BITSET_TO_STREAM_STACK_RESERVATION) + #if _USE_STD_VECTOR_ALGORITHMS extern "C" { __declspec(noalias) void __stdcall __std_bitset_to_string_1( @@ -357,26 +361,7 @@ public: // convert bitset to string basic_string<_Elem, _Tr, _Alloc> _Str; _Str._Resize_and_overwrite(_Bits, [this, _Elem0, _Elem1](_Elem* _Buf, size_t _Len) { -#if _USE_STD_VECTOR_ALGORITHMS - constexpr size_t _Bitset_vector_threshold = 32; - if constexpr (_Bits >= _Bitset_vector_threshold && is_integral_v<_Elem> && sizeof(_Elem) <= 2) { - if (!_Is_constant_evaluated()) { - if constexpr (sizeof(_Elem) == 1) { - __std_bitset_to_string_1(reinterpret_cast(_Buf), _Array, _Len, static_cast(_Elem0), - static_cast(_Elem1)); - } else { - _STL_INTERNAL_STATIC_ASSERT(sizeof(_Elem) == 2); - __std_bitset_to_string_2(reinterpret_cast(_Buf), _Array, _Len, - static_cast(_Elem0), static_cast(_Elem1)); - } - return _Len; - } - } -#endif // _USE_STD_VECTOR_ALGORITHMS - - for (size_t _Pos = 0; _Pos < _Len; ++_Pos) { - _Buf[_Pos] = _Subscript(_Len - 1 - _Pos) ? _Elem1 : _Elem0; - } + _To_string(_Buf, _Len, _Elem0, _Elem1); return _Len; }); return _Str; @@ -473,6 +458,32 @@ public: return _Array[_Wpos]; } + template + _CONSTEXPR23 void _To_string( + _Elem* const _Buf, const size_t _Len, const _Elem _Elem0, const _Elem _Elem1) const noexcept { +#if _USE_STD_VECTOR_ALGORITHMS + constexpr size_t _Bitset_vector_threshold = 32; + if constexpr (_Bits >= _Bitset_vector_threshold && is_integral_v<_Elem> && sizeof(_Elem) <= 2) { + if (!_Is_constant_evaluated()) { + if constexpr (sizeof(_Elem) == 1) { + __std_bitset_to_string_1(reinterpret_cast(_Buf), _Array, _Len, static_cast(_Elem0), + static_cast(_Elem1)); + } else { + _STL_INTERNAL_STATIC_ASSERT(sizeof(_Elem) == 2); + __std_bitset_to_string_2(reinterpret_cast(_Buf), _Array, _Len, + static_cast(_Elem0), static_cast(_Elem1)); + } + + return; + } + } +#endif // _USE_STD_VECTOR_ALGORITHMS + + for (size_t _Pos = 0; _Pos < _Len; ++_Pos) { + _Buf[_Pos] = _Subscript(_Len - 1 - _Pos) ? _Elem1 : _Elem0; + } + } + private: friend hash>; @@ -547,7 +558,14 @@ basic_ostream<_Elem, _Tr>& operator<<(basic_ostream<_Elem, _Tr>& _Ostr, const bi const _Elem _Elem0 = _Ctype_fac.widen('0'); const _Elem _Elem1 = _Ctype_fac.widen('1'); - return _Ostr << _Right.template to_string<_Elem, _Tr, allocator<_Elem>>(_Elem0, _Elem1); + if constexpr (_Bits * sizeof(_Elem) <= _STD_BITSET_TO_STREAM_STACK_RESERVATION) { + _Elem _Buf[_Bits + 1]; + _Right._To_string(_Buf, _Bits, _Elem0, _Elem1); + _Buf[_Bits] = _Elem{'\0'}; + return _Ostr << _Buf; + } else { + return _Ostr << _Right.template to_string<_Elem, _Tr, allocator<_Elem>>(_Elem0, _Elem1); + } } _EXPORT_STD template diff --git a/stl/inc/charconv b/stl/inc/charconv index 518841a249f..666be9f0372 100644 --- a/stl/inc/charconv +++ b/stl/inc/charconv @@ -208,7 +208,7 @@ _EXPORT_STD struct from_chars_result { const char* ptr; errc ec; #if _HAS_CXX20 - _NODISCARD_FRIEND bool operator==(const from_chars_result&, const from_chars_result&) = default; + _NODISCARD friend bool operator==(const from_chars_result&, const from_chars_result&) = default; #endif // _HAS_CXX20 }; diff --git a/stl/inc/cmath b/stl/inc/cmath index de7be7abc46..34052e7628d 100644 --- a/stl/inc/cmath +++ b/stl/inc/cmath @@ -611,6 +611,53 @@ _STD _Common_float_type_t<_Ty1, _Ty2> remquo(_Ty1 _Left, _Ty2 _Right, int* _Pquo return __builtin_##NAME(_Xx, _Yx); \ } +#define _CLANG_BUILTIN2_ARG_TEMPLATED(NAME, ARG) \ + template , int> = 0> \ + _NODISCARD _Check_return_ inline bool NAME(_In_ ARG _Xx, _In_ _Ty _Yx) noexcept /* strengthened */ { \ + return __builtin_##NAME(static_cast(_Xx), static_cast(_Yx)); \ + } + +#ifdef __cpp_char8_t +#define _CLANG_BUILTIN2_ARG_TEMPLATED_CHAR8_T(NAME) \ + template , int> = 0> \ + _NODISCARD _Check_return_ inline bool NAME(_In_ char8_t _Xx, _In_ _Ty _Yx) noexcept /* strengthened */ { \ + return __builtin_##NAME(static_cast(_Xx), static_cast(_Yx)); \ + } +#else // ^^^ defined(__cpp_char8_t) / !defined(__cpp_char8_t) vvv +#define _CLANG_BUILTIN2_ARG_TEMPLATED_CHAR8_T(NAME) +#endif // ^^^ !defined(__cpp_char8_t) ^^^ + +#ifdef _NATIVE_WCHAR_T_DEFINED +#define _CLANG_BUILTIN2_ARG_TEMPLATED_WCHAR_T(NAME) \ + template , int> = 0> \ + _NODISCARD _Check_return_ inline bool NAME(_In_ wchar_t _Xx, _In_ _Ty _Yx) noexcept /* strengthened */ { \ + return __builtin_##NAME(static_cast(_Xx), static_cast(_Yx)); \ + } +#else // ^^^ defined(_NATIVE_WCHAR_T_DEFINED) / !defined(_NATIVE_WCHAR_T_DEFINED) vvv +#define _CLANG_BUILTIN2_ARG_TEMPLATED_WCHAR_T(NAME) +#endif // ^^^ !defined(_NATIVE_WCHAR_T_DEFINED) ^^^ + +#define _CLANG_BUILTIN2_TEMPLATED(NAME) \ + _CLANG_BUILTIN2_ARG_TEMPLATED(NAME, float) \ + _CLANG_BUILTIN2_ARG_TEMPLATED(NAME, double) \ + _CLANG_BUILTIN2_ARG_TEMPLATED(NAME, long double) \ + _CLANG_BUILTIN2_ARG_TEMPLATED(NAME, signed char) \ + _CLANG_BUILTIN2_ARG_TEMPLATED(NAME, short) \ + _CLANG_BUILTIN2_ARG_TEMPLATED(NAME, int) \ + _CLANG_BUILTIN2_ARG_TEMPLATED(NAME, long) \ + _CLANG_BUILTIN2_ARG_TEMPLATED(NAME, long long) \ + _CLANG_BUILTIN2_ARG_TEMPLATED(NAME, unsigned char) \ + _CLANG_BUILTIN2_ARG_TEMPLATED(NAME, unsigned short) \ + _CLANG_BUILTIN2_ARG_TEMPLATED(NAME, unsigned int) \ + _CLANG_BUILTIN2_ARG_TEMPLATED(NAME, unsigned long) \ + _CLANG_BUILTIN2_ARG_TEMPLATED(NAME, unsigned long long) \ + _CLANG_BUILTIN2_ARG_TEMPLATED(NAME, bool) \ + _CLANG_BUILTIN2_ARG_TEMPLATED(NAME, char) \ + _CLANG_BUILTIN2_ARG_TEMPLATED_CHAR8_T(NAME) \ + _CLANG_BUILTIN2_ARG_TEMPLATED(NAME, char16_t) \ + _CLANG_BUILTIN2_ARG_TEMPLATED(NAME, char32_t) \ + _CLANG_BUILTIN2_ARG_TEMPLATED_WCHAR_T(NAME) + #define _CLANG_BUILTIN1(NAME) \ _CLANG_BUILTIN1_ARG(NAME, float) \ _CLANG_BUILTIN1_ARG(NAME, double) \ @@ -633,19 +680,30 @@ _CLANG_BUILTIN2(islessequal) _CLANG_BUILTIN2(islessgreater) _CLANG_BUILTIN2(isunordered) +_CLANG_BUILTIN2_TEMPLATED(isgreater) +_CLANG_BUILTIN2_TEMPLATED(isgreaterequal) +_CLANG_BUILTIN2_TEMPLATED(isless) +_CLANG_BUILTIN2_TEMPLATED(islessequal) +_CLANG_BUILTIN2_TEMPLATED(islessgreater) +_CLANG_BUILTIN2_TEMPLATED(isunordered) + #undef _CLANG_BUILTIN1_ARG #undef _CLANG_BUILTIN2_ARG #undef _CLANG_BUILTIN1 #undef _CLANG_BUILTIN2 +#undef _CLANG_BUILTIN2_ARG_TEMPLATED +#undef _CLANG_BUILTIN2_ARG_TEMPLATED_CHAR8_T +#undef _CLANG_BUILTIN2_ARG_TEMPLATED_WCHAR_T +#undef _CLANG_BUILTIN2_TEMPLATED #endif // ^^^ defined(__clang__) ^^^ -// TRANSITION, GH-519, should be provided by UCRT +// TRANSITION, DevCom-10294165, should be provided by UCRT template , int> = 0> _NODISCARD _Check_return_ _CONSTEXPR23 int fpclassify(_In_ const _Ty _Ix) noexcept /* strengthened */ { return _Ix == 0 ? FP_ZERO : FP_NORMAL; } -// TRANSITION, GH-519, should be provided by UCRT +// TRANSITION, DevCom-10294165, should be provided by UCRT template , int> = 0> _NODISCARD _Check_return_ _CONSTEXPR23 bool signbit(_In_ const _Ty _Ix) noexcept /* strengthened */ { if constexpr (static_cast<_Ty>(-1) < _Ty{}) { @@ -655,7 +713,7 @@ _NODISCARD _Check_return_ _CONSTEXPR23 bool signbit(_In_ const _Ty _Ix) noexcept } } -// TRANSITION, GH-519, additional overloads are not templated to avoid ambiguity with the major overload in UCRT +// TRANSITION, DevCom-10294165, additional overloads are not templated to avoid ambiguity with the overload in UCRT #define _GENERIC_MATH_ISNORMAL(TYPE) \ _NODISCARD _Check_return_ _CONSTEXPR23 bool isnormal(_In_ const TYPE _Ix) noexcept /* strengthened */ { \ return _Ix != 0; \ @@ -729,7 +787,7 @@ _GENERIC_MATH_ISNORMAL(wchar_t) #define _GENERIC_MATH2I(FUN, CLANG_INTRIN, MSVC_INTRIN) _GENERIC_MATH2_BASE(FUN, _CSTD FUN) #endif // ^^^ intrinsics unavailable ^^^ -// TRANSITION, GH-519, additional overloads are not templated to avoid ambiguity with the major overload in UCRT +// TRANSITION, DevCom-10294165, additional overloads are not templated to avoid ambiguity with the overload in UCRT #define _GENERIC_MATH_CLASSIFY1_RETV_INTEGER(FUN, RETV, TYPE) \ _NODISCARD _Check_return_ _CONSTEXPR23 bool FUN(_In_ TYPE) noexcept /* strengthened */ { \ return RETV; \ diff --git a/stl/inc/compare b/stl/inc/compare index 38246ebb61c..adc7730731a 100644 --- a/stl/inc/compare +++ b/stl/inc/compare @@ -47,52 +47,52 @@ _EXPORT_STD struct partial_ordering { static const partial_ordering greater; static const partial_ordering unordered; - _NODISCARD_FRIEND constexpr bool operator==(const partial_ordering _Val, _Literal_zero) noexcept { + _NODISCARD friend constexpr bool operator==(const partial_ordering _Val, _Literal_zero) noexcept { return _Val._Value == 0; } - _NODISCARD_FRIEND constexpr bool operator==(partial_ordering, partial_ordering) noexcept = default; + _NODISCARD friend constexpr bool operator==(partial_ordering, partial_ordering) noexcept = default; - _NODISCARD_FRIEND constexpr bool operator<(const partial_ordering _Val, _Literal_zero) noexcept { + _NODISCARD friend constexpr bool operator<(const partial_ordering _Val, _Literal_zero) noexcept { return _Val._Value == static_cast<_Compare_t>(_Compare_ord::less); } - _NODISCARD_FRIEND constexpr bool operator>(const partial_ordering _Val, _Literal_zero) noexcept { + _NODISCARD friend constexpr bool operator>(const partial_ordering _Val, _Literal_zero) noexcept { return _Val._Value > 0; } - _NODISCARD_FRIEND constexpr bool operator<=(const partial_ordering _Val, _Literal_zero) noexcept { + _NODISCARD friend constexpr bool operator<=(const partial_ordering _Val, _Literal_zero) noexcept { // The stored value is either less (0xff), equivalent (0x00), greater (0x01), or unordered (0x80). // Subtracting from 0 produces either 0x01, 0x00, 0xff, or 0x80. The result is greater than or equal to 0 // if and only if the initial value was less or equivalent, for which we want to return true. return static_cast(0 - static_cast(_Val._Value)) >= 0; } - _NODISCARD_FRIEND constexpr bool operator>=(const partial_ordering _Val, _Literal_zero) noexcept { + _NODISCARD friend constexpr bool operator>=(const partial_ordering _Val, _Literal_zero) noexcept { return _Val._Value >= 0; } - _NODISCARD_FRIEND constexpr bool operator<(_Literal_zero, const partial_ordering _Val) noexcept { + _NODISCARD friend constexpr bool operator<(_Literal_zero, const partial_ordering _Val) noexcept { return _Val > 0; } - _NODISCARD_FRIEND constexpr bool operator>(_Literal_zero, const partial_ordering _Val) noexcept { + _NODISCARD friend constexpr bool operator>(_Literal_zero, const partial_ordering _Val) noexcept { return _Val < 0; } - _NODISCARD_FRIEND constexpr bool operator<=(_Literal_zero, const partial_ordering _Val) noexcept { + _NODISCARD friend constexpr bool operator<=(_Literal_zero, const partial_ordering _Val) noexcept { return _Val >= 0; } - _NODISCARD_FRIEND constexpr bool operator>=(_Literal_zero, const partial_ordering _Val) noexcept { + _NODISCARD friend constexpr bool operator>=(_Literal_zero, const partial_ordering _Val) noexcept { return _Val <= 0; } - _NODISCARD_FRIEND constexpr partial_ordering operator<=>(const partial_ordering _Val, _Literal_zero) noexcept { + _NODISCARD friend constexpr partial_ordering operator<=>(const partial_ordering _Val, _Literal_zero) noexcept { return _Val; } - _NODISCARD_FRIEND constexpr partial_ordering operator<=>(_Literal_zero, const partial_ordering _Val) noexcept { + _NODISCARD friend constexpr partial_ordering operator<=>(_Literal_zero, const partial_ordering _Val) noexcept { // The stored value is either less (0xff), equivalent (0x00), greater (0x01), or unordered (0x80). // Subtracting from 0 produces either 0x01, 0x00, 0xff, or 0x80. Note that the effect is to // exchange less for greater (and vice versa), while leaving equivalent and unordered unchanged. @@ -116,49 +116,49 @@ _EXPORT_STD struct weak_ordering { return {static_cast<_Compare_t>(_Value)}; } - _NODISCARD_FRIEND constexpr bool operator==(const weak_ordering _Val, _Literal_zero) noexcept { + _NODISCARD friend constexpr bool operator==(const weak_ordering _Val, _Literal_zero) noexcept { return _Val._Value == 0; } - _NODISCARD_FRIEND constexpr bool operator==(weak_ordering, weak_ordering) noexcept = default; + _NODISCARD friend constexpr bool operator==(weak_ordering, weak_ordering) noexcept = default; - _NODISCARD_FRIEND constexpr bool operator<(const weak_ordering _Val, _Literal_zero) noexcept { + _NODISCARD friend constexpr bool operator<(const weak_ordering _Val, _Literal_zero) noexcept { return _Val._Value < 0; } - _NODISCARD_FRIEND constexpr bool operator>(const weak_ordering _Val, _Literal_zero) noexcept { + _NODISCARD friend constexpr bool operator>(const weak_ordering _Val, _Literal_zero) noexcept { return _Val._Value > 0; } - _NODISCARD_FRIEND constexpr bool operator<=(const weak_ordering _Val, _Literal_zero) noexcept { + _NODISCARD friend constexpr bool operator<=(const weak_ordering _Val, _Literal_zero) noexcept { return _Val._Value <= 0; } - _NODISCARD_FRIEND constexpr bool operator>=(const weak_ordering _Val, _Literal_zero) noexcept { + _NODISCARD friend constexpr bool operator>=(const weak_ordering _Val, _Literal_zero) noexcept { return _Val._Value >= 0; } - _NODISCARD_FRIEND constexpr bool operator<(_Literal_zero, const weak_ordering _Val) noexcept { + _NODISCARD friend constexpr bool operator<(_Literal_zero, const weak_ordering _Val) noexcept { return _Val > 0; } - _NODISCARD_FRIEND constexpr bool operator>(_Literal_zero, const weak_ordering _Val) noexcept { + _NODISCARD friend constexpr bool operator>(_Literal_zero, const weak_ordering _Val) noexcept { return _Val < 0; } - _NODISCARD_FRIEND constexpr bool operator<=(_Literal_zero, const weak_ordering _Val) noexcept { + _NODISCARD friend constexpr bool operator<=(_Literal_zero, const weak_ordering _Val) noexcept { return _Val >= 0; } - _NODISCARD_FRIEND constexpr bool operator>=(_Literal_zero, const weak_ordering _Val) noexcept { + _NODISCARD friend constexpr bool operator>=(_Literal_zero, const weak_ordering _Val) noexcept { return _Val <= 0; } - _NODISCARD_FRIEND constexpr weak_ordering operator<=>(const weak_ordering _Val, _Literal_zero) noexcept { + _NODISCARD friend constexpr weak_ordering operator<=>(const weak_ordering _Val, _Literal_zero) noexcept { return _Val; } - _NODISCARD_FRIEND constexpr weak_ordering operator<=>(_Literal_zero, const weak_ordering _Val) noexcept { + _NODISCARD friend constexpr weak_ordering operator<=>(_Literal_zero, const weak_ordering _Val) noexcept { return {static_cast<_Compare_t>(-_Val._Value)}; } @@ -183,49 +183,49 @@ _EXPORT_STD struct strong_ordering { return {static_cast<_Compare_t>(_Value)}; } - _NODISCARD_FRIEND constexpr bool operator==(const strong_ordering _Val, _Literal_zero) noexcept { + _NODISCARD friend constexpr bool operator==(const strong_ordering _Val, _Literal_zero) noexcept { return _Val._Value == 0; } - _NODISCARD_FRIEND constexpr bool operator==(strong_ordering, strong_ordering) noexcept = default; + _NODISCARD friend constexpr bool operator==(strong_ordering, strong_ordering) noexcept = default; - _NODISCARD_FRIEND constexpr bool operator<(const strong_ordering _Val, _Literal_zero) noexcept { + _NODISCARD friend constexpr bool operator<(const strong_ordering _Val, _Literal_zero) noexcept { return _Val._Value < 0; } - _NODISCARD_FRIEND constexpr bool operator>(const strong_ordering _Val, _Literal_zero) noexcept { + _NODISCARD friend constexpr bool operator>(const strong_ordering _Val, _Literal_zero) noexcept { return _Val._Value > 0; } - _NODISCARD_FRIEND constexpr bool operator<=(const strong_ordering _Val, _Literal_zero) noexcept { + _NODISCARD friend constexpr bool operator<=(const strong_ordering _Val, _Literal_zero) noexcept { return _Val._Value <= 0; } - _NODISCARD_FRIEND constexpr bool operator>=(const strong_ordering _Val, _Literal_zero) noexcept { + _NODISCARD friend constexpr bool operator>=(const strong_ordering _Val, _Literal_zero) noexcept { return _Val._Value >= 0; } - _NODISCARD_FRIEND constexpr bool operator<(_Literal_zero, const strong_ordering _Val) noexcept { + _NODISCARD friend constexpr bool operator<(_Literal_zero, const strong_ordering _Val) noexcept { return _Val > 0; } - _NODISCARD_FRIEND constexpr bool operator>(_Literal_zero, const strong_ordering _Val) noexcept { + _NODISCARD friend constexpr bool operator>(_Literal_zero, const strong_ordering _Val) noexcept { return _Val < 0; } - _NODISCARD_FRIEND constexpr bool operator<=(_Literal_zero, const strong_ordering _Val) noexcept { + _NODISCARD friend constexpr bool operator<=(_Literal_zero, const strong_ordering _Val) noexcept { return _Val >= 0; } - _NODISCARD_FRIEND constexpr bool operator>=(_Literal_zero, const strong_ordering _Val) noexcept { + _NODISCARD friend constexpr bool operator>=(_Literal_zero, const strong_ordering _Val) noexcept { return _Val <= 0; } - _NODISCARD_FRIEND constexpr strong_ordering operator<=>(const strong_ordering _Val, _Literal_zero) noexcept { + _NODISCARD friend constexpr strong_ordering operator<=>(const strong_ordering _Val, _Literal_zero) noexcept { return _Val; } - _NODISCARD_FRIEND constexpr strong_ordering operator<=>(_Literal_zero, const strong_ordering _Val) noexcept { + _NODISCARD friend constexpr strong_ordering operator<=>(_Literal_zero, const strong_ordering _Val) noexcept { return {static_cast<_Compare_t>(-_Val._Value)}; } diff --git a/stl/inc/deque b/stl/inc/deque index 905eb162137..7c8ad1f9be5 100644 --- a/stl/inc/deque +++ b/stl/inc/deque @@ -82,7 +82,7 @@ public: return _Tmp; } - _NODISCARD_FRIEND _Deque_unchecked_const_iterator operator+( + _NODISCARD friend _Deque_unchecked_const_iterator operator+( const difference_type _Off, _Deque_unchecked_const_iterator _Next) noexcept { _Next += _Off; return _Next; @@ -202,7 +202,7 @@ public: return _Tmp; } - _NODISCARD_FRIEND _Deque_unchecked_iterator operator+( + _NODISCARD friend _Deque_unchecked_iterator operator+( const difference_type _Off, _Deque_unchecked_iterator _Next) noexcept { _Next += _Off; return _Next; @@ -323,7 +323,7 @@ public: return _Tmp; } - _NODISCARD_FRIEND _Deque_const_iterator operator+( + _NODISCARD friend _Deque_const_iterator operator+( const difference_type _Off, _Deque_const_iterator _Next) noexcept { _Next += _Off; return _Next; @@ -484,7 +484,7 @@ public: return _Tmp; } - _NODISCARD_FRIEND _Deque_iterator operator+(const difference_type _Off, _Deque_iterator _Next) noexcept { + _NODISCARD friend _Deque_iterator operator+(const difference_type _Off, _Deque_iterator _Next) noexcept { _Next += _Off; return _Next; } @@ -1777,8 +1777,7 @@ deque(_Iter, _Iter, _Alloc = _Alloc()) -> deque<_Iter_value_t<_Iter>, _Alloc>; #endif // _HAS_CXX17 #if _HAS_CXX23 -template <_RANGES input_range _Rng, class _Alloc = allocator<_RANGES range_value_t<_Rng>>, - enable_if_t<_Is_allocator<_Alloc>::value, int> = 0> +template <_RANGES input_range _Rng, _Allocator_for_container _Alloc = allocator<_RANGES range_value_t<_Rng>>> deque(from_range_t, _Rng&&, _Alloc = _Alloc()) -> deque<_RANGES range_value_t<_Rng>, _Alloc>; #endif // _HAS_CXX23 diff --git a/stl/inc/exception b/stl/inc/exception index 95721640b89..a5bee7ae569 100644 --- a/stl/inc/exception +++ b/stl/inc/exception @@ -269,28 +269,28 @@ public: __ExceptionPtrSwap(&_Lhs, &_Rhs); } - _NODISCARD_FRIEND bool operator==(const exception_ptr& _Lhs, const exception_ptr& _Rhs) noexcept { + _NODISCARD friend bool operator==(const exception_ptr& _Lhs, const exception_ptr& _Rhs) noexcept { return __ExceptionPtrCompare(&_Lhs, &_Rhs); } - _NODISCARD_FRIEND bool operator==(const exception_ptr& _Lhs, nullptr_t) noexcept { + _NODISCARD friend bool operator==(const exception_ptr& _Lhs, nullptr_t) noexcept { return !_Lhs; } #if !_HAS_CXX20 - _NODISCARD_FRIEND bool operator==(nullptr_t, const exception_ptr& _Rhs) noexcept { + _NODISCARD friend bool operator==(nullptr_t, const exception_ptr& _Rhs) noexcept { return !_Rhs; } - _NODISCARD_FRIEND bool operator!=(const exception_ptr& _Lhs, const exception_ptr& _Rhs) noexcept { + _NODISCARD friend bool operator!=(const exception_ptr& _Lhs, const exception_ptr& _Rhs) noexcept { return !(_Lhs == _Rhs); } - _NODISCARD_FRIEND bool operator!=(const exception_ptr& _Lhs, nullptr_t) noexcept { + _NODISCARD friend bool operator!=(const exception_ptr& _Lhs, nullptr_t) noexcept { return !(_Lhs == nullptr); } - _NODISCARD_FRIEND bool operator!=(nullptr_t, const exception_ptr& _Rhs) noexcept { + _NODISCARD friend bool operator!=(nullptr_t, const exception_ptr& _Rhs) noexcept { return !(nullptr == _Rhs); } #endif // !_HAS_CXX20 diff --git a/stl/inc/expected b/stl/inc/expected index a7016c7a296..aad81b7007e 100644 --- a/stl/inc/expected +++ b/stl/inc/expected @@ -87,18 +87,14 @@ public: } friend constexpr void swap(unexpected& _Left, unexpected& _Right) noexcept(is_nothrow_swappable_v<_Err>) -#if defined(__clang__) || defined(__EDG__) // TRANSITION, /permissive - requires is_swappable_v<_Err> -#else // ^^^ no workaround / workaround vvv - requires is_swappable<_Err>::value -#endif // ^^^ workaround ^^^ + requires is_swappable<_Err>::value // TRANSITION, /permissive needs ::value { _Left.swap(_Right); } // [expected.un.eq] template - _NODISCARD_FRIEND constexpr bool operator==(const unexpected& _Left, const unexpected<_UErr>& _Right) noexcept( + _NODISCARD friend constexpr bool operator==(const unexpected& _Left, const unexpected<_UErr>& _Right) noexcept( noexcept(_STD _Fake_copy_init(_Left._Unexpected == _Right.error()))) /* strengthened */ { return _Left._Unexpected == _Right.error(); } @@ -612,11 +608,7 @@ public: friend constexpr void swap(expected& _Lhs, expected& _Rhs) noexcept( is_nothrow_move_constructible_v<_Ty> && is_nothrow_swappable_v<_Ty> && is_nothrow_move_constructible_v<_Err> && is_nothrow_swappable_v<_Err>) -#if defined(__clang__) || defined(__EDG__) // TRANSITION, /permissive - requires is_swappable_v<_Ty> && is_swappable_v<_Err> -#else // ^^^ no workaround / workaround vvv - requires is_swappable<_Ty>::value && is_swappable<_Err>::value -#endif // ^^^ workaround ^^^ + requires is_swappable<_Ty>::value && is_swappable<_Err>::value // TRANSITION, /permissive needs ::value && is_move_constructible_v<_Ty> && is_move_constructible_v<_Err> && (is_nothrow_move_constructible_v<_Ty> || is_nothrow_move_constructible_v<_Err>) { @@ -1140,7 +1132,7 @@ public: // [expected.object.eq] template requires (!is_void_v<_Uty>) - _NODISCARD_FRIEND constexpr bool operator==(const expected& _Left, const expected<_Uty, _UErr>& _Right) noexcept( + _NODISCARD friend constexpr bool operator==(const expected& _Left, const expected<_Uty, _UErr>& _Right) noexcept( noexcept(_STD _Fake_copy_init(_Left._Value == *_Right)) && noexcept( _STD _Fake_copy_init(_Left._Unexpected == _Right.error()))) /* strengthened */ { if (_Left._Has_value != _Right.has_value()) { @@ -1153,7 +1145,7 @@ public: } template - _NODISCARD_FRIEND constexpr bool operator==(const expected& _Left, const _Uty& _Right) noexcept( + _NODISCARD friend constexpr bool operator==(const expected& _Left, const _Uty& _Right) noexcept( noexcept(static_cast(_Left._Value == _Right))) /* strengthened */ { if (_Left._Has_value) { return static_cast(_Left._Value == _Right); @@ -1163,7 +1155,7 @@ public: } template - _NODISCARD_FRIEND constexpr bool operator==(const expected& _Left, const unexpected<_UErr>& _Right) noexcept( + _NODISCARD friend constexpr bool operator==(const expected& _Left, const unexpected<_UErr>& _Right) noexcept( noexcept(static_cast(_Left._Unexpected == _Right.error()))) /* strengthened */ { if (_Left._Has_value) { return false; @@ -1876,7 +1868,7 @@ public: // [expected.void.eq] template requires is_void_v<_Uty> - _NODISCARD_FRIEND constexpr bool operator==(const expected& _Left, const expected<_Uty, _UErr>& _Right) noexcept( + _NODISCARD friend constexpr bool operator==(const expected& _Left, const expected<_Uty, _UErr>& _Right) noexcept( noexcept(static_cast(_Left._Unexpected == _Right.error()))) /* strengthened */ { if (_Left._Has_value != _Right.has_value()) { return false; @@ -1886,7 +1878,7 @@ public: } template - _NODISCARD_FRIEND constexpr bool operator==(const expected& _Left, const unexpected<_UErr>& _Right) noexcept( + _NODISCARD friend constexpr bool operator==(const expected& _Left, const unexpected<_UErr>& _Right) noexcept( noexcept(static_cast(_Left._Unexpected == _Right.error()))) /* strengthened */ { if (_Left._Has_value) { return false; diff --git a/stl/inc/filesystem b/stl/inc/filesystem index 2867eec5bb2..5c321608490 100644 --- a/stl/inc/filesystem +++ b/stl/inc/filesystem @@ -1346,37 +1346,37 @@ namespace filesystem { return _Istr; } - _NODISCARD_FRIEND bool operator==(const path& _Left, const path& _Right) noexcept { + _NODISCARD friend bool operator==(const path& _Left, const path& _Right) noexcept { return _Left.compare(_Right._Text) == 0; } #if _HAS_CXX20 - _NODISCARD_FRIEND strong_ordering operator<=>(const path& _Left, const path& _Right) noexcept { + _NODISCARD friend strong_ordering operator<=>(const path& _Left, const path& _Right) noexcept { return _Left.compare(_Right._Text) <=> 0; } #else // ^^^ _HAS_CXX20 / !_HAS_CXX20 vvv - _NODISCARD_FRIEND bool operator!=(const path& _Left, const path& _Right) noexcept { + _NODISCARD friend bool operator!=(const path& _Left, const path& _Right) noexcept { return _Left.compare(_Right) != 0; } - _NODISCARD_FRIEND bool operator<(const path& _Left, const path& _Right) noexcept { + _NODISCARD friend bool operator<(const path& _Left, const path& _Right) noexcept { return _Left.compare(_Right) < 0; } - _NODISCARD_FRIEND bool operator>(const path& _Left, const path& _Right) noexcept { + _NODISCARD friend bool operator>(const path& _Left, const path& _Right) noexcept { return _Left.compare(_Right) > 0; } - _NODISCARD_FRIEND bool operator<=(const path& _Left, const path& _Right) noexcept { + _NODISCARD friend bool operator<=(const path& _Left, const path& _Right) noexcept { return _Left.compare(_Right) <= 0; } - _NODISCARD_FRIEND bool operator>=(const path& _Left, const path& _Right) noexcept { + _NODISCARD friend bool operator>=(const path& _Left, const path& _Right) noexcept { return _Left.compare(_Right) >= 0; } #endif // ^^^ !_HAS_CXX20 ^^^ - _NODISCARD_FRIEND path operator/(const path& _Left, const path& _Right) { // append a pair of paths together + _NODISCARD friend path operator/(const path& _Left, const path& _Right) { // append a pair of paths together const auto _Right_size = _Right._Text.size(); const auto _Right_first = _Right._Text.data(); const auto _Right_last = _Right_first + _Right_size; @@ -1578,12 +1578,12 @@ namespace filesystem { return _Tmp; } - _NODISCARD_FRIEND bool operator==(const _Path_iterator& _Lhs, const _Path_iterator& _Rhs) { + _NODISCARD friend bool operator==(const _Path_iterator& _Lhs, const _Path_iterator& _Rhs) { return _Lhs._Position == _Rhs._Position; } #if !_HAS_CXX20 - _NODISCARD_FRIEND bool operator!=(const _Path_iterator& _Lhs, const _Path_iterator& _Rhs) { + _NODISCARD friend bool operator!=(const _Path_iterator& _Lhs, const _Path_iterator& _Rhs) { return _Lhs._Position != _Rhs._Position; } #endif // !_HAS_CXX20 @@ -1981,7 +1981,7 @@ namespace filesystem { } #if _HAS_CXX20 - _NODISCARD_FRIEND bool operator==(const file_status& _Lhs, const file_status& _Rhs) noexcept { + _NODISCARD friend bool operator==(const file_status& _Lhs, const file_status& _Rhs) noexcept { return _Lhs._Myftype == _Rhs._Myftype && _Lhs._Myperms == _Rhs._Myperms; } #endif // _HAS_CXX20 @@ -3719,7 +3719,7 @@ namespace filesystem { uintmax_t available; #if _HAS_CXX20 - _NODISCARD_FRIEND constexpr bool operator==(const space_info&, const space_info&) noexcept = default; + _NODISCARD friend constexpr bool operator==(const space_info&, const space_info&) noexcept = default; #endif // _HAS_CXX20 }; diff --git a/stl/inc/format b/stl/inc/format index b734cb23b97..be7a99523d6 100644 --- a/stl/inc/format +++ b/stl/inc/format @@ -2079,8 +2079,6 @@ class _Format_arg_store<_Context> {}; _EXPORT_STD template class basic_format_args { public: - basic_format_args() noexcept = default; - basic_format_args(const _Format_arg_store<_Context>&) noexcept {} template @@ -2208,6 +2206,9 @@ private: _Out&& _OutputIt_, const basic_format_args& _Ctx_args, const _Lazy_locale& _Loc_) : _OutputIt(_STD move(_OutputIt_)), _Args(_Ctx_args), _Loc(_Loc_) {} + basic_format_context(const basic_format_context&) = delete; + basic_format_context& operator=(const basic_format_context&) = delete; + public: using iterator = _Out; using char_type = _CharT; @@ -2466,45 +2467,6 @@ using _Default_format_context = basic_format_context<_Basic_fmt_it<_CharT>, _Cha _EXPORT_STD using format_context = _Default_format_context; _EXPORT_STD using wformat_context = _Default_format_context; -#if _HAS_CXX23 -_EXPORT_STD enum class range_format { disabled, map, set, sequence, string, debug_string }; - -template -struct _Invalid_format_kind { - static_assert(_Always_false<_Ty>, "A program that instantiates the primary template of format_kind is ill-formed. " - "(N4964 [format.range.fmtkind]/1)"); -}; - -_EXPORT_STD template -constexpr _Invalid_format_kind<_Ty> format_kind; - -template -constexpr bool _Is_two_tuple = false; - -template -constexpr bool _Is_two_tuple> = true; - -template -constexpr bool _Is_two_tuple> = true; - -template <_RANGES input_range _Rng> - requires same_as<_Rng, remove_cvref_t<_Rng>> -constexpr range_format format_kind<_Rng> = []() consteval { - using _Ref_value_t = remove_cvref_t<_RANGES range_reference_t<_Rng>>; - if constexpr (same_as<_Ref_value_t, _Rng>) { - return range_format::disabled; - } else if constexpr (requires { typename _Rng::key_type; }) { - if constexpr (requires { typename _Rng::mapped_type; } && _Is_two_tuple<_Ref_value_t>) { - return range_format::map; - } else { - return range_format::set; - } - } else { - return range_format::sequence; - } -}(); -#endif // _HAS_CXX23 - _FMT_P2286_BEGIN template _NODISCARD _OutputIt _Fmt_write(_OutputIt _Out, monostate) { @@ -3986,8 +3948,6 @@ _NODISCARD int _Measure_display_width(const basic_string_view<_CharT> _Value) { return _Width; } -enum class _Fmt_tuple_type : uint8_t { _None, _Key_value, _No_brackets }; - template struct _Fill_align_and_width_specs { int _Width = -1; @@ -3998,12 +3958,12 @@ struct _Fill_align_and_width_specs { _CharT _Fill[4 / sizeof(_CharT)]{' '}; }; -template -class _Tuple_format_specs_setter { +template +class _Fill_align_and_width_specs_setter { public: - constexpr explicit _Tuple_format_specs_setter(_Fill_align_and_width_specs<_CharT>& _Specs_, - _Fmt_tuple_type& _Fmt_type_, basic_format_parse_context<_CharT>& _Parse_ctx_) - : _Specs(_Specs_), _Fmt_type(_Fmt_type_), _Parse_ctx(_Parse_ctx_) {} + constexpr explicit _Fill_align_and_width_specs_setter( + _Fill_align_and_width_specs<_CharT>& _Specs_, basic_format_parse_context<_CharT>& _Parse_ctx_) + : _Specs(_Specs_), _Parse_ctx(_Parse_ctx_) {} constexpr void _On_align(const _Fmt_align _Aln) { _Specs._Alignment = _Aln; @@ -4014,10 +3974,6 @@ public: _Throw_format_error("Invalid fill (too long)."); } - if (_Sv == _STATICALLY_WIDEN(_CharT, ":")) { - _Throw_format_error(R"(Invalid fill ":" for tuples and pairs.)"); - } - const auto _Pos = _STD _Copy_unchecked(_Sv._Unchecked_begin(), _Sv._Unchecked_end(), _Specs._Fill); _STD fill(_Pos, _STD end(_Specs._Fill), _CharT{}); _Specs._Fill_length = static_cast(_Sv.size()); @@ -4039,29 +3995,10 @@ public: _Specs._Dynamic_width_index = _Verify_dynamic_arg_index_in_range(_Arg_id); } - constexpr void _On_type(const _CharT _Type) { - if (_Type == _CharT{}) { - return; - } - - if (_Type == static_cast<_CharT>('n')) { - _Fmt_type = _Fmt_tuple_type::_No_brackets; - return; - } - - if constexpr (_IsTwoTuple) { - if (_Type == static_cast<_CharT>('m')) { - _Fmt_type = _Fmt_tuple_type::_Key_value; - return; - } - } - - _Throw_format_error("Invalid type specification."); - } +protected: + _Fill_align_and_width_specs<_CharT>& _Specs; private: - _Fill_align_and_width_specs<_CharT>& _Specs; - _Fmt_tuple_type& _Fmt_type; basic_format_parse_context<_CharT>& _Parse_ctx; _NODISCARD static constexpr int _Verify_dynamic_arg_index_in_range(const size_t _Idx) { @@ -4073,240 +4010,411 @@ private: } }; -template -_NODISCARD constexpr const _CharT* _Parse_tuple_format_specs( - const _CharT* _Begin, const _CharT* _End, _Callbacks_type&& _Callbacks) { - if (_Begin == _End || *_Begin == '}') { +template +struct _Range_specs : _Fill_align_and_width_specs<_CharT> { + bool _No_brackets = false; + char _Type = '\0'; +}; + +template +class _Range_specs_setter : public _Fill_align_and_width_specs_setter<_CharT> { +public: + constexpr explicit _Range_specs_setter( + _Range_specs<_CharT>& _Specs_, basic_format_parse_context<_CharT>& _Parse_ctx_) + : _Fill_align_and_width_specs_setter<_CharT>(_Specs_, _Parse_ctx_) {} + + constexpr void _On_no_brackets() { + static_cast<_Range_specs<_CharT>&>(this->_Specs)._No_brackets = true; + } + + constexpr void _On_type(const _CharT _Type) { + _STL_INTERNAL_CHECK(_Type == 'm' || _Type == 's' || _Type == '?'); + static_cast<_Range_specs<_CharT>&>(this->_Specs)._Type = static_cast(_Type); + } +}; + +template +_NODISCARD constexpr const _CharT* _Parse_range_specs( + const _CharT* _Begin, const _CharT* const _End, _Range_specs_setter<_CharT>& _Callbacks) { + if (_Begin == _End || *_Begin == '}' || *_Begin == ':') { return _Begin; } - _Begin = _STD _Parse_align(_Begin, _End, _Callbacks); + _Begin = _Parse_align(_Begin, _End, _Callbacks); if (_Begin == _End) { return _Begin; } - _Begin = _STD _Parse_width(_Begin, _End, _Callbacks); + _Begin = _Parse_width(_Begin, _End, _Callbacks); if (_Begin == _End) { return _Begin; } - // If there's anything remaining we assume it's a type. - if (*_Begin != '}') { - _Callbacks._On_type(*_Begin); + if (*_Begin == 'n') { + _Callbacks._On_no_brackets(); + if (++_Begin == _End) { + return _Begin; + } + } + + switch (const _CharT _Maybe_type = *_Begin) { + case '?': + if (++_Begin == _End || *_Begin != 's') { + _Throw_format_error("Invalid range-type '?'; was '?s' intended?"); + } + [[fallthrough]]; + case 'm': + case 's': + _Callbacks._On_type(_Maybe_type); ++_Begin; - } else { - // call the type callback so it gets a default type, this is required - // since _Specs_checker needs to be able to tell that it got a default type - // to raise an error for default formatted bools with a sign modifier - _Callbacks._On_type(_CharT{}); + break; + default: + break; } return _Begin; } -template -constexpr void _Set_tuple_debug_format(_FormatterType& _Formatter, _ParseContext& _Parse_ctx) { - _Formatter.parse(_Parse_ctx); - if constexpr (requires { _Formatter.set_debug_format(); }) { - _Formatter.set_debug_format(); - } -} - -template ... _Types> -class _Tuple_formatter_common_base { +_EXPORT_STD template + requires same_as, _Ty> && formattable<_Ty, _CharT> +class range_formatter { private: - tuple, _CharT>...> _Underlying; + formatter<_Ty, _CharT> _Underlying; basic_string_view<_CharT> _Separator = _STATICALLY_WIDEN(_CharT, ", "); - basic_string_view<_CharT> _Opening_bracket = _STATICALLY_WIDEN(_CharT, "("); - basic_string_view<_CharT> _Closing_bracket = _STATICALLY_WIDEN(_CharT, ")"); - - _Fill_align_and_width_specs<_CharT> _Specs; - - template - void _Format_to_context(_FormatContext& _Fmt_ctx, _ArgTypes&... _Args) const { - _STD _Copy_unchecked(_Opening_bracket._Unchecked_begin(), _Opening_bracket._Unchecked_end(), _Fmt_ctx.out()); - [&](index_sequence<_Indices...>) { - auto _Single_writer = [&](auto& _Arg) { - if constexpr (_Idx != 0) { - _STD _Copy_unchecked(_Separator._Unchecked_begin(), _Separator._Unchecked_end(), _Fmt_ctx.out()); - } - _STD get<_Idx>(_Underlying).format(_Arg, _Fmt_ctx); - }; - (_Single_writer.template operator()<_Indices>(_Args), ...); - }(index_sequence_for<_ArgTypes...>{}); - _STD _Copy_unchecked(_Closing_bracket._Unchecked_begin(), _Closing_bracket._Unchecked_end(), _Fmt_ctx.out()); - } - -protected: - static constexpr bool _Is_const_formattable = (formattable && ...); - - template - _FormatContext::iterator _Format(_FormatContext& _Fmt_ctx, _ArgTypes&... _Args) const { - _STL_INTERNAL_STATIC_ASSERT( - (is_same_v<_ArgTypes, remove_reference_t<_Maybe_const<_Is_const_formattable, _Types>>> && ...)); - - auto _Format_specs = _Specs; - if (_Specs._Dynamic_width_index >= 0) { - _Format_specs._Width = - _STD _Get_dynamic_specs<_Width_checker>(_Fmt_ctx.arg(static_cast(_Specs._Dynamic_width_index))); - } - - if (_Format_specs._Width <= 0) { - _Format_to_context(_Fmt_ctx, _Args...); - return _Fmt_ctx.out(); - } - - basic_string<_CharT> _Tmp_str; - if constexpr (is_same_v<_FormatContext, _Default_format_context<_CharT>>) { - _Fmt_iterator_buffer>, _CharT> _Tmp_buf{ - back_insert_iterator{_Tmp_str}}; - auto _Tmp_ctx = _FormatContext::_Make_from( - _Basic_fmt_it<_CharT>{_Tmp_buf}, _Fmt_ctx._Get_args(), _Fmt_ctx._Get_lazy_locale()); - _Format_to_context(_Tmp_ctx, _Args...); - } else { - _CSTD abort(); // no basic_format_context object other than _Default_format_context can be created - } - - const int _Width = _Measure_display_width<_CharT>(_Tmp_str); - return _STD _Write_aligned( - _Fmt_ctx.out(), _Width, _Format_specs, _Fmt_align::_Left, [&](typename _FormatContext::iterator _Out) { - return _STD _Fmt_write(_STD move(_Out), basic_string_view<_CharT>{_Tmp_str}); - }); - } + basic_string_view<_CharT> _Opening_bracket = _STATICALLY_WIDEN(_CharT, "["); + basic_string_view<_CharT> _Closing_bracket = _STATICALLY_WIDEN(_CharT, "]"); + _Range_specs<_CharT> _Specs; public: - constexpr void set_separator(const basic_string_view<_CharT> _Sep) noexcept { + constexpr void set_separator(basic_string_view<_CharT> _Sep) noexcept { _Separator = _Sep; } - constexpr void set_brackets( - const basic_string_view<_CharT> _Opening, const basic_string_view<_CharT> _Closing) noexcept { + constexpr void set_brackets(basic_string_view<_CharT> _Opening, basic_string_view<_CharT> _Closing) noexcept { _Opening_bracket = _Opening; _Closing_bracket = _Closing; } + _NODISCARD constexpr formatter<_Ty, _CharT>& underlying() noexcept { + return _Underlying; + } + + _NODISCARD constexpr const formatter<_Ty, _CharT>& underlying() const noexcept { + return _Underlying; + } + template constexpr _ParseContext::iterator parse(_ParseContext& _Ctx) { - _Fmt_tuple_type _Fmt_type = _Fmt_tuple_type::_None; - _Tuple_format_specs_setter<_CharT, sizeof...(_Types) == 2> _Callback{_Specs, _Fmt_type, _Ctx}; - const auto _It = _STD _Parse_tuple_format_specs(_Ctx._Unchecked_begin(), _Ctx._Unchecked_end(), _Callback); - if (_It != _Ctx._Unchecked_end() && *_It != '}') { - _STD _Throw_format_error("Missing '}' in format string."); - } + _Range_specs_setter<_CharT> _Callback{_Specs, _Ctx}; + auto _It = _STD _Parse_range_specs(_Ctx._Unchecked_begin(), _Ctx._Unchecked_end(), _Callback); - if (_Fmt_type == _Fmt_tuple_type::_No_brackets) { - set_brackets({}, {}); - } else if constexpr (sizeof...(_Types) == 2) { - if (_Fmt_type == _Fmt_tuple_type::_Key_value) { - set_separator(_STATICALLY_WIDEN(_CharT, ": ")); - set_brackets({}, {}); + _Ctx.advance_to(_Ctx.begin() + (_It - _Ctx._Unchecked_begin())); + bool _Has_underlying_spec = false; + if (_It != _Ctx._Unchecked_end()) { + if (*_It == ':') { + _Has_underlying_spec = true; + _Ctx.advance_to(_Ctx.begin() + 1); + } else if (*_It != '}') { + _Throw_format_error("Invalid range-format-spec."); } } - _Ctx.advance_to(_Ctx.begin() + (_It - _Ctx._Unchecked_begin())); - _STD apply([&_Ctx](auto&... _Elems) { (_Set_tuple_debug_format(_Elems, _Ctx), ...); }, _Underlying); + _It = _Underlying.parse(_Ctx)._Unwrapped(); + if (_It != _Ctx._Unchecked_end() && *_It != '}') { + _Throw_format_error("Missing '}' in format string."); + } - return _Ctx.begin(); - } -}; + switch (_Specs._Type) { + case 'm': + if constexpr (_Is_two_tuple<_Ty>) { + set_brackets(_STATICALLY_WIDEN(_CharT, "{"), _STATICALLY_WIDEN(_CharT, "}")); + set_separator(_STATICALLY_WIDEN(_CharT, ", ")); + _Underlying.set_brackets({}, {}); + _Underlying.set_separator(_STATICALLY_WIDEN(_CharT, ": ")); + } else { + _Throw_format_error("Range-type 'm' requires type T to be a pair or a 2-element tuple."); + } + [[fallthrough]]; -// formatter definition for all pairs and tuples, the deleted default constructor -// makes it "disabled" as per N4971 [format.formatter.spec]/5 + case '\0': + if constexpr (requires { _Underlying.set_debug_format(); }) { + if (!_Has_underlying_spec) { + _Underlying.set_debug_format(); + } + } + break; -template -struct _Tuple_formatter_base { - _Tuple_formatter_base() = delete; - _Tuple_formatter_base(const _Tuple_formatter_base&) = delete; - _Tuple_formatter_base& operator=(const _Tuple_formatter_base&) = delete; -}; + case 's': + case '?': + if constexpr (same_as<_Ty, _CharT>) { + if (_Specs._No_brackets) { + _Throw_format_error("Range-types 's' and '?s' cannot be combined with the 'n' option."); + } else if (_Has_underlying_spec) { + _Throw_format_error("Range-types 's' and '?s' cannot be combined with a range-underlying-spec."); + } + } else { + _Throw_format_error("Range-types 's' and '?s' require type T to be charT."); + } + + break; + + default: + _STL_UNREACHABLE; // can't happen, we've handled all possible outputs from _Parse_range_specs() + break; + } + + if (_Specs._No_brackets) { + set_brackets({}, {}); + } + + return _Ctx.begin() + (_It - _Ctx._Unchecked_begin()); + } + + template <_RANGES input_range _Range, class _FormatContext> + requires formattable<_RANGES range_reference_t<_Range>, _CharT> + && same_as>, _Ty> + _FormatContext::iterator format(_Range&& _Rng, _FormatContext& _Ctx) const { + return _Format(_STD forward<_Range>(_Rng), _Ctx); + } -template _Ty1, formattable<_CharT> _Ty2> -struct _Tuple_formatter_base, _CharT> : _Tuple_formatter_common_base<_CharT, _Ty1, _Ty2> { private: - using _Base = _Tuple_formatter_common_base<_CharT, _Ty1, _Ty2>; - using _Formatted_type = _Maybe_const<_Base::_Is_const_formattable, pair<_Ty1, _Ty2>>; + template <_RANGES input_range _Range, class _FormatContext> + _FormatContext::iterator _Format(_Range&&, _FormatContext&) const { + _Throw_format_error("Unsupported 'basic_format_context'."); + } -public: - template - _FormatContext::iterator format(_Formatted_type& _Elems, _FormatContext& _Ctx) const { - return this->_Format(_Ctx, _Elems.first, _Elems.second); + template <_RANGES input_range _Range, class _FormatContext> + requires _Is_specialization_v + && derived_from> + _FormatContext::iterator _Format(_Range&& _Rng, _FormatContext& _Ctx) const { + auto _Format_specs = _Specs; + if (_Specs._Dynamic_width_index >= 0) { + _Format_specs._Width = + _STD _Get_dynamic_specs<_Width_checker>(_Ctx.arg(static_cast(_Specs._Dynamic_width_index))); + } + + basic_string<_CharT> _Buffer; + { + _Fmt_iterator_buffer>, _CharT> _Fmt_buf( + back_insert_iterator{_Buffer}); + using _Inserter = back_insert_iterator<_Fmt_buffer<_CharT>>; + auto _Nested_context = basic_format_context<_Inserter, _CharT>::_Make_from( + _Inserter{_Fmt_buf}, _Ctx._Get_args(), _Ctx._Get_lazy_locale()); + + if constexpr (same_as<_Ty, _CharT>) { + if (_Specs._Type == 's' || _Specs._Type == '?') { + _Format_as_string(_STD forward<_Range>(_Rng), _Nested_context, _Specs._Type == '?'); + } else { + _Format_as_sequence(_STD forward<_Range>(_Rng), _Nested_context); + } + } else { + _Format_as_sequence(_STD forward<_Range>(_Rng), _Nested_context); + } + } + + const int _Width = _Measure_display_width<_CharT>(_Buffer); + return _STD _Write_aligned( + _Ctx.out(), _Width, _Format_specs, _Fmt_align::_Left, [&](_FormatContext::iterator _Out) { + return _STD _Fmt_write(_STD move(_Out), basic_string_view{_Buffer}); + }); + } + + template <_RANGES input_range _Range, class _FormatContext> + void _Format_as_sequence(_Range&& _Rng, _FormatContext& _Ctx) const { + _Ctx.advance_to(_STD _Fmt_write(_Ctx.out(), _Opening_bracket)); + bool _Separate = false; + for (auto&& _Elem : _Rng) { + if (_Separate) { + _Ctx.advance_to(_STD _Fmt_write(_Ctx.out(), _Separator)); + } + + _Separate = true; + _Ctx.advance_to(_Underlying.format(_Elem, _Ctx)); + } + + (void) _STD _Fmt_write(_Ctx.out(), _Closing_bracket); + } + + template <_RANGES input_range _Range, class _FormatContext> + void _Format_as_string(_Range&& _Rng, _FormatContext& _Ctx, const bool _Debug) const { + if constexpr (_RANGES contiguous_range<_Range>) { + const auto _Size = _STD _To_unsigned_like(_RANGES distance(_Rng)); + + if (!_STD in_range(_Size)) [[unlikely]] { + _Throw_format_error("Formatted range is too long."); + } + + formatter, _CharT> _String_view_formatter; + if (_Debug) { + _String_view_formatter.set_debug_format(); + } + + const basic_string_view<_CharT> _Str(_STD to_address(_RANGES begin(_Rng)), static_cast(_Size)); + _String_view_formatter.format(_Str, _Ctx); + } else { + using _String = basic_string<_CharT>; + formatter<_String, _CharT> _String_formatter; + if (_Debug) { + _String_formatter.set_debug_format(); + } + + _String_formatter.format(_String{from_range, _Rng}, _Ctx); + } } }; -template ... _Types> -struct _Tuple_formatter_base, _CharT> : _Tuple_formatter_common_base<_CharT, _Types...> { +template +concept _Const_formattable_range = + _RANGES input_range && formattable<_RANGES range_reference_t, _CharT>; + +template +using _Fmt_maybe_const = conditional_t<_Const_formattable_range<_Rng, _CharT>, const _Rng, _Rng>; + +template +struct _Range_default_formatter; + +template <_RANGES input_range _Rng, class _CharT> +struct _Range_default_formatter { private: - using _Base = _Tuple_formatter_common_base<_CharT, _Types...>; - using _Formatted_type = _Maybe_const<_Base::_Is_const_formattable, tuple<_Types...>>; + using _Range_type = _Fmt_maybe_const<_Rng, _CharT>; + + range_formatter>, _CharT> _Underlying; public: + constexpr void set_separator(const basic_string_view<_CharT> _Sep) noexcept { + _Underlying.set_separator(_Sep); + } + + constexpr void set_brackets( + const basic_string_view<_CharT> _Opening, const basic_string_view<_CharT> _Closing) noexcept { + _Underlying.set_brackets(_Opening, _Closing); + } + + template + constexpr _ParseContext::iterator parse(_ParseContext& _Ctx) { + return _Underlying.parse(_Ctx); + } + template - _FormatContext::iterator format(_Formatted_type& _Elems, _FormatContext& _Ctx) const { - return _STD apply([this, &_Ctx](auto&... _Args) { return this->_Format(_Ctx, _Args...); }, _Elems); + _FormatContext::iterator format(_Range_type& _Elems, _FormatContext& _Ctx) const { + return _Underlying.format(_Elems, _Ctx); } }; -// Per LWG-3997, `_CharT` in library-provided `formatter` specializations is -// constrained to character types supported by `format`. +template <_RANGES input_range _Rng, class _CharT> +struct _Range_default_formatter { +private: + using _Map_type = _Fmt_maybe_const<_Rng, _CharT>; + using _Element_type = remove_cvref_t<_RANGES range_reference_t<_Map_type>>; -template <_Format_supported_charT _CharT, class _Ty1, class _Ty2> -struct formatter, _CharT> : _Tuple_formatter_base, _CharT> {}; + range_formatter<_Element_type, _CharT> _Underlying; -template <_Format_supported_charT _CharT, class... _Types> -struct formatter, _CharT> : _Tuple_formatter_base, _CharT> {}; +public: + constexpr _Range_default_formatter() noexcept( + is_nothrow_default_constructible_v>) /* strengthened */ { + static_assert(_Is_two_tuple<_Element_type>, "the element type of the formatted range must be either pair " + "or tuple (N4981 [format.range.fmtmap]/1)"); -enum class _Add_newline : bool { _Nope, _Yes }; + _Underlying.set_brackets(_STATICALLY_WIDEN(_CharT, "{"), _STATICALLY_WIDEN(_CharT, "}")); + _Underlying.underlying().set_brackets({}, {}); + _Underlying.underlying().set_separator(_STATICALLY_WIDEN(_CharT, ": ")); + } -_NODISCARD inline string _Unescape_braces(const _Add_newline _Add_nl, const string_view _Old_str) { - string _Unescaped_str; + template + constexpr _ParseContext::iterator parse(_ParseContext& _Ctx) { + return _Underlying.parse(_Ctx); + } - if (_Old_str.empty()) { - if (_Add_nl == _Add_newline::_Yes) { - _Unescaped_str.push_back('\n'); - } + template + _FormatContext::iterator format(_Map_type& _Rx, _FormatContext& _Ctx) const { + return _Underlying.format(_Rx, _Ctx); + } +}; - return _Unescaped_str; +template <_RANGES input_range _Rng, class _CharT> +struct _Range_default_formatter { +private: + using _Set_type = _Fmt_maybe_const<_Rng, _CharT>; + range_formatter>, _CharT> _Underlying; + +public: + constexpr _Range_default_formatter() noexcept(is_nothrow_default_constructible_v< + range_formatter>, _CharT>>) /* strengthened */ { + _Underlying.set_brackets(_STATICALLY_WIDEN(_CharT, "{"), _STATICALLY_WIDEN(_CharT, "}")); } - size_t _Unescaped_str_expected_size = _Old_str.size(); + template + constexpr _ParseContext::iterator parse(_ParseContext& _Ctx) { + return _Underlying.parse(_Ctx); + } - if (_Add_nl == _Add_newline::_Yes) { - ++_Unescaped_str_expected_size; + template + _FormatContext::iterator format(_Set_type& _Rx, _FormatContext& _Ctx) const { + return _Underlying.format(_Rx, _Ctx); } +}; - _Unescaped_str.resize_and_overwrite(_Unescaped_str_expected_size, [_Add_nl, _Old_str](char* _Dest_ptr, size_t) { - char _Prev_char = _Old_str.front(); - size_t _Num_chars_written = 1; - *_Dest_ptr++ = _Prev_char; +template + requires (_Kind == range_format::string || _Kind == range_format::debug_string) +struct _Range_default_formatter<_Kind, _Rng, _CharT> { +private: + static_assert(is_same_v>, _CharT>, + "the element type of the formatted range must be the character type used in formatting " + "(N4981 [format.range.fmtstr]/1)"); - for (const auto _Curr_char : _Old_str.substr(1)) { - if ((_Curr_char == '{' && _Prev_char == '{') || (_Curr_char == '}' && _Prev_char == '}')) { - _Prev_char = '\0'; - } else { - *_Dest_ptr++ = _Curr_char; - ++_Num_chars_written; + using _Range_type = _Maybe_const<_RANGES input_range, _Rng>; - _Prev_char = _Curr_char; - } + formatter, _CharT> _Underlying; // avoid copying the string if possible + +public: + template + constexpr _ParseContext::iterator parse(_ParseContext& _Ctx) { + auto _Iter = _Underlying.parse(_Ctx); + if constexpr (_Kind == range_format::debug_string) { + _Underlying.set_debug_format(); } + return _Iter; + } - if (_Add_nl == _Add_newline::_Yes) { - *_Dest_ptr = '\n'; - ++_Num_chars_written; + template + _FormatContext::iterator format(_Range_type& _Rx, _FormatContext& _Ctx) const { + if constexpr (_RANGES contiguous_range<_Range_type>) { + const auto _Size = _STD _To_unsigned_like(_RANGES distance(_Rx)); + + if (!_STD in_range(_Size)) [[unlikely]] { + _Throw_format_error("Formatted range is too long."); + } + + const basic_string_view<_CharT> _Str(_STD to_address(_RANGES begin(_Rx)), static_cast(_Size)); + return _Underlying.format(_Str, _Ctx); + } else { + return _Underlying.format(basic_string<_CharT>{from_range, _Rx}, _Ctx); } + } +}; - return _Num_chars_written; - }); +// the deleted default constructor makes it "disabled" as per N4981 [format.formatter.spec]/5 - return _Unescaped_str; -} +template <_RANGES input_range _Rng, _Format_supported_charT _CharT> + requires _Formatting_enabled_range<_Rng> +struct formatter<_Rng, _CharT> { + formatter() = delete; + formatter(const formatter&) = delete; + formatter& operator=(const formatter&) = delete; +}; -template -class _Fill_align_and_width_specs_setter { +template <_RANGES input_range _Rng, _Format_supported_charT _CharT> + requires _Formatting_enabled_range<_Rng> && formattable<_RANGES range_reference_t<_Rng>, _CharT> +struct formatter<_Rng, _CharT> : _Range_default_formatter, _Rng, _CharT> {}; + +enum class _Fmt_tuple_type : uint8_t { _None, _Key_value, _No_brackets }; + +template +class _Tuple_format_specs_setter { public: - constexpr explicit _Fill_align_and_width_specs_setter( - _Fill_align_and_width_specs<_CharT>& _Specs_, basic_format_parse_context<_CharT>& _Parse_ctx_) - : _Specs(_Specs_), _Parse_ctx(_Parse_ctx_) {} + constexpr explicit _Tuple_format_specs_setter(_Fill_align_and_width_specs<_CharT>& _Specs_, + _Fmt_tuple_type& _Fmt_type_, basic_format_parse_context<_CharT>& _Parse_ctx_) + : _Specs(_Specs_), _Fmt_type(_Fmt_type_), _Parse_ctx(_Parse_ctx_) {} constexpr void _On_align(const _Fmt_align _Aln) { _Specs._Alignment = _Aln; @@ -4317,6 +4425,10 @@ public: _Throw_format_error("Invalid fill (too long)."); } + if (_Sv == _STATICALLY_WIDEN(_CharT, ":")) { + _Throw_format_error(R"(Invalid fill ":" for tuples and pairs.)"); + } + const auto _Pos = _STD _Copy_unchecked(_Sv._Unchecked_begin(), _Sv._Unchecked_end(), _Specs._Fill); _STD fill(_Pos, _STD end(_Specs._Fill), _CharT{}); _Specs._Fill_length = static_cast(_Sv.size()); @@ -4338,10 +4450,29 @@ public: _Specs._Dynamic_width_index = _Verify_dynamic_arg_index_in_range(_Arg_id); } -protected: - _Fill_align_and_width_specs<_CharT>& _Specs; + constexpr void _On_type(const _CharT _Type) { + if (_Type == _CharT{}) { + return; + } + + if (_Type == static_cast<_CharT>('n')) { + _Fmt_type = _Fmt_tuple_type::_No_brackets; + return; + } + + if constexpr (_IsTwoTuple) { + if (_Type == static_cast<_CharT>('m')) { + _Fmt_type = _Fmt_tuple_type::_Key_value; + return; + } + } + + _Throw_format_error("Invalid type specification."); + } private: + _Fill_align_and_width_specs<_CharT>& _Specs; + _Fmt_tuple_type& _Fmt_type; basic_format_parse_context<_CharT>& _Parse_ctx; _NODISCARD static constexpr int _Verify_dynamic_arg_index_in_range(const size_t _Idx) { @@ -4354,301 +4485,294 @@ private: }; template -_NODISCARD constexpr const _CharT* _Parse_fill_align_and_width_specs( +_NODISCARD constexpr const _CharT* _Parse_tuple_format_specs( const _CharT* _Begin, const _CharT* _End, _Callbacks_type&& _Callbacks) { if (_Begin == _End || *_Begin == '}') { return _Begin; } - _Begin = _Parse_align(_Begin, _End, _Callbacks); + _Begin = _STD _Parse_align(_Begin, _End, _Callbacks); if (_Begin == _End) { return _Begin; } - return _Parse_width(_Begin, _End, _Callbacks); -} - -template -struct _Fill_align_and_width_formatter { -public: - _NODISCARD constexpr auto _Parse(basic_format_parse_context<_CharT>& _Parse_ctx) { - _Fill_align_and_width_specs_setter<_CharT> _Callback{_Specs, _Parse_ctx}; - const auto _It = - _Parse_fill_align_and_width_specs(_Parse_ctx._Unchecked_begin(), _Parse_ctx._Unchecked_end(), _Callback); - if (_It != _Parse_ctx._Unchecked_end() && *_It != '}') { - _Throw_format_error("Missing '}' in format string."); - } + _Begin = _STD _Parse_width(_Begin, _End, _Callbacks); + if (_Begin == _End) { + return _Begin; + } - return _Parse_ctx.begin() + (_It - _Parse_ctx._Unchecked_begin()); + // If there's anything remaining we assume it's a type. + if (*_Begin != '}') { + _Callbacks._On_type(*_Begin); + ++_Begin; + } else { + // call the type callback so it gets a default type, this is required + // since _Specs_checker needs to be able to tell that it got a default type + // to raise an error for default formatted bools with a sign modifier + _Callbacks._On_type(_CharT{}); } - template - _NODISCARD constexpr auto _Format( - _FormatContext& _Format_ctx, const int _Width, _Fmt_align _Default_align, _Func&& _Fn) const { - _Fill_align_and_width_specs _Format_specs = _Specs; - if (_Specs._Dynamic_width_index >= 0) { - _Format_specs._Width = - _Get_dynamic_specs<_Width_checker>(_Format_ctx.arg(static_cast(_Specs._Dynamic_width_index))); - } + return _Begin; +} - return _Write_aligned(_Format_ctx.out(), _Width, _Format_specs, _Default_align, _STD forward<_Func>(_Fn)); +template +constexpr void _Set_tuple_debug_format(_FormatterType& _Formatter, _ParseContext& _Parse_ctx) { + _Formatter.parse(_Parse_ctx); + if constexpr (requires { _Formatter.set_debug_format(); }) { + _Formatter.set_debug_format(); } +} +template ... _Types> +class _Tuple_formatter_common_base { private: + tuple, _CharT>...> _Underlying; + basic_string_view<_CharT> _Separator = _STATICALLY_WIDEN(_CharT, ", "); + basic_string_view<_CharT> _Opening_bracket = _STATICALLY_WIDEN(_CharT, "("); + basic_string_view<_CharT> _Closing_bracket = _STATICALLY_WIDEN(_CharT, ")"); + _Fill_align_and_width_specs<_CharT> _Specs; -}; -template -struct _Range_specs : _Fill_align_and_width_specs<_CharT> { - bool _No_brackets = false; - char _Type = '\0'; -}; + template + void _Format_to_context(_FormatContext& _Fmt_ctx, _ArgTypes&... _Args) const { + _STD _Copy_unchecked(_Opening_bracket._Unchecked_begin(), _Opening_bracket._Unchecked_end(), _Fmt_ctx.out()); + [&](index_sequence<_Indices...>) { + auto _Single_writer = [&](auto& _Arg) { + if constexpr (_Idx != 0) { + _STD _Copy_unchecked(_Separator._Unchecked_begin(), _Separator._Unchecked_end(), _Fmt_ctx.out()); + } + _STD get<_Idx>(_Underlying).format(_Arg, _Fmt_ctx); + }; + (_Single_writer.template operator()<_Indices>(_Args), ...); + }(index_sequence_for<_ArgTypes...>{}); + _STD _Copy_unchecked(_Closing_bracket._Unchecked_begin(), _Closing_bracket._Unchecked_end(), _Fmt_ctx.out()); + } -template -class _Range_specs_setter : public _Fill_align_and_width_specs_setter<_CharT> { -public: - constexpr explicit _Range_specs_setter( - _Range_specs<_CharT>& _Specs_, basic_format_parse_context<_CharT>& _Parse_ctx_) - : _Fill_align_and_width_specs_setter<_CharT>(_Specs_, _Parse_ctx_) {} +protected: + static constexpr bool _Is_const_formattable = (formattable && ...); - constexpr void _On_no_brackets() { - static_cast<_Range_specs<_CharT>&>(this->_Specs)._No_brackets = true; - } + template + _FormatContext::iterator _Format(_FormatContext& _Fmt_ctx, _ArgTypes&... _Args) const { + _STL_INTERNAL_STATIC_ASSERT( + (is_same_v<_ArgTypes, remove_reference_t<_Maybe_const<_Is_const_formattable, _Types>>> && ...)); - constexpr void _On_type(const _CharT _Type) { - _STL_INTERNAL_CHECK(_Type == 'm' || _Type == 's' || _Type == '?'); - static_cast<_Range_specs<_CharT>&>(this->_Specs)._Type = static_cast(_Type); - } -}; + auto _Format_specs = _Specs; + if (_Specs._Dynamic_width_index >= 0) { + _Format_specs._Width = + _STD _Get_dynamic_specs<_Width_checker>(_Fmt_ctx.arg(static_cast(_Specs._Dynamic_width_index))); + } -template -_NODISCARD constexpr const _CharT* _Parse_range_specs( - const _CharT* _Begin, const _CharT* const _End, _Range_specs_setter<_CharT>& _Callbacks) { - if (_Begin == _End || *_Begin == '}' || *_Begin == ':') { - return _Begin; + if (_Format_specs._Width <= 0) { + _Format_to_context(_Fmt_ctx, _Args...); + return _Fmt_ctx.out(); + } + + basic_string<_CharT> _Tmp_str; + if constexpr (is_same_v<_FormatContext, _Default_format_context<_CharT>>) { + _Fmt_iterator_buffer>, _CharT> _Tmp_buf{ + back_insert_iterator{_Tmp_str}}; + auto _Tmp_ctx = _FormatContext::_Make_from( + _Basic_fmt_it<_CharT>{_Tmp_buf}, _Fmt_ctx._Get_args(), _Fmt_ctx._Get_lazy_locale()); + _Format_to_context(_Tmp_ctx, _Args...); + } else { + _CSTD abort(); // no basic_format_context object other than _Default_format_context can be created + } + + const int _Width = _Measure_display_width<_CharT>(_Tmp_str); + return _STD _Write_aligned( + _Fmt_ctx.out(), _Width, _Format_specs, _Fmt_align::_Left, [&](typename _FormatContext::iterator _Out) { + return _STD _Fmt_write(_STD move(_Out), basic_string_view<_CharT>{_Tmp_str}); + }); } - _Begin = _Parse_align(_Begin, _End, _Callbacks); - if (_Begin == _End) { - return _Begin; +public: + constexpr void set_separator(const basic_string_view<_CharT> _Sep) noexcept { + _Separator = _Sep; } - _Begin = _Parse_width(_Begin, _End, _Callbacks); - if (_Begin == _End) { - return _Begin; + constexpr void set_brackets( + const basic_string_view<_CharT> _Opening, const basic_string_view<_CharT> _Closing) noexcept { + _Opening_bracket = _Opening; + _Closing_bracket = _Closing; } - if (*_Begin == 'n') { - _Callbacks._On_no_brackets(); - if (++_Begin == _End) { - return _Begin; + template + constexpr _ParseContext::iterator parse(_ParseContext& _Ctx) { + _Fmt_tuple_type _Fmt_type = _Fmt_tuple_type::_None; + _Tuple_format_specs_setter<_CharT, sizeof...(_Types) == 2> _Callback{_Specs, _Fmt_type, _Ctx}; + const auto _It = _STD _Parse_tuple_format_specs(_Ctx._Unchecked_begin(), _Ctx._Unchecked_end(), _Callback); + if (_It != _Ctx._Unchecked_end() && *_It != '}') { + _STD _Throw_format_error("Missing '}' in format string."); } - } - switch (const _CharT _Maybe_type = *_Begin) { - case '?': - if (++_Begin == _End || *_Begin != 's') { - _Throw_format_error("Invalid range-type '?'; was '?s' intended?"); + if (_Fmt_type == _Fmt_tuple_type::_No_brackets) { + set_brackets({}, {}); + } else if constexpr (sizeof...(_Types) == 2) { + if (_Fmt_type == _Fmt_tuple_type::_Key_value) { + set_separator(_STATICALLY_WIDEN(_CharT, ": ")); + set_brackets({}, {}); + } } - [[fallthrough]]; - case 'm': - case 's': - _Callbacks._On_type(_Maybe_type); - ++_Begin; - break; - default: - break; + + _Ctx.advance_to(_Ctx.begin() + (_It - _Ctx._Unchecked_begin())); + _STD apply([&_Ctx](auto&... _Elems) { (_Set_tuple_debug_format(_Elems, _Ctx), ...); }, _Underlying); + + return _Ctx.begin(); } +}; - return _Begin; -} +// formatter definition for all pairs and tuples, the deleted default constructor +// makes it "disabled" as per N4971 [format.formatter.spec]/5 -_EXPORT_STD template - requires same_as, _Ty> && formattable<_Ty, _CharT> -class range_formatter { +template +struct _Tuple_formatter_base { + _Tuple_formatter_base() = delete; + _Tuple_formatter_base(const _Tuple_formatter_base&) = delete; + _Tuple_formatter_base& operator=(const _Tuple_formatter_base&) = delete; +}; + +template _Ty1, formattable<_CharT> _Ty2> +struct _Tuple_formatter_base, _CharT> : _Tuple_formatter_common_base<_CharT, _Ty1, _Ty2> { private: - formatter<_Ty, _CharT> _Underlying; - basic_string_view<_CharT> _Separator = _STATICALLY_WIDEN(_CharT, ", "); - basic_string_view<_CharT> _Opening_bracket = _STATICALLY_WIDEN(_CharT, "["); - basic_string_view<_CharT> _Closing_bracket = _STATICALLY_WIDEN(_CharT, "]"); - _Range_specs<_CharT> _Specs; + using _Base = _Tuple_formatter_common_base<_CharT, _Ty1, _Ty2>; + using _Formatted_type = _Maybe_const<_Base::_Is_const_formattable, pair<_Ty1, _Ty2>>; public: - constexpr void set_separator(basic_string_view<_CharT> _Sep) noexcept { - _Separator = _Sep; - } - - constexpr void set_brackets(basic_string_view<_CharT> _Opening, basic_string_view<_CharT> _Closing) noexcept { - _Opening_bracket = _Opening; - _Closing_bracket = _Closing; + template + _FormatContext::iterator format(_Formatted_type& _Elems, _FormatContext& _Ctx) const { + return this->_Format(_Ctx, _Elems.first, _Elems.second); } +}; - _NODISCARD constexpr formatter<_Ty, _CharT>& underlying() noexcept { - return _Underlying; - } +template ... _Types> +struct _Tuple_formatter_base, _CharT> : _Tuple_formatter_common_base<_CharT, _Types...> { +private: + using _Base = _Tuple_formatter_common_base<_CharT, _Types...>; + using _Formatted_type = _Maybe_const<_Base::_Is_const_formattable, tuple<_Types...>>; - _NODISCARD constexpr const formatter<_Ty, _CharT>& underlying() const noexcept { - return _Underlying; +public: + template + _FormatContext::iterator format(_Formatted_type& _Elems, _FormatContext& _Ctx) const { + return _STD apply([this, &_Ctx](auto&... _Args) { return this->_Format(_Ctx, _Args...); }, _Elems); } +}; - template - constexpr _ParseContext::iterator parse(_ParseContext& _Ctx) { - _Range_specs_setter<_CharT> _Callback{_Specs, _Ctx}; - auto _It = _STD _Parse_range_specs(_Ctx._Unchecked_begin(), _Ctx._Unchecked_end(), _Callback); +// specializations for tuple-like types that are input ranges and not formattable as tuples - _Ctx.advance_to(_Ctx.begin() + (_It - _Ctx._Unchecked_begin())); - bool _Has_underlying_spec = false; - if (_It != _Ctx._Unchecked_end()) { - if (*_It == ':') { - _Has_underlying_spec = true; - _Ctx.advance_to(_Ctx.begin() + 1); - } else if (*_It != '}') { - _Throw_format_error("Invalid range-format-spec."); - } - } +template <_Format_supported_charT _CharT, class _Ty1, class _Ty2> + requires (!formattable<_Ty1, _CharT> || !formattable<_Ty2, _CharT>) + // TRANSITION, clang-format, () should be redundant + && (_RANGES input_range>) && _Formatting_enabled_range> + && formattable<_RANGES range_reference_t>, _CharT> +struct _Tuple_formatter_base, _CharT> + : _Range_default_formatter>, pair<_Ty1, _Ty2>, _CharT> {}; - _It = _Underlying.parse(_Ctx)._Unwrapped(); - if (_It != _Ctx._Unchecked_end() && *_It != '}') { - _Throw_format_error("Missing '}' in format string."); - } +template <_Format_supported_charT _CharT, class... _Types> + requires ((!formattable<_Types, _CharT>) || ...) + // TRANSITION, clang-format, () should be redundant + && (_RANGES input_range>) && _Formatting_enabled_range> + && formattable<_RANGES range_reference_t>, _CharT> +struct _Tuple_formatter_base, _CharT> + : _Range_default_formatter>, tuple<_Types...>, _CharT> {}; - switch (_Specs._Type) { - case 'm': - if constexpr (_Is_two_tuple<_Ty>) { - set_brackets(_STATICALLY_WIDEN(_CharT, "{"), _STATICALLY_WIDEN(_CharT, "}")); - set_separator(_STATICALLY_WIDEN(_CharT, ", ")); - _Underlying.set_brackets({}, {}); - _Underlying.set_separator(_STATICALLY_WIDEN(_CharT, ": ")); - } else { - _Throw_format_error("Range-type 'm' requires type T to be a pair or a 2-element tuple."); - } - [[fallthrough]]; +// Per LWG-3997, `_CharT` in library-provided `formatter` specializations is +// constrained to character types supported by `format`. - case '\0': - if constexpr (requires { _Underlying.set_debug_format(); }) { - if (!_Has_underlying_spec) { - _Underlying.set_debug_format(); - } - } - break; +template <_Format_supported_charT _CharT, class _Ty1, class _Ty2> +struct formatter, _CharT> : _Tuple_formatter_base, _CharT> {}; - case 's': - case '?': - if constexpr (same_as<_Ty, _CharT>) { - if (_Specs._No_brackets) { - _Throw_format_error("Range-types 's' and '?s' cannot be combined with the 'n' option."); - } else if (_Has_underlying_spec) { - _Throw_format_error("Range-types 's' and '?s' cannot be combined with a range-underlying-spec."); - } - } else { - _Throw_format_error("Range-types 's' and '?s' require type T to be charT."); - } +template <_Format_supported_charT _CharT, class... _Types> +struct formatter, _CharT> : _Tuple_formatter_base, _CharT> {}; - break; +enum class _Add_newline : bool { _Nope, _Yes }; - default: - _STL_UNREACHABLE; // can't happen, we've handled all possible outputs from _Parse_range_specs() - break; - } +_NODISCARD inline string _Unescape_braces(const _Add_newline _Add_nl, const string_view _Old_str) { + string _Unescaped_str; - if (_Specs._No_brackets) { - set_brackets({}, {}); + if (_Old_str.empty()) { + if (_Add_nl == _Add_newline::_Yes) { + _Unescaped_str.push_back('\n'); } - return _Ctx.begin() + (_It - _Ctx._Unchecked_begin()); + return _Unescaped_str; } - template <_RANGES input_range _Range, class _FormatContext> - requires formattable<_RANGES range_reference_t<_Range>, _CharT> - && same_as>, _Ty> - _FormatContext::iterator format(_Range&& _Rng, _FormatContext& _Ctx) const { - return _Format(_STD forward<_Range>(_Rng), _Ctx); - } + size_t _Unescaped_str_expected_size = _Old_str.size(); -private: - template <_RANGES input_range _Range, class _FormatContext> - _FormatContext::iterator _Format(_Range&&, _FormatContext&) const { - _Throw_format_error("Unsupported 'basic_format_context'."); + if (_Add_nl == _Add_newline::_Yes) { + ++_Unescaped_str_expected_size; } - template <_RANGES input_range _Range, class _FormatContext> - requires _Is_specialization_v - && derived_from> - _FormatContext::iterator _Format(_Range&& _Rng, _FormatContext& _Ctx) const { - auto _Format_specs = _Specs; - if (_Specs._Dynamic_width_index >= 0) { - _Format_specs._Width = - _STD _Get_dynamic_specs<_Width_checker>(_Ctx.arg(static_cast(_Specs._Dynamic_width_index))); - } - - basic_string<_CharT> _Buffer; - { - _Fmt_iterator_buffer>, _CharT> _Fmt_buf( - back_insert_iterator{_Buffer}); - using _Inserter = back_insert_iterator<_Fmt_buffer<_CharT>>; - auto _Nested_context = basic_format_context<_Inserter, _CharT>::_Make_from( - _Inserter{_Fmt_buf}, _Ctx._Get_args(), _Ctx._Get_lazy_locale()); + _Unescaped_str.resize_and_overwrite(_Unescaped_str_expected_size, [_Add_nl, _Old_str](char* _Dest_ptr, size_t) { + char _Prev_char = _Old_str.front(); + size_t _Num_chars_written = 1; + *_Dest_ptr++ = _Prev_char; - if constexpr (same_as<_Ty, _CharT>) { - if (_Specs._Type == 's' || _Specs._Type == '?') { - _Format_as_string(_STD forward<_Range>(_Rng), _Nested_context, _Specs._Type == '?'); - } else { - _Format_as_sequence(_STD forward<_Range>(_Rng), _Nested_context); - } + for (const auto _Curr_char : _Old_str.substr(1)) { + if ((_Curr_char == '{' && _Prev_char == '{') || (_Curr_char == '}' && _Prev_char == '}')) { + _Prev_char = '\0'; } else { - _Format_as_sequence(_STD forward<_Range>(_Rng), _Nested_context); + *_Dest_ptr++ = _Curr_char; + ++_Num_chars_written; + + _Prev_char = _Curr_char; } } - const int _Width = _Measure_display_width<_CharT>(_Buffer); - return _STD _Write_aligned( - _Ctx.out(), _Width, _Format_specs, _Fmt_align::_Left, [&](_FormatContext::iterator _Out) { - return _STD _Fmt_write(_STD move(_Out), basic_string_view{_Buffer}); - }); - } + if (_Add_nl == _Add_newline::_Yes) { + *_Dest_ptr = '\n'; + ++_Num_chars_written; + } - template <_RANGES input_range _Range, class _FormatContext> - void _Format_as_sequence(_Range&& _Rng, _FormatContext& _Ctx) const { - _Ctx.advance_to(_STD _Fmt_write(_Ctx.out(), _Opening_bracket)); - bool _Separate = false; - for (auto&& _Elem : _Rng) { - if (_Separate) { - _Ctx.advance_to(_STD _Fmt_write(_Ctx.out(), _Separator)); - } + return _Num_chars_written; + }); - _Separate = true; - _Ctx.advance_to(_Underlying.format(_Elem, _Ctx)); - } + return _Unescaped_str; +} - (void) _STD _Fmt_write(_Ctx.out(), _Closing_bracket); +template +_NODISCARD constexpr const _CharT* _Parse_fill_align_and_width_specs( + const _CharT* _Begin, const _CharT* _End, _Callbacks_type&& _Callbacks) { + if (_Begin == _End || *_Begin == '}') { + return _Begin; } - template <_RANGES input_range _Range, class _FormatContext> - void _Format_as_string(_Range&& _Rng, _FormatContext& _Ctx, const bool _Debug) const { - if constexpr (_RANGES contiguous_range<_Range>) { - const auto _Size = _STD _To_unsigned_like(_RANGES distance(_Rng)); + _Begin = _Parse_align(_Begin, _End, _Callbacks); + if (_Begin == _End) { + return _Begin; + } - if (!_STD in_range(_Size)) [[unlikely]] { - _Throw_format_error("Formatted range is too long."); - } + return _Parse_width(_Begin, _End, _Callbacks); +} - formatter, _CharT> _String_view_formatter; - if (_Debug) { - _String_view_formatter.set_debug_format(); - } +template +struct _Fill_align_and_width_formatter { +public: + _NODISCARD constexpr auto _Parse(basic_format_parse_context<_CharT>& _Parse_ctx) { + _Fill_align_and_width_specs_setter<_CharT> _Callback{_Specs, _Parse_ctx}; + const auto _It = + _Parse_fill_align_and_width_specs(_Parse_ctx._Unchecked_begin(), _Parse_ctx._Unchecked_end(), _Callback); + if (_It != _Parse_ctx._Unchecked_end() && *_It != '}') { + _Throw_format_error("Missing '}' in format string."); + } - const basic_string_view<_CharT> _Str(_STD to_address(_RANGES begin(_Rng)), static_cast(_Size)); - _String_view_formatter.format(_Str, _Ctx); - } else { - using _String = basic_string<_CharT>; - formatter<_String, _CharT> _String_formatter; - if (_Debug) { - _String_formatter.set_debug_format(); - } + return _Parse_ctx.begin() + (_It - _Parse_ctx._Unchecked_begin()); + } - _String_formatter.format(_String{from_range, _Rng}, _Ctx); + template + _NODISCARD constexpr auto _Format( + _FormatContext& _Format_ctx, const int _Width, _Fmt_align _Default_align, _Func&& _Fn) const { + _Fill_align_and_width_specs _Format_specs = _Specs; + if (_Specs._Dynamic_width_index >= 0) { + _Format_specs._Width = + _Get_dynamic_specs<_Width_checker>(_Format_ctx.arg(static_cast(_Specs._Dynamic_width_index))); } + + return _Write_aligned(_Format_ctx.out(), _Width, _Format_specs, _Default_align, _STD forward<_Func>(_Fn)); } + +private: + _Fill_align_and_width_specs<_CharT> _Specs; }; #endif // _HAS_CXX23 _STD_END diff --git a/stl/inc/forward_list b/stl/inc/forward_list index 433452691e6..afcdbf99254 100644 --- a/stl/inc/forward_list +++ b/stl/inc/forward_list @@ -1561,8 +1561,7 @@ forward_list(_Iter, _Iter, _Alloc = _Alloc()) -> forward_list<_Iter_value_t<_Ite #endif // _HAS_CXX17 #if _HAS_CXX23 -template <_RANGES input_range _Rng, class _Alloc = allocator<_RANGES range_value_t<_Rng>>, - enable_if_t<_Is_allocator<_Alloc>::value, int> = 0> +template <_RANGES input_range _Rng, _Allocator_for_container _Alloc = allocator<_RANGES range_value_t<_Rng>>> forward_list(from_range_t, _Rng&&, _Alloc = _Alloc()) -> forward_list<_RANGES range_value_t<_Rng>, _Alloc>; #endif // _HAS_CXX23 diff --git a/stl/inc/functional b/stl/inc/functional index 5150939b5dd..5e81fc599f1 100644 --- a/stl/inc/functional +++ b/stl/inc/functional @@ -1946,7 +1946,7 @@ public: _Fn1._Swap(_Fn2); } - _NODISCARD_FRIEND bool operator==(const move_only_function& _This, nullptr_t) noexcept { + _NODISCARD friend bool operator==(const move_only_function& _This, nullptr_t) noexcept { return _This._Is_null(); } }; diff --git a/stl/inc/generator b/stl/inc/generator index efcb80fb671..c09710308df 100644 --- a/stl/inc/generator +++ b/stl/inc/generator @@ -427,7 +427,7 @@ public: ++*this; } - _NODISCARD_FRIEND bool operator==(const _Iterator& _It, default_sentinel_t) noexcept /* strengthened */ + _NODISCARD friend bool operator==(const _Iterator& _It, default_sentinel_t) noexcept /* strengthened */ { return _It._Coro.done(); } diff --git a/stl/inc/hash_map b/stl/inc/hash_map index ee9400087af..011a0667683 100644 --- a/stl/inc/hash_map +++ b/stl/inc/hash_map @@ -58,6 +58,11 @@ namespace stdext { using _Deduce_key = const _Kty&; using key_equal = _Tr; +#if _HAS_CXX20 && defined(__EDG__) // TRANSITION, DevCom-10678753 + template + static constexpr bool _Supports_transparency = false; +#endif // ^^^ workaround ^^^ + _Hmap_traits() = default; _Hmap_traits(const _Tr& _Traits) noexcept(_STD is_nothrow_copy_constructible_v<_Tr>) : _Tr(_Traits) {} diff --git a/stl/inc/hash_set b/stl/inc/hash_set index bd915e7b887..8b7f9a25869 100644 --- a/stl/inc/hash_set +++ b/stl/inc/hash_set @@ -53,6 +53,11 @@ namespace stdext { using _Deduce_key = const _Kty&; using key_equal = _Tr; +#if _HAS_CXX20 && defined(__EDG__) // TRANSITION, DevCom-10678753 + template + static constexpr bool _Supports_transparency = false; +#endif // ^^^ workaround ^^^ + _Hset_traits() = default; _Hset_traits(const _Tr& _Traits) noexcept(_STD is_nothrow_copy_constructible_v<_Tr>) : _Tr(_Traits) {} diff --git a/stl/inc/iosfwd b/stl/inc/iosfwd index 666c823a6ea..8e49430ac21 100644 --- a/stl/inc/iosfwd +++ b/stl/inc/iosfwd @@ -98,13 +98,13 @@ public: } template , int> = 0> - _NODISCARD_FRIEND bool operator==(const fpos& _Left, const _Int _Right) noexcept /* strengthened */ { + _NODISCARD friend bool operator==(const fpos& _Left, const _Int _Right) noexcept /* strengthened */ { return static_cast(_Left) == _Right; } #if !_HAS_CXX20 template , int> = 0> - _NODISCARD_FRIEND bool operator==(const _Int _Left, const fpos& _Right) noexcept /* strengthened */ { + _NODISCARD friend bool operator==(const _Int _Left, const fpos& _Right) noexcept /* strengthened */ { return _Left == static_cast(_Right); } @@ -113,12 +113,12 @@ public: } template , int> = 0> - _NODISCARD_FRIEND bool operator!=(const fpos& _Left, const _Int _Right) noexcept /* strengthened */ { + _NODISCARD friend bool operator!=(const fpos& _Left, const _Int _Right) noexcept /* strengthened */ { return static_cast(_Left) != _Right; } template , int> = 0> - _NODISCARD_FRIEND bool operator!=(const _Int _Left, const fpos& _Right) noexcept /* strengthened */ { + _NODISCARD friend bool operator!=(const _Int _Left, const fpos& _Right) noexcept /* strengthened */ { return _Left != static_cast(_Right); } #endif // !_HAS_CXX20 diff --git a/stl/inc/iterator b/stl/inc/iterator index 4fa118f4186..25ebe3b4345 100644 --- a/stl/inc/iterator +++ b/stl/inc/iterator @@ -285,7 +285,7 @@ public: } #if _HAS_CXX20 - _NODISCARD_FRIEND bool operator==(const istream_iterator& _Left, default_sentinel_t) noexcept /* strengthened */ { + _NODISCARD friend bool operator==(const istream_iterator& _Left, default_sentinel_t) noexcept /* strengthened */ { return !_Left._Myistr; } #endif // _HAS_CXX20 @@ -448,7 +448,7 @@ public: } #if _HAS_CXX20 - _NODISCARD_FRIEND bool operator==(const istreambuf_iterator& _Left, default_sentinel_t) { + _NODISCARD friend bool operator==(const istreambuf_iterator& _Left, default_sentinel_t) { if (!_Left._Got) { _Left._Peek(); } @@ -997,7 +997,7 @@ public: template _OSe> requires sentinel_for<_Se, _OIter> - _NODISCARD_FRIEND constexpr bool operator==( + _NODISCARD friend constexpr bool operator==( const common_iterator& _Left, const common_iterator<_OIter, _OSe>& _Right) { auto& _Right_val = _Right._Get_val(); #if _ITERATOR_DEBUG_LEVEL != 0 @@ -1027,7 +1027,7 @@ public: template _OIter, sized_sentinel_for<_Iter> _OSe> requires sized_sentinel_for<_Se, _OIter> - _NODISCARD_FRIEND constexpr iter_difference_t<_OIter> operator-( + _NODISCARD friend constexpr iter_difference_t<_OIter> operator-( const common_iterator& _Left, const common_iterator<_OIter, _OSe>& _Right) { auto& _Right_val = _Right._Get_val(); #if _ITERATOR_DEBUG_LEVEL != 0 @@ -1051,7 +1051,7 @@ public: } } - _NODISCARD_FRIEND constexpr decltype(auto) iter_move(const common_iterator& _Right) noexcept( + _NODISCARD friend constexpr decltype(auto) iter_move(const common_iterator& _Right) noexcept( noexcept(_RANGES iter_move(_Right._Val._Get_first()))) requires input_iterator<_Iter> { @@ -1288,7 +1288,7 @@ public: return counted_iterator{_Current + _Diff, static_cast>(_Length - _Diff)}; } - _NODISCARD_FRIEND constexpr counted_iterator operator+( + _NODISCARD friend constexpr counted_iterator operator+( const iter_difference_t<_Iter> _Diff, const counted_iterator& _Right) requires random_access_iterator<_Iter> { @@ -1313,7 +1313,7 @@ public: } template _Other> - _NODISCARD_FRIEND constexpr iter_difference_t<_Other> operator-( + _NODISCARD friend constexpr iter_difference_t<_Other> operator-( const counted_iterator& _Left, const counted_iterator<_Other>& _Right) noexcept /* strengthened */ { #if _ITERATOR_DEBUG_LEVEL != 0 _Same_sequence(_Left, _Right); @@ -1321,12 +1321,12 @@ public: return _Right.count() - _Left._Length; } - _NODISCARD_FRIEND constexpr iter_difference_t<_Iter> operator-( + _NODISCARD friend constexpr iter_difference_t<_Iter> operator-( const counted_iterator& _Left, default_sentinel_t) noexcept /* strengthened */ { return -_Left._Length; } - _NODISCARD_FRIEND constexpr iter_difference_t<_Iter> operator-( + _NODISCARD friend constexpr iter_difference_t<_Iter> operator-( default_sentinel_t, const counted_iterator& _Right) noexcept /* strengthened */ { return _Right._Length; } @@ -1344,7 +1344,7 @@ public: // [counted.iter.cmp] template _Other> - _NODISCARD_FRIEND constexpr bool operator==( + _NODISCARD friend constexpr bool operator==( const counted_iterator& _Left, const counted_iterator<_Other>& _Right) noexcept /* strengthened */ { #if _ITERATOR_DEBUG_LEVEL != 0 _Same_sequence(_Left, _Right); @@ -1352,13 +1352,13 @@ public: return _Left._Length == _Right.count(); } - _NODISCARD_FRIEND constexpr bool operator==(const counted_iterator& _Left, default_sentinel_t) noexcept + _NODISCARD friend constexpr bool operator==(const counted_iterator& _Left, default_sentinel_t) noexcept /* strengthened */ { return _Left._Length == 0; } template _Other> - _NODISCARD_FRIEND constexpr strong_ordering operator<=>( + _NODISCARD friend constexpr strong_ordering operator<=>( const counted_iterator& _Left, const counted_iterator<_Other>& _Right) noexcept /* strengthened */ { #if _ITERATOR_DEBUG_LEVEL != 0 _Same_sequence(_Left, _Right); @@ -1367,7 +1367,7 @@ public: } // [counted.iter.cust] - _NODISCARD_FRIEND constexpr decltype(auto) iter_move(const counted_iterator& _Right) noexcept( + _NODISCARD friend constexpr decltype(auto) iter_move(const counted_iterator& _Right) noexcept( noexcept(_RANGES iter_move(_Right._Current))) requires input_iterator<_Iter> { @@ -1585,7 +1585,7 @@ public: return _Tmp; } - _NODISCARD_FRIEND constexpr checked_array_iterator operator+( + _NODISCARD friend constexpr checked_array_iterator operator+( const difference_type _Off, const checked_array_iterator<_Ptr>& _Next) noexcept { return _Next + _Off; } @@ -1776,7 +1776,7 @@ public: return _Tmp; } - _NODISCARD_FRIEND constexpr unchecked_array_iterator operator+( + _NODISCARD friend constexpr unchecked_array_iterator operator+( const difference_type _Off, const unchecked_array_iterator& _Next) noexcept { return _Next + _Off; } diff --git a/stl/inc/list b/stl/inc/list index ccc49ff243e..84160362f46 100644 --- a/stl/inc/list +++ b/stl/inc/list @@ -1864,8 +1864,7 @@ list(_Iter, _Iter, _Alloc = _Alloc()) -> list<_Iter_value_t<_Iter>, _Alloc>; #endif // _HAS_CXX17 #if _HAS_CXX23 -template <_RANGES input_range _Rng, class _Alloc = allocator<_RANGES range_value_t<_Rng>>, - enable_if_t<_Is_allocator<_Alloc>::value, int> = 0> +template <_RANGES input_range _Rng, _Allocator_for_container _Alloc = allocator<_RANGES range_value_t<_Rng>>> list(from_range_t, _Rng&&, _Alloc = _Alloc()) -> list<_RANGES range_value_t<_Rng>, _Alloc>; #endif // _HAS_CXX23 diff --git a/stl/inc/map b/stl/inc/map index a8b764723f4..ecb13ccb948 100644 --- a/stl/inc/map +++ b/stl/inc/map @@ -385,12 +385,12 @@ map(initializer_list>, _Alloc) -> map<_Kty, _Ty, less<_Kty>, _Al #if _HAS_CXX23 template <_RANGES input_range _Rng, class _Pr = less<_Range_key_type<_Rng>>, - class _Alloc = allocator<_Range_to_alloc_type<_Rng>>, - enable_if_t>, _Is_allocator<_Alloc>>, int> = 0> + _Allocator_for_container _Alloc = allocator<_Range_to_alloc_type<_Rng>>> + requires (!_Allocator_for_container<_Pr>) map(from_range_t, _Rng&&, _Pr = _Pr(), _Alloc = _Alloc()) -> map<_Range_key_type<_Rng>, _Range_mapped_type<_Rng>, _Pr, _Alloc>; -template <_RANGES input_range _Rng, class _Alloc, enable_if_t<_Is_allocator<_Alloc>::value, int> = 0> +template <_RANGES input_range _Rng, _Allocator_for_container _Alloc> map(from_range_t, _Rng&&, _Alloc) -> map<_Range_key_type<_Rng>, _Range_mapped_type<_Rng>, less<_Range_key_type<_Rng>>, _Alloc>; #endif // _HAS_CXX23 @@ -616,12 +616,12 @@ multimap(initializer_list>, _Alloc) -> multimap<_Kty, _Ty, less< #if _HAS_CXX23 template <_RANGES input_range _Rng, class _Pr = less<_Range_key_type<_Rng>>, - class _Alloc = allocator<_Range_to_alloc_type<_Rng>>, - enable_if_t>, _Is_allocator<_Alloc>>, int> = 0> + _Allocator_for_container _Alloc = allocator<_Range_to_alloc_type<_Rng>>> + requires (!_Allocator_for_container<_Pr>) multimap(from_range_t, _Rng&&, _Pr = _Pr(), _Alloc = _Alloc()) -> multimap<_Range_key_type<_Rng>, _Range_mapped_type<_Rng>, _Pr, _Alloc>; -template <_RANGES input_range _Rng, class _Alloc, enable_if_t<_Is_allocator<_Alloc>::value, int> = 0> +template <_RANGES input_range _Rng, _Allocator_for_container _Alloc> multimap(from_range_t, _Rng&&, _Alloc) -> multimap<_Range_key_type<_Rng>, _Range_mapped_type<_Rng>, less<_Range_key_type<_Rng>>, _Alloc>; #endif // _HAS_CXX23 diff --git a/stl/inc/mdspan b/stl/inc/mdspan index 3f5b9d3a117..2535e0d5cd3 100644 --- a/stl/inc/mdspan +++ b/stl/inc/mdspan @@ -253,7 +253,7 @@ public: : extents(span{_Exts}, make_index_sequence{}) {} template - _NODISCARD_FRIEND constexpr bool operator==( + _NODISCARD friend constexpr bool operator==( const extents& _Left, const extents<_OtherIndexType, _OtherExtents...>& _Right) noexcept { if constexpr (rank() != sizeof...(_OtherExtents)) { return false; @@ -603,7 +603,7 @@ public: template requires (extents_type::rank() == _OtherExtents::rank()) - _NODISCARD_FRIEND constexpr bool operator==(const mapping& _Left, const mapping<_OtherExtents>& _Right) noexcept { + _NODISCARD friend constexpr bool operator==(const mapping& _Left, const mapping<_OtherExtents>& _Right) noexcept { return _Left._Exts == _Right.extents(); } @@ -756,7 +756,7 @@ public: template requires (extents_type::rank() == _OtherExtents::rank()) - _NODISCARD_FRIEND constexpr bool operator==(const mapping& _Left, const mapping<_OtherExtents>& _Right) noexcept { + _NODISCARD friend constexpr bool operator==(const mapping& _Left, const mapping<_OtherExtents>& _Right) noexcept { return _Left._Exts == _Right.extents(); } @@ -986,7 +986,7 @@ public: template requires _Layout_mapping_alike<_OtherMapping> && (extents_type::rank() == _OtherMapping::extents_type::rank()) && (_OtherMapping::is_always_strided()) - _NODISCARD_FRIEND constexpr bool operator==(const mapping& _Left, const _OtherMapping& _Right) noexcept { + _NODISCARD friend constexpr bool operator==(const mapping& _Left, const _OtherMapping& _Right) noexcept { if constexpr (extents_type::rank() != 0) { if (_Left.extents() != _Right.extents()) { return false; diff --git a/stl/inc/numeric b/stl/inc/numeric index 34287fa0a97..528969fdc63 100644 --- a/stl/inc/numeric +++ b/stl/inc/numeric @@ -625,6 +625,19 @@ _NODISCARD constexpr common_type_t<_Mt, _Nt> gcd(const _Mt _Mx, const _Nt _Nx) n using _Common = common_type_t<_Mt, _Nt>; using _Common_unsigned = make_unsigned_t<_Common>; + if constexpr (is_signed_v<_Common>) { +#ifndef _DEBUG + if (_STD _Is_constant_evaluated()) +#endif // ^^^ !defined(_DEBUG) ^^^ + { + constexpr auto _Min_common = _STD _Min_limit<_Common>(); + if (_Mx == _Min_common || _Nx == _Min_common) { + _STL_REPORT_ERROR("Preconditions: |m| and |n| are representable as a value of common_type_t. " + "(N4981 [numeric.ops.gcd]/2, N4981 [numeric.ops.lcm]/2)"); + } + } + } + return _Select_countr_zero_impl<_Common_unsigned>([=](auto _Countr_zero_impl) { _Common_unsigned _Mx_magnitude = _Abs_u(_Mx); _Common_unsigned _Nx_magnitude = _Abs_u(_Nx); @@ -670,7 +683,21 @@ _NODISCARD constexpr common_type_t<_Mt, _Nt> lcm(const _Mt _Mx, const _Nt _Nx) n return 0; } - return static_cast<_Common>((_Mx_magnitude / _STD gcd(_Mx_magnitude, _Nx_magnitude)) * _Nx_magnitude); +#ifndef _DEBUG + if (!_STD _Is_constant_evaluated()) { + return static_cast<_Common>((_Mx_magnitude / _STD gcd(_Mx_magnitude, _Nx_magnitude)) * _Nx_magnitude); + } +#endif // ^^^ !defined(_DEBUG) ^^^ + + _Common_unsigned _Result = 0; + _Common_unsigned _Tmp = static_cast<_Common_unsigned>(_Mx_magnitude / _STD gcd(_Mx_magnitude, _Nx_magnitude)); + + if (_Mul_overflow(_Tmp, _Nx_magnitude, _Result) || !_In_range<_Common>(_Result)) { + _STL_REPORT_ERROR("Preconditions: The least common multiple of |m| and |n| is representable as a value of " + "type common_type_t. (N4981 [numeric.ops.lcm]/2)"); + } + + return static_cast<_Common>(_Result); } #endif // _HAS_CXX17 diff --git a/stl/inc/queue b/stl/inc/queue index 39f224afae3..b61ce25002d 100644 --- a/stl/inc/queue +++ b/stl/inc/queue @@ -50,7 +50,7 @@ public: : c(_STD move(_Cont)) {} #if _HAS_CXX23 - template , int> = 0> + template <_Iterator_for_container _InIt> queue(_InIt _First, _InIt _Last) noexcept(is_nothrow_constructible_v<_Container, _InIt, _InIt>) // strengthened : c(_STD move(_First), _STD move(_Last)) {} @@ -79,8 +79,8 @@ public: : c(_STD move(_Right.c), _Al) {} #if _HAS_CXX23 - template , uses_allocator<_Container, _Alloc>>, int> = 0> + template <_Iterator_for_container _InIt, class _Alloc> + requires uses_allocator_v<_Container, _Alloc> queue(_InIt _First, _InIt _Last, const _Alloc& _Al) noexcept( is_nothrow_constructible_v<_Container, _InIt, _InIt, const _Alloc&>) // strengthened : c(_STD move(_First), _STD move(_Last), _Al) {} @@ -169,12 +169,10 @@ queue(_Container, _Alloc) -> queue; #endif // _HAS_CXX17 #if _HAS_CXX23 -template >, - enable_if_t, _Is_allocator<_Alloc>>, int> = 0> +template <_Iterator_for_container _InIt, _Allocator_for_container _Alloc = allocator<_Iter_value_t<_InIt>>> queue(_InIt, _InIt, _Alloc = _Alloc()) -> queue<_Iter_value_t<_InIt>, deque<_Iter_value_t<_InIt>, _Alloc>>; -template <_RANGES input_range _Rng, class _Alloc = allocator<_RANGES range_value_t<_Rng>>, - enable_if_t<_Is_allocator<_Alloc>::value, int> = 0> +template <_RANGES input_range _Rng, _Allocator_for_container _Alloc = allocator<_RANGES range_value_t<_Rng>>> queue(from_range_t, _Rng&&, _Alloc = _Alloc()) -> queue<_RANGES range_value_t<_Rng>, deque<_RANGES range_value_t<_Rng>, _Alloc>>; #endif // _HAS_CXX23 @@ -345,15 +343,15 @@ public: } #if _HAS_CXX23 - template <_Container_compatible_range<_Ty> _Rng, class _Alloc, - enable_if_t, int> = 0> + template <_Container_compatible_range<_Ty> _Rng, class _Alloc> + requires uses_allocator_v<_Container, _Alloc> priority_queue(from_range_t, _Rng&& _Range, const _Pr& _Pred, const _Alloc& _Al) : c(_RANGES to<_Container>(_STD forward<_Rng>(_Range), _Al)), comp(_Pred) { _Make_heap(); } - template <_Container_compatible_range<_Ty> _Rng, class _Alloc, - enable_if_t, int> = 0> + template <_Container_compatible_range<_Ty> _Rng, class _Alloc> + requires uses_allocator_v<_Container, _Alloc> priority_queue(from_range_t, _Rng&& _Range, const _Alloc& _Al) : c(_RANGES to<_Container>(_STD forward<_Rng>(_Range), _Al)), comp() { _Make_heap(); diff --git a/stl/inc/random b/stl/inc/random index 2f4fc83cc26..a429b7ab954 100644 --- a/stl/inc/random +++ b/stl/inc/random @@ -261,30 +261,37 @@ private: vector _Myvec; }; -_NODISCARD constexpr int _Generate_canonical_iterations(const int _Bits, const uint64_t _Gmin, const uint64_t _Gmax) { - // For a URBG type `G` with range == `(G::max() - G::min()) + 1`, returns the number of calls to generate at least - // _Bits bits of entropy. Specifically, max(1, ceil(_Bits / log2(range))). - - _STL_INTERNAL_CHECK(0 <= _Bits && _Bits <= 64); +struct _Urbg_gen_can_params { + bool _Rx_is_pow2 = false; // $R$ (in N4981 [rand.util.canonical]/1.2) is a power of 2 + int _Kx = 0; // $k$ in N4981 [rand.util.canonical]/1.4 + uint64_t _Xx = 0; // $x$ in N4981 [rand.util.canonical]/1.5 + float _Scale = 0.0f; // $r^{-d}$, always representable as a float + int _Smax_bits = 0; // number of bits in $R^k$ +}; - if (_Bits == 0 || (_Gmax == UINT64_MAX && _Gmin == 0)) { - return 1; +_NODISCARD constexpr _Urbg_gen_can_params _Generate_canonical_params(const size_t _Bits, const uint64_t _Rm1) { + const auto _Rx = _Unsigned128{_Rm1} + 1; // $R$ in N4981 [rand.util.canonical]/1.2 + const auto _Target = _Unsigned128{1} << _Bits; // $r^d$ + _Unsigned128 _Product = 1; + _Urbg_gen_can_params _Result; + _Result._Rx_is_pow2 = (_Rx & (_Rx - 1)) == 0; + _Result._Kx = 0; + while (_Product < _Target) { + _Product *= _Rx; + ++_Result._Kx; } - const auto _Range = (_Gmax - _Gmin) + 1; - const auto _Target = ~uint64_t{0} >> (64 - _Bits); - uint64_t _Prod = 1; - int _Ceil = 0; - while (_Prod <= _Target) { - ++_Ceil; - if (_Prod > UINT64_MAX / _Range) { - break; - } - - _Prod *= _Range; + _Result._Xx = static_cast(_Product / _Target); + _Result._Scale = 1.0f / static_cast(1ULL << _Bits); + _Result._Smax_bits = 0; + // $S \in [0, _Product)$ + --_Product; + while (_Product > 0) { + ++_Result._Smax_bits; + _Product >>= 1; } - return _Ceil; + return _Result; } _EXPORT_STD template @@ -294,27 +301,110 @@ _NODISCARD _Real generate_canonical(_Gen& _Gx) { // build a floating-point value constexpr auto _Digits = static_cast(numeric_limits<_Real>::digits); constexpr auto _Minbits = static_cast(_Digits < _Bits ? _Digits : _Bits); - constexpr auto _Gxmin = static_cast<_Real>((_Gen::min)()); - constexpr auto _Gxmax = static_cast<_Real>((_Gen::max)()); - constexpr auto _Rx = (_Gxmax - _Gxmin) + _Real{1}; + if constexpr (_Minbits == 0) { + return _Real{0}; + } else { + using _Result_uint_type = conditional_t<_Minbits <= 32, uint32_t, uint64_t>; + + constexpr auto _Gxmin = (_Gen::min)(); + constexpr auto _Gxmax = (_Gen::max)(); + constexpr auto _Params = _Generate_canonical_params(_Minbits, _Gxmax - _Gxmin); + + using _Sx_type = conditional_t<_Params._Smax_bits <= 32, uint32_t, + conditional_t<_Params._Smax_bits <= 64, uint64_t, _Unsigned128>>; + _Sx_type _Sx; + + if constexpr (_Params._Rx_is_pow2) { + // Always needs only one attempt. Multiplications can be replaced with shift/add. Optimize k=1 case. + if constexpr (_Params._Kx == 1) { + _Sx = static_cast<_Sx_type>(_Gx() - _Gxmin); + } else if constexpr (_Params._Kx > 1) { + constexpr int _Rx_bits = _Params._Smax_bits / _Params._Kx; + _Sx = 0; + int _Shift = 0; + for (int _Idx = 0; _Idx < _Params._Kx; ++_Idx) { + _Sx += static_cast<_Sx_type>(_Gx() - _Gxmin) << _Shift; + _Shift += _Rx_bits; + } + } else { + _STL_INTERNAL_STATIC_ASSERT(false); // unexpected k + } - constexpr int _Kx = _Generate_canonical_iterations(_Minbits, (_Gen::min)(), (_Gen::max)()); + _Sx >>= _Params._Smax_bits - _Minbits; + return static_cast<_Real>(static_cast<_Result_uint_type>(_Sx)) * static_cast<_Real>(_Params._Scale); + } else { + constexpr auto _Rx = _Sx_type{_Gxmax - _Gxmin} + 1u; + constexpr _Sx_type _Limit = static_cast<_Sx_type>(_Params._Xx) * (_Sx_type{1} << _Minbits); + + do { + // unroll first two iterations to avoid unnecessary multiplications + _Sx = static_cast<_Sx_type>(_Gx() - _Gxmin); + if constexpr (_Params._Kx == 2) { + _Sx += static_cast<_Sx_type>(_Gx() - _Gxmin) * _Rx; + } else if constexpr (_Params._Kx > 2) { + _Sx += static_cast<_Sx_type>(_Gx() - _Gxmin) * _Rx; + _Sx_type _Factor = _Rx; + for (int _Idx = 2; _Idx < _Params._Kx; ++_Idx) { + _Factor *= _Rx; + _Sx += static_cast<_Sx_type>(_Gx() - _Gxmin) * _Factor; + } + } + } while (_Sx >= _Limit); - _Real _Ans{0}; - _Real _Factor{1}; + return static_cast<_Real>(static_cast<_Result_uint_type>(_Sx / _Params._Xx)) + * static_cast<_Real>(_Params._Scale); + } + } +} - for (int _Idx = 0; _Idx < _Kx; ++_Idx) { // add in another set of bits - _Ans += (static_cast<_Real>(_Gx()) - _Gxmin) * _Factor; - _Factor *= _Rx; +template +bool _Nrand_for_tr1( + const uint64_t _Rd, const uint64_t _Rx, _Gen& _Gx, _Real& _Val, uint64_t& _Sx_init, uint64_t& _Factor_init) { + // Minimally-constexpr generate_canonical algorithm. Will save work and exit if _Factor would overflow. + _Uint_type _Sx = _Sx_init; + _Uint_type _Factor = _Factor_init; + const auto _Gxmin = (_Gx.min)(); + const auto _Overflow_limit = UINT64_MAX / _Rx; + + _Uint_type _Xx = 0; + _Uint_type _Limit = 0; + bool _Init = false; + for (;;) { + while (_Factor < _Rd) { + if constexpr (is_same_v<_Uint_type, uint64_t>) { + if (_Factor > _Overflow_limit) { + _Sx_init = _Sx; + _Factor_init = _Factor; + return true; + } + } + + _Sx += (_Gx() - _Gxmin) * _Factor; + _Factor *= _Rx; + } + + if (!_Init) { + _Init = true; + _Xx = _Factor / _Rd; + _Limit = _Xx * _Rd; + } + + if (_Sx < _Limit) { + break; + } else { + _Sx = 0; + _Factor = 1; + } } - return _Ans / _Factor; + _Val = static_cast<_Real>(static_cast(_Sx / _Xx)); + return false; } template struct _Has_static_min_max : false_type {}; -// This checks a requirement of N4950 [rand.req.urng] `concept uniform_random_bit_generator` but doesn't attempt +// This checks a requirement of N4981 [rand.req.urng] `concept uniform_random_bit_generator` but doesn't attempt // to implement the whole concept - we just need to distinguish Standard machinery from tr1 machinery. template struct _Has_static_min_max<_Gen, void_t::value)>> : true_type {}; @@ -323,18 +413,40 @@ template _NODISCARD _Real _Nrand_impl(_Gen& _Gx) { // build a floating-point value from random sequence _RNG_REQUIRE_REALTYPE(_Nrand_impl, _Real); - constexpr auto _Digits = static_cast(numeric_limits<_Real>::digits); - constexpr auto _Bits = ~size_t{0}; - constexpr auto _Minbits = _Digits < _Bits ? _Digits : _Bits; + constexpr auto _Digits = static_cast(numeric_limits<_Real>::digits); + + if constexpr (_Has_static_min_max<_Gen>::value) { + return _STD generate_canonical<_Real, _Digits>(_Gx); + } else if constexpr (is_integral_v) { + // TRANSITION, for integral tr1 machinery only; Standard machinery can call generate_canonical directly + const auto _Gxmax = (_Gx.max)(); + const auto _Gxmin = (_Gx.min)(); + _Real _Val{0}; + + if (_Gxmax == UINT64_MAX && _Gxmin == 0) { + // special case when uint64_t can't hold the full URBG range + _Val = static_cast<_Real>(static_cast(_Gx()) >> (64 - _Digits)); + } else { + constexpr auto _Rd = 1ULL << _Digits; + const auto _Rx = static_cast(_Gxmax - _Gxmin) + 1; + uint64_t _Sx = 0; + uint64_t _Factor = 1; + + // Try with 64 bits first, upgrade to 128 if necessary. + const bool _Would_overflow = _Nrand_for_tr1(_Rd, _Rx, _Gx, _Val, _Sx, _Factor); + if (_Would_overflow) { + _Nrand_for_tr1<_Unsigned128>(_Rd, _Rx, _Gx, _Val, _Sx, _Factor); + } + } - if constexpr (_Has_static_min_max<_Gen>::value && _Minbits <= 64) { - return _STD generate_canonical<_Real, _Minbits>(_Gx); - } else { // TRANSITION, for tr1 machinery only; Standard machinery can call generate_canonical directly + return _STD ldexp(_Val, -static_cast(_Digits)); + } else { + // TRANSITION, the pre-P0952R2 algorithm, for non-integral tr1 machinery only (e.g. subtract_with_carry_01) const _Real _Gxmin = static_cast<_Real>((_Gx.min)()); const _Real _Gxmax = static_cast<_Real>((_Gx.max)()); const _Real _Rx = (_Gxmax - _Gxmin) + _Real{1}; - const int _Ceil = static_cast(_STD ceil(static_cast<_Real>(_Minbits) / _STD log2(_Rx))); + const int _Ceil = static_cast(_STD ceil(static_cast<_Real>(_Digits) / _STD log2(_Rx))); const int _Kx = _Ceil < 1 ? 1 : _Ceil; _Real _Ans{0}; @@ -508,14 +620,14 @@ public: _Prev = _Temp; } - _NODISCARD_FRIEND bool operator==( + _NODISCARD friend bool operator==( const linear_congruential_engine& _Lhs, const linear_congruential_engine& _Rhs) noexcept /* strengthened */ { return _Lhs._Prev == _Rhs._Prev; } #if !_HAS_CXX20 - _NODISCARD_FRIEND bool operator!=( + _NODISCARD friend bool operator!=( const linear_congruential_engine& _Lhs, const linear_congruential_engine& _Rhs) noexcept /* strengthened */ { return _Lhs._Prev != _Rhs._Prev; @@ -599,13 +711,13 @@ public: _Prev = _Temp; } - _NODISCARD_FRIEND bool operator==(const linear_congruential& _Lhs, const linear_congruential& _Rhs) noexcept + _NODISCARD friend bool operator==(const linear_congruential& _Lhs, const linear_congruential& _Rhs) noexcept /* strengthened */ { return _Lhs._Prev == _Rhs._Prev; } #if !_HAS_CXX20 - _NODISCARD_FRIEND bool operator!=(const linear_congruential& _Lhs, const linear_congruential& _Rhs) noexcept + _NODISCARD friend bool operator!=(const linear_congruential& _Lhs, const linear_congruential& _Rhs) noexcept /* strengthened */ { return _Lhs._Prev != _Rhs._Prev; } @@ -752,12 +864,12 @@ public: } } - _NODISCARD_FRIEND bool operator==(const _Swc_base& _Left, const _Swc_base& _Right) noexcept /* strengthened */ { + _NODISCARD friend bool operator==(const _Swc_base& _Left, const _Swc_base& _Right) noexcept /* strengthened */ { return static_cast(_Left)._Equals(_Right) && _Left._Carry == _Right._Carry; } #if !_HAS_CXX20 - _NODISCARD_FRIEND bool operator!=(const _Swc_base& _Left, const _Swc_base& _Right) noexcept /* strengthened */ { + _NODISCARD friend bool operator!=(const _Swc_base& _Left, const _Swc_base& _Right) noexcept /* strengthened */ { return !(_Left == _Right); } #endif // !_HAS_CXX20 @@ -987,13 +1099,13 @@ public: return _Mx - 1; } - _NODISCARD_FRIEND bool operator==( + _NODISCARD friend bool operator==( const subtract_with_carry_engine& _Left, const subtract_with_carry_engine& _Right) noexcept /* strengthened */ { return static_cast(_Left) == static_cast(_Right); } #if !_HAS_CXX20 - _NODISCARD_FRIEND bool operator!=( + _NODISCARD friend bool operator!=( const subtract_with_carry_engine& _Left, const subtract_with_carry_engine& _Right) noexcept /* strengthened */ { return static_cast(_Left) != static_cast(_Right); } @@ -1186,13 +1298,13 @@ public: this->_Idx = _Nx; } - _NODISCARD_FRIEND bool operator==(const mersenne_twister& _Left, const mersenne_twister& _Right) noexcept + _NODISCARD friend bool operator==(const mersenne_twister& _Left, const mersenne_twister& _Right) noexcept /* strengthened */ { return _Left._Equals(_Right); } #if !_HAS_CXX20 - _NODISCARD_FRIEND bool operator!=(const mersenne_twister& _Left, const mersenne_twister& _Right) noexcept + _NODISCARD friend bool operator!=(const mersenne_twister& _Left, const mersenne_twister& _Right) noexcept /* strengthened */ { return !_Left._Equals(_Right); } @@ -1389,13 +1501,13 @@ public: return _Mybase::_WMSK; } - _NODISCARD_FRIEND bool operator==( + _NODISCARD friend bool operator==( const mersenne_twister_engine& _Left, const mersenne_twister_engine& _Right) noexcept /* strengthened */ { return static_cast(_Left) == static_cast(_Right); } #if !_HAS_CXX20 - _NODISCARD_FRIEND bool operator!=( + _NODISCARD friend bool operator!=( const mersenne_twister_engine& _Left, const mersenne_twister_engine& _Right) noexcept /* strengthened */ { return static_cast(_Left) != static_cast(_Right); } @@ -1492,12 +1604,12 @@ public: } } - _NODISCARD_FRIEND bool operator==(const discard_block& _Left, const discard_block& _Right) { + _NODISCARD friend bool operator==(const discard_block& _Left, const discard_block& _Right) { return _Left._Eng == _Right._Eng && _Left._Nx == _Right._Nx; } #if !_HAS_CXX20 - _NODISCARD_FRIEND bool operator!=(const discard_block& _Left, const discard_block& _Right) { + _NODISCARD friend bool operator!=(const discard_block& _Left, const discard_block& _Right) { return !(_Left == _Right); } #endif // !_HAS_CXX20 @@ -1573,12 +1685,12 @@ public: } } - _NODISCARD_FRIEND bool operator==(const _Discard_block_base& _Left, const _Discard_block_base& _Right) { + _NODISCARD friend bool operator==(const _Discard_block_base& _Left, const _Discard_block_base& _Right) { return _Left._Eng == _Right._Eng && _Left._Nx == _Right._Nx; } #if !_HAS_CXX20 - _NODISCARD_FRIEND bool operator!=(const _Discard_block_base& _Left, const _Discard_block_base& _Right) { + _NODISCARD friend bool operator!=(const _Discard_block_base& _Left, const _Discard_block_base& _Right) { return !(_Left == _Right); } #endif // !_HAS_CXX20 @@ -1659,12 +1771,12 @@ public: return (_Engine::max)(); } - _NODISCARD_FRIEND bool operator==(const discard_block_engine& _Left, const discard_block_engine& _Right) { + _NODISCARD friend bool operator==(const discard_block_engine& _Left, const discard_block_engine& _Right) { return static_cast(_Left) == static_cast(_Right); } #if !_HAS_CXX20 - _NODISCARD_FRIEND bool operator!=(const discard_block_engine& _Left, const discard_block_engine& _Right) { + _NODISCARD friend bool operator!=(const discard_block_engine& _Left, const discard_block_engine& _Right) { return static_cast(_Left) != static_cast(_Right); } #endif // !_HAS_CXX20 @@ -1774,12 +1886,12 @@ public: } } - _NODISCARD_FRIEND bool operator==(const independent_bits_engine& _Left, const independent_bits_engine& _Right) { + _NODISCARD friend bool operator==(const independent_bits_engine& _Left, const independent_bits_engine& _Right) { return _Left.base() == _Right.base(); } #if !_HAS_CXX20 - _NODISCARD_FRIEND bool operator!=(const independent_bits_engine& _Left, const independent_bits_engine& _Right) { + _NODISCARD friend bool operator!=(const independent_bits_engine& _Left, const independent_bits_engine& _Right) { return !(_Left == _Right); } #endif // !_HAS_CXX20 @@ -1904,12 +2016,12 @@ public: } } - _NODISCARD_FRIEND bool operator==(const shuffle_order_engine& _Left, const shuffle_order_engine& _Right) { + _NODISCARD friend bool operator==(const shuffle_order_engine& _Left, const shuffle_order_engine& _Right) { return _Left.base() == _Right.base(); } #if !_HAS_CXX20 - _NODISCARD_FRIEND bool operator!=(const shuffle_order_engine& _Left, const shuffle_order_engine& _Right) { + _NODISCARD friend bool operator!=(const shuffle_order_engine& _Left, const shuffle_order_engine& _Right) { return !(_Left == _Right); } #endif // !_HAS_CXX20 @@ -1968,8 +2080,8 @@ public: explicit _Rng_from_urng_v2(_Urng& _Func) noexcept : _Ref(_Func) {} _Diff operator()(_Diff _Index) { // adapt _Urng closed range to [0, _Index) - // From Daniel Lemire, "Fast Random Integer Generation in an Interval", ACM Trans. Model. Comput. Simul. 29 (1), - // 2019. + // From Daniel Lemire, "Fast Random Integer Generation in an Interval", + // ACM Trans. Model. Comput. Simul. 29 (1), 2019. // // Algorithm 5 <-> This Code: // m <-> _Product @@ -2093,13 +2205,13 @@ public: _Init(_Min0, _Max0); } - _NODISCARD_FRIEND bool operator==(const param_type& _Left, const param_type& _Right) noexcept + _NODISCARD friend bool operator==(const param_type& _Left, const param_type& _Right) noexcept /* strengthened */ { return _Left._Min == _Right._Min && _Left._Max == _Right._Max; } #if !_HAS_CXX20 - _NODISCARD_FRIEND bool operator!=(const param_type& _Left, const param_type& _Right) noexcept + _NODISCARD friend bool operator!=(const param_type& _Left, const param_type& _Right) noexcept /* strengthened */ { return !(_Left == _Right); } @@ -2301,13 +2413,13 @@ public: return _Ostr << static_cast(_Dist); } - _NODISCARD_FRIEND bool operator==( + _NODISCARD friend bool operator==( const uniform_int_distribution& _Left, const uniform_int_distribution& _Right) noexcept /* strengthened */ { return _Left.param() == _Right.param(); } #if !_HAS_CXX20 - _NODISCARD_FRIEND bool operator!=( + _NODISCARD friend bool operator!=( const uniform_int_distribution& _Left, const uniform_int_distribution& _Right) noexcept /* strengthened */ { return !(_Left == _Right); } @@ -2330,13 +2442,13 @@ public: _Init(_Px0); } - _NODISCARD_FRIEND bool operator==(const param_type& _Left, const param_type& _Right) noexcept + _NODISCARD friend bool operator==(const param_type& _Left, const param_type& _Right) noexcept /* strengthened */ { return _Left._Px == _Right._Px; } #if !_HAS_CXX20 - _NODISCARD_FRIEND bool operator!=(const param_type& _Left, const param_type& _Right) noexcept + _NODISCARD friend bool operator!=(const param_type& _Left, const param_type& _Right) noexcept /* strengthened */ { return !(_Left == _Right); } @@ -2396,13 +2508,13 @@ public: return _Eval(_Eng, _Par0); } - _NODISCARD_FRIEND bool operator==( + _NODISCARD friend bool operator==( const bernoulli_distribution& _Left, const bernoulli_distribution& _Right) noexcept /* strengthened */ { return _Left.param() == _Right.param(); } #if !_HAS_CXX20 - _NODISCARD_FRIEND bool operator!=( + _NODISCARD friend bool operator!=( const bernoulli_distribution& _Left, const bernoulli_distribution& _Right) noexcept /* strengthened */ { return !(_Left == _Right); } @@ -2490,13 +2602,13 @@ public: _Init(_Px0); } - _NODISCARD_FRIEND bool operator==(const param_type& _Left, const param_type& _Right) noexcept + _NODISCARD friend bool operator==(const param_type& _Left, const param_type& _Right) noexcept /* strengthened */ { return _Left._Px == _Right._Px; } #if !_HAS_CXX20 - _NODISCARD_FRIEND bool operator!=(const param_type& _Left, const param_type& _Right) noexcept + _NODISCARD friend bool operator!=(const param_type& _Left, const param_type& _Right) noexcept /* strengthened */ { return !(_Left == _Right); } @@ -2557,13 +2669,13 @@ public: return _Eval(_Eng, _Par0); } - _NODISCARD_FRIEND bool operator==( + _NODISCARD friend bool operator==( const geometric_distribution& _Left, const geometric_distribution& _Right) noexcept /* strengthened */ { return _Left.param() == _Right.param(); } #if !_HAS_CXX20 - _NODISCARD_FRIEND bool operator!=( + _NODISCARD friend bool operator!=( const geometric_distribution& _Left, const geometric_distribution& _Right) noexcept /* strengthened */ { return !(_Left == _Right); } @@ -2646,13 +2758,13 @@ public: _Init(_Mean0); } - _NODISCARD_FRIEND bool operator==(const param_type& _Left, const param_type& _Right) noexcept + _NODISCARD friend bool operator==(const param_type& _Left, const param_type& _Right) noexcept /* strengthened */ { return _Left._Mean == _Right._Mean; } #if !_HAS_CXX20 - _NODISCARD_FRIEND bool operator!=(const param_type& _Left, const param_type& _Right) noexcept + _NODISCARD friend bool operator!=(const param_type& _Left, const param_type& _Right) noexcept /* strengthened */ { return !(_Left == _Right); } @@ -2720,13 +2832,13 @@ public: return _Eval(_Eng, _Par0); } - _NODISCARD_FRIEND bool operator==(const poisson_distribution& _Left, const poisson_distribution& _Right) noexcept + _NODISCARD friend bool operator==(const poisson_distribution& _Left, const poisson_distribution& _Right) noexcept /* strengthened */ { return _Left.param() == _Right.param(); } #if !_HAS_CXX20 - _NODISCARD_FRIEND bool operator!=(const poisson_distribution& _Left, const poisson_distribution& _Right) noexcept + _NODISCARD friend bool operator!=(const poisson_distribution& _Left, const poisson_distribution& _Right) noexcept /* strengthened */ { return !(_Left == _Right); } @@ -2801,13 +2913,13 @@ public: _Init(_Tx0, _Px0); } - _NODISCARD_FRIEND bool operator==(const param_type& _Left, const param_type& _Right) noexcept + _NODISCARD friend bool operator==(const param_type& _Left, const param_type& _Right) noexcept /* strengthened */ { return _Left._Tx == _Right._Tx && _Left._Px == _Right._Px; } #if !_HAS_CXX20 - _NODISCARD_FRIEND bool operator!=(const param_type& _Left, const param_type& _Right) noexcept + _NODISCARD friend bool operator!=(const param_type& _Left, const param_type& _Right) noexcept /* strengthened */ { return !(_Left == _Right); } @@ -2892,13 +3004,13 @@ public: return _Eval(_Eng, _Par0); } - _NODISCARD_FRIEND bool operator==(const binomial_distribution& _Left, const binomial_distribution& _Right) noexcept + _NODISCARD friend bool operator==(const binomial_distribution& _Left, const binomial_distribution& _Right) noexcept /* strengthened */ { return _Left.param() == _Right.param(); } #if !_HAS_CXX20 - _NODISCARD_FRIEND bool operator!=(const binomial_distribution& _Left, const binomial_distribution& _Right) noexcept + _NODISCARD friend bool operator!=(const binomial_distribution& _Left, const binomial_distribution& _Right) noexcept /* strengthened */ { return !(_Left == _Right); } @@ -2925,8 +3037,8 @@ public: private: template - result_type _Eval( - _Engine& _Eng, const param_type& _Par0) const { // Press et al., Numerical Recipes in C, 2nd ed., pp 295-296. + result_type _Eval(_Engine& _Eng, const param_type& _Par0) const { + // Press et al., Numerical Recipes in C, 2nd ed., pp 295-296. _Ty _Res; if (_Par0._Tx < 25) { // generate directly _Res = 0; @@ -3002,13 +3114,13 @@ public: _Init(_Min0, _Max0); } - _NODISCARD_FRIEND bool operator==(const param_type& _Left, const param_type& _Right) noexcept + _NODISCARD friend bool operator==(const param_type& _Left, const param_type& _Right) noexcept /* strengthened */ { return _Left._Min == _Right._Min && _Left._Max == _Right._Max; } #if !_HAS_CXX20 - _NODISCARD_FRIEND bool operator!=(const param_type& _Left, const param_type& _Right) noexcept + _NODISCARD friend bool operator!=(const param_type& _Left, const param_type& _Right) noexcept /* strengthened */ { return !(_Left == _Right); } @@ -3192,13 +3304,13 @@ public: return _Ostr << static_cast(_Dist); } - _NODISCARD_FRIEND bool operator==( + _NODISCARD friend bool operator==( const uniform_real_distribution& _Left, const uniform_real_distribution& _Right) noexcept /* strengthened */ { return _Left.param() == _Right.param(); } #if !_HAS_CXX20 - _NODISCARD_FRIEND bool operator!=( + _NODISCARD friend bool operator!=( const uniform_real_distribution& _Left, const uniform_real_distribution& _Right) noexcept /* strengthened */ { return !(_Left == _Right); } @@ -3224,13 +3336,13 @@ public: _Init(_Lambda0); } - _NODISCARD_FRIEND bool operator==(const param_type& _Left, const param_type& _Right) noexcept + _NODISCARD friend bool operator==(const param_type& _Left, const param_type& _Right) noexcept /* strengthened */ { return _Left._Lambda == _Right._Lambda; } #if !_HAS_CXX20 - _NODISCARD_FRIEND bool operator!=(const param_type& _Left, const param_type& _Right) noexcept + _NODISCARD friend bool operator!=(const param_type& _Left, const param_type& _Right) noexcept /* strengthened */ { return !(_Left == _Right); } @@ -3289,13 +3401,13 @@ public: return _Eval(_Eng, _Par0); } - _NODISCARD_FRIEND bool operator==( + _NODISCARD friend bool operator==( const exponential_distribution& _Left, const exponential_distribution& _Right) noexcept /* strengthened */ { return _Left.param() == _Right.param(); } #if !_HAS_CXX20 - _NODISCARD_FRIEND bool operator!=( + _NODISCARD friend bool operator!=( const exponential_distribution& _Left, const exponential_distribution& _Right) noexcept /* strengthened */ { return !(_Left == _Right); } @@ -3344,13 +3456,13 @@ public: _Init(_Mean0, _Sigma0); } - _NODISCARD_FRIEND bool operator==(const param_type& _Left, const param_type& _Right) noexcept + _NODISCARD friend bool operator==(const param_type& _Left, const param_type& _Right) noexcept /* strengthened */ { return _Left._Mean == _Right._Mean && _Left._Sigma == _Right._Sigma; } #if !_HAS_CXX20 - _NODISCARD_FRIEND bool operator!=(const param_type& _Left, const param_type& _Right) noexcept + _NODISCARD friend bool operator!=(const param_type& _Left, const param_type& _Right) noexcept /* strengthened */ { return !(_Left == _Right); } @@ -3430,13 +3542,13 @@ public: return _Eval(_Eng, _Par0); } - _NODISCARD_FRIEND bool operator==(const normal_distribution& _Left, const normal_distribution& _Right) noexcept + _NODISCARD friend bool operator==(const normal_distribution& _Left, const normal_distribution& _Right) noexcept /* strengthened */ { return _Left.param() == _Right.param(); } #if !_HAS_CXX20 - _NODISCARD_FRIEND bool operator!=(const normal_distribution& _Left, const normal_distribution& _Right) noexcept + _NODISCARD friend bool operator!=(const normal_distribution& _Left, const normal_distribution& _Right) noexcept /* strengthened */ { return !(_Left == _Right); } @@ -3536,13 +3648,13 @@ public: _Init(_Alpha0, _Beta0); } - _NODISCARD_FRIEND bool operator==(const param_type& _Left, const param_type& _Right) noexcept + _NODISCARD friend bool operator==(const param_type& _Left, const param_type& _Right) noexcept /* strengthened */ { return _Left._Alpha == _Right._Alpha && _Left._Beta == _Right._Beta; } #if !_HAS_CXX20 - _NODISCARD_FRIEND bool operator!=(const param_type& _Left, const param_type& _Right) noexcept + _NODISCARD friend bool operator!=(const param_type& _Left, const param_type& _Right) noexcept /* strengthened */ { return !(_Left == _Right); } @@ -3617,13 +3729,13 @@ public: return _Eval(_Eng, _Par0); } - _NODISCARD_FRIEND bool operator==(const gamma_distribution& _Left, const gamma_distribution& _Right) noexcept + _NODISCARD friend bool operator==(const gamma_distribution& _Left, const gamma_distribution& _Right) noexcept /* strengthened */ { return _Left.param() == _Right.param(); } #if !_HAS_CXX20 - _NODISCARD_FRIEND bool operator!=(const gamma_distribution& _Left, const gamma_distribution& _Right) noexcept + _NODISCARD friend bool operator!=(const gamma_distribution& _Left, const gamma_distribution& _Right) noexcept /* strengthened */ { return !(_Left == _Right); } @@ -3730,13 +3842,13 @@ public: _Init(_Ax0, _Bx0); } - _NODISCARD_FRIEND bool operator==(const param_type& _Left, const param_type& _Right) noexcept + _NODISCARD friend bool operator==(const param_type& _Left, const param_type& _Right) noexcept /* strengthened */ { return _Left._Ax == _Right._Ax && _Left._Bx == _Right._Bx; } #if !_HAS_CXX20 - _NODISCARD_FRIEND bool operator!=(const param_type& _Left, const param_type& _Right) noexcept + _NODISCARD friend bool operator!=(const param_type& _Left, const param_type& _Right) noexcept /* strengthened */ { return !(_Left == _Right); } @@ -3806,13 +3918,13 @@ public: return _Eval(_Eng, _Par0); } - _NODISCARD_FRIEND bool operator==(const weibull_distribution& _Left, const weibull_distribution& _Right) noexcept + _NODISCARD friend bool operator==(const weibull_distribution& _Left, const weibull_distribution& _Right) noexcept /* strengthened */ { return _Left.param() == _Right.param(); } #if !_HAS_CXX20 - _NODISCARD_FRIEND bool operator!=(const weibull_distribution& _Left, const weibull_distribution& _Right) noexcept + _NODISCARD friend bool operator!=(const weibull_distribution& _Left, const weibull_distribution& _Right) noexcept /* strengthened */ { return !(_Left == _Right); } @@ -3865,13 +3977,13 @@ public: _Init(_Ax0, _Bx0); } - _NODISCARD_FRIEND bool operator==(const param_type& _Left, const param_type& _Right) noexcept + _NODISCARD friend bool operator==(const param_type& _Left, const param_type& _Right) noexcept /* strengthened */ { return _Left._Ax == _Right._Ax && _Left._Bx == _Right._Bx; } #if !_HAS_CXX20 - _NODISCARD_FRIEND bool operator!=(const param_type& _Left, const param_type& _Right) noexcept + _NODISCARD friend bool operator!=(const param_type& _Left, const param_type& _Right) noexcept /* strengthened */ { return !(_Left == _Right); } @@ -3940,13 +4052,13 @@ public: return _Eval(_Eng, _Par0); } - _NODISCARD_FRIEND bool operator==( + _NODISCARD friend bool operator==( const extreme_value_distribution& _Left, const extreme_value_distribution& _Right) noexcept /* strengthened */ { return _Left.param() == _Right.param(); } #if !_HAS_CXX20 - _NODISCARD_FRIEND bool operator!=( + _NODISCARD friend bool operator!=( const extreme_value_distribution& _Left, const extreme_value_distribution& _Right) noexcept /* strengthened */ { return !(_Left == _Right); } @@ -3999,13 +4111,13 @@ public: _Init(_Mx0, _Sx0); } - _NODISCARD_FRIEND bool operator==(const param_type& _Left, const param_type& _Right) noexcept + _NODISCARD friend bool operator==(const param_type& _Left, const param_type& _Right) noexcept /* strengthened */ { return _Left._Mx == _Right._Mx && _Left._Sx == _Right._Sx; } #if !_HAS_CXX20 - _NODISCARD_FRIEND bool operator!=(const param_type& _Left, const param_type& _Right) noexcept + _NODISCARD friend bool operator!=(const param_type& _Left, const param_type& _Right) noexcept /* strengthened */ { return !(_Left == _Right); } @@ -4074,13 +4186,13 @@ public: return _Eval(_Eng, _Par0); } - _NODISCARD_FRIEND bool operator==( + _NODISCARD friend bool operator==( const lognormal_distribution& _Left, const lognormal_distribution& _Right) noexcept /* strengthened */ { return _Left.param() == _Right.param(); } #if !_HAS_CXX20 - _NODISCARD_FRIEND bool operator!=( + _NODISCARD friend bool operator!=( const lognormal_distribution& _Left, const lognormal_distribution& _Right) noexcept /* strengthened */ { return !(_Left == _Right); } @@ -4133,13 +4245,13 @@ public: _Init(_Nx0); } - _NODISCARD_FRIEND bool operator==(const param_type& _Left, const param_type& _Right) noexcept + _NODISCARD friend bool operator==(const param_type& _Left, const param_type& _Right) noexcept /* strengthened */ { return _Left._Nx == _Right._Nx; } #if !_HAS_CXX20 - _NODISCARD_FRIEND bool operator!=(const param_type& _Left, const param_type& _Right) noexcept + _NODISCARD friend bool operator!=(const param_type& _Left, const param_type& _Right) noexcept /* strengthened */ { return !(_Left == _Right); } @@ -4198,13 +4310,13 @@ public: return _Eval(_Eng, _Par0); } - _NODISCARD_FRIEND bool operator==( + _NODISCARD friend bool operator==( const chi_squared_distribution& _Left, const chi_squared_distribution& _Right) noexcept /* strengthened */ { return _Left.param() == _Right.param(); } #if !_HAS_CXX20 - _NODISCARD_FRIEND bool operator!=( + _NODISCARD friend bool operator!=( const chi_squared_distribution& _Left, const chi_squared_distribution& _Right) noexcept /* strengthened */ { return !(_Left == _Right); } @@ -4253,13 +4365,13 @@ public: _Init(_Ax0, _Bx0); } - _NODISCARD_FRIEND bool operator==(const param_type& _Left, const param_type& _Right) noexcept + _NODISCARD friend bool operator==(const param_type& _Left, const param_type& _Right) noexcept /* strengthened */ { return _Left._Ax == _Right._Ax && _Left._Bx == _Right._Bx; } #if !_HAS_CXX20 - _NODISCARD_FRIEND bool operator!=(const param_type& _Left, const param_type& _Right) noexcept + _NODISCARD friend bool operator!=(const param_type& _Left, const param_type& _Right) noexcept /* strengthened */ { return !(_Left == _Right); } @@ -4328,13 +4440,13 @@ public: return _Eval(_Eng, _Par0); } - _NODISCARD_FRIEND bool operator==(const cauchy_distribution& _Left, const cauchy_distribution& _Right) noexcept + _NODISCARD friend bool operator==(const cauchy_distribution& _Left, const cauchy_distribution& _Right) noexcept /* strengthened */ { return _Left.param() == _Right.param(); } #if !_HAS_CXX20 - _NODISCARD_FRIEND bool operator!=(const cauchy_distribution& _Left, const cauchy_distribution& _Right) noexcept + _NODISCARD friend bool operator!=(const cauchy_distribution& _Left, const cauchy_distribution& _Right) noexcept /* strengthened */ { return !(_Left == _Right); } @@ -4446,13 +4558,13 @@ public: _Init(_Mx0, _Nx0); } - _NODISCARD_FRIEND bool operator==(const param_type& _Left, const param_type& _Right) noexcept + _NODISCARD friend bool operator==(const param_type& _Left, const param_type& _Right) noexcept /* strengthened */ { return _Left._Mx == _Right._Mx && _Left._Nx == _Right._Nx; } #if !_HAS_CXX20 - _NODISCARD_FRIEND bool operator!=(const param_type& _Left, const param_type& _Right) noexcept + _NODISCARD friend bool operator!=(const param_type& _Left, const param_type& _Right) noexcept /* strengthened */ { return !(_Left == _Right); } @@ -4522,13 +4634,13 @@ public: return _Eval(_Eng, _Par0); } - _NODISCARD_FRIEND bool operator==(const fisher_f_distribution& _Left, const fisher_f_distribution& _Right) noexcept + _NODISCARD friend bool operator==(const fisher_f_distribution& _Left, const fisher_f_distribution& _Right) noexcept /* strengthened */ { return _Left.param() == _Right.param(); } #if !_HAS_CXX20 - _NODISCARD_FRIEND bool operator!=(const fisher_f_distribution& _Left, const fisher_f_distribution& _Right) noexcept + _NODISCARD friend bool operator!=(const fisher_f_distribution& _Left, const fisher_f_distribution& _Right) noexcept /* strengthened */ { return !(_Left == _Right); } @@ -4592,13 +4704,13 @@ public: _Init(_Nx0); } - _NODISCARD_FRIEND bool operator==(const param_type& _Left, const param_type& _Right) noexcept + _NODISCARD friend bool operator==(const param_type& _Left, const param_type& _Right) noexcept /* strengthened */ { return _Left._Nx == _Right._Nx; } #if !_HAS_CXX20 - _NODISCARD_FRIEND bool operator!=(const param_type& _Left, const param_type& _Right) noexcept + _NODISCARD friend bool operator!=(const param_type& _Left, const param_type& _Right) noexcept /* strengthened */ { return !(_Left == _Right); } @@ -4657,13 +4769,13 @@ public: return _Eval(_Eng, _Par0); } - _NODISCARD_FRIEND bool operator==( + _NODISCARD friend bool operator==( const student_t_distribution& _Left, const student_t_distribution& _Right) noexcept /* strengthened */ { return _Left.param() == _Right.param(); } #if !_HAS_CXX20 - _NODISCARD_FRIEND bool operator!=( + _NODISCARD friend bool operator!=( const student_t_distribution& _Left, const student_t_distribution& _Right) noexcept /* strengthened */ { return !(_Left == _Right); } @@ -4727,13 +4839,13 @@ public: _Init(_Kx0, _Px0); } - _NODISCARD_FRIEND bool operator==(const param_type& _Left, const param_type& _Right) noexcept + _NODISCARD friend bool operator==(const param_type& _Left, const param_type& _Right) noexcept /* strengthened */ { return _Left._Kx == _Right._Kx && _Left._Px == _Right._Px; } #if !_HAS_CXX20 - _NODISCARD_FRIEND bool operator!=(const param_type& _Left, const param_type& _Right) noexcept + _NODISCARD friend bool operator!=(const param_type& _Left, const param_type& _Right) noexcept /* strengthened */ { return !(_Left == _Right); } @@ -4803,13 +4915,13 @@ public: return _Eval(_Eng, _Par0); } - _NODISCARD_FRIEND bool operator==(const negative_binomial_distribution& _Left, + _NODISCARD friend bool operator==(const negative_binomial_distribution& _Left, const negative_binomial_distribution& _Right) noexcept /* strengthened */ { return _Left.param() == _Right.param(); } #if !_HAS_CXX20 - _NODISCARD_FRIEND bool operator!=(const negative_binomial_distribution& _Left, + _NODISCARD friend bool operator!=(const negative_binomial_distribution& _Left, const negative_binomial_distribution& _Right) noexcept /* strengthened */ { return !(_Left == _Right); } @@ -4892,12 +5004,12 @@ public: _Init(); } - _NODISCARD_FRIEND bool operator==(const param_type& _Left, const param_type& _Right) { + _NODISCARD friend bool operator==(const param_type& _Left, const param_type& _Right) { return _Left._Pvec == _Right._Pvec; } #if !_HAS_CXX20 - _NODISCARD_FRIEND bool operator!=(const param_type& _Left, const param_type& _Right) { + _NODISCARD friend bool operator!=(const param_type& _Left, const param_type& _Right) { return !(_Left == _Right); } #endif // !_HAS_CXX20 @@ -5009,12 +5121,12 @@ public: return _Eval(_Eng, _Par0); } - _NODISCARD_FRIEND bool operator==(const discrete_distribution& _Left, const discrete_distribution& _Right) { + _NODISCARD friend bool operator==(const discrete_distribution& _Left, const discrete_distribution& _Right) { return _Left.param() == _Right.param(); } #if !_HAS_CXX20 - _NODISCARD_FRIEND bool operator!=(const discrete_distribution& _Left, const discrete_distribution& _Right) { + _NODISCARD friend bool operator!=(const discrete_distribution& _Left, const discrete_distribution& _Right) { return !(_Left == _Right); } #endif // !_HAS_CXX20 @@ -5101,13 +5213,13 @@ public: } } - _NODISCARD_FRIEND bool operator==(const param_type& _Left, const param_type& _Right) { + _NODISCARD friend bool operator==(const param_type& _Left, const param_type& _Right) { return static_cast(_Left) == static_cast(_Right) && _Left._Bvec == _Right._Bvec; } #if !_HAS_CXX20 - _NODISCARD_FRIEND bool operator!=(const param_type& _Left, const param_type& _Right) { + _NODISCARD friend bool operator!=(const param_type& _Left, const param_type& _Right) { return !(_Left == _Right); } #endif // !_HAS_CXX20 @@ -5185,13 +5297,13 @@ public: return _Eval(_Eng, _Par0); } - _NODISCARD_FRIEND bool operator==( + _NODISCARD friend bool operator==( const piecewise_constant_distribution& _Left, const piecewise_constant_distribution& _Right) { return _Left.param() == _Right.param(); } #if !_HAS_CXX20 - _NODISCARD_FRIEND bool operator!=( + _NODISCARD friend bool operator!=( const piecewise_constant_distribution& _Left, const piecewise_constant_distribution& _Right) { return !(_Left == _Right); } @@ -5298,13 +5410,13 @@ public: _Init(); } - _NODISCARD_FRIEND bool operator==(const param_type& _Left, const param_type& _Right) { + _NODISCARD friend bool operator==(const param_type& _Left, const param_type& _Right) { return static_cast(_Left) == static_cast(_Right) && _Left._Bvec == _Right._Bvec; } #if !_HAS_CXX20 - _NODISCARD_FRIEND bool operator!=(const param_type& _Left, const param_type& _Right) { + _NODISCARD friend bool operator!=(const param_type& _Left, const param_type& _Right) { return !(_Left == _Right); } #endif // !_HAS_CXX20 @@ -5409,13 +5521,13 @@ public: return _Eval(_Eng, _Par0); } - _NODISCARD_FRIEND bool operator==( + _NODISCARD friend bool operator==( const piecewise_linear_distribution& _Left, const piecewise_linear_distribution& _Right) { return _Left.param() == _Right.param(); } #if !_HAS_CXX20 - _NODISCARD_FRIEND bool operator!=( + _NODISCARD friend bool operator!=( const piecewise_linear_distribution& _Left, const piecewise_linear_distribution& _Right) { return !(_Left == _Right); } diff --git a/stl/inc/ranges b/stl/inc/ranges index 8129f9b14c6..db45abf8e13 100644 --- a/stl/inc/ranges +++ b/stl/inc/ranges @@ -813,46 +813,46 @@ namespace ranges { } } - _NODISCARD_FRIEND constexpr bool operator==(const _Ioterator& _Left, const _Ioterator& _Right) noexcept( + _NODISCARD friend constexpr bool operator==(const _Ioterator& _Left, const _Ioterator& _Right) noexcept( noexcept(_Left._Current == _Right._Current)) requires equality_comparable<_Wi> { return _Left._Current == _Right._Current; } - _NODISCARD_FRIEND constexpr bool operator<(const _Ioterator& _Left, const _Ioterator& _Right) noexcept( + _NODISCARD friend constexpr bool operator<(const _Ioterator& _Left, const _Ioterator& _Right) noexcept( noexcept(_Left._Current < _Right._Current)) /* strengthened */ requires totally_ordered<_Wi> { return _Left._Current < _Right._Current; } - _NODISCARD_FRIEND constexpr bool operator>(const _Ioterator& _Left, const _Ioterator& _Right) noexcept( + _NODISCARD friend constexpr bool operator>(const _Ioterator& _Left, const _Ioterator& _Right) noexcept( noexcept(_Right._Current < _Left._Current)) /* strengthened */ requires totally_ordered<_Wi> { return _Right._Current < _Left._Current; } - _NODISCARD_FRIEND constexpr bool operator<=(const _Ioterator& _Left, const _Ioterator& _Right) noexcept( + _NODISCARD friend constexpr bool operator<=(const _Ioterator& _Left, const _Ioterator& _Right) noexcept( noexcept(!(_Right._Current < _Left._Current))) /* strengthened */ requires totally_ordered<_Wi> { return !(_Right._Current < _Left._Current); } - _NODISCARD_FRIEND constexpr bool operator>=(const _Ioterator& _Left, const _Ioterator& _Right) noexcept( + _NODISCARD friend constexpr bool operator>=(const _Ioterator& _Left, const _Ioterator& _Right) noexcept( noexcept(!(_Left._Current < _Right._Current))) /* strengthened */ requires totally_ordered<_Wi> { return !(_Left._Current < _Right._Current); } - _NODISCARD_FRIEND constexpr auto operator<=>(const _Ioterator& _Left, const _Ioterator& _Right) noexcept( + _NODISCARD friend constexpr auto operator<=>(const _Ioterator& _Left, const _Ioterator& _Right) noexcept( noexcept(_Left._Current <=> _Right._Current)) requires totally_ordered<_Wi> && three_way_comparable<_Wi> { return _Left._Current <=> _Right._Current; } - _NODISCARD_FRIEND constexpr _Ioterator operator+(_Ioterator _It, const difference_type _Off) noexcept( + _NODISCARD friend constexpr _Ioterator operator+(_Ioterator _It, const difference_type _Off) noexcept( is_nothrow_move_constructible_v<_Ioterator> // && noexcept(_It += _Off)) /* strengthened */ requires _Advanceable<_Wi> @@ -860,7 +860,7 @@ namespace ranges { _It += _Off; return _It; } - _NODISCARD_FRIEND constexpr _Ioterator operator+(const difference_type _Off, _Ioterator _It) noexcept( + _NODISCARD friend constexpr _Ioterator operator+(const difference_type _Off, _Ioterator _It) noexcept( is_nothrow_move_constructible_v<_Wi> // && noexcept(static_cast<_Wi>(_It._Current + _Off))) /* strengthened */ requires _Advanceable<_Wi> @@ -868,7 +868,7 @@ namespace ranges { return _Ioterator{static_cast<_Wi>(_It._Current + _Off)}; } - _NODISCARD_FRIEND constexpr _Ioterator operator-(_Ioterator _It, const difference_type _Off) noexcept( + _NODISCARD friend constexpr _Ioterator operator-(_Ioterator _It, const difference_type _Off) noexcept( is_nothrow_move_constructible_v<_Ioterator> // && noexcept(_It -= _Off)) /* strengthened */ requires _Advanceable<_Wi> @@ -877,7 +877,7 @@ namespace ranges { return _It; } - _NODISCARD_FRIEND constexpr difference_type operator-(const _Ioterator& _Left, + _NODISCARD friend constexpr difference_type operator-(const _Ioterator& _Left, const _Ioterator& _Right) noexcept(noexcept(_Left._Current - _Right._Current)) /* strengthened */ requires _Advanceable<_Wi> { @@ -916,19 +916,19 @@ namespace ranges { public: /* [[no_unique_address]] */ _Bo _Last{}; - _NODISCARD_FRIEND constexpr bool operator==(const _It& _Left, const _Iotinel& _Right) noexcept( + _NODISCARD friend constexpr bool operator==(const _It& _Left, const _Iotinel& _Right) noexcept( noexcept(_Right._Equal(_Left))) /* strengthened */ { return _Right._Equal(_Left); } - _NODISCARD_FRIEND constexpr iter_difference_t<_Wi> operator-(const _It& _Left, const _Iotinel& _Right) noexcept( + _NODISCARD friend constexpr iter_difference_t<_Wi> operator-(const _It& _Left, const _Iotinel& _Right) noexcept( noexcept(_Right._Delta(_Left))) /* strengthened */ requires sized_sentinel_for<_Bo, _Wi> { return -_Right._Delta(_Left); } - _NODISCARD_FRIEND constexpr iter_difference_t<_Wi> operator-(const _Iotinel& _Left, const _It& _Right) noexcept( + _NODISCARD friend constexpr iter_difference_t<_Wi> operator-(const _Iotinel& _Left, const _It& _Right) noexcept( noexcept(_Left._Delta(_Right))) /* strengthened */ requires sized_sentinel_for<_Bo, _Wi> { @@ -1044,10 +1044,10 @@ namespace ranges { struct _Iota_fn { template _NODISCARD _STATIC_CALL_OPERATOR constexpr auto operator()(_Ty&& _Val) _CONST_CALL_OPERATOR - noexcept(noexcept(iota_view(static_cast<_Ty&&>(_Val)))) - requires requires { iota_view(static_cast<_Ty&&>(_Val)); } + noexcept(noexcept(iota_view>(static_cast<_Ty&&>(_Val)))) + requires requires { iota_view>(static_cast<_Ty&&>(_Val)); } { - return iota_view(static_cast<_Ty&&>(_Val)); + return iota_view>(static_cast<_Ty&&>(_Val)); } template @@ -1197,32 +1197,32 @@ namespace ranges { return *(*this + _Idx); } - _NODISCARD_FRIEND constexpr bool operator==(const _Iterator& _Left, const _Iterator& _Right) noexcept + _NODISCARD friend constexpr bool operator==(const _Iterator& _Left, const _Iterator& _Right) noexcept /* strengthened */ { return _Left._Current == _Right._Current; } - _NODISCARD_FRIEND constexpr auto operator<=>(const _Iterator& _Left, const _Iterator& _Right) noexcept + _NODISCARD friend constexpr auto operator<=>(const _Iterator& _Left, const _Iterator& _Right) noexcept /* strengthened */ { return _Left._Current <=> _Right._Current; } - _NODISCARD_FRIEND constexpr _Iterator operator+(_Iterator _Iter, difference_type _Off) noexcept + _NODISCARD friend constexpr _Iterator operator+(_Iterator _Iter, difference_type _Off) noexcept /* strengthened */ { _Iter += _Off; return _Iter; } - _NODISCARD_FRIEND constexpr _Iterator operator+(difference_type _Off, _Iterator _Iter) noexcept + _NODISCARD friend constexpr _Iterator operator+(difference_type _Off, _Iterator _Iter) noexcept /* strengthened */ { _Iter += _Off; return _Iter; } - _NODISCARD_FRIEND constexpr _Iterator operator-(_Iterator _Iter, difference_type _Off) noexcept + _NODISCARD friend constexpr _Iterator operator-(_Iterator _Iter, difference_type _Off) noexcept /* strengthened */ { _Iter -= _Off; return _Iter; } - _NODISCARD_FRIEND constexpr difference_type operator-( + _NODISCARD friend constexpr difference_type operator-( const _Iterator& _Left, const _Iterator& _Right) noexcept /* strengthened */ { return static_cast( static_cast(_Left._Current) - static_cast(_Right._Current)); @@ -1365,7 +1365,7 @@ namespace ranges { return _Parent->_Val; } - _NODISCARD_FRIEND bool operator==(const _Iterator& _Left, default_sentinel_t) noexcept /* strengthened */ { + _NODISCARD friend bool operator==(const _Iterator& _Left, default_sentinel_t) noexcept /* strengthened */ { return _Left._Parent->_Stream_at_end(); } }; @@ -1523,8 +1523,10 @@ namespace ranges { constexpr auto _Compile_time_max_size> = _Compile_time_max_size; namespace views { + // direct-non-list-initialization is specified in the Standard (N4981 [range.as.rvalue.overview]/2.2) + // and needed for EDG, DevCom-10698021 template - concept _Can_as_rvalue = requires(_Rng&& __r) { as_rvalue_view{static_cast<_Rng&&>(__r)}; }; + concept _Can_as_rvalue = requires(_Rng&& __r) { as_rvalue_view(static_cast<_Rng&&>(__r)); }; class _As_rvalue_fn : public _Pipe::_Base<_As_rvalue_fn> { private: @@ -1532,10 +1534,10 @@ namespace ranges { template _NODISCARD static consteval _Choice_t<_St> _Choose() noexcept { - if constexpr (same_as, range_reference_t<_Rng>>) { + if constexpr (input_range<_Rng> && same_as, range_reference_t<_Rng>>) { return {_St::_All, noexcept(views::all(_STD declval<_Rng>()))}; } else if constexpr (_Can_as_rvalue<_Rng>) { - return {_St::_As_rvalue, noexcept(as_rvalue_view{_STD declval<_Rng>()})}; + return {_St::_As_rvalue, noexcept(as_rvalue_view(_STD declval<_Rng>()))}; } else { return {_St::_None}; } @@ -1553,7 +1555,7 @@ namespace ranges { if constexpr (_Strat == _St::_All) { return views::all(_STD forward<_Rng>(_Range)); } else if constexpr (_Strat == _St::_As_rvalue) { - return as_rvalue_view{_STD forward<_Rng>(_Range)}; + return as_rvalue_view(_STD forward<_Rng>(_Range)); } else { _STL_INTERNAL_STATIC_ASSERT(false); // unexpected strategy } @@ -1686,7 +1688,7 @@ namespace ranges { return _Tmp; } - _NODISCARD_FRIEND constexpr bool operator==(const _Iterator& _Left, const _Iterator& _Right) + _NODISCARD friend constexpr bool operator==(const _Iterator& _Left, const _Iterator& _Right) requires equality_comparable> { #if _ITERATOR_DEBUG_LEVEL != 0 @@ -1696,7 +1698,7 @@ namespace ranges { return _Left._Current == _Right._Current; } - _NODISCARD_FRIEND constexpr range_rvalue_reference_t<_Vw> iter_move(const _Iterator& _It) noexcept( + _NODISCARD friend constexpr range_rvalue_reference_t<_Vw> iter_move(const _Iterator& _It) noexcept( noexcept(_RANGES iter_move(_It._Current))) { #if _ITERATOR_DEBUG_LEVEL != 0 _It._Check_dereference(); @@ -1737,7 +1739,7 @@ namespace ranges { return _Last; } - _NODISCARD_FRIEND constexpr bool operator==(const _Iterator& _It, const _Sentinel& _Se) noexcept( + _NODISCARD friend constexpr bool operator==(const _Iterator& _It, const _Sentinel& _Se) noexcept( noexcept(_It._Equal(_Se._Last))) /* strengthened */ { return _It._Equal(_Se._Last); } @@ -1870,13 +1872,13 @@ namespace ranges { return _Last; } - _NODISCARD_FRIEND constexpr bool operator==(const _Counted_iter<_Const>& _Left, const _Sentinel& _Right) { + _NODISCARD friend constexpr bool operator==(const _Counted_iter<_Const>& _Left, const _Sentinel& _Right) { return _Left.count() == 0 || _Left.base() == _Right._Last; } template requires sentinel_for<_Base_sentinel, _Base_iterator<_OtherConst>> - _NODISCARD_FRIEND constexpr bool operator==( + _NODISCARD friend constexpr bool operator==( const _Counted_iter<_OtherConst>& _Left, const _Sentinel& _Right) { return _Left.count() == 0 || _Left.base() == _Right._Last; } @@ -2167,13 +2169,13 @@ namespace ranges { return _Last; } - _NODISCARD_FRIEND constexpr bool operator==(const _Base_iterator& _Left, const _Sentinel& _Right) { + _NODISCARD friend constexpr bool operator==(const _Base_iterator& _Left, const _Sentinel& _Right) { return _Right._Last == _Left || !_STD invoke(*_Right._Pred, *_Left); } template requires sentinel_for<_Base_sentinel, _Maybe_const_iter<_OtherConst>> - _NODISCARD_FRIEND constexpr bool operator==( + _NODISCARD friend constexpr bool operator==( const _Maybe_const_iter<_OtherConst>& _Left, const _Sentinel& _Right) { return _Right._Last == _Left || !_STD invoke(*_Right._Pred, *_Left); } @@ -2882,7 +2884,7 @@ namespace ranges { return _Tmp; } - _NODISCARD_FRIEND constexpr bool operator==(const _Iterator& _Left, const _Iterator& _Right) noexcept( + _NODISCARD friend constexpr bool operator==(const _Iterator& _Left, const _Iterator& _Right) noexcept( noexcept(_Left._Outer == _Right._Outer && _Left._Inner == _Right._Inner)) /* strengthened */ requires _Deref_is_glvalue && forward_range<_Base> && equality_comparable<_InnerIter> { @@ -2892,7 +2894,7 @@ namespace ranges { return _Left._Outer == _Right._Outer && _Left._Inner == _Right._Inner; } - _NODISCARD_FRIEND constexpr decltype(auto) iter_move(const _Iterator& _It) noexcept( + _NODISCARD friend constexpr decltype(auto) iter_move(const _Iterator& _It) noexcept( noexcept(_RANGES iter_move(*_It._Inner))) { #if _ITERATOR_DEBUG_LEVEL != 0 _It._Check_dereference(); @@ -2946,7 +2948,7 @@ namespace ranges { template requires sentinel_for, _Maybe_const_iter<_OtherConst>> - _NODISCARD_FRIEND constexpr bool operator==(const _Iterator<_OtherConst>& _Left, + _NODISCARD friend constexpr bool operator==(const _Iterator<_OtherConst>& _Left, const _Sentinel& _Right) noexcept(noexcept(_Right._Equal(_Left))) /* strengthened */ { return _Right._Equal(_Left); } @@ -3047,15 +3049,40 @@ namespace ranges { } // namespace views #if _HAS_CXX23 - template - concept _Compatible_joinable_ranges = - common_with, range_value_t<_Pat>> - && common_reference_with, range_reference_t<_Pat>> - && common_reference_with, range_rvalue_reference_t<_Pat>>; + template + using _Concat_reference_t = common_reference_t...>; + + template + using _Concat_value_t = common_type_t...>; + + template + using _Concat_rvalue_reference_t = common_reference_t...>; + + template + concept _Concat_indirectly_readable_impl = requires(const _It __i) { + { *__i } -> convertible_to<_Ref>; + { _RANGES iter_move(__i) } -> convertible_to<_RRef>; + }; + + template + concept _Concat_indirectly_readable = + common_reference_with<_Concat_reference_t<_Rngs...>&&, _Concat_value_t<_Rngs...>&> + && common_reference_with<_Concat_reference_t<_Rngs...>&&, _Concat_rvalue_reference_t<_Rngs...>&&> + && common_reference_with<_Concat_rvalue_reference_t<_Rngs...>&&, const _Concat_value_t<_Rngs...>&> + && (_Concat_indirectly_readable_impl<_Concat_reference_t<_Rngs...>, _Concat_rvalue_reference_t<_Rngs...>, + iterator_t<_Rngs>> + && ...); + + template + concept _Concatable = requires { + typename _Concat_reference_t<_Rngs...>; + typename _Concat_value_t<_Rngs...>; + typename _Concat_rvalue_reference_t<_Rngs...>; + } && _Concat_indirectly_readable<_Rngs...>; _EXPORT_STD template requires view<_Vw> && input_range> && view<_Pat> - && _Compatible_joinable_ranges, _Pat> + && _Concatable, _Pat> class join_with_view; template @@ -3089,7 +3116,7 @@ namespace ranges { _EXPORT_STD template requires view<_Vw> && input_range> && view<_Pat> - && _Compatible_joinable_ranges, _Pat> + && _Concatable, _Pat> class join_with_view : public _Join_with_view_outer_iter_base<_Vw, _Pat> { private: template @@ -3362,7 +3389,7 @@ namespace ranges { return _Tmp; } - _NODISCARD_FRIEND constexpr bool operator==(const _Iterator& _Left, const _Iterator& _Right) + _NODISCARD friend constexpr bool operator==(const _Iterator& _Left, const _Iterator& _Right) requires _Deref_is_glvalue && forward_range<_Base> && equality_comparable<_InnerIter> { if (_Left._Outer_it != _Right._Outer_it) { @@ -3385,7 +3412,7 @@ namespace ranges { _STL_UNREACHABLE; } - _NODISCARD_FRIEND constexpr decltype(auto) iter_move(const _Iterator& _It) { + _NODISCARD friend constexpr decltype(auto) iter_move(const _Iterator& _It) { using _Rvalue_ref = common_reference_t, iter_rvalue_reference_t<_PatternIter>>; return _It._Visit_inner_it<_Rvalue_ref>(_RANGES iter_move); @@ -3456,7 +3483,7 @@ namespace ranges { template requires sentinel_for, iterator_t<_Maybe_const<_OtherConst, _Vw>>> - _NODISCARD_FRIEND constexpr bool operator==(const _Iterator<_OtherConst>& _Left, + _NODISCARD friend constexpr bool operator==(const _Iterator<_OtherConst>& _Left, const _Sentinel& _Right) noexcept(noexcept(_Right._Equal(_Left))) /* strengthened */ { return _Right._Equal(_Left); } @@ -3500,7 +3527,7 @@ namespace ranges { _NODISCARD constexpr auto begin() const requires forward_range && forward_range && is_reference_v<_InnerRng> - && input_range<_InnerRng> + && input_range<_InnerRng> && _Concatable, const _Pat> { return _Iterator{*this, _RANGES begin(_Range)}; } @@ -3517,7 +3544,7 @@ namespace ranges { _NODISCARD constexpr auto end() const requires forward_range && forward_range && is_reference_v<_InnerRng> - && input_range<_InnerRng> + && input_range<_InnerRng> && _Concatable, const _Pat> { if constexpr (forward_range<_InnerRng> && common_range<_Vw> && common_range<_InnerRng>) { return _Iterator{*this, _RANGES end(_Range)}; @@ -3756,13 +3783,13 @@ namespace ranges { } } - _NODISCARD_FRIEND constexpr bool operator==(const _Outer_iter& _Left, const _Outer_iter& _Right) noexcept( + _NODISCARD friend constexpr bool operator==(const _Outer_iter& _Left, const _Outer_iter& _Right) noexcept( noexcept(_Left._Current == _Right._Current)) /* strengthened */ requires forward_range<_BaseTy> { return _Left._Current == _Right._Current && _Left._Trailing_empty == _Right._Trailing_empty; } - _NODISCARD_FRIEND constexpr bool operator==(const _Outer_iter& _Left, default_sentinel_t) noexcept( + _NODISCARD friend constexpr bool operator==(const _Outer_iter& _Left, default_sentinel_t) noexcept( noexcept(_Left._At_end())) /* strengthened */ { return _Left._At_end() && !_Left._Trailing_empty; } @@ -3886,17 +3913,17 @@ namespace ranges { } } - _NODISCARD_FRIEND constexpr bool operator==(const _Inner_iter& _Left, const _Inner_iter& _Right) + _NODISCARD friend constexpr bool operator==(const _Inner_iter& _Left, const _Inner_iter& _Right) requires forward_range<_BaseTy> { return _Left._Equal(_Right); } - _NODISCARD_FRIEND constexpr bool operator==(const _Inner_iter& _Left, default_sentinel_t) { + _NODISCARD friend constexpr bool operator==(const _Inner_iter& _Left, default_sentinel_t) { return _Left._At_end(); } - _NODISCARD_FRIEND constexpr decltype(auto) iter_move(const _Inner_iter& _Iter) noexcept( + _NODISCARD friend constexpr decltype(auto) iter_move(const _Inner_iter& _Iter) noexcept( noexcept(_RANGES iter_move(_Iter._Get_current()))) { return _RANGES iter_move(_Iter._Get_current()); } @@ -4073,7 +4100,7 @@ namespace ranges { return _Tmp; } - _NODISCARD_FRIEND constexpr bool operator==(const _Iterator& _Left, const _Iterator& _Right) noexcept( + _NODISCARD friend constexpr bool operator==(const _Iterator& _Left, const _Iterator& _Right) noexcept( noexcept(_Left._Current == _Right._Current)) /* strengthened */ { return _Left._Current == _Right._Current && _Left._Trailing_empty == _Right._Trailing_empty; } @@ -4095,7 +4122,7 @@ namespace ranges { && is_nothrow_move_constructible_v>) // strengthened : _Last(_RANGES end(_Parent._Range)) {} - _NODISCARD_FRIEND constexpr bool operator==(const _Iterator& _It, const _Sentinel& _Se) noexcept( + _NODISCARD friend constexpr bool operator==(const _Iterator& _It, const _Sentinel& _Se) noexcept( noexcept(_Se._Equal(_It))) /* strengthened */ { return _Se._Equal(_It); } @@ -4845,46 +4872,46 @@ namespace ranges { return static_cast<_ElemTy>(_STD get<_Index>(*(_Current + _Idx))); } - _NODISCARD_FRIEND constexpr bool operator==(const _Iterator& _Left, const _Iterator& _Right) noexcept( + _NODISCARD friend constexpr bool operator==(const _Iterator& _Left, const _Iterator& _Right) noexcept( noexcept(_Left._Current == _Right._Current)) /* strengthened */ requires equality_comparable> { return _Left._Current == _Right._Current; } - _NODISCARD_FRIEND constexpr bool operator<(const _Iterator& _Left, const _Iterator& _Right) noexcept( + _NODISCARD friend constexpr bool operator<(const _Iterator& _Left, const _Iterator& _Right) noexcept( noexcept(_Left._Current < _Right._Current)) /* strengthened */ requires random_access_range<_Base> { return _Left._Current < _Right._Current; } - _NODISCARD_FRIEND constexpr bool operator>(const _Iterator& _Left, const _Iterator& _Right) noexcept( + _NODISCARD friend constexpr bool operator>(const _Iterator& _Left, const _Iterator& _Right) noexcept( noexcept(_Left._Current < _Right._Current)) /* strengthened */ requires random_access_range<_Base> { return _Right < _Left; } - _NODISCARD_FRIEND constexpr bool operator<=(const _Iterator& _Left, const _Iterator& _Right) noexcept( + _NODISCARD friend constexpr bool operator<=(const _Iterator& _Left, const _Iterator& _Right) noexcept( noexcept(_Left._Current < _Right._Current)) /* strengthened */ requires random_access_range<_Base> { return !(_Right < _Left); } - _NODISCARD_FRIEND constexpr bool operator>=(const _Iterator& _Left, const _Iterator& _Right) noexcept( + _NODISCARD friend constexpr bool operator>=(const _Iterator& _Left, const _Iterator& _Right) noexcept( noexcept(_Left._Current < _Right._Current)) /* strengthened */ requires random_access_range<_Base> { return !(_Left < _Right); } - _NODISCARD_FRIEND constexpr auto operator<=>(const _Iterator& _Left, const _Iterator& _Right) noexcept( + _NODISCARD friend constexpr auto operator<=>(const _Iterator& _Left, const _Iterator& _Right) noexcept( noexcept(_Left._Current <=> _Right._Current)) /* strengthened */ requires random_access_range<_Base> && three_way_comparable> { return _Left._Current <=> _Right._Current; } - _NODISCARD_FRIEND constexpr _Iterator operator+(const _Iterator& _It, const difference_type _Off) noexcept( + _NODISCARD friend constexpr _Iterator operator+(const _Iterator& _It, const difference_type _Off) noexcept( noexcept(_STD declval&>() += _Off) && is_nothrow_copy_constructible_v>) /* strengthened */ requires random_access_range<_Base> @@ -4897,7 +4924,7 @@ namespace ranges { return _Copy; } - _NODISCARD_FRIEND constexpr _Iterator operator+(const difference_type _Off, const _Iterator& _It) noexcept( + _NODISCARD friend constexpr _Iterator operator+(const difference_type _Off, const _Iterator& _It) noexcept( noexcept(_STD declval&>() += _Off) && is_nothrow_copy_constructible_v>) /* strengthened */ requires random_access_range<_Base> @@ -4910,7 +4937,7 @@ namespace ranges { return _Copy; } - _NODISCARD_FRIEND constexpr _Iterator operator-(const _Iterator& _It, const difference_type _Off) noexcept( + _NODISCARD friend constexpr _Iterator operator-(const _Iterator& _It, const difference_type _Off) noexcept( noexcept(_STD declval&>() -= _Off) && is_nothrow_copy_constructible_v>) /* strengthened */ requires random_access_range<_Base> @@ -4924,7 +4951,7 @@ namespace ranges { return _Copy; } - _NODISCARD_FRIEND constexpr difference_type operator-(const _Iterator& _Left, + _NODISCARD friend constexpr difference_type operator-(const _Iterator& _Left, const _Iterator& _Right) noexcept(noexcept(_Left._Current - _Right._Current)) /* strengthened */ requires sized_sentinel_for, iterator_t<_Base>> { @@ -4967,14 +4994,14 @@ namespace ranges { template requires sentinel_for, _Maybe_const_iter<_OtherConst>> - _NODISCARD_FRIEND constexpr bool operator==(const _Iterator<_OtherConst>& _Left, + _NODISCARD friend constexpr bool operator==(const _Iterator<_OtherConst>& _Left, const _Sentinel& _Right) noexcept(noexcept(_Get_current(_Left) == _Right._Last)) /* strengthened */ { return _Get_current(_Left) == _Right._Last; } template requires sized_sentinel_for, _Maybe_const_iter<_OtherConst>> - _NODISCARD_FRIEND constexpr range_difference_t<_Maybe_const<_OtherConst, _Vw>> operator-( + _NODISCARD friend constexpr range_difference_t<_Maybe_const<_OtherConst, _Vw>> operator-( const _Iterator<_OtherConst>& _Left, const _Sentinel& _Right) noexcept(noexcept(_Get_current(_Left) - _Right._Last)) /* strengthened */ { return _Get_current(_Left) - _Right._Last; @@ -4982,7 +5009,7 @@ namespace ranges { template requires sized_sentinel_for, _Maybe_const_iter<_OtherConst>> - _NODISCARD_FRIEND constexpr range_difference_t<_Maybe_const<_OtherConst, _Vw>> + _NODISCARD friend constexpr range_difference_t<_Maybe_const<_OtherConst, _Vw>> operator-(const _Sentinel& _Left, const _Iterator<_OtherConst>& _Right) noexcept( noexcept(_Left._Last - _Get_current(_Right))) /* strengthened */ { return _Left._Last - _Get_current(_Right); @@ -5214,16 +5241,16 @@ namespace ranges { return _Reference_type{static_cast(_Pos + _Off), _Current[_Off]}; } - _NODISCARD_FRIEND constexpr bool operator==(const _Iterator& _Left, const _Iterator& _Right) noexcept { + _NODISCARD friend constexpr bool operator==(const _Iterator& _Left, const _Iterator& _Right) noexcept { return _Left._Pos == _Right._Pos; } - _NODISCARD_FRIEND constexpr strong_ordering operator<=>( + _NODISCARD friend constexpr strong_ordering operator<=>( const _Iterator& _Left, const _Iterator& _Right) noexcept { return _Left._Pos <=> _Right._Pos; } - _NODISCARD_FRIEND constexpr _Iterator operator+(const _Iterator& _It, const difference_type _Off) noexcept( + _NODISCARD friend constexpr _Iterator operator+(const _Iterator& _It, const difference_type _Off) noexcept( is_nothrow_copy_constructible_v<_Iterator> // && noexcept(_STD declval<_Iterator&>() += _Off)) // strengthened requires random_access_range<_Base_t> @@ -5233,14 +5260,14 @@ namespace ranges { return _Tmp; } - _NODISCARD_FRIEND constexpr _Iterator operator+(const difference_type _Off, const _Iterator& _It) noexcept( + _NODISCARD friend constexpr _Iterator operator+(const difference_type _Off, const _Iterator& _It) noexcept( noexcept(_It + _Off)) // strengthened requires random_access_range<_Base_t> { return _It + _Off; } - _NODISCARD_FRIEND constexpr _Iterator operator-(const _Iterator& _It, const difference_type _Off) noexcept( + _NODISCARD friend constexpr _Iterator operator-(const _Iterator& _It, const difference_type _Off) noexcept( is_nothrow_copy_constructible_v<_Iterator> // && noexcept(_STD declval<_Iterator&>() -= _Off)) // strengthened requires random_access_range<_Base_t> @@ -5250,12 +5277,12 @@ namespace ranges { return _Tmp; } - _NODISCARD_FRIEND constexpr difference_type operator-( + _NODISCARD friend constexpr difference_type operator-( const _Iterator& _Left, const _Iterator& _Right) noexcept { return _Left._Pos - _Right._Pos; } - _NODISCARD_FRIEND constexpr auto iter_move(const _Iterator& _It) noexcept( + _NODISCARD friend constexpr auto iter_move(const _Iterator& _It) noexcept( noexcept(_RANGES iter_move(_It._Current)) && is_nothrow_move_constructible_v>) { return tuple>{ @@ -5306,14 +5333,14 @@ namespace ranges { template requires sentinel_for<_Base_sentinel, iterator_t<_Maybe_const<_OtherConst, _Vw>>> - _NODISCARD_FRIEND constexpr bool operator==(const _Iterator<_OtherConst>& _It, + _NODISCARD friend constexpr bool operator==(const _Iterator<_OtherConst>& _It, const _Sentinel& _Se) noexcept(noexcept(_Se._Equal(_It))) /* strengthened */ { return _Se._Equal(_It); } template requires sized_sentinel_for<_Base_sentinel, iterator_t<_Maybe_const<_OtherConst, _Vw>>> - _NODISCARD_FRIEND constexpr range_difference_t<_Maybe_const<_OtherConst, _Vw>> operator-( + _NODISCARD friend constexpr range_difference_t<_Maybe_const<_OtherConst, _Vw>> operator-( const _Iterator<_OtherConst>& _It, const _Sentinel& _Se) // noexcept(noexcept(_Se._Distance_from(_It))) /* strengthened */ { return -_Se._Distance_from(_It); @@ -5321,7 +5348,7 @@ namespace ranges { template requires sized_sentinel_for<_Base_sentinel, iterator_t<_Maybe_const<_OtherConst, _Vw>>> - _NODISCARD_FRIEND constexpr range_difference_t<_Maybe_const<_OtherConst, _Vw>> operator-( + _NODISCARD friend constexpr range_difference_t<_Maybe_const<_OtherConst, _Vw>> operator-( const _Sentinel& _Se, const _Iterator<_OtherConst>& _It) // noexcept(noexcept(_Se._Distance_from(_It))) /* strengthened */ { return _Se._Distance_from(_It); @@ -5516,26 +5543,26 @@ namespace ranges { } } - _NODISCARD_FRIEND constexpr bool operator==(const _Inner_iterator& _Left, default_sentinel_t) noexcept + _NODISCARD friend constexpr bool operator==(const _Inner_iterator& _Left, default_sentinel_t) noexcept /* strengthened */ { return _Left._Get_remainder() == 0; } - _NODISCARD_FRIEND constexpr difference_type operator-(default_sentinel_t, + _NODISCARD friend constexpr difference_type operator-(default_sentinel_t, const _Inner_iterator& _Right) noexcept(noexcept(_Right._Get_size())) /* strengthened */ requires sized_sentinel_for, iterator_t<_Vw>> { return _Right._Get_size(); } - _NODISCARD_FRIEND constexpr difference_type operator-(const _Inner_iterator& _Left, + _NODISCARD friend constexpr difference_type operator-(const _Inner_iterator& _Left, default_sentinel_t) noexcept(noexcept(_Left._Get_size())) /* strengthened */ requires sized_sentinel_for, iterator_t<_Vw>> { return -_Left._Get_size(); } - _NODISCARD_FRIEND constexpr range_rvalue_reference_t<_Vw> iter_move(const _Inner_iterator& _It) noexcept( + _NODISCARD friend constexpr range_rvalue_reference_t<_Vw> iter_move(const _Inner_iterator& _It) noexcept( noexcept(_RANGES iter_move(_It._Get_current()))) { return _RANGES iter_move(_It._Get_current()); } @@ -5625,19 +5652,19 @@ namespace ranges { _Parent->_Remainder = _Parent->_Count; } - _NODISCARD_FRIEND constexpr bool operator==(const _Outer_iterator& _Left, default_sentinel_t) noexcept( + _NODISCARD friend constexpr bool operator==(const _Outer_iterator& _Left, default_sentinel_t) noexcept( noexcept(_Left._Is_end())) /* strengthened */ { return _Left._Is_end(); } - _NODISCARD_FRIEND constexpr difference_type operator-(default_sentinel_t, + _NODISCARD friend constexpr difference_type operator-(default_sentinel_t, const _Outer_iterator& _Right) noexcept(noexcept(_Right._Get_size())) /* strengthened */ requires sized_sentinel_for, iterator_t<_Vw>> { return _Right._Get_size(); } - _NODISCARD_FRIEND constexpr difference_type operator-(const _Outer_iterator& _Left, + _NODISCARD friend constexpr difference_type operator-(const _Outer_iterator& _Left, default_sentinel_t) noexcept(noexcept(_Left._Get_size())) /* strengthened */ requires sized_sentinel_for, iterator_t<_Vw>> { @@ -5821,52 +5848,52 @@ namespace ranges { return *(*this + _Off); } - _NODISCARD_FRIEND constexpr bool operator==(const _Iterator& _Left, const _Iterator& _Right) noexcept( + _NODISCARD friend constexpr bool operator==(const _Iterator& _Left, const _Iterator& _Right) noexcept( noexcept(_STD _Fake_copy_init(_Left._Current == _Right._Current))) /* strengthened */ { return _Left._Current == _Right._Current; } - _NODISCARD_FRIEND constexpr bool operator==(const _Iterator& _Left, default_sentinel_t) noexcept( + _NODISCARD friend constexpr bool operator==(const _Iterator& _Left, default_sentinel_t) noexcept( noexcept(_STD _Fake_copy_init(_Left._Current == _Left._End))) /* strengthened */ { return _Left._Current == _Left._End; } - _NODISCARD_FRIEND constexpr bool operator<(const _Iterator& _Left, const _Iterator& _Right) noexcept( + _NODISCARD friend constexpr bool operator<(const _Iterator& _Left, const _Iterator& _Right) noexcept( noexcept(_STD _Fake_copy_init(_Left._Current < _Right._Current))) /* strengthened */ requires random_access_range<_Base> { return _Left._Current < _Right._Current; } - _NODISCARD_FRIEND constexpr bool operator>(const _Iterator& _Left, const _Iterator& _Right) noexcept( + _NODISCARD friend constexpr bool operator>(const _Iterator& _Left, const _Iterator& _Right) noexcept( noexcept(_STD _Fake_copy_init(_Right._Current < _Left._Current))) /* strengthened */ requires random_access_range<_Base> { return _Right._Current < _Left._Current; } - _NODISCARD_FRIEND constexpr bool operator<=(const _Iterator& _Left, const _Iterator& _Right) noexcept( + _NODISCARD friend constexpr bool operator<=(const _Iterator& _Left, const _Iterator& _Right) noexcept( noexcept(_STD _Fake_copy_init(!(_Right._Current < _Left._Current)))) /* strengthened */ requires random_access_range<_Base> { return !(_Right._Current < _Left._Current); } - _NODISCARD_FRIEND constexpr bool operator>=(const _Iterator& _Left, const _Iterator& _Right) noexcept( + _NODISCARD friend constexpr bool operator>=(const _Iterator& _Left, const _Iterator& _Right) noexcept( noexcept(_STD _Fake_copy_init(!(_Left._Current < _Right._Current)))) /* strengthened */ requires random_access_range<_Base> { return !(_Left._Current < _Right._Current); } - _NODISCARD_FRIEND constexpr auto operator<=>(const _Iterator& _Left, const _Iterator& _Right) noexcept( + _NODISCARD friend constexpr auto operator<=>(const _Iterator& _Left, const _Iterator& _Right) noexcept( noexcept(_Left._Current <=> _Right._Current)) /* strengthened */ requires random_access_range<_Base> && three_way_comparable<_Base_iterator> { return _Left._Current <=> _Right._Current; } - _NODISCARD_FRIEND constexpr _Iterator operator+(const _Iterator& _It, const difference_type _Off) noexcept( + _NODISCARD friend constexpr _Iterator operator+(const _Iterator& _It, const difference_type _Off) noexcept( is_nothrow_copy_constructible_v<_Iterator> // && noexcept(_STD declval<_Iterator&>() += _Off)) /* strengthened */ requires random_access_range<_Base> @@ -5876,7 +5903,7 @@ namespace ranges { return _Copy; } - _NODISCARD_FRIEND constexpr _Iterator operator+(const difference_type _Off, const _Iterator& _It) noexcept( + _NODISCARD friend constexpr _Iterator operator+(const difference_type _Off, const _Iterator& _It) noexcept( is_nothrow_copy_constructible_v<_Iterator> // && noexcept(_STD declval<_Iterator&>() += _Off)) /* strengthened */ requires random_access_range<_Base> @@ -5886,7 +5913,7 @@ namespace ranges { return _Copy; } - _NODISCARD_FRIEND constexpr _Iterator operator-(const _Iterator& _It, const difference_type _Off) noexcept( + _NODISCARD friend constexpr _Iterator operator-(const _Iterator& _It, const difference_type _Off) noexcept( is_nothrow_copy_constructible_v<_Iterator> // && noexcept(_STD declval<_Iterator&>() -= _Off)) /* strengthened */ requires random_access_range<_Base> @@ -5896,21 +5923,21 @@ namespace ranges { return _Copy; } - _NODISCARD_FRIEND constexpr difference_type operator-(const _Iterator& _Left, + _NODISCARD friend constexpr difference_type operator-(const _Iterator& _Left, const _Iterator& _Right) noexcept(noexcept(_Left._Current - _Right._Current)) /* strengthened */ requires sized_sentinel_for<_Base_iterator, _Base_iterator> { return (_Left._Current - _Right._Current + _Left._Missing - _Right._Missing) / _Left._Count; } - _NODISCARD_FRIEND constexpr difference_type operator-(default_sentinel_t, const _Iterator& _Right) noexcept( + _NODISCARD friend constexpr difference_type operator-(default_sentinel_t, const _Iterator& _Right) noexcept( noexcept(_Right._End - _Right._Current)) /* strengthened */ requires sized_sentinel_for<_Base_sentinel, _Base_iterator> { return _Div_ceil(_Right._End - _Right._Current, _Right._Count); } - _NODISCARD_FRIEND constexpr difference_type operator-(const _Iterator& _Left, default_sentinel_t) noexcept( + _NODISCARD friend constexpr difference_type operator-(const _Iterator& _Left, default_sentinel_t) noexcept( noexcept(_Left._End - _Left._Current)) /* strengthened */ requires sized_sentinel_for<_Base_sentinel, _Base_iterator> { @@ -6178,7 +6205,7 @@ namespace ranges { return views::counted(_Current + _Off, _Count); } - _NODISCARD_FRIEND constexpr bool operator==(const _Iterator& _Left, const _Iterator& _Right) noexcept( + _NODISCARD friend constexpr bool operator==(const _Iterator& _Left, const _Iterator& _Right) noexcept( noexcept(_STD _Fake_copy_init(_Left._Current == _Right._Current))) /* strengthened */ { if constexpr (_Slide_caches_first<_Base>) { return _Left._Last_element == _Right._Last_element; @@ -6187,42 +6214,42 @@ namespace ranges { } } - _NODISCARD_FRIEND constexpr bool operator<(const _Iterator& _Left, const _Iterator& _Right) noexcept( + _NODISCARD friend constexpr bool operator<(const _Iterator& _Left, const _Iterator& _Right) noexcept( noexcept(_STD _Fake_copy_init(_Left._Current < _Right._Current))) /* strengthened */ requires random_access_range<_Base> { return _Left._Current < _Right._Current; } - _NODISCARD_FRIEND constexpr bool operator>(const _Iterator& _Left, const _Iterator& _Right) noexcept( + _NODISCARD friend constexpr bool operator>(const _Iterator& _Left, const _Iterator& _Right) noexcept( noexcept(_STD _Fake_copy_init(_Right._Current < _Left._Current))) /* strengthened */ requires random_access_range<_Base> { return _Right._Current < _Left._Current; } - _NODISCARD_FRIEND constexpr bool operator<=(const _Iterator& _Left, const _Iterator& _Right) noexcept( + _NODISCARD friend constexpr bool operator<=(const _Iterator& _Left, const _Iterator& _Right) noexcept( noexcept(_STD _Fake_copy_init(!(_Right._Current < _Left._Current)))) /* strengthened */ requires random_access_range<_Base> { return !(_Right._Current < _Left._Current); } - _NODISCARD_FRIEND constexpr bool operator>=(const _Iterator& _Left, const _Iterator& _Right) noexcept( + _NODISCARD friend constexpr bool operator>=(const _Iterator& _Left, const _Iterator& _Right) noexcept( noexcept(_STD _Fake_copy_init(!(_Left._Current < _Right._Current)))) /* strengthened */ requires random_access_range<_Base> { return !(_Left._Current < _Right._Current); } - _NODISCARD_FRIEND constexpr auto operator<=>(const _Iterator& _Left, const _Iterator& _Right) noexcept( + _NODISCARD friend constexpr auto operator<=>(const _Iterator& _Left, const _Iterator& _Right) noexcept( noexcept(_Left._Current <=> _Right._Current)) /* strengthened */ requires random_access_range<_Base> && three_way_comparable<_Base_iterator> { return _Left._Current <=> _Right._Current; } - _NODISCARD_FRIEND constexpr _Iterator operator+(const _Iterator& _It, const difference_type _Off) noexcept( + _NODISCARD friend constexpr _Iterator operator+(const _Iterator& _It, const difference_type _Off) noexcept( noexcept(_STD declval<_Iterator&>() += _Off)) /* strengthened */ requires random_access_range<_Base> { @@ -6231,7 +6258,7 @@ namespace ranges { return _Copy; } - _NODISCARD_FRIEND constexpr _Iterator operator+(const difference_type _Off, const _Iterator& _It) noexcept( + _NODISCARD friend constexpr _Iterator operator+(const difference_type _Off, const _Iterator& _It) noexcept( noexcept(_STD declval<_Iterator&>() += _Off)) /* strengthened */ requires random_access_range<_Base> { @@ -6240,7 +6267,7 @@ namespace ranges { return _Copy; } - _NODISCARD_FRIEND constexpr _Iterator operator-(const _Iterator& _It, const difference_type _Off) noexcept( + _NODISCARD friend constexpr _Iterator operator-(const _Iterator& _It, const difference_type _Off) noexcept( noexcept(_STD declval<_Iterator&>() -= _Off)) /* strengthened */ requires random_access_range<_Base> { @@ -6249,7 +6276,7 @@ namespace ranges { return _Copy; } - _NODISCARD_FRIEND constexpr difference_type operator-(const _Iterator& _Left, + _NODISCARD friend constexpr difference_type operator-(const _Iterator& _Left, const _Iterator& _Right) noexcept(noexcept(_Left._Current - _Right._Current)) /* strengthened */ requires sized_sentinel_for<_Base_iterator, _Base_iterator> { @@ -6273,20 +6300,20 @@ namespace ranges { public: _Sentinel() = default; - _NODISCARD_FRIEND constexpr bool + _NODISCARD friend constexpr bool operator==(const _Iterator& _Left, const _Sentinel& _Right) noexcept(noexcept( _STD _Fake_copy_init(_Left._Get_last_element() == _Right._Last))) /* strengthened */ { return _Left._Get_last_element() == _Right._Last; } - _NODISCARD_FRIEND constexpr range_difference_t<_Vw> operator-(const _Iterator& _Left, + _NODISCARD friend constexpr range_difference_t<_Vw> operator-(const _Iterator& _Left, const _Sentinel& _Right) noexcept(noexcept(_Left._Get_last_element() - _Right._Last)) /* strengthened */ requires sized_sentinel_for, iterator_t<_Vw>> { return _Left._Get_last_element() - _Right._Last; } - _NODISCARD_FRIEND constexpr range_difference_t<_Vw> + _NODISCARD friend constexpr range_difference_t<_Vw> operator-(const _Sentinel& _Left, const _Iterator& _Right) noexcept( noexcept(_Left._Last - _Right._Get_last_element())) /* strengthened */ requires sized_sentinel_for, iterator_t<_Vw>> @@ -6524,12 +6551,12 @@ namespace ranges { return _Tmp; } - _NODISCARD_FRIEND constexpr bool operator==(const _Iterator& _Left, const _Iterator& _Right) noexcept( + _NODISCARD friend constexpr bool operator==(const _Iterator& _Left, const _Iterator& _Right) noexcept( noexcept(_STD _Fake_copy_init(_Left._Current == _Right._Current))) /* strengthened */ { return _Left._Current == _Right._Current; } - _NODISCARD_FRIEND constexpr bool operator==(const _Iterator& _Left, default_sentinel_t) noexcept( + _NODISCARD friend constexpr bool operator==(const _Iterator& _Left, default_sentinel_t) noexcept( noexcept(_STD _Fake_copy_init(_Left._Current == _Left._Next))) /* strengthened */ { return _Left._Current == _Left._Next; } @@ -6789,54 +6816,54 @@ namespace ranges { return *(*this + _Off); } - _NODISCARD_FRIEND constexpr bool operator==(const _Iterator& _It, default_sentinel_t) noexcept( + _NODISCARD friend constexpr bool operator==(const _Iterator& _It, default_sentinel_t) noexcept( noexcept(_STD _Fake_copy_init(_It._Current == _It._End))) /* strengthened */ { return _It._Current == _It._End; } - _NODISCARD_FRIEND constexpr bool operator==(const _Iterator& _Left, const _Iterator& _Right) noexcept( + _NODISCARD friend constexpr bool operator==(const _Iterator& _Left, const _Iterator& _Right) noexcept( noexcept(_STD _Fake_copy_init(_Left._Current == _Right._Current))) // strengthened requires equality_comparable<_Base_iterator> { return _Left._Current == _Right._Current; } - _NODISCARD_FRIEND constexpr bool operator<(const _Iterator& _Left, const _Iterator& _Right) noexcept( + _NODISCARD friend constexpr bool operator<(const _Iterator& _Left, const _Iterator& _Right) noexcept( noexcept(_STD _Fake_copy_init(_Left._Current < _Right._Current))) // strengthened requires random_access_range<_Base> { return _Left._Current < _Right._Current; } - _NODISCARD_FRIEND constexpr bool operator>(const _Iterator& _Left, const _Iterator& _Right) noexcept( + _NODISCARD friend constexpr bool operator>(const _Iterator& _Left, const _Iterator& _Right) noexcept( noexcept(_STD _Fake_copy_init(_Right._Current < _Left._Current))) // strengthened requires random_access_range<_Base> { return _Right._Current < _Left._Current; } - _NODISCARD_FRIEND constexpr bool operator<=(const _Iterator& _Left, const _Iterator& _Right) noexcept( + _NODISCARD friend constexpr bool operator<=(const _Iterator& _Left, const _Iterator& _Right) noexcept( noexcept(_STD _Fake_copy_init(!(_Right._Current < _Left._Current)))) // strengthened requires random_access_range<_Base> { return !(_Right._Current < _Left._Current); } - _NODISCARD_FRIEND constexpr bool operator>=(const _Iterator& _Left, const _Iterator& _Right) noexcept( + _NODISCARD friend constexpr bool operator>=(const _Iterator& _Left, const _Iterator& _Right) noexcept( noexcept(_STD _Fake_copy_init(!(_Left._Current < _Right._Current)))) // strengthened requires random_access_range<_Base> { return !(_Left._Current < _Right._Current); } - _NODISCARD_FRIEND constexpr auto operator<=>(const _Iterator& _Left, const _Iterator& _Right) noexcept( + _NODISCARD friend constexpr auto operator<=>(const _Iterator& _Left, const _Iterator& _Right) noexcept( noexcept(_Left._Current <=> _Right._Current)) // strengthened requires random_access_range<_Base> && three_way_comparable<_Base_iterator> { return _Left._Current <=> _Right._Current; } - _NODISCARD_FRIEND constexpr _Iterator operator+(const _Iterator& _It, const difference_type _Off) + _NODISCARD friend constexpr _Iterator operator+(const _Iterator& _It, const difference_type _Off) requires random_access_range<_Base> { auto _Copy = _It; @@ -6844,7 +6871,7 @@ namespace ranges { return _Copy; } - _NODISCARD_FRIEND constexpr _Iterator operator+(const difference_type _Off, const _Iterator& _It) + _NODISCARD friend constexpr _Iterator operator+(const difference_type _Off, const _Iterator& _It) requires random_access_range<_Base> { auto _Copy = _It; @@ -6852,7 +6879,7 @@ namespace ranges { return _Copy; } - _NODISCARD_FRIEND constexpr _Iterator operator-(const _Iterator& _It, const difference_type _Off) + _NODISCARD friend constexpr _Iterator operator-(const _Iterator& _It, const difference_type _Off) requires random_access_range<_Base> { auto _Copy = _It; @@ -6860,7 +6887,7 @@ namespace ranges { return _Copy; } - _NODISCARD_FRIEND constexpr difference_type operator-(const _Iterator& _Left, const _Iterator& _Right) // + _NODISCARD friend constexpr difference_type operator-(const _Iterator& _Left, const _Iterator& _Right) // noexcept(noexcept(_Left._Current - _Right._Current)) // strengthened requires sized_sentinel_for<_Base_iterator, _Base_iterator> { @@ -6876,21 +6903,21 @@ namespace ranges { } } - _NODISCARD_FRIEND constexpr difference_type operator-(default_sentinel_t, const _Iterator& _It) noexcept( + _NODISCARD friend constexpr difference_type operator-(default_sentinel_t, const _Iterator& _It) noexcept( noexcept(_It._End - _It._Current)) // strengthened requires sized_sentinel_for<_Base_sentinel, _Base_iterator> { return _Div_ceil(_It._End - _It._Current, _It._Stride); } - _NODISCARD_FRIEND constexpr difference_type operator-(const _Iterator& _It, default_sentinel_t) noexcept( + _NODISCARD friend constexpr difference_type operator-(const _Iterator& _It, default_sentinel_t) noexcept( noexcept(_It._End - _It._Current)) // strengthened requires sized_sentinel_for<_Base_sentinel, _Base_iterator> { return -_Div_ceil(_It._End - _It._Current, _It._Stride); } - _NODISCARD_FRIEND constexpr range_rvalue_reference_t<_Base> iter_move(const _Iterator& _It) noexcept( + _NODISCARD friend constexpr range_rvalue_reference_t<_Base> iter_move(const _Iterator& _It) noexcept( noexcept(_RANGES iter_move(_It._Current))) { return _RANGES iter_move(_It._Current); } @@ -7264,7 +7291,7 @@ namespace ranges { _Current); } - _NODISCARD_FRIEND constexpr bool operator==(const _Iterator& _Lhs, const _Iterator& _Rhs) noexcept( + _NODISCARD friend constexpr bool operator==(const _Iterator& _Lhs, const _Iterator& _Rhs) noexcept( noexcept(_Zip_iterator_sentinel_equal(_Lhs._Current, _Rhs._Current))) // strengthened requires (equality_comparable>> && ...) { @@ -7276,13 +7303,13 @@ namespace ranges { } } - _NODISCARD_FRIEND constexpr auto operator<=>(const _Iterator& _Lhs, const _Iterator& _Rhs) + _NODISCARD friend constexpr auto operator<=>(const _Iterator& _Lhs, const _Iterator& _Rhs) requires _All_random_access<_IsConst, _ViewTypes...> { return _Lhs._Current <=> _Rhs._Current; } - _NODISCARD_FRIEND constexpr _Iterator operator+(const _Iterator& _Lhs, const difference_type _Rhs) noexcept( + _NODISCARD friend constexpr _Iterator operator+(const _Iterator& _Lhs, const difference_type _Rhs) noexcept( noexcept(_STD declval<_Iterator&>() += _Rhs) && is_nothrow_copy_constructible_v<_Iterator>) // strengthened requires _All_random_access<_IsConst, _ViewTypes...> @@ -7293,14 +7320,14 @@ namespace ranges { return _Modified_iterator; } - _NODISCARD_FRIEND constexpr _Iterator operator+(const difference_type _Lhs, const _Iterator& _Rhs) noexcept( + _NODISCARD friend constexpr _Iterator operator+(const difference_type _Lhs, const _Iterator& _Rhs) noexcept( noexcept(_Rhs + _Lhs)) /* strengthened */ requires _All_random_access<_IsConst, _ViewTypes...> { return _Rhs + _Lhs; } - _NODISCARD_FRIEND constexpr _Iterator operator-(const _Iterator& _Lhs, const difference_type _Rhs) noexcept( + _NODISCARD friend constexpr _Iterator operator-(const _Iterator& _Lhs, const difference_type _Rhs) noexcept( noexcept(_STD declval<_Iterator&>() -= _Rhs) && is_nothrow_copy_constructible_v<_Iterator>) // strengthened requires _All_random_access<_IsConst, _ViewTypes...> @@ -7311,7 +7338,7 @@ namespace ranges { return _Modified_iterator; } - _NODISCARD_FRIEND constexpr difference_type + _NODISCARD friend constexpr difference_type operator-(const _Iterator& _Lhs, const _Iterator& _Rhs) noexcept( noexcept(_Zip_get_smallest_distance(_STD declval<_My_tuple>(), _STD declval<_My_tuple>()))) // strengthened @@ -7322,7 +7349,7 @@ namespace ranges { return _Zip_get_smallest_distance(_Lhs._Current, _Rhs._Current); } - _NODISCARD_FRIEND constexpr auto iter_move(const _Iterator& _Itr) noexcept( + _NODISCARD friend constexpr auto iter_move(const _Iterator& _Itr) noexcept( (noexcept(_RANGES iter_move(_STD declval>&>())) && ...) && (is_nothrow_move_constructible_v>> @@ -7383,7 +7410,7 @@ namespace ranges { requires (sentinel_for>, iterator_t<_Maybe_const<_IteratorConst, _ViewTypes>>> && ...) - _NODISCARD_FRIEND constexpr bool + _NODISCARD friend constexpr bool operator==(const _Iterator<_IteratorConst>& _Lhs, const _Sentinel& _Rhs) noexcept( noexcept(_Zip_iterator_sentinel_equal(_Get_iterator_tuple(_Lhs), _Rhs._End))) /* strengthened */ { return _Zip_iterator_sentinel_equal(_Get_iterator_tuple(_Lhs), _Rhs._End); @@ -7393,7 +7420,7 @@ namespace ranges { requires (sized_sentinel_for>, iterator_t<_Maybe_const<_IteratorConst, _ViewTypes>>> && ...) - _NODISCARD_FRIEND constexpr common_type_t>...> + _NODISCARD friend constexpr common_type_t>...> operator-(const _Iterator<_IteratorConst>& _Lhs, const _Sentinel& _Rhs) noexcept( noexcept(_Zip_get_smallest_distance< common_type_t>...>>( @@ -7406,7 +7433,7 @@ namespace ranges { requires (sized_sentinel_for>, iterator_t<_Maybe_const<_IteratorConst, _ViewTypes>>> && ...) - _NODISCARD_FRIEND constexpr common_type_t>...> + _NODISCARD friend constexpr common_type_t>...> operator-(const _Sentinel& _Lhs, const _Iterator<_IteratorConst>& _Rhs) noexcept( noexcept(-(_Rhs - _Lhs))) /* strengthened */ { return -(_Rhs - _Lhs); @@ -7679,42 +7706,42 @@ namespace ranges { return _STD apply(_Subscript_closure(_Where), _Inner._Current); } - _NODISCARD_FRIEND constexpr bool operator==(const _Iterator& _Lhs, const _Iterator& _Rhs) noexcept( + _NODISCARD friend constexpr bool operator==(const _Iterator& _Lhs, const _Iterator& _Rhs) noexcept( noexcept(_Lhs._Inner == _Rhs._Inner)) // strengthened requires equality_comparable<_Ziperator<_IsConst>> { return _Lhs._Inner == _Rhs._Inner; } - _NODISCARD_FRIEND constexpr auto operator<=>(const _Iterator& _Lhs, const _Iterator& _Rhs) noexcept( + _NODISCARD friend constexpr auto operator<=>(const _Iterator& _Lhs, const _Iterator& _Rhs) noexcept( noexcept(_Lhs._Inner <=> _Rhs._Inner)) // strengthened requires random_access_range<_Base_t> { return _Lhs._Inner <=> _Rhs._Inner; } - _NODISCARD_FRIEND constexpr _Iterator operator+(const _Iterator& _Lhs, const difference_type _Rhs) noexcept( + _NODISCARD friend constexpr _Iterator operator+(const _Iterator& _Lhs, const difference_type _Rhs) noexcept( noexcept(_Iterator{*_Lhs._Parent, _Lhs._Inner + _Rhs})) // strengthened requires random_access_range<_Base_t> { return _Iterator{*_Lhs._Parent, _Lhs._Inner + _Rhs}; } - _NODISCARD_FRIEND constexpr _Iterator operator+(const difference_type _Lhs, const _Iterator& _Rhs) noexcept( + _NODISCARD friend constexpr _Iterator operator+(const difference_type _Lhs, const _Iterator& _Rhs) noexcept( noexcept(_Iterator{*_Rhs._Parent, _Rhs._Inner + _Lhs})) // strengthened requires random_access_range<_Base_t> { return _Iterator{*_Rhs._Parent, _Rhs._Inner + _Lhs}; } - _NODISCARD_FRIEND constexpr _Iterator operator-(const _Iterator& _Lhs, const difference_type _Rhs) noexcept( + _NODISCARD friend constexpr _Iterator operator-(const _Iterator& _Lhs, const difference_type _Rhs) noexcept( noexcept(_Iterator{*_Lhs._Parent, _Lhs._Inner - _Rhs})) // strengthened requires random_access_range<_Base_t> { return _Iterator{*_Lhs._Parent, _Lhs._Inner - _Rhs}; } - _NODISCARD_FRIEND constexpr difference_type operator-(const _Iterator& _Lhs, + _NODISCARD friend constexpr difference_type operator-(const _Iterator& _Lhs, const _Iterator& _Rhs) noexcept(noexcept(_Lhs._Inner - _Rhs._Inner)) // strengthened requires sized_sentinel_for<_Ziperator<_IsConst>, _Ziperator<_IsConst>> { @@ -7768,14 +7795,14 @@ namespace ranges { template requires sentinel_for<_Zentinel<_IsConst>, _Ziperator<_IteratorConst>> - _NODISCARD_FRIEND constexpr bool operator==(const _Iterator<_IteratorConst>& _Lhs, + _NODISCARD friend constexpr bool operator==(const _Iterator<_IteratorConst>& _Lhs, const _Sentinel& _Rhs) noexcept(noexcept(_Get_iterator_inner(_Lhs) == _Rhs._Inner)) /* strengthened */ { return _Get_iterator_inner(_Lhs) == _Rhs._Inner; } template requires sized_sentinel_for<_Zentinel<_IsConst>, _Ziperator<_IteratorConst>> - _NODISCARD_FRIEND constexpr _Iter_sent_difference_type<_IteratorConst> // TRANSITION, DevCom-10253131 + _NODISCARD friend constexpr _Iter_sent_difference_type<_IteratorConst> // TRANSITION, DevCom-10253131 operator-(const _Iterator<_IteratorConst>& _Lhs, const _Sentinel & _Rhs) noexcept( noexcept(_Get_iterator_inner(_Lhs) - _Rhs._Inner)) /* strengthened */ { return _Get_iterator_inner(_Lhs) - _Rhs._Inner; @@ -7783,7 +7810,7 @@ namespace ranges { template requires sized_sentinel_for<_Zentinel<_IsConst>, _Ziperator<_IteratorConst>> - _NODISCARD_FRIEND constexpr _Iter_sent_difference_type<_IteratorConst> // TRANSITION, DevCom-10253131 + _NODISCARD friend constexpr _Iter_sent_difference_type<_IteratorConst> // TRANSITION, DevCom-10253131 operator-(const _Sentinel & _Lhs, const _Iterator<_IteratorConst>& _Rhs) noexcept( noexcept(_Lhs._Inner - _Get_iterator_inner(_Rhs))) /* strengthened */ { return _Lhs._Inner - _Get_iterator_inner(_Rhs); @@ -8085,48 +8112,48 @@ namespace ranges { return _RANGES _Tuple_transform([&](auto& _It) -> decltype(auto) { return _It[_Off]; }, _Current); } - _NODISCARD_FRIEND constexpr bool operator==(const _Iterator& _Left, const _Iterator& _Right) noexcept( + _NODISCARD friend constexpr bool operator==(const _Iterator& _Left, const _Iterator& _Right) noexcept( noexcept(_STD _Fake_copy_init(_Left._Current.back() == _Right._Current.back()))) // strengthened { return _Left._Current.back() == _Right._Current.back(); } - _NODISCARD_FRIEND constexpr bool operator<(const _Iterator& _Left, const _Iterator& _Right) noexcept( + _NODISCARD friend constexpr bool operator<(const _Iterator& _Left, const _Iterator& _Right) noexcept( noexcept(_STD _Fake_copy_init(_Left._Current.back() < _Right._Current.back()))) // strengthened requires random_access_range<_Base> { return _Left._Current.back() < _Right._Current.back(); } - _NODISCARD_FRIEND constexpr bool operator>(const _Iterator& _Left, const _Iterator& _Right) noexcept( + _NODISCARD friend constexpr bool operator>(const _Iterator& _Left, const _Iterator& _Right) noexcept( noexcept(_Right < _Left)) // strengthened requires random_access_range<_Base> { return _Right < _Left; } - _NODISCARD_FRIEND constexpr bool operator<=(const _Iterator& _Left, const _Iterator& _Right) noexcept( + _NODISCARD friend constexpr bool operator<=(const _Iterator& _Left, const _Iterator& _Right) noexcept( noexcept(!(_Right < _Left))) // strengthened requires random_access_range<_Base> { return !(_Right < _Left); } - _NODISCARD_FRIEND constexpr bool operator>=(const _Iterator& _Left, const _Iterator& _Right) noexcept( + _NODISCARD friend constexpr bool operator>=(const _Iterator& _Left, const _Iterator& _Right) noexcept( noexcept(!(_Left < _Right))) // strengthened requires random_access_range<_Base> { return !(_Left < _Right); } - _NODISCARD_FRIEND constexpr auto operator<=>(const _Iterator& _Left, const _Iterator& _Right) noexcept( + _NODISCARD friend constexpr auto operator<=>(const _Iterator& _Left, const _Iterator& _Right) noexcept( noexcept(_Left._Current.back() <=> _Right._Current.back())) // strengthened requires random_access_range<_Base> && three_way_comparable<_Base_iterator> { return _Left._Current.back() <=> _Right._Current.back(); } - _NODISCARD_FRIEND constexpr _Iterator operator+(const _Iterator& _It, const difference_type _Off) noexcept( + _NODISCARD friend constexpr _Iterator operator+(const _Iterator& _It, const difference_type _Off) noexcept( noexcept(_STD declval<_Iterator&>() += _Off) && is_nothrow_copy_constructible_v<_Iterator>) // strengthened requires random_access_range<_Base> @@ -8136,7 +8163,7 @@ namespace ranges { return _Tmp; } - _NODISCARD_FRIEND constexpr _Iterator operator+(const difference_type _Off, const _Iterator& _It) noexcept( + _NODISCARD friend constexpr _Iterator operator+(const difference_type _Off, const _Iterator& _It) noexcept( noexcept(_STD declval<_Iterator&>() += _Off) && is_nothrow_copy_constructible_v<_Iterator>) // strengthened requires random_access_range<_Base> @@ -8146,7 +8173,7 @@ namespace ranges { return _Tmp; } - _NODISCARD_FRIEND constexpr _Iterator operator-(const _Iterator& _It, const difference_type _Off) noexcept( + _NODISCARD friend constexpr _Iterator operator-(const _Iterator& _It, const difference_type _Off) noexcept( noexcept(_STD declval<_Iterator&>() -= _Off) && is_nothrow_copy_constructible_v<_Iterator>) // strengthened requires random_access_range<_Base> @@ -8156,7 +8183,7 @@ namespace ranges { return _Tmp; } - _NODISCARD_FRIEND constexpr difference_type + _NODISCARD friend constexpr difference_type operator-(const _Iterator& _Left, const _Iterator& _Right) noexcept( noexcept(_Left._Current.back() - _Right._Current.back())) // strengthened requires sized_sentinel_for<_Base_iterator, _Base_iterator> @@ -8164,7 +8191,7 @@ namespace ranges { return _Left._Current.back() - _Right._Current.back(); } - _NODISCARD_FRIEND constexpr auto iter_move(const _Iterator& _It) noexcept( + _NODISCARD friend constexpr auto iter_move(const _Iterator& _It) noexcept( noexcept(_RANGES iter_move(_STD declval())) && is_nothrow_move_constructible_v>) { return _RANGES _Tuple_transform(_RANGES iter_move, _It._Current); @@ -8218,14 +8245,14 @@ namespace ranges { template requires sentinel_for<_Base_sentinel, iterator_t<_Maybe_const<_OtherConst, _Vw>>> - _NODISCARD_FRIEND constexpr bool operator==(const _Iterator<_OtherConst>& _It, + _NODISCARD friend constexpr bool operator==(const _Iterator<_OtherConst>& _It, const _Sentinel& _Se) noexcept(noexcept(_Se._Equal(_It))) /* strengthened */ { return _Se._Equal(_It); } template requires sized_sentinel_for<_Base_sentinel, iterator_t<_Maybe_const<_OtherConst, _Vw>>> - _NODISCARD_FRIEND constexpr range_difference_t<_Maybe_const<_OtherConst, _Vw>> operator-( + _NODISCARD friend constexpr range_difference_t<_Maybe_const<_OtherConst, _Vw>> operator-( const _Iterator<_OtherConst>& _It, const _Sentinel& _Se) noexcept( // noexcept(_Se._Distance_from(_It))) /* strengthened */ { return -_Se._Distance_from(_It); @@ -8233,7 +8260,7 @@ namespace ranges { template requires sized_sentinel_for<_Base_sentinel, iterator_t<_Maybe_const<_OtherConst, _Vw>>> - _NODISCARD_FRIEND constexpr range_difference_t<_Maybe_const<_OtherConst, _Vw>> operator-( + _NODISCARD friend constexpr range_difference_t<_Maybe_const<_OtherConst, _Vw>> operator-( const _Sentinel& _Se, const _Iterator<_OtherConst>& _It) noexcept( // noexcept(_Se._Distance_from(_It))) /* strengthened */ { return _Se._Distance_from(_It); @@ -8343,7 +8370,7 @@ namespace ranges { template _NODISCARD _STATIC_CALL_OPERATOR constexpr auto operator()(_Rng&&) _CONST_CALL_OPERATOR noexcept - requires (_Nx == 0) + requires (_Nx == 0) && forward_range<_Rng> { return empty_view>{}; } @@ -8481,68 +8508,68 @@ namespace ranges { _Inner._Current); } - _NODISCARD_FRIEND constexpr bool operator==(const _Iterator& _Left, const _Iterator& _Right) noexcept( + _NODISCARD friend constexpr bool operator==(const _Iterator& _Left, const _Iterator& _Right) noexcept( noexcept(_Left._Inner == _Right._Inner)) /* strengthened */ { return _Left._Inner == _Right._Inner; } - _NODISCARD_FRIEND constexpr bool operator<(const _Iterator& _Left, const _Iterator& _Right) noexcept( + _NODISCARD friend constexpr bool operator<(const _Iterator& _Left, const _Iterator& _Right) noexcept( noexcept(_Left._Inner < _Right._Inner)) // strengthened requires random_access_range<_Base> { return _Left._Inner < _Right._Inner; } - _NODISCARD_FRIEND constexpr bool operator>(const _Iterator& _Left, const _Iterator& _Right) noexcept( + _NODISCARD friend constexpr bool operator>(const _Iterator& _Left, const _Iterator& _Right) noexcept( noexcept(_Left._Inner > _Right._Inner)) // strengthened requires random_access_range<_Base> { return _Left._Inner > _Right._Inner; } - _NODISCARD_FRIEND constexpr bool operator<=(const _Iterator& _Left, const _Iterator& _Right) noexcept( + _NODISCARD friend constexpr bool operator<=(const _Iterator& _Left, const _Iterator& _Right) noexcept( noexcept(_Left._Inner <= _Right._Inner)) // strengthened requires random_access_range<_Base> { return _Left._Inner <= _Right._Inner; } - _NODISCARD_FRIEND constexpr bool operator>=(const _Iterator& _Left, const _Iterator& _Right) noexcept( + _NODISCARD friend constexpr bool operator>=(const _Iterator& _Left, const _Iterator& _Right) noexcept( noexcept(_Left._Inner >= _Right._Inner)) // strengthened requires random_access_range<_Base> { return _Left._Inner >= _Right._Inner; } - _NODISCARD_FRIEND constexpr auto operator<=>(const _Iterator& _Left, const _Iterator& _Right) noexcept( + _NODISCARD friend constexpr auto operator<=>(const _Iterator& _Left, const _Iterator& _Right) noexcept( noexcept(_Left._Inner <=> _Right._Inner)) // strengthened requires random_access_range<_Base> && three_way_comparable<_Inner_iterator<_Const>> { return _Left._Inner <=> _Right._Inner; } - _NODISCARD_FRIEND constexpr _Iterator operator+(const _Iterator& _It, const difference_type _Off) noexcept( + _NODISCARD friend constexpr _Iterator operator+(const _Iterator& _It, const difference_type _Off) noexcept( noexcept(_It._Inner + _Off) && is_nothrow_move_constructible_v<_Inner_iterator<_Const>>) // strengthened requires random_access_range<_Base> { return _Iterator{*_It._Parent, _It._Inner + _Off}; } - _NODISCARD_FRIEND constexpr _Iterator operator+(const difference_type _Off, const _Iterator& _It) noexcept( + _NODISCARD friend constexpr _Iterator operator+(const difference_type _Off, const _Iterator& _It) noexcept( noexcept(_It._Inner + _Off) && is_nothrow_move_constructible_v<_Inner_iterator<_Const>>) // strengthened requires random_access_range<_Base> { return _Iterator{*_It._Parent, _It._Inner + _Off}; } - _NODISCARD_FRIEND constexpr _Iterator operator-(const _Iterator& _It, const difference_type _Off) noexcept( + _NODISCARD friend constexpr _Iterator operator-(const _Iterator& _It, const difference_type _Off) noexcept( noexcept(_It._Inner - _Off) && is_nothrow_move_constructible_v<_Inner_iterator<_Const>>) // strengthened requires random_access_range<_Base> { return _Iterator{*_It._Parent, _It._Inner - _Off}; } - _NODISCARD_FRIEND constexpr difference_type operator-(const _Iterator& _Left, const _Iterator& _Right) // + _NODISCARD friend constexpr difference_type operator-(const _Iterator& _Left, const _Iterator& _Right) // noexcept(noexcept(_Left._Inner - _Right._Inner)) // strengthened requires sized_sentinel_for<_Inner_iterator<_Const>, _Inner_iterator<_Const>> { @@ -8582,14 +8609,14 @@ namespace ranges { template requires sentinel_for<_Inner_sentinel<_Const>, _Inner_iterator<_OtherConst>> - _NODISCARD_FRIEND constexpr bool operator==(const _Iterator<_OtherConst>& _It, + _NODISCARD friend constexpr bool operator==(const _Iterator<_OtherConst>& _It, const _Sentinel& _Se) noexcept(noexcept(_Se._Equal(_It))) /* strengthened */ { return _Se._Equal(_It); } template requires sized_sentinel_for<_Inner_sentinel<_Const>, _Inner_iterator<_OtherConst>> - _NODISCARD_FRIEND constexpr range_difference_t<_Maybe_const<_OtherConst, _Inner_view>> operator-( + _NODISCARD friend constexpr range_difference_t<_Maybe_const<_OtherConst, _Inner_view>> operator-( const _Iterator<_OtherConst>& _It, const _Sentinel& _Se) noexcept( // noexcept(_Se._Distance_from(_It))) /* strengthened */ { return -_Se._Distance_from(_It); @@ -8597,7 +8624,7 @@ namespace ranges { template requires sized_sentinel_for<_Inner_sentinel<_Const>, _Inner_iterator<_OtherConst>> - _NODISCARD_FRIEND constexpr range_difference_t<_Maybe_const<_OtherConst, _Inner_view>> operator-( + _NODISCARD friend constexpr range_difference_t<_Maybe_const<_OtherConst, _Inner_view>> operator-( const _Sentinel& _Se, const _Iterator<_OtherConst>& _It) noexcept( // noexcept(_Se._Distance_from(_It))) /* strengthened */ { return _Se._Distance_from(_It); @@ -8679,7 +8706,8 @@ namespace ranges { template _NODISCARD _STATIC_CALL_OPERATOR constexpr auto operator()(_Rng&&, _Fn&& _Func) _CONST_CALL_OPERATOR noexcept(noexcept(views::zip_transform(_STD forward<_Fn>(_Func)))) - requires (_Nx == 0) && requires { views::zip_transform(_STD forward<_Fn>(_Func)); } + requires (_Nx == 0) + && forward_range<_Rng> && requires { views::zip_transform(_STD forward<_Fn>(_Func)); } { return views::zip_transform(_STD forward<_Fn>(_Func)); } @@ -9004,59 +9032,59 @@ namespace ranges { return *(*this + _Off); } - _NODISCARD_FRIEND constexpr bool operator==(const _Iterator& _Left, const _Iterator& _Right) + _NODISCARD friend constexpr bool operator==(const _Iterator& _Left, const _Iterator& _Right) requires equality_comparable>> { return _Left._Current == _Right._Current; } - _NODISCARD_FRIEND constexpr bool operator==(const _Iterator& _It, default_sentinel_t) { + _NODISCARD friend constexpr bool operator==(const _Iterator& _It, default_sentinel_t) { return _It._Is_end(make_index_sequence<1 + sizeof...(_Rest)>{}); } - _NODISCARD_FRIEND constexpr auto operator<=>(const _Iterator& _Left, const _Iterator& _Right) + _NODISCARD friend constexpr auto operator<=>(const _Iterator& _Left, const _Iterator& _Right) requires _All_random_access<_Const, _First, _Rest...> { return _Left._Current <=> _Right._Current; } - _NODISCARD_FRIEND constexpr _Iterator operator+(const _Iterator& _It, const difference_type _Off) + _NODISCARD friend constexpr _Iterator operator+(const _Iterator& _It, const difference_type _Off) requires _Cartesian_product_is_random_access<_Const, _First, _Rest...> { return _Iterator{_It} += _Off; } - _NODISCARD_FRIEND constexpr _Iterator operator+(const difference_type _Off, const _Iterator& _It) + _NODISCARD friend constexpr _Iterator operator+(const difference_type _Off, const _Iterator& _It) requires _Cartesian_product_is_random_access<_Const, _First, _Rest...> { return _It + _Off; } - _NODISCARD_FRIEND constexpr _Iterator operator-(const _Iterator& _It, const difference_type _Off) + _NODISCARD friend constexpr _Iterator operator-(const _Iterator& _It, const difference_type _Off) requires _Cartesian_product_is_random_access<_Const, _First, _Rest...> { return _Iterator{_It} -= _Off; } - _NODISCARD_FRIEND constexpr difference_type operator-(const _Iterator& _Left, const _Iterator& _Right) + _NODISCARD friend constexpr difference_type operator-(const _Iterator& _Left, const _Iterator& _Right) requires _Cartesian_is_sized_sentinel<_Const, iterator_t, _First, _Rest...> { return _Left._Distance_from(_Right._Current); } - _NODISCARD_FRIEND constexpr difference_type operator-(const _Iterator& _It, default_sentinel_t) + _NODISCARD friend constexpr difference_type operator-(const _Iterator& _It, default_sentinel_t) requires _Cartesian_is_sized_sentinel<_Const, sentinel_t, _First, _Rest...> { return _It._Distance_from(_It._End_tuple(make_index_sequence{})); } - _NODISCARD_FRIEND constexpr difference_type operator-(default_sentinel_t _Se, const _Iterator& _It) + _NODISCARD friend constexpr difference_type operator-(default_sentinel_t _Se, const _Iterator& _It) requires _Cartesian_is_sized_sentinel<_Const, sentinel_t, _First, _Rest...> { return -(_It - _Se); } - _NODISCARD_FRIEND constexpr auto iter_move(const _Iterator& _It) noexcept( + _NODISCARD friend constexpr auto iter_move(const _Iterator& _It) noexcept( _Is_iter_move_nothrow(make_index_sequence<1 + sizeof...(_Rest)>{})) { return _RANGES _Tuple_transform(_RANGES iter_move, _It._Current); } diff --git a/stl/inc/set b/stl/inc/set index 08a60f028b6..44bb78db034 100644 --- a/stl/inc/set +++ b/stl/inc/set @@ -196,11 +196,11 @@ set(initializer_list<_Kty>, _Alloc) -> set<_Kty, less<_Kty>, _Alloc>; #if _HAS_CXX23 template <_RANGES input_range _Rng, class _Pr = less<_RANGES range_value_t<_Rng>>, - class _Alloc = allocator<_RANGES range_value_t<_Rng>>, - enable_if_t>, _Is_allocator<_Alloc>>, int> = 0> + _Allocator_for_container _Alloc = allocator<_RANGES range_value_t<_Rng>>> + requires (!_Allocator_for_container<_Pr>) set(from_range_t, _Rng&&, _Pr = _Pr(), _Alloc = _Alloc()) -> set<_RANGES range_value_t<_Rng>, _Pr, _Alloc>; -template <_RANGES input_range _Rng, class _Alloc, enable_if_t<_Is_allocator<_Alloc>::value, int> = 0> +template <_RANGES input_range _Rng, _Allocator_for_container _Alloc> set(from_range_t, _Rng&&, _Alloc) -> set<_RANGES range_value_t<_Rng>, less<_RANGES range_value_t<_Rng>>, _Alloc>; #endif // _HAS_CXX23 #endif // _HAS_CXX17 @@ -410,11 +410,11 @@ multiset(initializer_list<_Kty>, _Alloc) -> multiset<_Kty, less<_Kty>, _Alloc>; #if _HAS_CXX23 template <_RANGES input_range _Rng, class _Pr = less<_RANGES range_value_t<_Rng>>, - class _Alloc = allocator<_RANGES range_value_t<_Rng>>, - enable_if_t>, _Is_allocator<_Alloc>>, int> = 0> + _Allocator_for_container _Alloc = allocator<_RANGES range_value_t<_Rng>>> + requires (!_Allocator_for_container<_Pr>) multiset(from_range_t, _Rng&&, _Pr = _Pr(), _Alloc = _Alloc()) -> multiset<_RANGES range_value_t<_Rng>, _Pr, _Alloc>; -template <_RANGES input_range _Rng, class _Alloc, enable_if_t<_Is_allocator<_Alloc>::value, int> = 0> +template <_RANGES input_range _Rng, _Allocator_for_container _Alloc> multiset(from_range_t, _Rng&&, _Alloc) -> multiset<_RANGES range_value_t<_Rng>, less<_RANGES range_value_t<_Rng>>, _Alloc>; #endif // _HAS_CXX23 diff --git a/stl/inc/span b/stl/inc/span index d18667c64fc..018bc98cc98 100644 --- a/stl/inc/span +++ b/stl/inc/span @@ -110,7 +110,7 @@ struct _Span_iterator { return _Tmp; } - _NODISCARD_FRIEND constexpr _Span_iterator operator+(const difference_type _Off, _Span_iterator _Next) noexcept { + _NODISCARD friend constexpr _Span_iterator operator+(const difference_type _Off, _Span_iterator _Next) noexcept { _Next += _Off; return _Next; } diff --git a/stl/inc/sstream b/stl/inc/sstream index 4d44166fa34..338f3f41cd6 100644 --- a/stl/inc/sstream +++ b/stl/inc/sstream @@ -230,8 +230,7 @@ public: } #if _HAS_CXX20 - template - requires _Is_allocator<_Alloc2>::value + template <_Allocator_for_container _Alloc2> _NODISCARD basic_string<_Elem, _Traits, _Alloc2> str(const _Alloc2& _Al) const { return basic_string<_Elem, _Traits, _Alloc2>{view(), _Al}; } @@ -694,8 +693,7 @@ public: } #if _HAS_CXX20 - template - requires _Is_allocator<_Alloc2>::value + template <_Allocator_for_container _Alloc2> _NODISCARD basic_string<_Elem, _Traits, _Alloc2> str(const _Alloc2& _Al) const { return _Stringbuffer.str(_Al); } @@ -814,7 +812,7 @@ public: } #if _HAS_CXX20 - template ::value, int> = 0> + template <_Allocator_for_container _Alloc2> _NODISCARD basic_string<_Elem, _Traits, _Alloc2> str(const _Alloc2& _Al) const { return _Stringbuffer.str(_Al); } @@ -939,7 +937,7 @@ public: } #if _HAS_CXX20 - template ::value, int> = 0> + template <_Allocator_for_container _Alloc2> _NODISCARD basic_string<_Elem, _Traits, _Alloc2> str(const _Alloc2& _Al) const { return _Stringbuffer.str(_Al); } diff --git a/stl/inc/stack b/stl/inc/stack index 6dd94f1104b..e98e69dee43 100644 --- a/stl/inc/stack +++ b/stl/inc/stack @@ -43,7 +43,7 @@ public: : c(_STD move(_Cont)) {} #if _HAS_CXX23 - template , int> = 0> + template <_Iterator_for_container _InIt> stack(_InIt _First, _InIt _Last) noexcept(is_nothrow_constructible_v<_Container, _InIt, _InIt>) // strengthened : c(_STD move(_First), _STD move(_Last)) {} @@ -72,8 +72,8 @@ public: : c(_STD move(_Right.c), _Al) {} #if _HAS_CXX23 - template , uses_allocator<_Container, _Alloc>>, int> = 0> + template <_Iterator_for_container _InIt, class _Alloc> + requires uses_allocator_v<_Container, _Alloc> stack(_InIt _First, _InIt _Last, const _Alloc& _Al) noexcept( is_nothrow_constructible_v<_Container, _InIt, _InIt, const _Alloc&>) // strengthened : c(_STD move(_First), _STD move(_Last), _Al) {} @@ -154,14 +154,13 @@ stack(_Container, _Alloc) -> stack; #endif // _HAS_CXX17 #if _HAS_CXX23 -template >, - enable_if_t, _Is_allocator<_Alloc>>, int> = 0> +template <_Iterator_for_container _InIt, _Allocator_for_container _Alloc = allocator<_Iter_value_t<_InIt>>> stack(_InIt, _InIt, _Alloc = _Alloc()) -> stack<_Iter_value_t<_InIt>, deque<_Iter_value_t<_InIt>, _Alloc>>; template <_RANGES input_range _Rng> stack(from_range_t, _Rng&&) -> stack<_RANGES range_value_t<_Rng>>; -template <_RANGES input_range _Rng, class _Alloc, enable_if_t<_Is_allocator<_Alloc>::value, int> = 0> +template <_RANGES input_range _Rng, _Allocator_for_container _Alloc> stack(from_range_t, _Rng&&, _Alloc) -> stack<_RANGES range_value_t<_Rng>, deque<_RANGES range_value_t<_Rng>, _Alloc>>; #endif // _HAS_CXX23 diff --git a/stl/inc/stacktrace b/stl/inc/stacktrace index cc182e617d9..b5b57c00c9b 100644 --- a/stl/inc/stacktrace +++ b/stl/inc/stacktrace @@ -107,9 +107,9 @@ public: return __std_stacktrace_source_line(_Address); } - _NODISCARD_FRIEND constexpr bool operator==(const stacktrace_entry&, const stacktrace_entry&) noexcept = default; + _NODISCARD friend constexpr bool operator==(const stacktrace_entry&, const stacktrace_entry&) noexcept = default; - _NODISCARD_FRIEND constexpr strong_ordering operator<=>( + _NODISCARD friend constexpr strong_ordering operator<=>( const stacktrace_entry&, const stacktrace_entry&) noexcept = default; private: @@ -253,12 +253,12 @@ public: } template - _NODISCARD_FRIEND bool operator==(const basic_stacktrace& _Lhs, const basic_stacktrace<_Al2>& _Rhs) noexcept { + _NODISCARD friend bool operator==(const basic_stacktrace& _Lhs, const basic_stacktrace<_Al2>& _Rhs) noexcept { return _Lhs._Hash == _Rhs._Hash && _STD equal(_Lhs.begin(), _Lhs.end(), _Rhs.begin(), _Rhs.end()); } template - _NODISCARD_FRIEND strong_ordering operator<=>( + _NODISCARD friend strong_ordering operator<=>( const basic_stacktrace& _Lhs, const basic_stacktrace<_Al2>& _Rhs) noexcept { const auto _Result = _Lhs._Frames.size() <=> _Rhs._Frames.size(); if (_Result != strong_ordering::equal) { diff --git a/stl/inc/stop_token b/stl/inc/stop_token index 5702d902199..6e37adb0158 100644 --- a/stl/inc/stop_token +++ b/stl/inc/stop_token @@ -162,7 +162,7 @@ public: return _Local != nullptr && _Local->_Stop_possible(); } - _NODISCARD_FRIEND bool operator==(const stop_token& _Lhs, const stop_token& _Rhs) noexcept = default; + _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); @@ -234,7 +234,7 @@ public: return _Local && _Local->_Request_stop(); } - _NODISCARD_FRIEND bool operator==(const stop_source& _Lhs, const stop_source& _Rhs) noexcept = default; + _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); diff --git a/stl/inc/system_error b/stl/inc/system_error index b8697d328cc..66ef51bb0fc 100644 --- a/stl/inc/system_error +++ b/stl/inc/system_error @@ -212,39 +212,39 @@ public: } #if _STL_OPTIMIZE_SYSTEM_ERROR_OPERATORS - _NODISCARD_FRIEND bool operator==(const error_code& _Left, const error_code& _Right) noexcept { + _NODISCARD friend bool operator==(const error_code& _Left, const error_code& _Right) noexcept { return _Left.category() == _Right.category() && _Left.value() == _Right.value(); } - _NODISCARD_FRIEND bool operator==(const error_code& _Left, const error_condition& _Right) noexcept { + _NODISCARD friend bool operator==(const error_code& _Left, const error_condition& _Right) noexcept { return _System_error_equal(_Left, _Right); } #if _HAS_CXX20 - _NODISCARD_FRIEND strong_ordering operator<=>(const error_code& _Left, const error_code& _Right) noexcept { + _NODISCARD friend strong_ordering operator<=>(const error_code& _Left, const error_code& _Right) noexcept { if (const auto _Result = _Left.category() <=> _Right.category(); _Result != 0) { return _Result; } return _Left.value() <=> _Right.value(); } #else // ^^^ _HAS_CXX20 / !_HAS_CXX20 vvv - _NODISCARD_FRIEND bool operator<(const error_code& _Left, const error_code& _Right) noexcept { + _NODISCARD friend bool operator<(const error_code& _Left, const error_code& _Right) noexcept { return _Left.category() < _Right.category() || (_Left.category() == _Right.category() && _Left.value() < _Right.value()); } - _NODISCARD_FRIEND bool operator==(const error_condition& _Left, const error_code& _Right) noexcept { + _NODISCARD friend bool operator==(const error_condition& _Left, const error_code& _Right) noexcept { return _System_error_equal(_Right, _Left); } - _NODISCARD_FRIEND bool operator!=(const error_code& _Left, const error_code& _Right) noexcept { + _NODISCARD friend bool operator!=(const error_code& _Left, const error_code& _Right) noexcept { return !(_Left == _Right); } - _NODISCARD_FRIEND bool operator!=(const error_code& _Left, const error_condition& _Right) noexcept { + _NODISCARD friend bool operator!=(const error_code& _Left, const error_condition& _Right) noexcept { return !_System_error_equal(_Left, _Right); } - _NODISCARD_FRIEND bool operator!=(const error_condition& _Left, const error_code& _Right) noexcept { + _NODISCARD friend bool operator!=(const error_condition& _Left, const error_code& _Right) noexcept { return !_System_error_equal(_Right, _Left); } #endif // ^^^ !_HAS_CXX20 ^^^ @@ -301,12 +301,12 @@ public: } #if _STL_OPTIMIZE_SYSTEM_ERROR_OPERATORS - _NODISCARD_FRIEND bool operator==(const error_condition& _Left, const error_condition& _Right) noexcept { + _NODISCARD friend bool operator==(const error_condition& _Left, const error_condition& _Right) noexcept { return _Left.category() == _Right.category() && _Left.value() == _Right.value(); } #if _HAS_CXX20 - _NODISCARD_FRIEND strong_ordering operator<=>( + _NODISCARD friend strong_ordering operator<=>( const error_condition& _Left, const error_condition& _Right) noexcept { if (const auto _Result = _Left.category() <=> _Right.category(); _Result != 0) { return _Result; @@ -314,11 +314,11 @@ public: return _Left.value() <=> _Right.value(); } #else // ^^^ _HAS_CXX20 / !_HAS_CXX20 vvv - _NODISCARD_FRIEND bool operator<(const error_condition& _Left, const error_condition& _Right) noexcept { + _NODISCARD friend bool operator<(const error_condition& _Left, const error_condition& _Right) noexcept { return _Left.category() < _Right.category() || (_Left.category() == _Right.category() && _Left.value() < _Right.value()); } - _NODISCARD_FRIEND bool operator!=(const error_condition& _Left, const error_condition& _Right) noexcept { + _NODISCARD friend bool operator!=(const error_condition& _Left, const error_condition& _Right) noexcept { return !(_Left == _Right); } #endif // ^^^ !_HAS_CXX20 ^^^ diff --git a/stl/inc/tuple b/stl/inc/tuple index b9fa78920dd..0f79be7872e 100644 --- a/stl/inc/tuple +++ b/stl/inc/tuple @@ -119,16 +119,6 @@ struct _Tuple_perfect_val, _Uty0, _Uty1, _Uty2> : bool_constant, allocator_arg_t>>, is_same<_Remove_cvref_t<_Ty0>, allocator_arg_t>>> {}; -struct _Ignore { // struct that ignores assignments - template - constexpr const _Ignore& operator=(const _Ty&) const noexcept /* strengthened */ { - // do nothing - return *this; - } -}; - -_EXPORT_STD _INLINE_VAR constexpr _Ignore ignore{}; - // Note: To improve throughput, this file uses extra _STD qualification for names that appear in the // arguments of enable_if_t. Specifically, we qualify names which appear anywhere in the STL as members of // some class - including injected-class-names! - that we know are not members of the class being defined. @@ -288,14 +278,14 @@ public: #if _HAS_CXX23 template <_Tuple_like_non_tuple _Other> - _NODISCARD_FRIEND constexpr bool operator==(const tuple&, const _Other&) noexcept /* strengthened */ { + _NODISCARD friend constexpr bool operator==(const tuple&, const _Other&) noexcept /* strengthened */ { static_assert(tuple_size_v<_Other> == 0, "Cannot compare tuples of different sizes (N4950 [tuple.rel]/2)."); return true; } template <_Tuple_like_non_tuple _Other> requires (tuple_size_v> == 0) - _NODISCARD_FRIEND constexpr strong_ordering operator<=>(const tuple&, const _Other&) noexcept /* strengthened */ { + _NODISCARD friend constexpr strong_ordering operator<=>(const tuple&, const _Other&) noexcept /* strengthened */ { return strong_ordering::equal; } #endif // _HAS_CXX23 @@ -563,12 +553,11 @@ public: } #if _HAS_CXX23 - template , - _STD _Is_copy_assignable_no_precondition_check...>, - int> = 0> + template + requires conjunction_v<_STD _Is_copy_assignable_no_precondition_check, + _STD _Is_copy_assignable_no_precondition_check...> constexpr const tuple& operator=(_Identity_t _Right) const - noexcept(conjunction_v, + noexcept(conjunction_v, is_nothrow_copy_assignable...>) /* strengthened */ { _Myfirst._Val = _Right._Myfirst._Val; _Get_rest() = _Right._Get_rest(); @@ -588,12 +577,11 @@ public: } #if _HAS_CXX23 - template , - _STD _Is_assignable_no_precondition_check...>, - int> = 0> + template + requires conjunction_v<_STD _Is_assignable_no_precondition_check, + _STD _Is_assignable_no_precondition_check...> constexpr const tuple& operator=(_Identity_t<_Myself&&> _Right) const - noexcept(conjunction_v, + noexcept(conjunction_v, is_nothrow_assignable...>) /* strengthened */ { _Myfirst._Val = _STD forward<_This>(_Right._Myfirst._Val); _Get_rest() = _STD forward<_Mybase>(_Right._Get_rest()); @@ -612,9 +600,8 @@ public: } #if _HAS_CXX23 - template >>, - _STD _Tuple_assignable_val>, - int> = 0> + template + requires (!is_same_v>) && _Tuple_assignable_v constexpr const tuple& operator=(const tuple<_Other...>& _Right) const noexcept(_Tuple_nothrow_assignable_v) /* strengthened */ { _Myfirst._Val = _Right._Myfirst._Val; @@ -634,9 +621,8 @@ public: } #if _HAS_CXX23 - template >>, - _STD _Tuple_assignable_val>, - int> = 0> + template + requires (!is_same_v>) && _Tuple_assignable_v constexpr const tuple& operator=(tuple<_Other...>&& _Right) const noexcept(_Tuple_nothrow_assignable_v) /* strengthened */ { _Myfirst._Val = _STD forward::_This_type>(_Right._Myfirst._Val); @@ -655,8 +641,8 @@ public: } #if _HAS_CXX23 - template , int> = 0> + template + requires _Tuple_assignable_v constexpr const tuple& operator=(const pair<_First, _Second>& _Right) const noexcept(_Tuple_nothrow_assignable_v) /* strengthened */ { _Myfirst._Val = _Right.first; @@ -674,7 +660,8 @@ public: } #if _HAS_CXX23 - template , int> = 0> + template + requires _Tuple_assignable_v constexpr const tuple& operator=(pair<_First, _Second>&& _Right) const noexcept(_Tuple_nothrow_assignable_v) /* strengthened */ { _Myfirst._Val = _STD forward<_First>(_Right.first); @@ -781,7 +768,7 @@ public: } template <_Tuple_like_non_tuple _Other> - _NODISCARD_FRIEND constexpr bool operator==(const tuple& _Left, const _Other& _Right) { + _NODISCARD friend constexpr bool operator==(const tuple& _Left, const _Other& _Right) { static_assert(1 + sizeof...(_Rest) == tuple_size_v<_Other>, "Cannot compare tuples of different sizes (N4950 [tuple.rel]/2)."); static_assert(_Can_equal_compare_with_tuple_like_v<_Other>, @@ -799,7 +786,7 @@ public: } template <_Tuple_like_non_tuple _Other> - _NODISCARD_FRIEND constexpr auto operator<=>(const tuple& _Left, const _Other& _Right) + _NODISCARD friend constexpr auto operator<=>(const tuple& _Left, const _Other& _Right) -> _Three_way_comparison_result_with_tuple_like_t { return _Left._Three_way_compare_with_tuple_like(_Right, make_index_sequence<1 + sizeof...(_Rest)>{}); } @@ -906,7 +893,8 @@ _CONSTEXPR20 void swap(tuple<_Types...>& _Left, tuple<_Types...>& _Right) noexce } #if _HAS_CXX23 -_EXPORT_STD template ...>, int> = 0> +_EXPORT_STD template + requires conjunction_v...> constexpr void swap(const tuple<_Types...>& _Left, const tuple<_Types...>& _Right) noexcept( noexcept(_Left.swap(_Right))) { _Left.swap(_Right); diff --git a/stl/inc/unordered_map b/stl/inc/unordered_map index bff9e8d6a26..d0f0b2aa902 100644 --- a/stl/inc/unordered_map +++ b/stl/inc/unordered_map @@ -497,22 +497,22 @@ unordered_map(initializer_list>, _Guide_size_type_t<_Alloc>, _Ha -> unordered_map<_Kty, _Ty, _Hasher, equal_to<_Kty>, _Alloc>; #if _HAS_CXX23 -template <_RANGES input_range _Rng, class _Hasher = hash<_Range_key_type<_Rng>>, - class _Keyeq = equal_to<_Range_key_type<_Rng>>, class _Alloc = allocator<_Range_to_alloc_type<_Rng>>, - enable_if_t, negation<_Is_allocator<_Keyeq>>, _Is_allocator<_Alloc>>, int> = 0> +template <_RANGES input_range _Rng, _Hasher_for_container _Hasher = hash<_Range_key_type<_Rng>>, + class _Keyeq = equal_to<_Range_key_type<_Rng>>, + _Allocator_for_container _Alloc = allocator<_Range_to_alloc_type<_Rng>>> + requires (!_Allocator_for_container<_Keyeq>) unordered_map(from_range_t, _Rng&&, _Guide_size_type_t<_Alloc> = 0, _Hasher = _Hasher(), _Keyeq = _Keyeq(), _Alloc = _Alloc()) -> unordered_map<_Range_key_type<_Rng>, _Range_mapped_type<_Rng>, _Hasher, _Keyeq, _Alloc>; -template <_RANGES input_range _Rng, class _Alloc, enable_if_t<_Is_allocator<_Alloc>::value, int> = 0> +template <_RANGES input_range _Rng, _Allocator_for_container _Alloc> unordered_map(from_range_t, _Rng&&, _Guide_size_type_t<_Alloc>, _Alloc) -> unordered_map<_Range_key_type<_Rng>, _Range_mapped_type<_Rng>, hash<_Range_key_type<_Rng>>, equal_to<_Range_key_type<_Rng>>, _Alloc>; -template <_RANGES input_range _Rng, class _Alloc, enable_if_t<_Is_allocator<_Alloc>::value, int> = 0> +template <_RANGES input_range _Rng, _Allocator_for_container _Alloc> unordered_map(from_range_t, _Rng&&, _Alloc) -> unordered_map<_Range_key_type<_Rng>, _Range_mapped_type<_Rng>, hash<_Range_key_type<_Rng>>, equal_to<_Range_key_type<_Rng>>, _Alloc>; -template <_RANGES input_range _Rng, class _Hasher, class _Alloc, - enable_if_t, _Is_allocator<_Alloc>>, int> = 0> +template <_RANGES input_range _Rng, _Hasher_for_container _Hasher, _Allocator_for_container _Alloc> unordered_map(from_range_t, _Rng&&, _Guide_size_type_t<_Alloc>, _Hasher, _Alloc) -> unordered_map<_Range_key_type<_Rng>, _Range_mapped_type<_Rng>, _Hasher, equal_to<_Range_key_type<_Rng>>, _Alloc>; #endif // _HAS_CXX23 @@ -867,23 +867,23 @@ unordered_multimap(initializer_list>, _Guide_size_type_t<_Alloc> -> unordered_multimap<_Kty, _Ty, _Hasher, equal_to<_Kty>, _Alloc>; #if _HAS_CXX23 -template <_RANGES input_range _Rng, class _Hasher = hash<_Range_key_type<_Rng>>, - class _Keyeq = equal_to<_Range_key_type<_Rng>>, class _Alloc = allocator<_Range_to_alloc_type<_Rng>>, - enable_if_t, negation<_Is_allocator<_Keyeq>>, _Is_allocator<_Alloc>>, int> = 0> +template <_RANGES input_range _Rng, _Hasher_for_container _Hasher = hash<_Range_key_type<_Rng>>, + class _Keyeq = equal_to<_Range_key_type<_Rng>>, + _Allocator_for_container _Alloc = allocator<_Range_to_alloc_type<_Rng>>> + requires (!_Allocator_for_container<_Keyeq>) unordered_multimap(from_range_t, _Rng&&, _Guide_size_type_t<_Alloc> = 0, _Hasher = _Hasher(), _Keyeq = _Keyeq(), _Alloc = _Alloc()) -> unordered_multimap<_Range_key_type<_Rng>, _Range_mapped_type<_Rng>, _Hasher, _Keyeq, _Alloc>; -template <_RANGES input_range _Rng, class _Alloc, enable_if_t<_Is_allocator<_Alloc>::value, int> = 0> +template <_RANGES input_range _Rng, _Allocator_for_container _Alloc> unordered_multimap(from_range_t, _Rng&&, _Guide_size_type_t<_Alloc>, _Alloc) -> unordered_multimap<_Range_key_type<_Rng>, _Range_mapped_type<_Rng>, hash<_Range_key_type<_Rng>>, equal_to<_Range_key_type<_Rng>>, _Alloc>; -template <_RANGES input_range _Rng, class _Alloc, enable_if_t<_Is_allocator<_Alloc>::value, int> = 0> +template <_RANGES input_range _Rng, _Allocator_for_container _Alloc> unordered_multimap(from_range_t, _Rng&&, _Alloc) -> unordered_multimap<_Range_key_type<_Rng>, _Range_mapped_type<_Rng>, hash<_Range_key_type<_Rng>>, equal_to<_Range_key_type<_Rng>>, _Alloc>; -template <_RANGES input_range _Rng, class _Hasher, class _Alloc, - enable_if_t, _Is_allocator<_Alloc>>, int> = 0> +template <_RANGES input_range _Rng, _Hasher_for_container _Hasher, _Allocator_for_container _Alloc> unordered_multimap(from_range_t, _Rng&&, _Guide_size_type_t<_Alloc>, _Hasher, _Alloc) -> unordered_multimap<_Range_key_type<_Rng>, _Range_mapped_type<_Rng>, _Hasher, equal_to<_Range_key_type<_Rng>>, _Alloc>; diff --git a/stl/inc/unordered_set b/stl/inc/unordered_set index d9a390c2565..e94e2b68062 100644 --- a/stl/inc/unordered_set +++ b/stl/inc/unordered_set @@ -353,22 +353,22 @@ unordered_set(initializer_list<_Kty>, _Guide_size_type_t<_Alloc>, _Hasher, _Allo -> unordered_set<_Kty, _Hasher, equal_to<_Kty>, _Alloc>; #if _HAS_CXX23 -template <_RANGES input_range _Rng, class _Hasher = hash<_RANGES range_value_t<_Rng>>, - class _Keyeq = equal_to<_RANGES range_value_t<_Rng>>, class _Alloc = allocator<_RANGES range_value_t<_Rng>>, - enable_if_t, negation<_Is_allocator<_Keyeq>>, _Is_allocator<_Alloc>>, int> = 0> +template <_RANGES input_range _Rng, _Hasher_for_container _Hasher = hash<_RANGES range_value_t<_Rng>>, + class _Keyeq = equal_to<_RANGES range_value_t<_Rng>>, + _Allocator_for_container _Alloc = allocator<_RANGES range_value_t<_Rng>>> + requires (!_Allocator_for_container<_Keyeq>) unordered_set(from_range_t, _Rng&&, _Guide_size_type_t<_Alloc> = 0, _Hasher = _Hasher(), _Keyeq = _Keyeq(), _Alloc = _Alloc()) -> unordered_set<_RANGES range_value_t<_Rng>, _Hasher, _Keyeq, _Alloc>; -template <_RANGES input_range _Rng, class _Alloc, enable_if_t<_Is_allocator<_Alloc>::value, int> = 0> +template <_RANGES input_range _Rng, _Allocator_for_container _Alloc> unordered_set(from_range_t, _Rng&&, _Guide_size_type_t<_Alloc>, _Alloc) -> unordered_set<_RANGES range_value_t<_Rng>, hash<_RANGES range_value_t<_Rng>>, equal_to<_RANGES range_value_t<_Rng>>, _Alloc>; -template <_RANGES input_range _Rng, class _Alloc, enable_if_t<_Is_allocator<_Alloc>::value, int> = 0> +template <_RANGES input_range _Rng, _Allocator_for_container _Alloc> unordered_set(from_range_t, _Rng&&, _Alloc) -> unordered_set<_RANGES range_value_t<_Rng>, hash<_RANGES range_value_t<_Rng>>, equal_to<_RANGES range_value_t<_Rng>>, _Alloc>; -template <_RANGES input_range _Rng, class _Hasher, class _Alloc, - enable_if_t, _Is_allocator<_Alloc>>, int> = 0> +template <_RANGES input_range _Rng, _Hasher_for_container _Hasher, _Allocator_for_container _Alloc> unordered_set(from_range_t, _Rng&&, _Guide_size_type_t<_Alloc>, _Hasher, _Alloc) -> unordered_set<_RANGES range_value_t<_Rng>, _Hasher, equal_to<_RANGES range_value_t<_Rng>>, _Alloc>; #endif // _HAS_CXX23 @@ -696,23 +696,23 @@ unordered_multiset(initializer_list<_Kty>, _Guide_size_type_t<_Alloc>, _Hasher, -> unordered_multiset<_Kty, _Hasher, equal_to<_Kty>, _Alloc>; #if _HAS_CXX23 -template <_RANGES input_range _Rng, class _Hasher = hash<_RANGES range_value_t<_Rng>>, - class _Keyeq = equal_to<_RANGES range_value_t<_Rng>>, class _Alloc = allocator<_RANGES range_value_t<_Rng>>, - enable_if_t, negation<_Is_allocator<_Keyeq>>, _Is_allocator<_Alloc>>, int> = 0> +template <_RANGES input_range _Rng, _Hasher_for_container _Hasher = hash<_RANGES range_value_t<_Rng>>, + class _Keyeq = equal_to<_RANGES range_value_t<_Rng>>, + _Allocator_for_container _Alloc = allocator<_RANGES range_value_t<_Rng>>> + requires (!_Allocator_for_container<_Keyeq>) unordered_multiset(from_range_t, _Rng&&, _Guide_size_type_t<_Alloc> = 0, _Hasher = _Hasher(), _Keyeq = _Keyeq(), _Alloc = _Alloc()) -> unordered_multiset<_RANGES range_value_t<_Rng>, _Hasher, _Keyeq, _Alloc>; -template <_RANGES input_range _Rng, class _Alloc, enable_if_t<_Is_allocator<_Alloc>::value, int> = 0> +template <_RANGES input_range _Rng, _Allocator_for_container _Alloc> unordered_multiset(from_range_t, _Rng&&, _Guide_size_type_t<_Alloc>, _Alloc) -> unordered_multiset<_RANGES range_value_t<_Rng>, hash<_RANGES range_value_t<_Rng>>, equal_to<_RANGES range_value_t<_Rng>>, _Alloc>; -template <_RANGES input_range _Rng, class _Alloc, enable_if_t<_Is_allocator<_Alloc>::value, int> = 0> +template <_RANGES input_range _Rng, _Allocator_for_container _Alloc> unordered_multiset(from_range_t, _Rng&&, _Alloc) -> unordered_multiset<_RANGES range_value_t<_Rng>, hash<_RANGES range_value_t<_Rng>>, equal_to<_RANGES range_value_t<_Rng>>, _Alloc>; -template <_RANGES input_range _Rng, class _Hasher, class _Alloc, - enable_if_t, _Is_allocator<_Alloc>>, int> = 0> +template <_RANGES input_range _Rng, _Hasher_for_container _Hasher, _Allocator_for_container _Alloc> unordered_multiset(from_range_t, _Rng&&, _Guide_size_type_t<_Alloc>, _Hasher, _Alloc) -> unordered_multiset<_RANGES range_value_t<_Rng>, _Hasher, equal_to<_RANGES range_value_t<_Rng>>, _Alloc>; #endif // _HAS_CXX23 diff --git a/stl/inc/utility b/stl/inc/utility index d5e58acc007..df825320fd6 100644 --- a/stl/inc/utility +++ b/stl/inc/utility @@ -134,6 +134,16 @@ _EXPORT_STD struct piecewise_construct_t { // tag type for pair tuple arguments _EXPORT_STD _INLINE_VAR constexpr piecewise_construct_t piecewise_construct{}; +struct _Ignore { // struct that ignores assignments + template + constexpr const _Ignore& operator=(const _Ty&) const noexcept { + // do nothing + return *this; + } +}; + +_EXPORT_STD _INLINE_VAR constexpr _Ignore ignore{}; + _EXPORT_STD template class tuple; @@ -251,8 +261,8 @@ struct pair { // store a pair of values pair(pair&&) = default; #if _HAS_CXX23 - template , is_constructible<_Ty2, _Other2&>>, int> = 0> + template + requires is_constructible_v<_Ty1, _Other1&> && is_constructible_v<_Ty2, _Other2&> constexpr explicit(!conjunction_v, is_convertible<_Other2&, _Ty2>>) pair(pair<_Other1, _Other2>& _Right) noexcept( is_nothrow_constructible_v<_Ty1, _Other1&> && is_nothrow_constructible_v<_Ty2, _Other2&>) // strengthened @@ -276,9 +286,8 @@ struct pair { // store a pair of values : first(_STD forward<_Other1>(_Right.first)), second(_STD forward<_Other2>(_Right.second)) {} #if _HAS_CXX23 - template , is_constructible<_Ty2, const _Other2>>, int> = - 0> + template + requires is_constructible_v<_Ty1, const _Other1> && is_constructible_v<_Ty2, const _Other2> constexpr explicit(!conjunction_v, is_convertible>) pair(const pair<_Other1, _Other2>&& _Right) noexcept( is_nothrow_constructible_v<_Ty1, const _Other1> @@ -325,10 +334,9 @@ struct pair { // store a pair of values } #if _HAS_CXX23 - template , - _Is_copy_assignable_no_precondition_check>, - int> = 0> + template + requires _Is_copy_assignable_unchecked_v + && _Is_copy_assignable_unchecked_v constexpr const pair& operator=(_Identity_t _Right) const noexcept(conjunction_v, is_nothrow_copy_assignable>) /* strengthened */ { @@ -350,10 +358,9 @@ struct pair { // store a pair of values } #if _HAS_CXX23 - template , - _Is_assignable_no_precondition_check>, - int> = 0> + template + requires _Is_assignable_no_precondition_check::value + && _Is_assignable_no_precondition_check::value constexpr const pair& operator=(_Identity_t<_Myself&&> _Right) const noexcept(conjunction_v, is_nothrow_assignable>) /* strengthened */ { @@ -376,10 +383,9 @@ struct pair { // store a pair of values } #if _HAS_CXX23 - template >>, - is_assignable, is_assignable>, - int> = 0> + template + requires (!is_same_v>) + && is_assignable_v && is_assignable_v constexpr const pair& operator=(const pair<_Other1, _Other2>& _Right) const noexcept(is_nothrow_assignable_v && is_nothrow_assignable_v) /* strengthened */ { @@ -401,10 +407,9 @@ struct pair { // store a pair of values } #if _HAS_CXX23 - template >>, is_assignable, - is_assignable>, - int> = 0> + template + requires (!is_same_v>) + && is_assignable_v && is_assignable_v constexpr const pair& operator=(pair<_Other1, _Other2>&& _Right) const noexcept(is_nothrow_assignable_v && is_nothrow_assignable_v) /* strengthened */ { @@ -471,8 +476,8 @@ _CONSTEXPR20 void swap(pair<_Ty1, _Ty2>& _Left, pair<_Ty1, _Ty2>& _Right) noexce } #if _HAS_CXX23 -_EXPORT_STD template && is_swappable_v, int> = 0> +_EXPORT_STD template + requires is_swappable::value && is_swappable::value // TRANSITION, /permissive needs ::value constexpr void swap(const pair<_Ty1, _Ty2>& _Left, const pair<_Ty1, _Ty2>& _Right) noexcept( noexcept(_Left.swap(_Right))) { _Left.swap(_Right); @@ -784,14 +789,9 @@ _EXPORT_STD template constexpr in_place_index_t<_Idx> in_place_index{}; #endif // _HAS_CXX17 -template -constexpr bool _Is_standard_integer = _Is_any_of_v, signed char, short, int, long, long long, - unsigned char, unsigned short, unsigned int, unsigned long, unsigned long long>; - template _NODISCARD constexpr bool _Cmp_equal(const _Ty1 _Left, const _Ty2 _Right) noexcept { - static_assert(_Is_standard_integer<_Ty1> && _Is_standard_integer<_Ty2>, - "The integer comparison functions only accept standard and extended integer types."); + _STL_INTERNAL_STATIC_ASSERT(_Is_nonbool_integral<_Ty1> && _Is_nonbool_integral<_Ty2>); // allows character types if constexpr (is_signed_v<_Ty1> == is_signed_v<_Ty2>) { return _Left == _Right; } else if constexpr (is_signed_v<_Ty2>) { @@ -808,8 +808,7 @@ _NODISCARD constexpr bool _Cmp_not_equal(const _Ty1 _Left, const _Ty2 _Right) no template _NODISCARD constexpr bool _Cmp_less(const _Ty1 _Left, const _Ty2 _Right) noexcept { - static_assert(_Is_standard_integer<_Ty1> && _Is_standard_integer<_Ty2>, - "The integer comparison functions only accept standard and extended integer types."); + _STL_INTERNAL_STATIC_ASSERT(_Is_nonbool_integral<_Ty1> && _Is_nonbool_integral<_Ty2>); // allows character types if constexpr (is_signed_v<_Ty1> == is_signed_v<_Ty2>) { return _Left < _Right; } else if constexpr (is_signed_v<_Ty2>) { @@ -858,8 +857,7 @@ _NODISCARD constexpr _Ty _Max_limit() noexcept { // same as (numeric_limits<_Ty> template _NODISCARD constexpr bool _In_range(const _Ty _Value) noexcept { - static_assert(_Is_standard_integer<_Rx> && _Is_standard_integer<_Ty>, - "The integer comparison functions only accept standard and extended integer types."); + _STL_INTERNAL_STATIC_ASSERT(_Is_nonbool_integral<_Rx> && _Is_nonbool_integral<_Ty>); // allows character types constexpr auto _Ty_min = _Min_limit<_Ty>(); constexpr auto _Rx_min = _Min_limit<_Rx>(); @@ -883,38 +881,56 @@ _NODISCARD constexpr bool _In_range(const _Ty _Value) noexcept { } #if _HAS_CXX20 +template +constexpr bool _Is_standard_integer = _Is_any_of_v, signed char, short, int, long, long long, + unsigned char, unsigned short, unsigned int, unsigned long, unsigned long long>; + _EXPORT_STD template _NODISCARD constexpr bool cmp_equal(const _Ty1 _Left, const _Ty2 _Right) noexcept { + static_assert(_Is_standard_integer<_Ty1> && _Is_standard_integer<_Ty2>, + "The integer comparison functions only accept standard and extended integer types."); return _STD _Cmp_equal(_Left, _Right); } _EXPORT_STD template _NODISCARD constexpr bool cmp_not_equal(const _Ty1 _Left, const _Ty2 _Right) noexcept { + static_assert(_Is_standard_integer<_Ty1> && _Is_standard_integer<_Ty2>, + "The integer comparison functions only accept standard and extended integer types."); return _STD _Cmp_not_equal(_Left, _Right); } _EXPORT_STD template _NODISCARD constexpr bool cmp_less(const _Ty1 _Left, const _Ty2 _Right) noexcept { + static_assert(_Is_standard_integer<_Ty1> && _Is_standard_integer<_Ty2>, + "The integer comparison functions only accept standard and extended integer types."); return _STD _Cmp_less(_Left, _Right); } _EXPORT_STD template _NODISCARD constexpr bool cmp_greater(const _Ty1 _Left, const _Ty2 _Right) noexcept { + static_assert(_Is_standard_integer<_Ty1> && _Is_standard_integer<_Ty2>, + "The integer comparison functions only accept standard and extended integer types."); return _STD _Cmp_greater(_Left, _Right); } _EXPORT_STD template _NODISCARD constexpr bool cmp_less_equal(const _Ty1 _Left, const _Ty2 _Right) noexcept { + static_assert(_Is_standard_integer<_Ty1> && _Is_standard_integer<_Ty2>, + "The integer comparison functions only accept standard and extended integer types."); return _STD _Cmp_less_equal(_Left, _Right); } _EXPORT_STD template _NODISCARD constexpr bool cmp_greater_equal(const _Ty1 _Left, const _Ty2 _Right) noexcept { + static_assert(_Is_standard_integer<_Ty1> && _Is_standard_integer<_Ty2>, + "The integer comparison functions only accept standard and extended integer types."); return _STD _Cmp_greater_equal(_Left, _Right); } _EXPORT_STD template _NODISCARD constexpr bool in_range(const _Ty _Value) noexcept { + static_assert(_Is_standard_integer<_Rx> && _Is_standard_integer<_Ty>, + "The integer comparison functions only accept standard and extended integer types."); return _STD _In_range<_Rx>(_Value); } #endif // _HAS_CXX20 diff --git a/stl/inc/valarray b/stl/inc/valarray index 79ad50083a1..38303a6419a 100644 --- a/stl/inc/valarray +++ b/stl/inc/valarray @@ -1439,7 +1439,7 @@ public: } #if _HAS_CXX20 - _NODISCARD_FRIEND bool operator==(const slice& _Left, const slice& _Right) noexcept /* strengthened */ { + _NODISCARD friend bool operator==(const slice& _Left, const slice& _Right) noexcept /* strengthened */ { return _Left.start() == _Right.start() && _Left.size() == _Right.size() && _Left.stride() == _Right.stride(); } #endif // _HAS_CXX20 diff --git a/stl/inc/vector b/stl/inc/vector index e2d7e0cc600..bc99da1dc7b 100644 --- a/stl/inc/vector +++ b/stl/inc/vector @@ -136,7 +136,7 @@ public: return _Tmp; } - _NODISCARD_FRIEND _CONSTEXPR20 _Vector_const_iterator operator+( + _NODISCARD friend _CONSTEXPR20 _Vector_const_iterator operator+( const difference_type _Off, _Vector_const_iterator _Next) noexcept { _Next += _Off; return _Next; @@ -316,7 +316,7 @@ public: return _Tmp; } - _NODISCARD_FRIEND _CONSTEXPR20 _Vector_iterator operator+( + _NODISCARD friend _CONSTEXPR20 _Vector_iterator operator+( const difference_type _Off, _Vector_iterator _Next) noexcept { _Next += _Off; return _Next; @@ -2208,8 +2208,7 @@ vector(_Iter, _Iter, _Alloc = _Alloc()) -> vector<_Iter_value_t<_Iter>, _Alloc>; #endif // _HAS_CXX17 #if _HAS_CXX23 -template <_RANGES input_range _Rng, class _Alloc = allocator<_RANGES range_value_t<_Rng>>, - enable_if_t<_Is_allocator<_Alloc>::value, int> = 0> +template <_RANGES input_range _Rng, _Allocator_for_container _Alloc = allocator<_RANGES range_value_t<_Rng>>> vector(from_range_t, _Rng&&, _Alloc = _Alloc()) -> vector<_RANGES range_value_t<_Rng>, _Alloc>; #endif // _HAS_CXX23 @@ -2569,7 +2568,7 @@ public: return _Tmp; } - _NODISCARD_FRIEND _CONSTEXPR20 _Vb_const_iterator operator+( + _NODISCARD friend _CONSTEXPR20 _Vb_const_iterator operator+( const difference_type _Off, _Vb_const_iterator _Right) noexcept { _Right += _Off; return _Right; @@ -2742,7 +2741,7 @@ public: return _Tmp; } - _NODISCARD_FRIEND _CONSTEXPR20 _Vb_iterator operator+(const difference_type _Off, _Vb_iterator _Right) noexcept { + _NODISCARD friend _CONSTEXPR20 _Vb_iterator operator+(const difference_type _Off, _Vb_iterator _Right) noexcept { _Right += _Off; return _Right; } diff --git a/stl/inc/xatomic_wait.h b/stl/inc/xatomic_wait.h index 178f91fa9e8..5058335d974 100644 --- a/stl/inc/xatomic_wait.h +++ b/stl/inc/xatomic_wait.h @@ -21,23 +21,9 @@ _STL_DISABLE_CLANG_WARNINGS extern "C" { inline constexpr unsigned long __std_atomic_wait_no_timeout = 0xFFFF'FFFF; // Pass as partial timeout -enum class __std_atomic_api_level : unsigned long { - __not_set, - __detecting, - __has_srwlock, - __has_wait_on_address, -}; - -// This function allows testing the atomic wait support while always using the APIs for a platform with fewer -// capabilities; it attempts to lock the APIs used to the level `_Requested_api_level`, and returns the actual API level -// in use. Once the API level has been set by calling this function (or detected by a call to one of the atomic wait -// functions), it can no longer be changed. -__std_atomic_api_level __stdcall __std_atomic_set_api_level(__std_atomic_api_level _Requested_api_level) noexcept; - // Support for atomic waits. // The "direct" functions are used when the underlying infrastructure can use WaitOnAddress directly; that is, _Size is -// 1, 2, 4, or 8. The contract is the same as the WaitOnAddress function from the Windows SDK. If WaitOnAddress is not -// available on the current platform, falls back to a similar solution based on SRWLOCK and CONDITION_VARIABLE. +// 1, 2, 4, or 8. The contract is the same as the WaitOnAddress function from the Windows SDK. int __stdcall __std_atomic_wait_direct( const void* _Storage, void* _Comparand, size_t _Size, unsigned long _Remaining_timeout) noexcept; void __stdcall __std_atomic_notify_one_direct(const void* _Storage) noexcept; diff --git a/stl/inc/xcharconv.h b/stl/inc/xcharconv.h index 07f6c2f8752..7140f489ca1 100644 --- a/stl/inc/xcharconv.h +++ b/stl/inc/xcharconv.h @@ -37,7 +37,7 @@ _EXPORT_STD struct to_chars_result { char* ptr; errc ec; #if _HAS_CXX20 - _NODISCARD_FRIEND bool operator==(const to_chars_result&, const to_chars_result&) = default; + _NODISCARD friend bool operator==(const to_chars_result&, const to_chars_result&) = default; #endif // _HAS_CXX20 }; diff --git a/stl/inc/xhash b/stl/inc/xhash index 20f884eefa0..dfa0cf3f2b8 100644 --- a/stl/inc/xhash +++ b/stl/inc/xhash @@ -93,17 +93,22 @@ _STD_END #endif // _SILENCE_STDEXT_HASH_DEPRECATION_WARNINGS _STD_BEGIN -template +template struct _Uhash_choose_transparency { // transparency selector for non-transparent hashed containers template using _Deduce_key = const _Kty&; + +#if _HAS_CXX20 && defined(__EDG__) // TRANSITION, DevCom-10678753 + template + static constexpr bool _Supports_transparency = false; +#endif // ^^^ workaround ^^^ }; #if _HAS_CXX20 template -struct _Uhash_choose_transparency<_Kty, _Hasher, _Keyeq, - enable_if_t, _Is_transparent<_Keyeq>>>> { + requires _Is_transparent_v<_Hasher> && _Is_transparent_v<_Keyeq> +struct _Uhash_choose_transparency<_Kty, _Hasher, _Keyeq> { // transparency selector for transparent hashed containers template using _Deduce_key = const _Keyty&; @@ -194,12 +199,12 @@ struct _Reinterpret_move_iter { // post ++ intentionally omitted - _NODISCARD_FRIEND bool operator==(const _Reinterpret_move_iter& _Lhs, const _Reinterpret_move_iter& _Rhs) { + _NODISCARD friend bool operator==(const _Reinterpret_move_iter& _Lhs, const _Reinterpret_move_iter& _Rhs) { return _Lhs._Base == _Rhs._Base; } #if !_HAS_CXX20 - _NODISCARD_FRIEND bool operator!=(const _Reinterpret_move_iter& _Lhs, const _Reinterpret_move_iter& _Rhs) { + _NODISCARD friend bool operator!=(const _Reinterpret_move_iter& _Lhs, const _Reinterpret_move_iter& _Rhs) { return _Lhs._Base != _Rhs._Base; } #endif // !_HAS_CXX20 @@ -1137,8 +1142,8 @@ public: } #if _HAS_CXX23 - template , int> = 0> + template + requires (_Traits::template _Supports_transparency<_Hash, _Kx>) size_type erase(_Kx&& _Keyval) noexcept(noexcept(_Erase(_Keyval))) /* strengthened */ { return _Erase(_Keyval); } @@ -1347,8 +1352,8 @@ public: } #if _HAS_CXX23 - template , int> = 0> + template + requires (_Traits::template _Supports_transparency<_Hash, _Kx>) node_type extract(_Kx&& _Keyval) { const auto _Ptr = _Extract(_Keyval); if (!_Ptr) { @@ -1967,9 +1972,17 @@ protected: }; #if _HAS_CXX17 -// For constraining deduction guides (N4950 [unord.req.general]/243.3) +// For constraining deduction guides (N4981 [unord.req.general]/248.3) +#if _HAS_CXX23 +template +concept _Hasher_for_container = !integral<_Hasher> && !_Allocator_for_container<_Hasher>; + +template +using _Is_hasher = bool_constant<_Hasher_for_container<_Hasher>>; +#else // ^^^ _HAS_CXX23 / !_HAS_CXX23 vvv template using _Is_hasher = negation, _Is_allocator<_Hasher>>>; +#endif // ^^^ !_HAS_CXX23 ^^^ #endif // _HAS_CXX17 template diff --git a/stl/inc/xpolymorphic_allocator.h b/stl/inc/xpolymorphic_allocator.h index 0903ce5863f..ea0825c7c9f 100644 --- a/stl/inc/xpolymorphic_allocator.h +++ b/stl/inc/xpolymorphic_allocator.h @@ -310,13 +310,13 @@ namespace pmr { return _Resource; } - _NODISCARD_FRIEND bool operator==( + _NODISCARD friend bool operator==( const polymorphic_allocator& _Lhs, const polymorphic_allocator& _Rhs) noexcept { return *_Lhs._Resource == *_Rhs._Resource; } #if !_HAS_CXX20 - _NODISCARD_FRIEND bool operator!=( + _NODISCARD friend bool operator!=( const polymorphic_allocator& _Lhs, const polymorphic_allocator& _Rhs) noexcept { return *_Lhs._Resource != *_Rhs._Resource; } diff --git a/stl/inc/xstring b/stl/inc/xstring index b048c1f2f41..7b458d16c5b 100644 --- a/stl/inc/xstring +++ b/stl/inc/xstring @@ -141,7 +141,7 @@ public: return _Tmp; } - _NODISCARD_FRIEND _CONSTEXPR20 _String_const_iterator operator+( + _NODISCARD friend _CONSTEXPR20 _String_const_iterator operator+( const difference_type _Off, _String_const_iterator _Next) noexcept { _Next += _Off; return _Next; @@ -318,7 +318,7 @@ public: return _Tmp; } - _NODISCARD_FRIEND _CONSTEXPR20 _String_iterator operator+( + _NODISCARD friend _CONSTEXPR20 _String_iterator operator+( const difference_type _Off, _String_iterator _Next) noexcept { _Next += _Off; return _Next; @@ -3106,8 +3106,7 @@ basic_string(basic_string_view<_Elem, _Traits>, _Guide_size_type_t<_Alloc>, _Gui const _Alloc& = _Alloc()) -> basic_string<_Elem, _Traits, _Alloc>; #if _HAS_CXX23 -template <_RANGES input_range _Rng, class _Alloc = allocator<_RANGES range_value_t<_Rng>>, - enable_if_t<_Is_allocator<_Alloc>::value, int> = 0> +template <_RANGES input_range _Rng, _Allocator_for_container _Alloc = allocator<_RANGES range_value_t<_Rng>>> basic_string(from_range_t, _Rng&&, _Alloc = _Alloc()) -> basic_string<_RANGES range_value_t<_Rng>, char_traits<_RANGES range_value_t<_Rng>>, _Alloc>; #endif // _HAS_CXX23 diff --git a/stl/inc/xtree b/stl/inc/xtree index 5d970ede45d..42c10a95341 100644 --- a/stl/inc/xtree +++ b/stl/inc/xtree @@ -433,6 +433,20 @@ public: using _Unchecked_const_iterator = _Tree_unchecked_const_iterator<_Tree_val>; using const_iterator = _Tree_const_iterator<_Tree_val>; + template + struct _NODISCARD _Erase_tree_and_orphan_guard { + _Tree_val* _Val_ptr; + _AllocNode& _Al; + _Nodeptr _New_root; + + _Erase_tree_and_orphan_guard& operator=(const _Erase_tree_and_orphan_guard&) = delete; + ~_Erase_tree_and_orphan_guard() noexcept { + if (_Val_ptr != nullptr) { + _Val_ptr->_Erase_tree_and_orphan(_Al, _New_root); // subtree copy failed, bail out + } + } + }; + _Tree_val() noexcept : _Myhead(), _Mysize(0) {} enum _Redbl { // colors for link to parent @@ -1335,10 +1349,9 @@ public: } #if _HAS_CXX23 - template , - negation, is_convertible<_Kx, iterator>>>>, - int> = 0> + template + requires _Is_transparent_v + && (!is_convertible_v<_Kx, const_iterator>) && (!is_convertible_v<_Kx, iterator>) size_type erase(_Kx&& _Keyval) noexcept(noexcept(_Eqrange(_Keyval))) /* strengthened */ { return _Erase(_Eqrange(_Keyval)); } @@ -1390,7 +1403,8 @@ public: return _Lower_bound_duplicate(_Find_lower_bound(_Keyval)._Bound, _Keyval); } - template , int> = 0> + template + requires _Is_transparent_v _NODISCARD bool contains(const _Other& _Keyval) const { return _Lower_bound_duplicate(_Find_lower_bound(_Keyval)._Bound, _Keyval); } @@ -1661,20 +1675,16 @@ protected: _Nodeptr _Newroot = _Scary->_Myhead; // point at nil node if (!_Rootnode->_Isnil) { // copy or move a node, then any subtrees - _Nodeptr _Pnode = _Copy_or_move<_Strat>(_Rootnode->_Myval); - _Pnode->_Parent = _Wherenode; - _Pnode->_Color = _Rootnode->_Color; - if (_Newroot->_Isnil) { - _Newroot = _Pnode; // memorize new root - } + _Newroot = _Copy_or_move<_Strat>(_Rootnode->_Myval); // memorize new root + _Newroot->_Parent = _Wherenode; + _Newroot->_Color = _Rootnode->_Color; + + typename _Scary_val::template _Erase_tree_and_orphan_guard<_Alnode> _Guard{_Scary, _Getal(), _Newroot}; + + _Newroot->_Left = _Copy_nodes<_Strat>(_Rootnode->_Left, _Newroot); + _Newroot->_Right = _Copy_nodes<_Strat>(_Rootnode->_Right, _Newroot); - _TRY_BEGIN - _Pnode->_Left = _Copy_nodes<_Strat>(_Rootnode->_Left, _Pnode); - _Pnode->_Right = _Copy_nodes<_Strat>(_Rootnode->_Right, _Pnode); - _CATCH_ALL - _Scary->_Erase_tree_and_orphan(_Getal(), _Newroot); // subtree copy failed, bail out - _RERAISE; - _CATCH_END + _Guard._Val_ptr = nullptr; } return _Newroot; // return newly constructed tree @@ -1743,10 +1753,9 @@ public: } #if _HAS_CXX23 - template , - negation, is_convertible<_Kx, iterator>>>>, - int> = 0> + template + requires _Is_transparent_v + && (!is_convertible_v<_Kx, const_iterator>) && (!is_convertible_v<_Kx, iterator>) node_type extract(_Kx&& _Keyval) { const const_iterator _Where = find(_Keyval); if (_Where == end()) { diff --git a/stl/inc/xutility b/stl/inc/xutility index ee83e903b9e..fbed6751ec2 100644 --- a/stl/inc/xutility +++ b/stl/inc/xutility @@ -960,31 +960,28 @@ concept contiguous_iterator = random_access_iterator<_It> // clang-format on _EXPORT_STD template -concept indirectly_unary_invocable = - indirectly_readable<_It> && copy_constructible<_Fn> && invocable<_Fn&, _Indirect_value_t<_It>> - && invocable<_Fn&, iter_reference_t<_It>> && invocable<_Fn&, iter_common_reference_t<_It>> - && common_reference_with>, - invoke_result_t<_Fn&, iter_reference_t<_It>>>; +concept indirectly_unary_invocable = indirectly_readable<_It> && copy_constructible<_Fn> + && invocable<_Fn&, _Indirect_value_t<_It>> && invocable<_Fn&, iter_reference_t<_It>> + && common_reference_with>, + invoke_result_t<_Fn&, iter_reference_t<_It>>>; _EXPORT_STD template concept indirectly_regular_unary_invocable = indirectly_readable<_It> && copy_constructible<_Fn> && regular_invocable<_Fn&, _Indirect_value_t<_It>> - && regular_invocable<_Fn&, iter_reference_t<_It>> && regular_invocable<_Fn&, iter_common_reference_t<_It>> + && regular_invocable<_Fn&, iter_reference_t<_It>> && common_reference_with>, invoke_result_t<_Fn&, iter_reference_t<_It>>>; _EXPORT_STD template -concept indirect_unary_predicate = - indirectly_readable<_It> && copy_constructible<_Fn> && predicate<_Fn&, _Indirect_value_t<_It>> - && predicate<_Fn&, iter_reference_t<_It>> && predicate<_Fn&, iter_common_reference_t<_It>>; +concept indirect_unary_predicate = indirectly_readable<_It> && copy_constructible<_Fn> + && predicate<_Fn&, _Indirect_value_t<_It>> && predicate<_Fn&, iter_reference_t<_It>>; _EXPORT_STD template concept indirect_binary_predicate = indirectly_readable<_It1> && indirectly_readable<_It2> && copy_constructible<_Fn> && predicate<_Fn&, _Indirect_value_t<_It1>, _Indirect_value_t<_It2>> && predicate<_Fn&, _Indirect_value_t<_It1>, iter_reference_t<_It2>> && predicate<_Fn&, iter_reference_t<_It1>, _Indirect_value_t<_It2>> - && predicate<_Fn&, iter_reference_t<_It1>, iter_reference_t<_It2>> - && predicate<_Fn&, iter_common_reference_t<_It1>, iter_common_reference_t<_It2>>; + && predicate<_Fn&, iter_reference_t<_It1>, iter_reference_t<_It2>>; _EXPORT_STD template concept indirect_equivalence_relation = @@ -992,17 +989,14 @@ concept indirect_equivalence_relation = && equivalence_relation<_Fn&, _Indirect_value_t<_It1>, _Indirect_value_t<_It2>> && equivalence_relation<_Fn&, _Indirect_value_t<_It1>, iter_reference_t<_It2>> && equivalence_relation<_Fn&, iter_reference_t<_It1>, _Indirect_value_t<_It2>> - && equivalence_relation<_Fn&, iter_reference_t<_It1>, iter_reference_t<_It2>> - && equivalence_relation<_Fn&, iter_common_reference_t<_It1>, iter_common_reference_t<_It2>>; + && equivalence_relation<_Fn&, iter_reference_t<_It1>, iter_reference_t<_It2>>; _EXPORT_STD template -concept indirect_strict_weak_order = - indirectly_readable<_It1> && indirectly_readable<_It2> && copy_constructible<_Fn> - && strict_weak_order<_Fn&, _Indirect_value_t<_It1>, _Indirect_value_t<_It2>> - && strict_weak_order<_Fn&, _Indirect_value_t<_It1>, iter_reference_t<_It2>> - && strict_weak_order<_Fn&, iter_reference_t<_It1>, _Indirect_value_t<_It2>> - && strict_weak_order<_Fn&, iter_reference_t<_It1>, iter_reference_t<_It2>> - && strict_weak_order<_Fn&, iter_common_reference_t<_It1>, iter_common_reference_t<_It2>>; +concept indirect_strict_weak_order = indirectly_readable<_It1> && indirectly_readable<_It2> && copy_constructible<_Fn> + && strict_weak_order<_Fn&, _Indirect_value_t<_It1>, _Indirect_value_t<_It2>> + && strict_weak_order<_Fn&, _Indirect_value_t<_It1>, iter_reference_t<_It2>> + && strict_weak_order<_Fn&, iter_reference_t<_It1>, _Indirect_value_t<_It2>> + && strict_weak_order<_Fn&, iter_reference_t<_It1>, iter_reference_t<_It2>>; _EXPORT_STD template requires (indirectly_readable<_Its> && ...) && invocable<_Fn, iter_reference_t<_Its>...> @@ -1205,6 +1199,16 @@ using _Common_diff_t = common_type_t<_Iter_diff_t<_Iters>...>; template using _Iter_cat_t = typename iterator_traits<_Iter>::iterator_category; +#if _HAS_CXX20 +template +concept _Iterator_for_container = requires { typename _Iter_cat_t<_Ty>; }; + +template +constexpr bool _Is_iterator_v = _Iterator_for_container<_Ty>; + +template +struct _Is_iterator : bool_constant<_Iterator_for_container<_Ty>> {}; +#else // ^^^ _HAS_CXX20 / !_HAS_CXX20 vvv template constexpr bool _Is_iterator_v = false; @@ -1213,6 +1217,7 @@ constexpr bool _Is_iterator_v<_Ty, void_t<_Iter_cat_t<_Ty>>> = true; template struct _Is_iterator : bool_constant<_Is_iterator_v<_Ty>> {}; +#endif // ^^^ !_HAS_CXX20 ^^^ template constexpr bool _Is_cpp17_input_iter_v = is_convertible_v<_Iter_cat_t<_Iter>, input_iterator_tag>; @@ -1423,6 +1428,17 @@ constexpr void _Seek_wrapped(_Iter& _It, _UIter&& _UIt) { } #if _HAS_CXX17 +#if _HAS_CXX20 +// detects whether _Ty resembles an allocator, N4981 [container.reqmts]/69 +template +concept _Allocator_for_container = requires(_Ty& _Alloc) { + typename _Ty::value_type; + _Alloc.deallocate(_Alloc.allocate(size_t{1}), size_t{1}); +}; + +template +struct _Is_allocator : bool_constant<_Allocator_for_container<_Ty>> {}; +#else // ^^^ _HAS_CXX20 / !_HAS_CXX20 vvv template struct _Is_allocator : false_type {}; // selected when _Ty can't possibly be an allocator @@ -1430,6 +1446,7 @@ template struct _Is_allocator<_Ty, void_t().deallocate( _STD declval<_Ty&>().allocate(size_t{1}), size_t{1}))>> : true_type {}; // selected when _Ty resembles an allocator, N4950 [container.reqmts]/69 +#endif // ^^^ !_HAS_CXX20 ^^^ // deduction guide utilities (N4950 [associative.general]/2) template @@ -1760,7 +1777,7 @@ public: } #if _HAS_CXX20 - _NODISCARD_FRIEND constexpr iter_rvalue_reference_t<_BidIt> iter_move(const reverse_iterator& _It) noexcept( + _NODISCARD friend constexpr iter_rvalue_reference_t<_BidIt> iter_move(const reverse_iterator& _It) noexcept( is_nothrow_copy_constructible_v<_BidIt> // && noexcept(_RANGES iter_move(--_STD declval<_BidIt&>()))) { auto _Tmp = _It.current; @@ -2363,47 +2380,47 @@ public: template <_Not_a_const_iterator _Other> requires random_access_iterator<_Iter> && totally_ordered_with<_Iter, _Other> - _NODISCARD_FRIEND constexpr bool operator<(const _Other& _Left, const basic_const_iterator& _Right) noexcept( + _NODISCARD friend constexpr bool operator<(const _Other& _Left, const basic_const_iterator& _Right) noexcept( noexcept(_STD _Fake_copy_init(_Left < _Right._Current))) /* strengthened */ { return _Left < _Right._Current; } template <_Not_a_const_iterator _Other> requires random_access_iterator<_Iter> && totally_ordered_with<_Iter, _Other> - _NODISCARD_FRIEND constexpr bool operator>(const _Other& _Left, const basic_const_iterator& _Right) noexcept( + _NODISCARD friend constexpr bool operator>(const _Other& _Left, const basic_const_iterator& _Right) noexcept( noexcept(_STD _Fake_copy_init(_Left > _Right._Current))) /* strengthened */ { return _Left > _Right._Current; } template <_Not_a_const_iterator _Other> requires random_access_iterator<_Iter> && totally_ordered_with<_Iter, _Other> - _NODISCARD_FRIEND constexpr bool operator<=(const _Other& _Left, const basic_const_iterator& _Right) noexcept( + _NODISCARD friend constexpr bool operator<=(const _Other& _Left, const basic_const_iterator& _Right) noexcept( noexcept(_STD _Fake_copy_init(_Left <= _Right._Current))) /* strengthened */ { return _Left <= _Right._Current; } template <_Not_a_const_iterator _Other> requires random_access_iterator<_Iter> && totally_ordered_with<_Iter, _Other> - _NODISCARD_FRIEND constexpr bool operator>=(const _Other& _Left, const basic_const_iterator& _Right) noexcept( + _NODISCARD friend constexpr bool operator>=(const _Other& _Left, const basic_const_iterator& _Right) noexcept( noexcept(_STD _Fake_copy_init(_Left >= _Right._Current))) /* strengthened */ { return _Left >= _Right._Current; } - _NODISCARD_FRIEND constexpr basic_const_iterator operator+(const basic_const_iterator& _It, + _NODISCARD friend constexpr basic_const_iterator operator+(const basic_const_iterator& _It, const difference_type _Off) noexcept(noexcept(basic_const_iterator{_It._Current + _Off})) // strengthened requires random_access_iterator<_Iter> { return basic_const_iterator{_It._Current + _Off}; } - _NODISCARD_FRIEND constexpr basic_const_iterator operator+(const difference_type _Off, + _NODISCARD friend constexpr basic_const_iterator operator+(const difference_type _Off, const basic_const_iterator& _It) noexcept(noexcept(basic_const_iterator{_It._Current + _Off})) // strengthened requires random_access_iterator<_Iter> { return basic_const_iterator{_It._Current + _Off}; } - _NODISCARD_FRIEND constexpr basic_const_iterator operator-(const basic_const_iterator& _It, + _NODISCARD friend constexpr basic_const_iterator operator-(const basic_const_iterator& _It, const difference_type _Off) noexcept(noexcept(basic_const_iterator{_It._Current - _Off})) // strengthened requires random_access_iterator<_Iter> { @@ -2418,12 +2435,12 @@ public: template <_Not_a_const_iterator _Sent> requires sized_sentinel_for<_Sent, _Iter> - _NODISCARD_FRIEND constexpr difference_type operator-(const _Sent& _Se, const basic_const_iterator& _It) noexcept( + _NODISCARD friend constexpr difference_type operator-(const _Sent& _Se, const basic_const_iterator& _It) noexcept( noexcept(_Se - _It._Current)) /* strengthened */ { return _Se - _It._Current; } - _NODISCARD_FRIEND constexpr _Rvalue_reference iter_move(const basic_const_iterator& _It) noexcept( + _NODISCARD friend constexpr _Rvalue_reference iter_move(const basic_const_iterator& _It) noexcept( noexcept(static_cast<_Rvalue_reference>(_RANGES iter_move(_It._Current)))) { return static_cast<_Rvalue_reference>(_RANGES iter_move(_It._Current)); } @@ -4290,25 +4307,25 @@ public: #if _HAS_CXX20 template _Sent> - _NODISCARD_FRIEND constexpr bool + _NODISCARD friend constexpr bool operator==(const move_iterator& _Left, const move_sentinel<_Sent>& _Right) noexcept( noexcept(_STD _Fake_copy_init(_Left._Current == _Right._Get_last()))) /* strengthened */ { return _Left._Current == _Right._Get_last(); } template _Sent> - _NODISCARD_FRIEND constexpr difference_type operator-(const move_sentinel<_Sent>& _Left, + _NODISCARD friend constexpr difference_type operator-(const move_sentinel<_Sent>& _Left, const move_iterator& _Right) noexcept(noexcept(_Left._Get_last() - _Right._Current)) /* strengthened */ { return _Left._Get_last() - _Right._Current; } template _Sent> - _NODISCARD_FRIEND constexpr difference_type operator-(const move_iterator& _Left, + _NODISCARD friend constexpr difference_type operator-(const move_iterator& _Left, const move_sentinel<_Sent>& _Right) noexcept(noexcept(_Left._Current - _Right._Get_last())) /* strengthened */ { return _Left._Current - _Right._Get_last(); } - _NODISCARD_FRIEND constexpr reference iter_move(const move_iterator& _It) noexcept( + _NODISCARD friend constexpr reference iter_move(const move_iterator& _It) noexcept( noexcept(_RANGES iter_move(_It._Current))) { return _RANGES iter_move(_It._Current); } @@ -4477,7 +4494,7 @@ _EXPORT_STD struct unreachable_sentinel_t; namespace _Unreachable_sentinel_detail { struct _Base { template - _NODISCARD_FRIEND constexpr bool operator==(const unreachable_sentinel_t&, const _Winc&) noexcept { + _NODISCARD friend constexpr bool operator==(const unreachable_sentinel_t&, const _Winc&) noexcept { return false; } }; @@ -5358,15 +5375,6 @@ template constexpr bool _Equal_memcmp_is_safe = _Equal_memcmp_is_safe_helper, remove_const_t<_Iter2>, remove_const_t<_Pr>>; -template -_NODISCARD int _Memcmp_ranges(_CtgIt1 _First1, _CtgIt1 _Last1, _CtgIt2 _First2) { - _STL_INTERNAL_STATIC_ASSERT(sizeof(_Iter_value_t<_CtgIt1>) == sizeof(_Iter_value_t<_CtgIt2>)); - const auto _First1_ch = reinterpret_cast(_STD _To_address(_First1)); - const auto _Last1_ch = reinterpret_cast(_STD _To_address(_Last1)); - const auto _First2_ch = reinterpret_cast(_STD _To_address(_First2)); - return _CSTD memcmp(_First1_ch, _First2_ch, static_cast(_Last1_ch - _First1_ch)); -} - template _NODISCARD int _Memcmp_count(_CtgIt1 _First1, _CtgIt2 _First2, const size_t _Count) { _STL_INTERNAL_STATIC_ASSERT(sizeof(_Iter_value_t<_CtgIt1>) == sizeof(_Iter_value_t<_CtgIt2>)); @@ -5387,7 +5395,11 @@ _NODISCARD _CONSTEXPR20 bool equal(const _InIt1 _First1, const _InIt1 _Last1, co if (!_STD is_constant_evaluated()) #endif // _HAS_CXX20 { - return _STD _Memcmp_ranges(_UFirst1, _ULast1, _UFirst2) == 0; + _STL_INTERNAL_STATIC_ASSERT( + sizeof(_Iter_value_t) == sizeof(_Iter_value_t)); + const auto _First1_ch = reinterpret_cast(_STD _To_address(_UFirst1)); + const auto _Size = reinterpret_cast(_STD _To_address(_ULast1)) - _First1_ch; + return _CSTD memcmp(_First1_ch, _STD _To_address(_UFirst2), static_cast(_Size)) == 0; } } @@ -6987,7 +6999,7 @@ namespace ranges { } } #endif // _USE_STD_VECTOR_ALGORITHMS - if constexpr (forward_range<_Rng> && _Prefer_iterator_copies>) { + if constexpr (forward_range<_Rng> && _Prefer_iterator_copies) { return static_cast>(*_RANGES _Max_element_unchecked( _STD move(_UFirst), _STD move(_ULast), _STD _Pass_fn(_Pred), _STD _Pass_fn(_Proj))); } else { @@ -7205,7 +7217,7 @@ namespace ranges { } } #endif // _USE_STD_VECTOR_ALGORITHMS - if constexpr (forward_range<_Rng> && _Prefer_iterator_copies>) { + if constexpr (forward_range<_Rng> && _Prefer_iterator_copies) { return static_cast>(*_RANGES _Min_element_unchecked( _STD move(_UFirst), _STD move(_ULast), _STD _Pass_fn(_Pred), _STD _Pass_fn(_Proj))); } else { @@ -7349,16 +7361,25 @@ _NODISCARD constexpr bool _Add_overflow(const _Int _Left, const _Int _Right, _In } } } +#endif // _HAS_CXX23 +#if _HAS_CXX17 +#if _HAS_CXX20 template <_Integer_like _Int> +#else // ^^^ _HAS_CXX20 / !_HAS_CXX20 vvv +template , int> = 0> +#endif // ^^^ !_HAS_CXX20 ^^^ _NODISCARD constexpr bool _Mul_overflow(const _Int _Left, const _Int _Right, _Int& _Out) { +#if defined(__clang__) && !_HAS_CXX20 + return __builtin_mul_overflow(_Left, _Right, &_Out); +#else // ^^^ defined(__clang__) && !_HAS_CXX20 / !defined(__clang__) || _HAS_CXX20 vvv #ifdef __clang__ - if constexpr (integral<_Int>) { + if constexpr (is_integral_v<_Int>) { return __builtin_mul_overflow(_Left, _Right, &_Out); } else #endif // defined(__clang__) { - if constexpr (!_Signed_integer_like<_Int>) { + if constexpr (static_cast<_Int>(-1) > static_cast<_Int>(0)) { constexpr auto _UInt_max = _STD _Max_limit<_Int>(); const bool _Overflow = _Left != 0 && _Right > _UInt_max / _Left; if (!_Overflow) { @@ -7397,8 +7418,9 @@ _NODISCARD constexpr bool _Mul_overflow(const _Int _Left, const _Int _Right, _In // ^^^ Based on llvm::MulOverflow ^^^ } } +#endif // ^^^ !defined(__clang__) || _HAS_CXX20 ^^^ } -#endif // _HAS_CXX23 +#endif // _HAS_CXX17 _STD_END diff --git a/stl/inc/yvals.h b/stl/inc/yvals.h index d2201390f57..33ac7c51203 100644 --- a/stl/inc/yvals.h +++ b/stl/inc/yvals.h @@ -315,22 +315,6 @@ _EMIT_STL_WARNING(STL4001, "/clr:pure is deprecated and will be REMOVED."); #define _LOCK_STREAM 2 #define _LOCK_DEBUG 3 -#ifndef _STD_ATOMIC_ALWAYS_USE_CMPXCHG16B -#if _STL_WIN32_WINNT >= _STL_WIN32_WINNT_WINBLUE && defined(_WIN64) -#define _STD_ATOMIC_ALWAYS_USE_CMPXCHG16B 1 -#else // ^^^ modern 64-bit / less modern or 32-bit vvv -#define _STD_ATOMIC_ALWAYS_USE_CMPXCHG16B 0 -#endif // _STL_WIN32_WINNT >= _STL_WIN32_WINNT_WINBLUE && defined(_WIN64) -#endif // !defined(_STD_ATOMIC_ALWAYS_USE_CMPXCHG16B) - -#if _STD_ATOMIC_ALWAYS_USE_CMPXCHG16B == 0 && defined(_M_ARM64) -#error ARM64 requires _STD_ATOMIC_ALWAYS_USE_CMPXCHG16B to be 1. -#endif // _STD_ATOMIC_ALWAYS_USE_CMPXCHG16B == 0 && defined(_M_ARM64) - -#if _STD_ATOMIC_ALWAYS_USE_CMPXCHG16B == 1 && !defined(_WIN64) -#error _STD_ATOMIC_ALWAYS_USE_CMPXCHG16B == 1 requires 64-bit. -#endif // _STD_ATOMIC_ALWAYS_USE_CMPXCHG16B == 1 && !defined(_WIN64) - _STD_BEGIN enum _Uninitialized { // tag for suppressing initialization _Noinit diff --git a/stl/inc/yvals_core.h b/stl/inc/yvals_core.h index 29793d7eefc..8daa211d4cc 100644 --- a/stl/inc/yvals_core.h +++ b/stl/inc/yvals_core.h @@ -62,6 +62,7 @@ // P0883R2 Fixing Atomic Initialization // P0935R0 Eradicating Unnecessarily Explicit Default Constructors // P0941R2 Feature-Test Macros +// P0952R2 A New Specification For generate_canonical() // P0972R0 noexcept For zero(), min(), max() // P1065R2 constexpr INVOKE // (the std::invoke function only; other components like bind and reference_wrapper are C++20 only) @@ -75,7 +76,10 @@ // P2338R4 Freestanding Library: Character Primitives And The C Library // (except for __cpp_lib_freestanding_charconv) // P2401R0 Conditional noexcept For exchange() +// P2407R5 Freestanding Library: Partial Classes +// (__cpp_lib_freestanding_algorithm and __cpp_lib_freestanding_array only) // P2937R0 Freestanding Library: Remove strtok +// P2968R2 Make std::ignore A First-Class Object // _HAS_CXX17 directly controls: // P0005R4 not_fn() @@ -132,6 +136,9 @@ // (basic_string_view always provides this behavior) // P2338R4 Freestanding Library: Character Primitives And The C Library // (including __cpp_lib_freestanding_charconv) +// P2407R5 Freestanding Library: Partial Classes +// (including __cpp_lib_freestanding_optional, __cpp_lib_freestanding_string_view, and +// __cpp_lib_freestanding_variant) // P2517R1 Conditional noexcept For apply() // P2875R4 Undeprecate polymorphic_allocator::destroy @@ -306,6 +313,7 @@ // P2770R0 Stashing Stashing Iterators For Proper Flattening // P2905R2 Runtime Format Strings // P2909R4 Fix Formatting Of Code Units As Integers +// P2997R1 Removing The Common Reference Requirement From The Indirectly Invocable Concepts // _HAS_CXX20 indirectly controls: // P0619R4 Removing C++17-Deprecated Features @@ -384,6 +392,8 @@ // P2693R1 Formatting thread::id And stacktrace // P2713R1 Escaping Improvements In std::format // P2763R1 Fixing layout_stride's Default Constructor For Fully Static Extents +// P2833R2 Freestanding Library: inout expected span +// (except for __cpp_lib_span which also covers C++26 span::at) // P2836R1 basic_const_iterator Should Follow Its Underlying Type's Convertibility // P3142R0 Printing Blank Lines With println() @@ -584,12 +594,6 @@ #define _NODISCARD_CTOR_MSG(_Msg) #endif // ^^^ defined(__has_cpp_attribute) && __has_cpp_attribute(nodiscard) < 201907L ^^^ -#if defined(__CUDACC__) && !defined(__clang__) // TRANSITION, VSO-568006 -#define _NODISCARD_FRIEND friend -#else // ^^^ workaround / no workaround vvv -#define _NODISCARD_FRIEND _NODISCARD friend -#endif // ^^^ no workaround ^^^ - #define _NODISCARD_REMOVE_ALG \ _NODISCARD_MSG("The 'remove' and 'remove_if' algorithms return the iterator past the last element " \ "that should be kept. You need to call container.erase(result, container.end()) afterwards. " \ @@ -881,7 +885,7 @@ #define _CPPLIB_VER 650 #define _MSVC_STL_VERSION 143 -#define _MSVC_STL_UPDATE 202406L +#define _MSVC_STL_UPDATE 202407L #ifndef _ALLOW_COMPILER_AND_STL_VERSION_MISMATCH #if defined(__CUDACC__) && defined(__CUDACC_VER_MAJOR__) @@ -895,8 +899,8 @@ _EMIT_STL_ERROR(STL1002, "Unexpected compiler version, expected CUDA 12.4 or new _EMIT_STL_ERROR(STL1000, "Unexpected compiler version, expected Clang 17.0.0 or newer."); #endif // ^^^ old Clang ^^^ #elif defined(_MSC_VER) -#if _MSC_VER < 1940 // Coarse-grained, not inspecting _MSC_FULL_VER -_EMIT_STL_ERROR(STL1001, "Unexpected compiler version, expected MSVC 19.40 or newer."); +#if _MSC_VER < 1941 // Coarse-grained, not inspecting _MSC_FULL_VER +_EMIT_STL_ERROR(STL1001, "Unexpected compiler version, expected MSVC 19.41 or newer."); #endif // ^^^ old MSVC ^^^ #else // vvv other compilers vvv // not attempting to detect other compilers @@ -1563,6 +1567,8 @@ _EMIT_STL_ERROR(STL1004, "C++98 unexpected() is incompatible with C++23 unexpect #define __cpp_lib_chrono_udls 201304L #define __cpp_lib_complex_udls 201309L #define __cpp_lib_exchange_function 201304L +#define __cpp_lib_freestanding_algorithm 202311L +#define __cpp_lib_freestanding_array 202311L #define __cpp_lib_freestanding_char_traits 202306L #define __cpp_lib_freestanding_cstdlib 202306L #define __cpp_lib_freestanding_cstring 202311L @@ -1626,6 +1632,9 @@ _EMIT_STL_ERROR(STL1004, "C++98 unexpected() is incompatible with C++23 unexpect #define __cpp_lib_clamp 201603L #define __cpp_lib_filesystem 201703L #define __cpp_lib_freestanding_charconv 202306L +#define __cpp_lib_freestanding_optional 202311L +#define __cpp_lib_freestanding_string_view 202311L +#define __cpp_lib_freestanding_variant 202311L #define __cpp_lib_gcd_lcm 201606L #define __cpp_lib_hardware_interference_size 201703L #define __cpp_lib_has_unique_object_representations 201606L @@ -1750,13 +1759,15 @@ _EMIT_STL_ERROR(STL1004, "C++98 unexpected() is incompatible with C++23 unexpect #define __cpp_lib_expected 202211L #define __cpp_lib_formatters 202302L #define __cpp_lib_forward_like 202207L +#define __cpp_lib_freestanding_expected 202311L +#define __cpp_lib_freestanding_mdspan 202311L #define __cpp_lib_generator 202207L #define __cpp_lib_invoke_r 202106L #define __cpp_lib_ios_noreplace 202207L #define __cpp_lib_is_scoped_enum 202011L #define __cpp_lib_mdspan 202207L #define __cpp_lib_move_only_function 202110L -#define __cpp_lib_out_ptr 202106L +#define __cpp_lib_out_ptr 202311L #define __cpp_lib_print 202207L #define __cpp_lib_ranges_as_const 202311L #define __cpp_lib_ranges_as_rvalue 202207L @@ -1829,7 +1840,8 @@ _EMIT_STL_ERROR(STL1004, "C++98 unexpected() is incompatible with C++23 unexpect #endif #if _HAS_CXX23 -#define __cpp_lib_ranges 202302L // P2609R3 Relaxing Ranges Just A Smidge +// P2997R1 Removing The Common Reference Requirement From The Indirectly Invocable Concepts +#define __cpp_lib_ranges 202406L #elif _HAS_CXX20 #define __cpp_lib_ranges 202110L // P2415R2 What Is A view? #endif @@ -1928,24 +1940,19 @@ compiler option, or define _ALLOW_RTCc_IN_STL to suppress this error. #error In yvals_core.h, defined(MRTDLL) implies defined(_M_CEE_PURE); !defined(_M_CEE_PURE) implies !defined(MRTDLL) #endif // defined(MRTDLL) && !defined(_M_CEE_PURE) -#define _STL_WIN32_WINNT_VISTA 0x0600 // _WIN32_WINNT_VISTA from sdkddkver.h -#define _STL_WIN32_WINNT_WIN7 0x0601 // _WIN32_WINNT_WIN7 from sdkddkver.h -#define _STL_WIN32_WINNT_WIN8 0x0602 // _WIN32_WINNT_WIN8 from sdkddkver.h -#define _STL_WIN32_WINNT_WINBLUE 0x0603 // _WIN32_WINNT_WINBLUE from sdkddkver.h -#define _STL_WIN32_WINNT_WIN10 0x0A00 // _WIN32_WINNT_WIN10 from sdkddkver.h +#define _STL_WIN32_WINNT_VISTA 0x0600 // _WIN32_WINNT_VISTA from sdkddkver.h +#define _STL_WIN32_WINNT_WIN8 0x0602 // _WIN32_WINNT_WIN8 from sdkddkver.h +#define _STL_WIN32_WINNT_WIN10 0x0A00 // _WIN32_WINNT_WIN10 from sdkddkver.h // Note that the STL DLL builds will set this to XP for ABI compatibility with VS2015 which supported XP. #ifndef _STL_WIN32_WINNT #if defined(_M_ARM64) // The first ARM64 Windows was Windows 10 #define _STL_WIN32_WINNT _STL_WIN32_WINNT_WIN10 -#elif defined(_M_ARM) || defined(_ONECORE) || defined(_CRT_APP) -// The first ARM or OneCore or App Windows was Windows 8 +#else // ^^^ defined(_M_ARM64) / !defined(_M_ARM64) vvv +// The earliest Windows supported by this implementation is Windows 8 #define _STL_WIN32_WINNT _STL_WIN32_WINNT_WIN8 -#else // ^^^ default to Win8 / default to Win7 vvv -// The earliest Windows supported by this implementation is Windows 7 -#define _STL_WIN32_WINNT _STL_WIN32_WINNT_WIN7 -#endif // ^^^ !defined(_M_ARM) && !defined(_M_ARM64) && !defined(_ONECORE) && !defined(_CRT_APP) ^^^ +#endif // ^^^ !defined(_M_ARM64) ^^^ #endif // !defined(_STL_WIN32_WINNT) #ifdef __cpp_noexcept_function_type diff --git a/stl/msbuild/stl_atomic_wait/msvcp_atomic_wait.settings.targets b/stl/msbuild/stl_atomic_wait/msvcp_atomic_wait.settings.targets index 869f8a1ecd2..0f29c995877 100644 --- a/stl/msbuild/stl_atomic_wait/msvcp_atomic_wait.settings.targets +++ b/stl/msbuild/stl_atomic_wait/msvcp_atomic_wait.settings.targets @@ -70,6 +70,7 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + diff --git a/stl/src/atomic_wait.cpp b/stl/src/atomic_wait.cpp index b45ed197403..4bafb1a86bb 100644 --- a/stl/src/atomic_wait.cpp +++ b/stl/src/atomic_wait.cpp @@ -5,11 +5,14 @@ #include #include +#include #include #include #include +#pragma comment(lib, "synchronization") + namespace { constexpr unsigned long long _Atomic_wait_no_deadline = 0xFFFF'FFFF'FFFF'FFFF; @@ -88,152 +91,13 @@ namespace { } #endif // defined(_DEBUG) } - -#ifndef _ATOMIC_WAIT_ON_ADDRESS_STATICALLY_AVAILABLE -#if _STL_WIN32_WINNT >= _STL_WIN32_WINNT_WIN8 -#define _ATOMIC_WAIT_ON_ADDRESS_STATICALLY_AVAILABLE 1 -#else // ^^^ _STL_WIN32_WINNT >= _STL_WIN32_WINNT_WIN8 / _STL_WIN32_WINNT < _STL_WIN32_WINNT_WIN8 vvv -#define _ATOMIC_WAIT_ON_ADDRESS_STATICALLY_AVAILABLE 0 -#endif // ^^^ _STL_WIN32_WINNT < _STL_WIN32_WINNT_WIN8 ^^^ -#endif // !defined(_ATOMIC_WAIT_ON_ADDRESS_STATICALLY_AVAILABLE) - -#if _ATOMIC_WAIT_ON_ADDRESS_STATICALLY_AVAILABLE - -#pragma comment(lib, "synchronization") - -#define __crtWaitOnAddress WaitOnAddress -#define __crtWakeByAddressSingle WakeByAddressSingle -#define __crtWakeByAddressAll WakeByAddressAll - -#else // ^^^ _ATOMIC_WAIT_ON_ADDRESS_STATICALLY_AVAILABLE / !_ATOMIC_WAIT_ON_ADDRESS_STATICALLY_AVAILABLE vvv - - struct _Wait_functions_table { - _STD atomic _Pfn_WaitOnAddress{nullptr}; - _STD atomic _Pfn_WakeByAddressSingle{nullptr}; - _STD atomic _Pfn_WakeByAddressAll{nullptr}; - _STD atomic<__std_atomic_api_level> _Api_level{__std_atomic_api_level::__not_set}; - }; - - _Wait_functions_table _Wait_functions; - - void _Force_wait_functions_srwlock_only() noexcept { - auto _Local = _Wait_functions._Api_level.load(_STD memory_order_acquire); - if (_Local <= __std_atomic_api_level::__detecting) { - while (!_Wait_functions._Api_level.compare_exchange_weak( - _Local, __std_atomic_api_level::__has_srwlock, _STD memory_order_acq_rel)) { - if (_Local > __std_atomic_api_level::__detecting) { - return; - } - } - } - } - - [[nodiscard]] __std_atomic_api_level _Init_wait_functions(__std_atomic_api_level _Level) { - while (!_Wait_functions._Api_level.compare_exchange_weak( - _Level, __std_atomic_api_level::__detecting, _STD memory_order_acq_rel)) { - if (_Level > __std_atomic_api_level::__detecting) { - return _Level; - } - } - - _Level = __std_atomic_api_level::__has_srwlock; - - const HMODULE _Sync_module = GetModuleHandleW(L"api-ms-win-core-synch-l1-2-0.dll"); - if (_Sync_module != nullptr) { - const auto _Wait_on_address = - reinterpret_cast(GetProcAddress(_Sync_module, "WaitOnAddress")); - const auto _Wake_by_address_single = - reinterpret_cast(GetProcAddress(_Sync_module, "WakeByAddressSingle")); - const auto _Wake_by_address_all = - reinterpret_cast(GetProcAddress(_Sync_module, "WakeByAddressAll")); - - if (_Wait_on_address != nullptr && _Wake_by_address_single != nullptr && _Wake_by_address_all != nullptr) { - _Wait_functions._Pfn_WaitOnAddress.store(_Wait_on_address, _STD memory_order_relaxed); - _Wait_functions._Pfn_WakeByAddressSingle.store(_Wake_by_address_single, _STD memory_order_relaxed); - _Wait_functions._Pfn_WakeByAddressAll.store(_Wake_by_address_all, _STD memory_order_relaxed); - _Level = __std_atomic_api_level::__has_wait_on_address; - } - } - - // for __has_srwlock, relaxed would have been enough, not distinguishing for consistency - _Wait_functions._Api_level.store(_Level, _STD memory_order_release); - return _Level; - } - - [[nodiscard]] __std_atomic_api_level _Acquire_wait_functions() noexcept { - auto _Level = _Wait_functions._Api_level.load(_STD memory_order_acquire); - if (_Level <= __std_atomic_api_level::__detecting) { - _Level = _Init_wait_functions(_Level); - } - - return _Level; - } - - [[nodiscard]] BOOL __crtWaitOnAddress( - volatile VOID* Address, PVOID CompareAddress, SIZE_T AddressSize, DWORD dwMilliseconds) { - const auto _Wait_on_address = _Wait_functions._Pfn_WaitOnAddress.load(_STD memory_order_relaxed); - return _Wait_on_address(Address, CompareAddress, AddressSize, dwMilliseconds); - } - - VOID __crtWakeByAddressSingle(PVOID Address) { - const auto _Wake_by_address_single = _Wait_functions._Pfn_WakeByAddressSingle.load(_STD memory_order_relaxed); - _Wake_by_address_single(Address); - } - - VOID __crtWakeByAddressAll(PVOID Address) { - const auto _Wake_by_address_all = _Wait_functions._Pfn_WakeByAddressAll.load(_STD memory_order_relaxed); - _Wake_by_address_all(Address); - } - - bool __stdcall _Atomic_wait_are_equal_direct_fallback( - const void* _Storage, void* _Comparand, size_t _Size, void*) noexcept { - switch (_Size) { - case 1: - return __iso_volatile_load8(static_cast(_Storage)) == *static_cast(_Comparand); - case 2: - return __iso_volatile_load16(static_cast(_Storage)) == *static_cast(_Comparand); - case 4: - return __iso_volatile_load32(static_cast(_Storage)) == *static_cast(_Comparand); - case 8: - return __iso_volatile_load64(static_cast(_Storage)) - == *static_cast(_Comparand); - default: - _CSTD abort(); - } - } -#endif // _ATOMIC_WAIT_ON_ADDRESS_STATICALLY_AVAILABLE - - [[nodiscard]] unsigned char __std_atomic_compare_exchange_128_fallback( - _Inout_bytecount_(16) long long* _Destination, _In_ long long _ExchangeHigh, _In_ long long _ExchangeLow, - _Inout_bytecount_(16) long long* _ComparandResult) noexcept { - static SRWLOCK _Mtx = SRWLOCK_INIT; - _SrwLock_guard _Guard{_Mtx}; - if (_Destination[0] == _ComparandResult[0] && _Destination[1] == _ComparandResult[1]) { - _ComparandResult[0] = _Destination[0]; - _ComparandResult[1] = _Destination[1]; - _Destination[0] = _ExchangeLow; - _Destination[1] = _ExchangeHigh; - return static_cast(true); - } else { - _ComparandResult[0] = _Destination[0]; - _ComparandResult[1] = _Destination[1]; - return static_cast(false); - } - } } // unnamed namespace extern "C" { int __stdcall __std_atomic_wait_direct(const void* const _Storage, void* const _Comparand, const size_t _Size, const unsigned long _Remaining_timeout) noexcept { -#if _ATOMIC_WAIT_ON_ADDRESS_STATICALLY_AVAILABLE == 0 - if (_Acquire_wait_functions() < __std_atomic_api_level::__has_wait_on_address) { - return __std_atomic_wait_indirect( - _Storage, _Comparand, _Size, nullptr, &_Atomic_wait_are_equal_direct_fallback, _Remaining_timeout); - } -#endif // _ATOMIC_WAIT_ON_ADDRESS_STATICALLY_AVAILABLE == 0 - - const auto _Result = __crtWaitOnAddress( - const_cast(_Storage), const_cast(_Comparand), _Size, _Remaining_timeout); + const auto _Result = + WaitOnAddress(const_cast(_Storage), const_cast(_Comparand), _Size, _Remaining_timeout); if (!_Result) { _Assume_timeout(); @@ -242,25 +106,11 @@ int __stdcall __std_atomic_wait_direct(const void* const _Storage, void* const _ } void __stdcall __std_atomic_notify_one_direct(const void* const _Storage) noexcept { -#if _ATOMIC_WAIT_ON_ADDRESS_STATICALLY_AVAILABLE == 0 - if (_Acquire_wait_functions() < __std_atomic_api_level::__has_wait_on_address) { - __std_atomic_notify_one_indirect(_Storage); - return; - } -#endif // _ATOMIC_WAIT_ON_ADDRESS_STATICALLY_AVAILABLE = 0 - - __crtWakeByAddressSingle(const_cast(_Storage)); + WakeByAddressSingle(const_cast(_Storage)); } void __stdcall __std_atomic_notify_all_direct(const void* const _Storage) noexcept { -#if _ATOMIC_WAIT_ON_ADDRESS_STATICALLY_AVAILABLE == 0 - if (_Acquire_wait_functions() < __std_atomic_api_level::__has_wait_on_address) { - __std_atomic_notify_all_indirect(_Storage); - return; - } -#endif // _ATOMIC_WAIT_ON_ADDRESS_STATICALLY_AVAILABLE == 0 - - __crtWakeByAddressAll(const_cast(_Storage)); + WakeByAddressAll(const_cast(_Storage)); } void __stdcall __std_atomic_notify_one_indirect(const void* const _Storage) noexcept { @@ -356,25 +206,10 @@ unsigned long __stdcall __std_atomic_wait_get_remaining_timeout(unsigned long lo return static_cast(_Remaining); } -__std_atomic_api_level __stdcall __std_atomic_set_api_level(__std_atomic_api_level _Requested_api_level) noexcept { -#if _ATOMIC_WAIT_ON_ADDRESS_STATICALLY_AVAILABLE - (void) _Requested_api_level; +// TRANSITION, ABI: preserved for binary compatibility +enum class __std_atomic_api_level : unsigned long { __not_set, __detecting, __has_srwlock, __has_wait_on_address }; +__std_atomic_api_level __stdcall __std_atomic_set_api_level(__std_atomic_api_level) noexcept { return __std_atomic_api_level::__has_wait_on_address; -#else // ^^^ _ATOMIC_WAIT_ON_ADDRESS_STATICALLY_AVAILABLE / !_ATOMIC_WAIT_ON_ADDRESS_STATICALLY_AVAILABLE vvv - switch (_Requested_api_level) { - case __std_atomic_api_level::__not_set: - case __std_atomic_api_level::__detecting: - _CSTD abort(); - case __std_atomic_api_level::__has_srwlock: - _Force_wait_functions_srwlock_only(); - break; - case __std_atomic_api_level::__has_wait_on_address: - default: // future compat: new header using an old DLL will get the highest requested level supported - break; - } - - return _Acquire_wait_functions(); -#endif // !_ATOMIC_WAIT_ON_ADDRESS_STATICALLY_AVAILABLE } #pragma warning(push) @@ -397,41 +232,27 @@ _Smtx_t* __stdcall __std_atomic_get_mutex(const void* const _Key) noexcept { } #pragma warning(pop) +// TRANSITION, ABI: preserved for binary compatibility [[nodiscard]] unsigned char __stdcall __std_atomic_compare_exchange_128(_Inout_bytecount_(16) long long* _Destination, _In_ long long _ExchangeHigh, _In_ long long _ExchangeLow, _Inout_bytecount_(16) long long* _ComparandResult) noexcept { -#if !defined(_WIN64) - return __std_atomic_compare_exchange_128_fallback(_Destination, _ExchangeHigh, _ExchangeLow, _ComparandResult); -#elif _STD_ATOMIC_ALWAYS_USE_CMPXCHG16B == 1 +#ifdef _WIN64 return _InterlockedCompareExchange128(_Destination, _ExchangeHigh, _ExchangeLow, _ComparandResult); -#else // ^^^ _STD_ATOMIC_ALWAYS_USE_CMPXCHG16B == 1 / _STD_ATOMIC_ALWAYS_USE_CMPXCHG16B == 0 vvv - if (__std_atomic_has_cmpxchg16b()) { - return _InterlockedCompareExchange128(_Destination, _ExchangeHigh, _ExchangeLow, _ComparandResult); - } - - return __std_atomic_compare_exchange_128_fallback(_Destination, _ExchangeHigh, _ExchangeLow, _ComparandResult); -#endif // ^^^ _STD_ATOMIC_ALWAYS_USE_CMPXCHG16B == 0 ^^^ +#else // ^^^ 64-bit / 32-bit vvv + (void) _Destination; + (void) _ExchangeHigh; + (void) _ExchangeLow; + (void) _ComparandResult; + _CSTD abort(); +#endif // ^^^ 32-bit ^^^ } +// TRANSITION, ABI: preserved for binary compatibility [[nodiscard]] char __stdcall __std_atomic_has_cmpxchg16b() noexcept { -#if !defined(_WIN64) - return false; -#elif _STD_ATOMIC_ALWAYS_USE_CMPXCHG16B == 1 +#ifdef _WIN64 return true; -#else // ^^^ _STD_ATOMIC_ALWAYS_USE_CMPXCHG16B == 1 / _STD_ATOMIC_ALWAYS_USE_CMPXCHG16B == 0 vvv - constexpr char _Cmpxchg_Absent = 0; - constexpr char _Cmpxchg_Present = 1; - constexpr char _Cmpxchg_Unknown = 2; - - static std::atomic _Cached_value{_Cmpxchg_Unknown}; - - char _Value = _Cached_value.load(std::memory_order_relaxed); - if (_Value == _Cmpxchg_Unknown) { - _Value = IsProcessorFeaturePresent(PF_COMPARE_EXCHANGE128) ? _Cmpxchg_Present : _Cmpxchg_Absent; - _Cached_value.store(_Value, std::memory_order_relaxed); - } - - return _Value; -#endif // ^^^ _STD_ATOMIC_ALWAYS_USE_CMPXCHG16B == 0 ^^^ +#else + _CSTD abort(); +#endif } } // extern "C" diff --git a/stl/src/awint.hpp b/stl/src/awint.hpp index da1e26e470a..797801b7a98 100644 --- a/stl/src/awint.hpp +++ b/stl/src/awint.hpp @@ -14,17 +14,6 @@ _CRT_BEGIN_C_HEADER -#if _STL_WIN32_WINNT >= _WIN32_WINNT_WIN8 - -#define __crtGetSystemTimePreciseAsFileTime(lpSystemTimeAsFileTime) \ - GetSystemTimePreciseAsFileTime(lpSystemTimeAsFileTime) - -#else // ^^^ _STL_WIN32_WINNT >= _WIN32_WINNT_WIN8 / _STL_WIN32_WINNT < _WIN32_WINNT_WIN8 vvv - -_CRTIMP2 void __cdecl __crtGetSystemTimePreciseAsFileTime(_Out_ LPFILETIME lpSystemTimeAsFileTime) noexcept; - -#endif // ^^^ _STL_WIN32_WINNT < _WIN32_WINNT_WIN8 ^^^ - _CRTIMP2 int __cdecl __crtCompareStringA(_In_z_ LPCWSTR _LocaleName, _In_ DWORD _DwCmpFlags, _In_reads_(_CchCount1) LPCSTR _LpString1, _In_ int _CchCount1, _In_reads_(_CchCount2) LPCSTR _LpString2, _In_ int _CchCount2, _In_ int _CodePage) noexcept; diff --git a/stl/src/ppltasks.cpp b/stl/src/ppltasks.cpp index ef1048cad14..62cf885e54a 100644 --- a/stl/src/ppltasks.cpp +++ b/stl/src/ppltasks.cpp @@ -26,12 +26,6 @@ namespace Concurrency { namespace details { [[noreturn]] _CRTIMP2 void __cdecl _ReportUnobservedException() { -#if (defined(_M_IX86) || defined(_M_X64)) && !defined(_CRT_APP) && _STL_WIN32_WINNT < _WIN32_WINNT_WIN8 - if (!IsProcessorFeaturePresent(PF_FASTFAIL_AVAILABLE)) { - std::abort(); - } -#endif // ^^^ __fastfail conditionally available ^^^ - __fastfail(FAST_FAIL_INVALID_ARG); } diff --git a/stl/src/vector_algorithms.cpp b/stl/src/vector_algorithms.cpp index 44cca169203..2abf6bff8e4 100644 --- a/stl/src/vector_algorithms.cpp +++ b/stl/src/vector_algorithms.cpp @@ -2087,6 +2087,7 @@ namespace { _Advance_bytes(_First, sizeof(_Ty)); } +#pragma loop(no_vector) // TRANSITION, VSO-2093761: work around a compiler back-end assertion for (auto _Ptr = static_cast(_First); _Ptr != _Last; ++_Ptr) { if constexpr ((_Mode & _Mode_min) != 0) { if (*_Ptr < _Cur_min_val) { diff --git a/stl/src/winapisupp.cpp b/stl/src/winapisupp.cpp index 94dc7a55b15..de6f6ae4d29 100644 --- a/stl/src/winapisupp.cpp +++ b/stl/src/winapisupp.cpp @@ -1,19 +1,12 @@ // Copyright (c) Microsoft Corporation. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// clang-format off -// Prevent clang-format from reordering before -#include -#include // for APPMODEL_ERROR_NO_PACKAGE -#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(_ONECORE) namespace { @@ -21,14 +14,6 @@ namespace { // Use this macro for defining the following function pointers #define DEFINEFUNCTIONPOINTER(fn_name) decltype(&fn_name) __KERNEL32Function_##fn_name = nullptr -#if !defined(_CRT_WINDOWS) && !defined(UNDOCKED_WINDOWS_UCRT) - DEFINEFUNCTIONPOINTER(GetCurrentPackageId); -#endif // !defined(_CRT_WINDOWS) && !defined(UNDOCKED_WINDOWS_UCRT) - -#if _STL_WIN32_WINNT < _WIN32_WINNT_WIN8 - DEFINEFUNCTIONPOINTER(GetSystemTimePreciseAsFileTime); -#endif // _STL_WIN32_WINNT < _WIN32_WINNT_WIN8 - DEFINEFUNCTIONPOINTER(GetTempPath2W); // Use this macro for caching a function pointer from a DLL @@ -43,107 +28,9 @@ namespace { #if !defined(_CRT_WINDOWS) && !defined(UNDOCKED_WINDOWS_UCRT) -#if !defined(_CRT_APP) -#if defined(_ONECORE) - -namespace { - struct HMODULETraits { - using Type = HMODULE; - - static bool Close(Type const h) noexcept { - return ::FreeLibrary(h) != FALSE; - } - - static Type GetInvalidValue() noexcept { - return nullptr; - } - }; - - using HMODULEHandle = Microsoft::WRL::Wrappers::HandleT; -} // unnamed namespace - -extern "C" int __crt_IsPackagedAppHelper() noexcept { - static wchar_t const* const possible_apisets[] = { - L"api-ms-win-appmodel-runtime-l1-1-1.dll", // Windows 8.1+ APISet - L"ext-ms-win-kernel32-package-current-l1-1-0.dll", // Legacy APISet - L"appmodel.dll" // LNM implementation DLL - }; - - for (auto& dll : possible_apisets) { - HMODULEHandle const apiset(LoadLibraryExW(dll, nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32)); - if (!apiset.IsValid()) { - continue; - } - - auto const get_current_package_id = - reinterpret_cast(GetProcAddress(apiset.Get(), "GetCurrentPackageId")); - - if (!get_current_package_id) { - continue; - } - - UINT32 buffer_length = 0; - if (get_current_package_id(&buffer_length, nullptr) == ERROR_INSUFFICIENT_BUFFER) { - return 1; - } else { - return 0; - } - } - - // Either the app is not packaged or we cannot determine if the app is packaged: - return 0; -} - -#else // ^^^ defined(_ONECORE) / !defined(_ONECORE) vvv - -extern "C" int __crt_IsPackagedAppHelper() noexcept { - LONG retValue = APPMODEL_ERROR_NO_PACKAGE; - UINT32 bufferLength = 0; - - IFDYNAMICGETCACHEDFUNCTION(GetCurrentPackageId) { - retValue = pfGetCurrentPackageId(&bufferLength, nullptr); - } - - if (retValue == ERROR_INSUFFICIENT_BUFFER) { - return 1; - } - - // If GetCurrentPackageId was not found, or it returned a different error, - // then this is NOT a Packaged app - return 0; -} - -#endif // ^^^ !defined(_ONECORE) ^^^ -#endif // ^^^ !defined(_CRT_APP) ^^^ - -// __crtIsPackagedApp() - Check if the current app is a Packaged app -// -// Purpose: -// Check if the current application was started through a package. -// This determines if the app is a Packaged app or not. -// -// This function uses a new Windows 8 API, GetCurrentPackageId, to detect -// if the application is deployed via a package. -// -// Entry: -// None -// -// Exit: -// TRUE if Packaged app, FALSE if not. // TRANSITION, ABI: preserved for binary compatibility extern "C" _CRTIMP2 BOOL __cdecl __crtIsPackagedApp() noexcept { -#ifdef _CRT_APP - return TRUE; -#else // ^^^ defined(_CRT_APP) / !defined(_CRT_APP) vvv - static int isPackaged = -1; // Initialize to undefined state - - // If we've already made this check, just return the prev result - if (isPackaged < 0) { - isPackaged = __crt_IsPackagedAppHelper(); - } - - return (isPackaged > 0) ? TRUE : FALSE; -#endif // ^^^ !defined(_CRT_APP) ^^^ + return FALSE; } #endif // !defined(_CRT_WINDOWS) && !defined(UNDOCKED_WINDOWS_UCRT) @@ -267,15 +154,9 @@ extern "C" _CRTIMP2 BOOL __cdecl __crtSetFileInformationByHandle(_In_ HANDLE con #if _STL_WIN32_WINNT < _WIN32_WINNT_WIN8 +// TRANSITION, ABI: preserved for binary compatibility extern "C" _CRTIMP2 void __cdecl __crtGetSystemTimePreciseAsFileTime(_Out_ LPFILETIME lpSystemTimeAsFileTime) noexcept { - // use GetSystemTimePreciseAsFileTime if it is available (only on Windows 8+)... - IFDYNAMICGETCACHEDFUNCTION(GetSystemTimePreciseAsFileTime) { - pfGetSystemTimePreciseAsFileTime(lpSystemTimeAsFileTime); - return; - } - - // ...otherwise use GetSystemTimeAsFileTime. - GetSystemTimeAsFileTime(lpSystemTimeAsFileTime); + GetSystemTimePreciseAsFileTime(lpSystemTimeAsFileTime); } #endif // _STL_WIN32_WINNT < _WIN32_WINNT_WIN8 @@ -305,14 +186,6 @@ static int __cdecl initialize_pointers() noexcept { HINSTANCE hKernel32 = GetModuleHandleW(L"kernel32.dll"); _Analysis_assume_(hKernel32); -#if !defined(_CRT_WINDOWS) && !defined(UNDOCKED_WINDOWS_UCRT) - STOREFUNCTIONPOINTER(hKernel32, GetCurrentPackageId); -#endif // !defined(_CRT_WINDOWS) && !defined(UNDOCKED_WINDOWS_UCRT) - -#if _STL_WIN32_WINNT < _WIN32_WINNT_WIN8 - STOREFUNCTIONPOINTER(hKernel32, GetSystemTimePreciseAsFileTime); -#endif // _STL_WIN32_WINNT < _WIN32_WINNT_WIN8 - // Note that GetTempPath2W is defined as of Windows 10 Build 20348 (a server release) or Windows 11, // but there is no "_WIN32_WINNT_WIN11" constant, so we will always dynamically load it STOREFUNCTIONPOINTER(hKernel32, GetTempPath2W); diff --git a/stl/src/xtime.cpp b/stl/src/xtime.cpp index c59d0fc73af..7499f42e19d 100644 --- a/stl/src/xtime.cpp +++ b/stl/src/xtime.cpp @@ -51,7 +51,7 @@ _CRTIMP2_PURE long long __cdecl _Xtime_get_ticks() noexcept { constexpr long long _Epoch = 0x19DB1DED53E8000LL; FILETIME ft; - __crtGetSystemTimePreciseAsFileTime(&ft); + GetSystemTimePreciseAsFileTime(&ft); return ((static_cast(ft.dwHighDateTime)) << 32) + static_cast(ft.dwLowDateTime) - _Epoch; } diff --git a/tests/libcxx/expected_results.txt b/tests/libcxx/expected_results.txt index b3f0faf60bc..5ae8f27917d 100644 --- a/tests/libcxx/expected_results.txt +++ b/tests/libcxx/expected_results.txt @@ -26,6 +26,12 @@ std/time/time.syn/formatter.year_month_weekday.pass.cpp:1 FAIL std/utilities/memory/specialized.algorithms/uninitialized.copy/uninitialized_copy.pass.cpp FAIL std/utilities/memory/specialized.algorithms/uninitialized.move/uninitialized_move.pass.cpp FAIL +# LLVM-90196: [libc++][format] Formatting range with m range-type is incorrect +std/utilities/format/format.range/format.range.formatter/format.functions.format.pass.cpp FAIL +std/utilities/format/format.range/format.range.formatter/format.functions.vformat.pass.cpp FAIL +std/utilities/format/format.range/format.range.fmtset/format.functions.format.pass.cpp FAIL +std/utilities/format/format.range/format.range.fmtset/format.functions.vformat.pass.cpp FAIL + # LLVM-94907: [libc++][test] Avoid -Wunused-variable warnings in mutex tests std/thread/thread.mutex/thread.mutex.requirements/thread.sharedtimedmutex.requirements/thread.sharedtimedmutex.class/default.pass.cpp:2 FAIL std/thread/thread.mutex/thread.mutex.requirements/thread.timedmutex.requirements/thread.timedmutex.class/default.pass.cpp:2 FAIL @@ -67,6 +73,9 @@ std/containers/unord/unord.set/insert_and_emplace_allocator_requirements.pass.cp # Bogus test believes that copyability of array must be the same as array std/containers/sequences/array/array.cons/implicit_copy.pass.cpp FAIL +# libc++ hasn't implemented P0952R2, which changes the generate_canonical algorithm. +std/numerics/rand/rand.util/rand.util.canonical/generate_canonical.pass.cpp FAIL + # Test expects __cpp_lib_chrono to have the old value 201611L for P0505R0; we define the C++20 value 201907L for P1466R3. std/language.support/support.limits/support.limits.general/chrono.version.compile.pass.cpp FAIL @@ -99,12 +108,29 @@ std/utilities/function.objects/range.cmp/less.pass.cpp FAIL std/utilities/function.objects/range.cmp/less_equal.pass.cpp FAIL std/utilities/function.objects/range.cmp/not_equal_to.pass.cpp FAIL +# libc++ has not implemented P2407R5: "Freestanding Library: Partial Classes" +std/language.support/support.limits/support.limits.general/array.version.compile.pass.cpp FAIL +std/language.support/support.limits/support.limits.general/optional.version.compile.pass.cpp FAIL +std/language.support/support.limits/support.limits.general/string_view.version.compile.pass.cpp FAIL + # libc++ doesn't implement P2588R3 barrier's Phase Completion Guarantees std/language.support/support.limits/support.limits.general/barrier.version.compile.pass.cpp FAIL +# libc++ has not implemented P2833R2: "Freestanding Library: inout expected span" +std/language.support/support.limits/support.limits.general/expected.version.compile.pass.cpp FAIL +std/language.support/support.limits/support.limits.general/mdspan.version.compile.pass.cpp FAIL + # libc++ has not implemented P2937R0: "Freestanding Library: Remove strtok" std/language.support/support.limits/support.limits.general/cstring.version.compile.pass.cpp FAIL +# libc++ has not implemented P2997R1: "Removing The Common Reference Requirement From The Indirectly Invocable Concepts" +std/iterators/iterator.requirements/indirectcallable/indirectinvocable/indirect_binary_predicate.compile.pass.cpp FAIL +std/iterators/iterator.requirements/indirectcallable/indirectinvocable/indirect_equivalence_relation.compile.pass.cpp FAIL +std/iterators/iterator.requirements/indirectcallable/indirectinvocable/indirect_strict_weak_order.compile.pass.cpp FAIL +std/iterators/iterator.requirements/indirectcallable/indirectinvocable/indirect_unary_predicate.compile.pass.cpp FAIL +std/iterators/iterator.requirements/indirectcallable/indirectinvocable/indirectly_regular_unary_invocable.compile.pass.cpp FAIL +std/iterators/iterator.requirements/indirectcallable/indirectinvocable/indirectly_unary_invocable.compile.pass.cpp FAIL + # Various bogosity (LLVM-D141004), warning C6011: Dereferencing NULL pointer # Note: The :1 (ASAN) configuration doesn't run static analysis. std/utilities/utility/mem.res/mem.poly.allocator.class/mem.poly.allocator.mem/construct_pair_const_lvalue_pair.pass.cpp:0 FAIL @@ -150,6 +176,13 @@ std/utilities/memory/specialized.algorithms/uninitialized.move/ranges_uninitiali std/ranges/range.adaptors/range.lazy.split/range.lazy.split.outer.value/ctor.default.pass.cpp FAIL std/ranges/range.adaptors/range.lazy.split/range.lazy.split.outer.value/ctor.iter.pass.cpp FAIL +# libc++ doesn't implement LWG-4061 +std/utilities/format/format.functions/bug_81590.compile.pass.cpp FAIL + +# libc++ doesn't implement LWG-4106 +std/utilities/format/format.arguments/format.args/ctor.pass.cpp FAIL +std/utilities/format/format.arguments/format.args/get.pass.cpp FAIL + # If any feature-test macro test is failing, this consolidated test will also fail. std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp FAIL @@ -219,29 +252,7 @@ std/containers/container.adaptors/container.adaptors.format/format.functions.vfo std/containers/container.adaptors/container.adaptors.format/format.pass.cpp FAIL std/containers/container.adaptors/container.adaptors.format/parse.pass.cpp FAIL std/containers/container.adaptors/container.adaptors.format/types.compile.pass.cpp FAIL -std/containers/sequences/vector.bool/vector.bool.fmt/format.functions.format.pass.cpp FAIL -std/containers/sequences/vector.bool/vector.bool.fmt/format.functions.vformat.pass.cpp FAIL -std/containers/sequences/vector.bool/vector.bool.fmt/format.pass.cpp FAIL -std/input.output/iostream.format/print.fun/includes.compile.pass.cpp FAIL std/utilities/format/format.formattable/concept.formattable.compile.pass.cpp FAIL -std/utilities/format/format.range/format.range.fmtdef/format.pass.cpp FAIL -std/utilities/format/format.range/format.range.fmtdef/parse.pass.cpp FAIL -std/utilities/format/format.range/format.range.fmtdef/set_brackets.pass.cpp FAIL -std/utilities/format/format.range/format.range.fmtdef/set_separator.pass.cpp FAIL -std/utilities/format/format.range/format.range.fmtmap/format.functions.format.pass.cpp FAIL -std/utilities/format/format.range/format.range.fmtmap/format.functions.vformat.pass.cpp FAIL -std/utilities/format/format.range/format.range.fmtmap/format.pass.cpp FAIL -std/utilities/format/format.range/format.range.fmtmap/parse.pass.cpp FAIL -std/utilities/format/format.range/format.range.fmtset/format.functions.format.pass.cpp FAIL -std/utilities/format/format.range/format.range.fmtset/format.functions.vformat.pass.cpp FAIL -std/utilities/format/format.range/format.range.fmtset/format.pass.cpp FAIL -std/utilities/format/format.range/format.range.fmtset/parse.pass.cpp FAIL -std/utilities/format/format.range/format.range.fmtstr/format.functions.format.pass.cpp FAIL -std/utilities/format/format.range/format.range.fmtstr/format.functions.vformat.pass.cpp FAIL -std/utilities/format/format.range/format.range.fmtstr/format.pass.cpp FAIL -std/utilities/format/format.range/format.range.fmtstr/parse.pass.cpp FAIL -std/utilities/format/format.range/format.range.formatter/format.functions.format.pass.cpp FAIL -std/utilities/format/format.range/format.range.formatter/format.functions.vformat.pass.cpp FAIL # *** MISSING COMPILER FEATURES *** @@ -965,6 +976,7 @@ std/input.output/string.streams/stringstream/stringstream.members/str.allocator_ # These formatter tests need to create basic_format_contexts, so test_format_context.h # says "Please create a vendor specific version of the test functions". # If we do, some of these tests should be able to work. +std/containers/sequences/vector.bool/vector.bool.fmt/format.pass.cpp FAIL std/thread/thread.threads/thread.thread.class/thread.thread.id/format.pass.cpp FAIL std/utilities/format/format.formatter/format.context/format.context/advance_to.pass.cpp FAIL std/utilities/format/format.formatter/format.context/format.context/arg.pass.cpp FAIL @@ -986,6 +998,12 @@ std/utilities/format/format.formatter/format.formatter.spec/formatter.unsigned_i std/utilities/format/format.range/format.range.formatter/format.pass.cpp FAIL std/utilities/format/format.range/format.range.formatter/set_brackets.pass.cpp FAIL std/utilities/format/format.range/format.range.formatter/set_separator.pass.cpp FAIL +std/utilities/format/format.range/format.range.fmtdef/format.pass.cpp FAIL +std/utilities/format/format.range/format.range.fmtdef/set_brackets.pass.cpp FAIL +std/utilities/format/format.range/format.range.fmtdef/set_separator.pass.cpp FAIL +std/utilities/format/format.range/format.range.fmtmap/format.pass.cpp FAIL +std/utilities/format/format.range/format.range.fmtset/format.pass.cpp FAIL +std/utilities/format/format.range/format.range.fmtstr/format.pass.cpp FAIL std/utilities/format/format.tuple/format.pass.cpp FAIL # Not analyzed. Apparent false positives from static analysis where it thinks that array indexing is out of bounds. diff --git a/tests/std/include/test_atomic_wait.hpp b/tests/std/include/test_atomic_wait.hpp deleted file mode 100644 index 28f4be97fba..00000000000 --- a/tests/std/include/test_atomic_wait.hpp +++ /dev/null @@ -1,366 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - -#pragma once - -#include -#include -#include -#include -#include -#include - -template