diff --git a/.vscode/settings.json b/.vscode/settings.json index 5a97ba29cee..5312b7ed5b4 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -5,6 +5,7 @@ "editor.formatOnSave": true, "files.associations": { ".clang-format": "yaml", + "header-units.json": "jsonc", "**/stl/inc/**": "cpp" }, "files.eol": "\r\n", diff --git a/CMakeLists.txt b/CMakeLists.txt index 1e712f36ad8..8b166a3d5a2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,7 +5,7 @@ if (NOT DEFINED CMAKE_TOOLCHAIN_FILE AND EXISTS "${CMAKE_CURRENT_LIST_DIR}/vcpkg set(CMAKE_TOOLCHAIN_FILE "${CMAKE_CURRENT_LIST_DIR}/vcpkg/scripts/buildsystems/vcpkg.cmake") endif() -cmake_minimum_required(VERSION 3.18) +cmake_minimum_required(VERSION 3.19) set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY) project(msvc_standard_libraries LANGUAGES CXX) diff --git a/README.md b/README.md index 570e9cedcf9..40546698950 100644 --- a/README.md +++ b/README.md @@ -143,10 +143,10 @@ Just try to follow these rules, so we can spend more time fixing bugs and implem The STL uses boost-math headers to provide P0226R1 Mathematical Special Functions. We recommend using [vcpkg][] to acquire this dependency. -1. Install Visual Studio 2019 16.9 Preview 2 or later. +1. Install Visual Studio 2019 16.9 Preview 3 or later. * 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.18 or later, and [Ninja][] 1.8.2 or later. + * Otherwise, install [CMake][] 3.19 or later, and [Ninja][] 1.10.2 or later. 2. Open Visual Studio, and choose the "Clone or check out code" option. Enter the URL of this repository, `https://github.com/microsoft/STL`. 3. Open a terminal in the IDE with `` Ctrl + ` `` (by default) or press on "View" in the top bar, and then "Terminal". @@ -158,10 +158,10 @@ acquire this dependency. # How To Build With A Native Tools Command Prompt -1. Install Visual Studio 2019 16.9 Preview 2 or later. +1. Install Visual Studio 2019 16.9 Preview 3 or later. * 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.18 or later, and [Ninja][] 1.8.2 or later. + * Otherwise, install [CMake][] 3.19 or later, and [Ninja][] 1.10.2 or later. 2. Open a command prompt. 3. Change directories to a location where you'd like a clone of this STL repository. 4. `git clone https://github.com/microsoft/STL` @@ -234,7 +234,7 @@ C:\Users\username\Desktop>dumpbin /IMPORTS .\example.exe | findstr msvcp # How To Run The Tests With A Native Tools Command Prompt 1. Follow either [How To Build With A Native Tools Command Prompt][] or [How To Build With The Visual Studio IDE][]. -2. Acquire [Python][] 3.9 or newer and have it on the `PATH` (or run it directly using its absolute or relative path). +2. Acquire [Python][] 3.9.1 or newer and have it on the `PATH` (or run it directly using its absolute or relative path). 3. Have LLVM's `bin` directory on the `PATH` (so `clang-cl.exe` is available). * We recommend selecting "C++ Clang tools for Windows" in the VS Installer. This will automatically add LLVM to the `PATH` of the x86 and x64 Native Tools Command Prompts, and will ensure that you're using a supported version. diff --git a/azure-devops/create-vmss.ps1 b/azure-devops/create-vmss.ps1 index 1434ce0ac48..963fb7f874a 100644 --- a/azure-devops/create-vmss.ps1 +++ b/azure-devops/create-vmss.ps1 @@ -17,6 +17,9 @@ or are running from Azure Cloud Shell. $ErrorActionPreference = 'Stop' +# https://aka.ms/azps-changewarnings +$Env:SuppressAzurePowerShellBreakingChangeWarnings = 'true' + $Location = 'westus2' $Prefix = 'StlBuild-' + (Get-Date -Format 'yyyy-MM-dd') $VMSize = 'Standard_D32as_v4' diff --git a/azure-devops/provision-image.ps1 b/azure-devops/provision-image.ps1 index ba9e940c575..8468b850ad6 100644 --- a/azure-devops/provision-image.ps1 +++ b/azure-devops/provision-image.ps1 @@ -50,36 +50,75 @@ Function Get-TempFilePath { return Join-Path $tempPath $tempName } +<# +.SYNOPSIS +Downloads and extracts a ZIP file to a newly created temporary subdirectory. + +.DESCRIPTION +DownloadAndExtractZip returns a path containing the extracted contents. + +.PARAMETER Url +The URL of the ZIP file to download. +#> +Function DownloadAndExtractZip { + Param( + [String]$Url + ) + + if ([String]::IsNullOrWhiteSpace($Url)) { + throw 'Missing Url' + } + + $ZipPath = Get-TempFilePath -Extension 'zip' + & curl.exe -L -o $ZipPath -s -S $Url + $TempSubdirPath = Get-TempFilePath -Extension 'dir' + Expand-Archive -Path $ZipPath -DestinationPath $TempSubdirPath -Force + + return $TempSubdirPath +} + $TranscriptPath = 'C:\provision-image-transcript.txt' if ([string]::IsNullOrEmpty($AdminUserPassword)) { - Start-Transcript -Path $TranscriptPath + Start-Transcript -Path $TranscriptPath -UseMinimalHeader } else { Write-Host 'AdminUser password supplied; switching to AdminUser.' - $PsExecPath = Get-TempFilePath -Extension 'exe' - Write-Host "Downloading psexec to: $PsExecPath" - & curl.exe -L -o $PsExecPath -s -S https://live.sysinternals.com/PsExec64.exe + + # https://docs.microsoft.com/en-us/sysinternals/downloads/psexec + $PsToolsZipUrl = 'https://download.sysinternals.com/files/PSTools.zip' + Write-Host "Downloading: $PsToolsZipUrl" + $ExtractedPsToolsPath = DownloadAndExtractZip -Url $PsToolsZipUrl + $PsExecPath = Join-Path $ExtractedPsToolsPath 'PsExec64.exe' + + # https://github.com/PowerShell/PowerShell/releases/latest + $PowerShellZipUrl = 'https://github.com/PowerShell/PowerShell/releases/download/v7.1.1/PowerShell-7.1.1-win-x64.zip' + Write-Host "Downloading: $PowerShellZipUrl" + $ExtractedPowerShellPath = DownloadAndExtractZip -Url $PowerShellZipUrl + $PwshPath = Join-Path $ExtractedPowerShellPath 'pwsh.exe' + $PsExecArgs = @( '-u', 'AdminUser', '-p', - $AdminUserPassword, + 'AdminUserPassword_REDACTED', '-accepteula', + '-i', '-h', - 'C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe', + $PwshPath, '-ExecutionPolicy', 'Unrestricted', '-File', $PSCommandPath ) - Write-Host "Executing: $PsExecPath $PsExecArgs" + $PsExecArgs[3] = $AdminUserPassword $proc = Start-Process -FilePath $PsExecPath -ArgumentList $PsExecArgs -Wait -PassThru Write-Host 'Reading transcript...' Get-Content -Path $TranscriptPath Write-Host 'Cleaning up...' - Remove-Item $PsExecPath + Remove-Item -Recurse -Path $ExtractedPsToolsPath + Remove-Item -Recurse -Path $ExtractedPowerShellPath exit $proc.ExitCode } @@ -100,7 +139,7 @@ $Workloads = @( $ReleaseInPath = 'Preview' $Sku = 'Enterprise' $VisualStudioBootstrapperUrl = 'https://aka.ms/vs/16/pre/vs_enterprise.exe' -$PythonUrl = 'https://www.python.org/ftp/python/3.9.0/python-3.9.0-amd64.exe' +$PythonUrl = 'https://www.python.org/ftp/python/3.9.1/python-3.9.1-amd64.exe' # https://docs.microsoft.com/en-us/windows-hardware/drivers/download-the-wdk $WindowsDriverKitUrl = 'https://go.microsoft.com/fwlink/?linkid=2128854' @@ -315,7 +354,7 @@ Function PipInstall { try { Write-Host "Installing or upgrading $Package..." - python.exe -m pip install --upgrade $Package + python.exe -m pip install --progress-bar off --upgrade $Package Write-Host "Done installing or upgrading $Package." } catch { @@ -358,3 +397,9 @@ Write-Host 'Finished updating PATH!' PipInstall pip PipInstall psutil + +# https://docs.microsoft.com/en-us/windows-hardware/drivers/devtest/bcdedit--set#verification-settings +Write-Host 'Enabling test-signed kernel-mode drivers...' +bcdedit /set testsigning on + +Write-Host 'Done!' diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 3fa907668b9..f342d73784b 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -6,7 +6,7 @@ variables: tmpDir: 'D:\Temp' -pool: 'StlBuild-2020-12-08-1' +pool: 'StlBuild-2021-01-20-2' stages: - stage: Code_Format diff --git a/stl/CMakeLists.txt b/stl/CMakeLists.txt index 394f28cd064..6f2686e6de2 100644 --- a/stl/CMakeLists.txt +++ b/stl/CMakeLists.txt @@ -146,6 +146,7 @@ set(HEADERS ${CMAKE_CURRENT_LIST_DIR}/inc/future ${CMAKE_CURRENT_LIST_DIR}/inc/hash_map ${CMAKE_CURRENT_LIST_DIR}/inc/hash_set + ${CMAKE_CURRENT_LIST_DIR}/inc/header-units.json ${CMAKE_CURRENT_LIST_DIR}/inc/initializer_list ${CMAKE_CURRENT_LIST_DIR}/inc/iomanip ${CMAKE_CURRENT_LIST_DIR}/inc/ios diff --git a/stl/inc/algorithm b/stl/inc/algorithm index 29d6bcbefe4..8eb7c131ae2 100644 --- a/stl/inc/algorithm +++ b/stl/inc/algorithm @@ -732,7 +732,6 @@ _NODISCARD pair<_FwdIt1, _FwdIt2> mismatch( } #endif // _HAS_CXX17 -#if _HAS_IF_CONSTEXPR template _NODISCARD _CONSTEXPR20 pair<_InIt1, _InIt2> mismatch( _InIt1 _First1, _InIt1 _Last1, _InIt2 _First2, _InIt2 _Last2, _Pr _Pred) { @@ -764,42 +763,6 @@ _NODISCARD _CONSTEXPR20 pair<_InIt1, _InIt2> mismatch( _Seek_wrapped(_First1, _UFirst1); return {_First1, _First2}; } -#else // ^^^ _HAS_IF_CONSTEXPR ^^^ // vvv !_HAS_IF_CONSTEXPR vvv -template -pair<_InIt1, _InIt2> _Mismatch_unchecked(_InIt1 _First1, const _InIt1 _Last1, _InIt2 _First2, const _InIt2 _Last2, - _Pr _Pred, input_iterator_tag, input_iterator_tag) { - // return [_First1, _Last1)/[_First2, _Last2) mismatch, no special optimization - while (_First1 != _Last1 && _First2 != _Last2 && _Pred(*_First1, *_First2)) { - ++_First1; - ++_First2; - } - - return {_First1, _First2}; -} - -template -pair<_InIt1, _InIt2> _Mismatch_unchecked(const _InIt1 _First1, const _InIt1 _Last1, const _InIt2 _First2, - const _InIt2 _Last2, _Pr _Pred, random_access_iterator_tag, random_access_iterator_tag) { - // return [_First1, _Last1)/[_First2, _Last2) mismatch, random-access iterators - using _CT = _Common_diff_t<_InIt1, _InIt2>; - const _CT _Count1 = _Last1 - _First1; - const _CT _Count2 = _Last2 - _First2; - const auto _Count = static_cast<_Iter_diff_t<_InIt1>>((_STD min)(_Count1, _Count2)); - return _STD mismatch(_First1, _First1 + _Count, _First2, _Pred); -} - -template -_NODISCARD pair<_InIt1, _InIt2> mismatch(_InIt1 _First1, _InIt1 _Last1, _InIt2 _First2, _InIt2 _Last2, _Pr _Pred) { - // return [_First1, _Last1)/[_First2, _Last2) mismatch - _Adl_verify_range(_First1, _Last1); - _Adl_verify_range(_First2, _Last2); - const auto _Result = _Mismatch_unchecked(_Get_unwrapped(_First1), _Get_unwrapped(_Last1), _Get_unwrapped(_First2), - _Get_unwrapped(_Last2), _Pass_fn(_Pred), _Iter_cat_t<_InIt1>{}, _Iter_cat_t<_InIt2>{}); - _Seek_wrapped(_First2, _Result.second); - _Seek_wrapped(_First1, _Result.first); - return {_First1, _First2}; -} -#endif // _HAS_IF_CONSTEXPR #if _HAS_CXX17 template = 0> @@ -2152,7 +2115,6 @@ namespace ranges { #endif // __cpp_lib_concepts // FUNCTION TEMPLATE _Equal_rev_pred_unchecked -#if _HAS_IF_CONSTEXPR template _NODISCARD _CONSTEXPR20 bool _Equal_rev_pred_unchecked(_InIt1 _First1, _InIt2 _First2, const _InIt2 _Last2, _Pr _Pred) { // compare [_First1, ...) to [_First2, _Last2) @@ -2161,9 +2123,9 @@ _NODISCARD _CONSTEXPR20 bool _Equal_rev_pred_unchecked(_InIt1 _First1, _InIt2 _F if (!_STD is_constant_evaluated()) #endif // __cpp_lib_is_constant_evaluated { - const auto _First1_ch = reinterpret_cast(_First1); - const auto _First2_ch = reinterpret_cast(_First2); - const auto _Count = static_cast(reinterpret_cast(_Last2) - _First2_ch); + const auto _First1_ch = _To_pointer(_First1); + const auto _First2_ch = _To_pointer(_First2); + const auto _Count = static_cast(_To_pointer(_Last2) - _First2_ch); return _CSTD memcmp(_First1_ch, _First2_ch, _Count) == 0; } } @@ -2176,31 +2138,8 @@ _NODISCARD _CONSTEXPR20 bool _Equal_rev_pred_unchecked(_InIt1 _First1, _InIt2 _F return true; } -#else // ^^^ _HAS_IF_CONSTEXPR ^^^ // vvv !_HAS_IF_CONSTEXPR vvv -template , int> = 0> -bool _Equal_rev_pred_unchecked(_InIt1 _First1, _InIt2 _First2, const _InIt2 _Last2, _Pr _Pred) { - // compare [_First1, ...) to [_First2, _Last2), no special optimization - for (; _First2 != _Last2; ++_First1, (void) ++_First2) { - if (!_Pred(*_First1, *_First2)) { - return false; - } - } - - return true; -} - -template , int> = 0> -bool _Equal_rev_pred_unchecked(const _InIt1 _First1, const _InIt2 _First2, const _InIt2 _Last2, _Pr) { - // compare [_First1, ...) to [_First2, _Last2), memcmp optimization - const auto _First1_ch = reinterpret_cast(_First1); - const auto _First2_ch = reinterpret_cast(_First2); - const auto _Count = static_cast(reinterpret_cast(_Last2) - _First2_ch); - return _CSTD memcmp(_First1_ch, _First2_ch, _Count) == 0; -} -#endif // _HAS_IF_CONSTEXPR // FUNCTION TEMPLATE search -#if _HAS_IF_CONSTEXPR template _NODISCARD _CONSTEXPR20 _FwdItHaystack search(_FwdItHaystack _First1, _FwdItHaystack _Last1, const _FwdItPat _First2, const _FwdItPat _Last2, _Pr _Pred) { // find first [_First2, _Last2) satisfying _Pred @@ -2243,57 +2182,6 @@ _NODISCARD _CONSTEXPR20 _FwdItHaystack search(_FwdItHaystack _First1, _FwdItHays return _Last1; } -#else // ^^^ _HAS_IF_CONSTEXPR ^^^ // vvv !_HAS_IF_CONSTEXPR vvv -template -_FwdItHaystack _Search_unchecked(_FwdItHaystack _First1, _FwdItHaystack _Last1, _FwdItPat _First2, _FwdItPat _Last2, - _Pr _Pred, forward_iterator_tag, forward_iterator_tag) { - // find first [_First2, _Last2) satisfying _Pred, arbitrary iterators - for (;; ++_First1) { // loop until match or end of a sequence - _FwdItHaystack _Mid1 = _First1; - for (_FwdItPat _Mid2 = _First2;; ++_Mid1, (void) ++_Mid2) { - if (_Mid2 == _Last2) { - return _First1; - } else if (_Mid1 == _Last1) { - return _Last1; - } else if (!_Pred(*_Mid1, *_Mid2)) { - break; - } - } - } -} - -template -_FwdItHaystack _Search_unchecked(_FwdItHaystack _First1, const _FwdItHaystack _Last1, const _FwdItPat _First2, - const _FwdItPat _Last2, _Pr _Pred, random_access_iterator_tag, random_access_iterator_tag) { - // find first [_First2, _Last2) satisfying _Pred, random-access iterators - _Iter_diff_t<_FwdItPat> _Count2 = _Last2 - _First2; - if (_Last1 - _First1 >= _Count2) { - const auto _Last_possible = _Last1 - static_cast<_Iter_diff_t<_FwdItHaystack>>(_Count2); - for (;; ++_First1) { - if (_Equal_rev_pred_unchecked(_First1, _First2, _Last2, _Pred)) { - return _First1; - } - - if (_First1 == _Last_possible) { - break; - } - } - } - - return _Last1; -} - -template -_NODISCARD _FwdItHaystack search(_FwdItHaystack _First1, const _FwdItHaystack _Last1, const _FwdItPat _First2, - const _FwdItPat _Last2, _Pr _Pred) { // find first [_First2, _Last2) satisfying _Pred - _Adl_verify_range(_First1, _Last1); - _Adl_verify_range(_First2, _Last2); - _Seek_wrapped( - _First1, _Search_unchecked(_Get_unwrapped(_First1), _Get_unwrapped(_Last1), _Get_unwrapped(_First2), - _Get_unwrapped(_Last2), _Pass_fn(_Pred), _Iter_cat_t<_FwdItHaystack>{}, _Iter_cat_t<_FwdItPat>{})); - return _First1; -} -#endif // _HAS_IF_CONSTEXPR #if _HAS_CXX17 template = 0> @@ -2475,7 +2363,6 @@ namespace ranges { #endif // __cpp_lib_concepts // FUNCTION TEMPLATE search_n -#if _HAS_IF_CONSTEXPR template _NODISCARD _CONSTEXPR20 _FwdIt search_n( const _FwdIt _First, _FwdIt _Last, const _Diff _Count_raw, const _Ty& _Val, _Pr _Pred) { @@ -2547,88 +2434,6 @@ _NODISCARD _CONSTEXPR20 _FwdIt search_n( return _Last; } -#else // ^^^ _HAS_IF_CONSTEXPR ^^^ // vvv !_HAS_IF_CONSTEXPR vvv -template -_FwdIt _Search_n_unchecked1(_FwdIt _First, const _FwdIt _Last, const _Diff _Count, const _Ty& _Val, _Pr _Pred, - forward_iterator_tag) { // find first _Count * _Val satisfying _Pred, forward iterators - for (; _First != _Last; ++_First) { - if (_Pred(*_First, _Val)) { // found start of possible match, check it out - _FwdIt _Mid = _First; - - for (_Diff _Count1 = _Count;;) { - if (--_Count1 == 0) { - return _First; // found rest of match, report it - } else if (++_Mid == _Last) { - return _Last; // short match at end - } else if (!_Pred(*_Mid, _Val)) { // short match not at end - break; - } - } - - _First = _Mid; // pick up just beyond failed match - } - } - - return _Last; -} - -template -_FwdIt _Search_n_unchecked1(_FwdIt _First, const _FwdIt _Last, const _Diff _Count, const _Ty& _Val, _Pr _Pred, - random_access_iterator_tag) { // find first _Count * _Val satisfying _Pred, random-access iterators - const auto _Count_diff = static_cast<_Iter_diff_t<_FwdIt>>(_Count); - _FwdIt _Old_first = _First; - for (_Iter_diff_t<_FwdIt> _Inc = 0; _Count_diff <= _Last - _Old_first;) { // enough room, look for a match - _First = _Old_first + _Inc; - if (_Pred(*_First, _Val)) { // found part of possible match, check it out - _Iter_diff_t<_FwdIt> _Count1 = _Count_diff; - _FwdIt _Mid = _First; - - while (_Old_first != _First && _Pred(*_Prev_iter(_First), _Val)) { - --_Count1; // back up over any skipped prefix - --_First; - } - - if (_Count1 <= _Last - _Mid) { - for (;;) { // enough left, test suffix - if (--_Count1 == 0) { - return _First; // found rest of match, report it - } else if (!_Pred(*++_Mid, _Val)) { // short match not at end - break; - } - } - } - _Old_first = ++_Mid; // failed match, take small jump - _Inc = 0; - } else { // no match, take big jump and back up as needed - _Old_first = _Next_iter(_First); - _Inc = _Count_diff - 1; - } - } - - return _Last; -} - -template -_NODISCARD _FwdIt search_n(_FwdIt _First, const _FwdIt _Last, const _Diff _Count_raw, const _Ty& _Val, _Pr _Pred) { - // find first _Count * _Val satisfying _Pred - const _Algorithm_int_t<_Diff> _Count = _Count_raw; - if (_Count <= 0) { - return _First; - } - - if (static_cast(_Count) > static_cast((numeric_limits<_Iter_diff_t<_FwdIt>>::max)())) { - // if the number of _Vals searched for is larger than the longest possible sequence, we can't find it - _First = _Last; - return _First; - } - - _Adl_verify_range(_First, _Last); - _Seek_wrapped(_First, _Search_n_unchecked1(_Get_unwrapped(_First), _Get_unwrapped(_Last), _Count, _Val, - _Pass_fn(_Pred), _Iter_cat_t<_FwdIt>{})); - - return _First; -} -#endif // _HAS_IF_CONSTEXPR #if _HAS_CXX17 template = 0> @@ -2815,7 +2620,6 @@ namespace ranges { #endif // __cpp_lib_concepts // FUNCTION TEMPLATE find_end -#if _HAS_IF_CONSTEXPR template _NODISCARD _CONSTEXPR20 _FwdIt1 find_end( _FwdIt1 _First1, const _FwdIt1 _Last1, const _FwdIt2 _First2, const _FwdIt2 _Last2, _Pr _Pred) { @@ -2896,96 +2700,6 @@ _NODISCARD _CONSTEXPR20 _FwdIt1 find_end( return _First1; } } -#else // ^^^ _HAS_IF_CONSTEXPR ^^^ // vvv !_HAS_IF_CONSTEXPR vvv -template -_FwdIt1 _Find_end_unchecked(_FwdIt1 _First1, const _FwdIt1 _Last1, const _FwdIt2 _First2, const _FwdIt2 _Last2, - _Pr _Pred, forward_iterator_tag, forward_iterator_tag) { - // find last [_First2, _Last2) satisfying _Pred in forward ranges - _FwdIt1 _Result = _Last1; - for (;;) { // try a match at _First1 - _FwdIt1 _Next1 = _First1; - _FwdIt2 _Next2 = _First2; - for (;;) { // test if [_First2, _Last2) is a prefix of [_First1, _Last1) - const bool _End_of_needle = static_cast(_Next2 == _Last2); - if (_End_of_needle) { // match candidate found - _Result = _First1; - } - - if (_Next1 == _Last1) { - // trying the next candidate would make [_First1, _Last1) shorter than [_First2, _Last2), done - return _Result; - } - - if (_End_of_needle || !_Pred(*_Next1, *_Next2)) { - break; // end of match or counterexample found, go to the next candidate - } - - ++_Next1; - ++_Next2; - } - - ++_First1; - } -} - -template -_BidIt1 _Find_end_unchecked(const _BidIt1 _First1, const _BidIt1 _Last1, const _BidIt2 _First2, const _BidIt2 _Last2, - _Pr _Pred, bidirectional_iterator_tag, bidirectional_iterator_tag) { - // find last [_First2, _Last2) satisfying _Pred in bidirectional ranges - for (_BidIt1 _Candidate = _Last1;; --_Candidate) { // try a match at _Candidate - _BidIt1 _Next1 = _Candidate; - _BidIt2 _Next2 = _Last2; - for (;;) { // test if [_First2, _Last2) is a suffix of [_First1, _Candidate) - if (_First2 == _Next2) { // match found - return _Next1; - } - - if (_First1 == _Next1) { - // [_First1, _Candidate) is shorter than [_First2, _Last2), remaining candidates nonviable - return _Last1; - } - - --_Next1; - --_Next2; - if (!_Pred(*_Next1, *_Next2)) { // counterexample found - break; - } - } - } -} - -template -_RanIt1 _Find_end_unchecked(const _RanIt1 _First1, const _RanIt1 _Last1, const _RanIt2 _First2, const _RanIt2 _Last2, - _Pr _Pred, random_access_iterator_tag, random_access_iterator_tag) { - // find last [_First2, _Last2) satisfying _Pred in random-access ranges - const _Iter_diff_t<_RanIt2> _Count2 = _Last2 - _First2; - if (_Count2 > 0 && _Count2 <= _Last1 - _First1) { - for (_RanIt1 _Candidate = _Last1 - static_cast<_Iter_diff_t<_RanIt1>>(_Count2);; --_Candidate) { - if (_Equal_rev_pred_unchecked(_Candidate, _First2, _Last2, _Pred)) { - return _Candidate; - } - - if (_First1 == _Candidate) { - break; - } - } - } - - return _Last1; -} - -template -_NODISCARD _FwdIt1 find_end(_FwdIt1 _First1, const _FwdIt1 _Last1, const _FwdIt2 _First2, const _FwdIt2 _Last2, - _Pr _Pred) { // find last [_First2, _Last2) satisfying _Pred - _Adl_verify_range(_First1, _Last1); - _Adl_verify_range(_First2, _Last2); - _Seek_wrapped( - _First1, _Find_end_unchecked(_Get_unwrapped(_First1), _Get_unwrapped(_Last1), _Get_unwrapped(_First2), - _Get_unwrapped(_Last2), _Pass_fn(_Pred), _Iter_cat_t<_FwdIt1>{}, _Iter_cat_t<_FwdIt2>{})); - - return _First1; -} -#endif // _HAS_IF_CONSTEXPR template _NODISCARD _CONSTEXPR20 _FwdIt1 find_end( @@ -4460,6 +4174,7 @@ namespace ranges { for (;; ++_Current) { if (++_First == _Last) { + ++_Current; return {_STD move(_Current), _STD move(_First)}; } @@ -4485,7 +4200,6 @@ namespace ranges { #endif // __cpp_lib_concepts // FUNCTION TEMPLATE unique_copy -#if _HAS_IF_CONSTEXPR // clang-format off #ifdef __cpp_lib_concepts template @@ -4553,83 +4267,6 @@ _CONSTEXPR20 _OutIt unique_copy(_InIt _First, _InIt _Last, _OutIt _Dest, _Pr _Pr return _Dest; } -#else // ^^^ _HAS_IF_CONSTEXPR / !_HAS_IF_CONSTEXPR vvv -template -_OutIt _Unique_copy_unchecked(_FwdIt _First, _FwdIt _Last, _OutIt _Dest, _Pr _Pred, true_type, _Any_tag) { - // copy compressing pairs satisfying _Pred, forward source iterator - // (can reread the source for comparison) - if (_First != _Last) { - _FwdIt _Firstb = _First; - - *_Dest = *_Firstb; - ++_Dest; - - while (++_First != _Last) { - if (!_Pred(*_Firstb, *_First)) { // copy unmatched - _Firstb = _First; - *_Dest = *_Firstb; - ++_Dest; - } - } - } - - return _Dest; -} - -template -_FwdIt _Unique_copy_unchecked(_InIt _First, _InIt _Last, _FwdIt _Dest, _Pr _Pred, false_type, true_type) { - // copy compressing pairs satisfying _Pred, forward dest iterator with matching T - // (assignment copies T; can reread dest for comparison) - if (_First != _Last) { - *_Dest = *_First; - - while (++_First != _Last) { - if (!_Pred(*_Dest, *_First)) { - *++_Dest = *_First; - } - } - - ++_Dest; - } - - return _Dest; -} - -template -_OutIt _Unique_copy_unchecked(_InIt _First, _InIt _Last, _OutIt _Dest, _Pr _Pred, false_type, false_type) { - // copy compressing pairs satisfying _Pred, otherwise - // (can't reread source or dest, construct a temporary) - if (_First != _Last) { - _Iter_value_t<_InIt> _Val = *_First; - - *_Dest = _Val; - ++_Dest; - - while (++_First != _Last) { - if (!_Pred(_Val, *_First)) { // copy unmatched - _Val = *_First; - *_Dest = _Val; - ++_Dest; - } - } - } - - return _Dest; -} - -template -_OutIt unique_copy(_InIt _First, _InIt _Last, _OutIt _Dest, _Pr _Pred) { // copy compressing pairs that match - _Adl_verify_range(_First, _Last); - _Seek_wrapped( - _Dest, _Unique_copy_unchecked(_Get_unwrapped(_First), _Get_unwrapped(_Last), _Get_unwrapped_unverified(_Dest), - _Pass_fn(_Pred), bool_constant<_Is_fwd_iter_v<_InIt>>{}, // to avoid ambiguity - bool_constant>, - is_same<_Iter_value_t<_InIt>, _Iter_value_t<_OutIt>>>>{})); - - return _Dest; -} -#endif // _HAS_IF_CONSTEXPR - template _CONSTEXPR20 _OutIt unique_copy(_InIt _First, _InIt _Last, _OutIt _Dest) { // copy compressing pairs that match return _STD unique_copy(_First, _Last, _Dest, equal_to<>{}); @@ -4840,7 +4477,7 @@ _CONSTEXPR20 _OutIt reverse_copy(_BidIt _First, _BidIt _Last, _OutIt _Dest) { auto _ULast = _Get_unwrapped(_Last); auto _UDest = _Get_unwrapped_n(_Dest, _Idl_distance<_BidIt>(_UFirst, _ULast)); -#if _HAS_IF_CONSTEXPR && _USE_STD_VECTOR_ALGORITHMS +#if _USE_STD_VECTOR_ALGORITHMS using _Elem = remove_pointer_t; using _DestElem = remove_pointer_t; constexpr bool _Allow_vectorization = conjunction_v, _DestElem>, @@ -4868,7 +4505,7 @@ _CONSTEXPR20 _OutIt reverse_copy(_BidIt _First, _BidIt _Last, _OutIt _Dest) { return _Dest; } } -#endif // _HAS_IF_CONSTEXPR && _USE_STD_VECTOR_ALGORITHMS +#endif // _USE_STD_VECTOR_ALGORITHMS for (; _UFirst != _ULast; ++_UDest) { *_UDest = *--_ULast; @@ -5629,7 +5266,6 @@ _FwdIt shift_right(_ExPo&&, _FwdIt _First, _FwdIt _Last, _Iter_diff_t<_FwdIt> _P #endif // _HAS_CXX20 // FUNCTION TEMPLATE partition -#if _HAS_IF_CONSTEXPR template _CONSTEXPR20 _FwdIt partition(_FwdIt _First, const _FwdIt _Last, _Pr _Pred) { // move elements satisfying _Pred to beginning of sequence @@ -5687,70 +5323,6 @@ _CONSTEXPR20 _FwdIt partition(_FwdIt _First, const _FwdIt _Last, _Pr _Pred) { _Seek_wrapped(_First, _UFirst); return _First; } -#else // ^^^ _HAS_IF_CONSTEXPR ^^^ // vvv !_HAS_IF_CONSTEXPR vvv -template -_FwdIt _Partition_unchecked(_FwdIt _First, const _FwdIt _Last, _Pr _Pred, forward_iterator_tag) { - // move elements satisfying _Pred to front, forward iterators - for (;;) { // skip in-place elements at beginning - if (_First == _Last) { - return _First; - } - - if (!_Pred(*_First)) { - break; - } - - ++_First; - } - - for (_FwdIt _Next = _First; ++_Next != _Last;) { - if (_Pred(*_Next)) { - _STD iter_swap(_First, _Next); // out of place, swap and loop - ++_First; - } - } - - return _First; -} - -template -_BidIt _Partition_unchecked(_BidIt _First, _BidIt _Last, _Pr _Pred, bidirectional_iterator_tag) { - // move elements satisfying _Pred to front, bidirectional iterators - for (;;) { // find any out-of-order pair - for (;;) { // skip in-place elements at beginning - if (_First == _Last) { - return _First; - } - - if (!_Pred(*_First)) { - break; - } - - ++_First; - } - - do { // skip in-place elements at end - --_Last; - if (_First == _Last) { - return _First; - } - } while (!_Pred(*_Last)); - - _STD iter_swap(_First, _Last); // out of place, swap and loop - ++_First; - } -} - -template -_FwdIt partition(_FwdIt _First, const _FwdIt _Last, _Pr _Pred) { - // move elements satisfying _Pred to beginning of sequence - _Adl_verify_range(_First, _Last); - _Seek_wrapped(_First, - _Partition_unchecked(_Get_unwrapped(_First), _Get_unwrapped(_Last), _Pass_fn(_Pred), _Iter_cat_t<_FwdIt>{})); - - return _First; -} -#endif // _HAS_IF_CONSTEXPR #if _HAS_CXX17 template = 0> diff --git a/stl/inc/atomic b/stl/inc/atomic index a13b177103b..5e229aefe28 100644 --- a/stl/inc/atomic +++ b/stl/inc/atomic @@ -287,14 +287,11 @@ template _NODISCARD _Integral _Atomic_reinterpret_as(const _Ty& _Source) noexcept { // interprets _Source as the supplied integral type static_assert(is_integral_v<_Integral>, "Tried to reinterpret memory as non-integral"); -#if _HAS_IF_CONSTEXPR if constexpr (is_integral_v<_Ty> && sizeof(_Integral) == sizeof(_Ty)) { return static_cast<_Integral>(_Source); } else if constexpr (is_pointer_v<_Ty> && sizeof(_Integral) == sizeof(_Ty)) { return reinterpret_cast<_Integral>(_Source); - } else -#endif // _HAS_IF_CONSTEXPR - { + } else { _Integral _Result{}; // zero padding bits _CSTD memcpy(&_Result, _STD addressof(_Source), sizeof(_Source)); return _Result; diff --git a/stl/inc/bitset b/stl/inc/bitset index 6c2b0bc3807..8d21a2676ce 100644 --- a/stl/inc/bitset +++ b/stl/inc/bitset @@ -282,12 +282,12 @@ public: constexpr bool _Bits_zero = _Bits == 0; constexpr bool _Bits_small = _Bits <= 32; constexpr bool _Bits_large = _Bits > 64; - if _CONSTEXPR_IF (_Bits_zero) { + if constexpr (_Bits_zero) { return 0; - } else if _CONSTEXPR_IF (_Bits_small) { + } else if constexpr (_Bits_small) { return static_cast(_Array[0]); } else { - if _CONSTEXPR_IF (_Bits_large) { + if constexpr (_Bits_large) { for (size_t _Idx = 1; _Idx <= _Words; ++_Idx) { if (_Array[_Idx] != 0) { _Xoflo(); // fail if any high-order words are nonzero @@ -306,10 +306,10 @@ public: _NODISCARD unsigned long long to_ullong() const { constexpr bool _Bits_zero = _Bits == 0; constexpr bool _Bits_large = _Bits > 64; - if _CONSTEXPR_IF (_Bits_zero) { + if constexpr (_Bits_zero) { return 0; } else { - if _CONSTEXPR_IF (_Bits_large) { + if constexpr (_Bits_large) { for (size_t _Idx = 1; _Idx <= _Words; ++_Idx) { if (_Array[_Idx] != 0) { _Xoflo(); // fail if any high-order words are nonzero @@ -398,7 +398,7 @@ public: _NODISCARD bool all() const noexcept { constexpr bool _Zero_length = _Bits == 0; - if _CONSTEXPR_IF (_Zero_length) { // must test for this, otherwise would count one full word + if constexpr (_Zero_length) { // must test for this, otherwise would count one full word return true; } @@ -432,7 +432,7 @@ private: void _Trim() noexcept { // clear any trailing bits in last word constexpr bool _Work_to_do = _Bits == 0 || _Bits % _Bitsperword != 0; - if _CONSTEXPR_IF (_Work_to_do) { + if constexpr (_Work_to_do) { _Array[_Words] &= (_Ty{1} << _Bits % _Bitsperword) - 1; } } @@ -534,7 +534,7 @@ basic_istream<_Elem, _Tr>& operator>>(basic_istream<_Elem, _Tr>& _Istr, bitset<_ constexpr bool _Has_bits = _Bits > 0; - if _CONSTEXPR_IF (_Has_bits) { + if constexpr (_Has_bits) { if (!_Changed) { _State |= _Istr_t::failbit; } diff --git a/stl/inc/cmath b/stl/inc/cmath index 354587044fe..46eecf2faff 100644 --- a/stl/inc/cmath +++ b/stl/inc/cmath @@ -562,26 +562,11 @@ double frexp(_Ty _Value, _Out_ int* const _Exp) noexcept /* strengthened */ { } // FUNCTION TEMPLATE fma -#if !_HAS_IF_CONSTEXPR -inline float _Fma(float _Left, float _Middle, float _Right) noexcept { - return _CSTD fmaf(_Left, _Middle, _Right); -} - -inline double _Fma(double _Left, double _Middle, double _Right) noexcept { - return _CSTD fma(_Left, _Middle, _Right); -} - -inline long double _Fma(long double _Left, long double _Middle, long double _Right) noexcept { - return _CSTD fmal(_Left, _Middle, _Right); -} -#endif // !_HAS_IF_CONSTEXPR - template && _STD is_arithmetic_v<_Ty2> && _STD is_arithmetic_v<_Ty3>, int> = 0> _NODISCARD _STD _Common_float_type_t<_Ty1, _STD _Common_float_type_t<_Ty2, _Ty3>> fma( _Ty1 _Left, _Ty2 _Middle, _Ty3 _Right) noexcept /* strengthened */ { using _Common = _STD _Common_float_type_t<_Ty1, _STD _Common_float_type_t<_Ty2, _Ty3>>; -#if _HAS_IF_CONSTEXPR if constexpr (_STD is_same_v<_Common, float>) { return _CSTD fmaf(static_cast<_Common>(_Left), static_cast<_Common>(_Middle), static_cast<_Common>(_Right)); } else if constexpr (_STD is_same_v<_Common, double>) { @@ -589,30 +574,12 @@ _NODISCARD _STD _Common_float_type_t<_Ty1, _STD _Common_float_type_t<_Ty2, _Ty3> } else { return _CSTD fmal(static_cast<_Common>(_Left), static_cast<_Common>(_Middle), static_cast<_Common>(_Right)); } -#else // ^^^ use "if constexpr" dispatch / use overload resolution vvv - return _Fma(static_cast<_Common>(_Left), static_cast<_Common>(_Middle), static_cast<_Common>(_Right)); -#endif // _HAS_IF_CONSTEXPR } // FUNCTION TEMPLATE remquo -#if !_HAS_IF_CONSTEXPR -inline float _Remquo(float _Left, float _Right, int* _Pquo) noexcept { - return _CSTD remquof(_Left, _Right, _Pquo); -} - -inline double _Remquo(double _Left, double _Right, int* _Pquo) noexcept { - return _CSTD remquo(_Left, _Right, _Pquo); -} - -inline long double _Remquo(long double _Left, long double _Right, int* _Pquo) noexcept { - return _CSTD remquol(_Left, _Right, _Pquo); -} -#endif // !_HAS_IF_CONSTEXPR - template && _STD is_arithmetic_v<_Ty2>, int> = 0> _STD _Common_float_type_t<_Ty1, _Ty2> remquo(_Ty1 _Left, _Ty2 _Right, int* _Pquo) noexcept /* strengthened */ { using _Common = _STD _Common_float_type_t<_Ty1, _Ty2>; -#if _HAS_IF_CONSTEXPR if constexpr (_STD is_same_v<_Common, float>) { return _CSTD remquof(static_cast<_Common>(_Left), static_cast<_Common>(_Right), _Pquo); } else if constexpr (_STD is_same_v<_Common, double>) { @@ -620,9 +587,6 @@ _STD _Common_float_type_t<_Ty1, _Ty2> remquo(_Ty1 _Left, _Ty2 _Right, int* _Pquo } else { return _CSTD remquol(static_cast<_Common>(_Left), static_cast<_Common>(_Right), _Pquo); } -#else // ^^^ use "if constexpr" dispatch / use overload resolution vvv - return _Remquo(static_cast<_Common>(_Left), static_cast<_Common>(_Right), _Pquo); -#endif // _HAS_IF_CONSTEXPR } #define _GENERIC_MATH1_BASE(NAME, RET, FUN) \ diff --git a/stl/inc/codecvt b/stl/inc/codecvt index 421aec7e4c1..0f713872300 100644 --- a/stl/inc/codecvt +++ b/stl/inc/codecvt @@ -96,7 +96,7 @@ protected: *_Pstate = 1; constexpr bool _Consuming = (_Mymode & consume_header) != 0; - if _CONSTEXPR_IF (_Consuming) { + if constexpr (_Consuming) { if (_Ch == 0xfeff) { // drop header and retry const result _Ans = do_in(_State, _Mid1, _Last1, _Mid1, _First2, _Last2, _Mid2); @@ -159,7 +159,7 @@ protected: if (*_Pstate == 0) { // first time, maybe generate header *_Pstate = 1; constexpr bool _Generating = (_Mymode & generate_header) != 0; - if _CONSTEXPR_IF (_Generating) { + if constexpr (_Generating) { if (_Last2 - _Mid2 < 3 + 1 + _Nextra) { return _Mybase::partial; // not enough room for both } @@ -254,7 +254,7 @@ protected: constexpr bool _Prefer_LE = (_Mymode & little_endian) != 0; constexpr char _Default_endian = _Prefer_LE ? _Little_first : _Big_first; - if _CONSTEXPR_IF (_Prefer_LE) { + if constexpr (_Prefer_LE) { _Ch0 = static_cast(_Ptr[1] << 8 | _Ptr[0]); } else { _Ch0 = static_cast(_Ptr[0] << 8 | _Ptr[1]); @@ -262,7 +262,7 @@ protected: *_Pstate = _Default_endian; constexpr bool _Consuming = (_Mymode & consume_header) != 0; - if _CONSTEXPR_IF (_Consuming) { + if constexpr (_Consuming) { if (_Ch0 == 0xfffeu) { *_Pstate = 3 - _Default_endian; } @@ -321,7 +321,7 @@ protected: if (*_Pstate == 0) { // determine endianness once, maybe generate header *_Pstate = (_Mymode & little_endian) != 0 ? _Little_first : _Big_first; constexpr bool _Generating = (_Mymode & generate_header) != 0; - if _CONSTEXPR_IF (_Generating) { + if constexpr (_Generating) { if (_Last2 - _Mid2 < 3 * _Bytes_per_word) { return _Mybase::partial; // not enough room for all } @@ -536,7 +536,7 @@ protected: *_Pstate = 1; constexpr bool _Consuming = (_Mymode & consume_header) != 0; - if _CONSTEXPR_IF (_Consuming) { + if constexpr (_Consuming) { if (_Ch == 0xfeffu) { // drop header and retry result _Ans = do_in(_State, _Mid1, _Last1, _Mid1, _First2, _Last2, _Mid2); diff --git a/stl/inc/cvt/one_one b/stl/inc/cvt/one_one index de4c7e09e8f..dbcd59e6b32 100644 --- a/stl/inc/cvt/one_one +++ b/stl/inc/cvt/one_one @@ -19,10 +19,6 @@ _STL_DISABLE_CLANG_WARNINGS #pragma push_macro("new") #undef new -#if !_HAS_IF_CONSTEXPR -#pragma warning(disable : 4127) // conditional expression is constant -#endif // !_HAS_IF_CONSTEXPR - namespace stdext { namespace cvt { @@ -75,7 +71,7 @@ namespace stdext { constexpr unsigned char _Default_endian = static_cast( (_Mode & _STD little_endian) != 0 ? _STD _Little_first : _STD _Big_first); - if _CONSTEXPR_IF ((_Mode & _STD little_endian) != 0) { + if constexpr ((_Mode & _STD little_endian) != 0) { for (_Count = _Bytes_per_word; 0 < _Count;) { _Ch = _Ch << 8 | _Ptr[--_Count]; } @@ -85,7 +81,7 @@ namespace stdext { } } - if _CONSTEXPR_IF ((_Mode & _STD consume_header) == 0) { + if constexpr ((_Mode & _STD consume_header) == 0) { *_Pstate = _Default_endian; } else if (_Ch != 0xfeff && _Ch != (0xfffe0000 >> 8 * (4 - _Bytes_per_word))) { *_Pstate = _Default_endian; @@ -124,13 +120,13 @@ namespace stdext { if (*_Pstate == 0) { // determine endianness once, maybe generate header unsigned long _Header = 0xfeff; - if _CONSTEXPR_IF ((_Mode & _STD little_endian) != 0) { + if constexpr ((_Mode & _STD little_endian) != 0) { *_Pstate = _STD _Little_first; } else { *_Pstate = _STD _Big_first; } - if _CONSTEXPR_IF ((_Mode & _STD generate_header) == 0) { + if constexpr ((_Mode & _STD generate_header) == 0) { (void) _Header; // unused } else if (_Last2 - _Mid2 < 2 * _Bytes_per_word) { return _Mybase::partial; // not enough room for both @@ -216,7 +212,7 @@ namespace stdext { } virtual int do_max_length() const noexcept override { // return maximum length required for a conversion - if _CONSTEXPR_IF ((_Mode & (_STD consume_header | _STD generate_header)) != 0) { + if constexpr ((_Mode & (_STD consume_header | _STD generate_header)) != 0) { return 2 * _Bytes_per_word; } else { return _Bytes_per_word; @@ -224,7 +220,7 @@ namespace stdext { } virtual int do_encoding() const noexcept override { // return length of code sequence (from codecvt) - if _CONSTEXPR_IF ((_Mode & (_STD consume_header | _STD generate_header)) != 0) { + if constexpr ((_Mode & (_STD consume_header | _STD generate_header)) != 0) { return -1; // -1 => state dependent } else { return static_cast(_Bytes_per_word); diff --git a/stl/inc/cvt/utf16 b/stl/inc/cvt/utf16 index 97dd72a2c68..7a53127b788 100644 --- a/stl/inc/cvt/utf16 +++ b/stl/inc/cvt/utf16 @@ -19,10 +19,6 @@ _STL_DISABLE_CLANG_WARNINGS #pragma push_macro("new") #undef new -#if !_HAS_IF_CONSTEXPR -#pragma warning(disable : 4127) // conditional expression is constant -#endif // !_HAS_IF_CONSTEXPR - namespace stdext { namespace cvt { using _Statype = _CSTD mbstate_t; @@ -69,13 +65,13 @@ namespace stdext { constexpr unsigned char _Default_endian = static_cast( (_Mode & _STD little_endian) != 0 ? _STD _Little_first : _STD _Big_first); - if _CONSTEXPR_IF ((_Mode & _STD little_endian) != 0) { + if constexpr ((_Mode & _STD little_endian) != 0) { _Ch0 = static_cast(_Ptr[1] << 8 | _Ptr[0]); } else { _Ch0 = static_cast(_Ptr[0] << 8 | _Ptr[1]); } - if _CONSTEXPR_IF ((_Mode & _STD consume_header) == 0) { + if constexpr ((_Mode & _STD consume_header) == 0) { *_Pstate = _Default_endian; } else if (_Ch0 != 0xfeff && _Ch0 != 0xfffe) { *_Pstate = _Default_endian; @@ -130,13 +126,13 @@ namespace stdext { _Mid2 = _First2; if (*_Pstate == 0) { // determine endianness once, maybe generate header - if _CONSTEXPR_IF ((_Mode & _STD little_endian) != 0) { + if constexpr ((_Mode & _STD little_endian) != 0) { *_Pstate = _STD _Little_first; } else { *_Pstate = _STD _Big_first; } - if _CONSTEXPR_IF ((_Mode & _STD generate_header) != 0) { + if constexpr ((_Mode & _STD generate_header) != 0) { if (_Last2 - _Mid2 < 3 * _Bytes_per_word) { return _Mybase::partial; // not enough room for both } @@ -245,7 +241,7 @@ namespace stdext { } virtual int do_max_length() const noexcept override { // return maximum length required for a conversion - if _CONSTEXPR_IF ((_Mode & (_STD consume_header | _STD generate_header)) != 0) { + if constexpr ((_Mode & (_STD consume_header | _STD generate_header)) != 0) { return 3 * _Bytes_per_word; } else { return 6 * _Bytes_per_word; @@ -253,7 +249,7 @@ namespace stdext { } virtual int do_encoding() const noexcept override { // return length of code sequence (from codecvt) - if _CONSTEXPR_IF ((_Mode & (_STD consume_header | _STD generate_header)) != 0) { + if constexpr ((_Mode & (_STD consume_header | _STD generate_header)) != 0) { return -1; // -1 => state dependent } else { return 0; // 0 => varying length diff --git a/stl/inc/cvt/utf8 b/stl/inc/cvt/utf8 index 15c49c204d3..d5c50aced94 100644 --- a/stl/inc/cvt/utf8 +++ b/stl/inc/cvt/utf8 @@ -19,10 +19,6 @@ _STL_DISABLE_CLANG_WARNINGS #pragma push_macro("new") #undef new -#if !_HAS_IF_CONSTEXPR -#pragma warning(disable : 4127) // conditional expression is constant -#endif // !_HAS_IF_CONSTEXPR - namespace stdext { namespace cvt { @@ -96,7 +92,7 @@ namespace stdext { if (*_Pstate == 0) { // first time, maybe look for and consume header *_Pstate = 1; - if _CONSTEXPR_IF ((_Mode & _STD consume_header) != 0) { + if constexpr ((_Mode & _STD consume_header) != 0) { if (_Ch == 0xfeff) { // drop header and retry result _Ans = do_in(_State, _Mid1, _Last1, _Mid1, _First2, _Last2, _Mid2); @@ -157,7 +153,7 @@ namespace stdext { if (*_Pstate == 0) { // first time, maybe generate header *_Pstate = 1; - if _CONSTEXPR_IF ((_Mode & _STD generate_header) != 0) { + if constexpr ((_Mode & _STD generate_header) != 0) { if (_Last2 - _Mid2 < 3 + 1 + _Nextra) { return _Mybase::partial; // not enough room for both } @@ -224,7 +220,7 @@ namespace stdext { } virtual int do_max_length() const noexcept override { // return maximum length required for a conversion - if _CONSTEXPR_IF ((_Mode & (_STD consume_header | _STD generate_header)) != 0) { + if constexpr ((_Mode & (_STD consume_header | _STD generate_header)) != 0) { return 9; } else { return 6; @@ -232,7 +228,7 @@ namespace stdext { } virtual int do_encoding() const noexcept override { // return length of code sequence (from codecvt) - if _CONSTEXPR_IF ((_Mode & (_STD consume_header | _STD generate_header)) != 0) { + if constexpr ((_Mode & (_STD consume_header | _STD generate_header)) != 0) { return -1; // -1 => state dependent } else { return 0; // 0 => varying length diff --git a/stl/inc/cvt/utf8_utf16 b/stl/inc/cvt/utf8_utf16 index bef9cc35a9b..7be19d42a8d 100644 --- a/stl/inc/cvt/utf8_utf16 +++ b/stl/inc/cvt/utf8_utf16 @@ -19,10 +19,6 @@ _STL_DISABLE_CLANG_WARNINGS #pragma push_macro("new") #undef new -#if !_HAS_IF_CONSTEXPR -#pragma warning(disable : 4127) // conditional expression is constant -#endif // !_HAS_IF_CONSTEXPR - namespace stdext { namespace cvt { @@ -142,7 +138,7 @@ namespace stdext { if (*_Pstate == 0) { // first time, maybe look for and consume header *_Pstate = 1; - if _CONSTEXPR_IF ((_Mode & _STD consume_header) != 0) { + if constexpr ((_Mode & _STD consume_header) != 0) { if (_Ch == 0xfeff) { // drop header and retry result _Ans = do_in(_State, _Mid1, _Last1, _Mid1, _First2, _Last2, _Mid2); @@ -208,7 +204,7 @@ namespace stdext { break; // not enough room, even without header } - if _CONSTEXPR_IF ((_Mode & _STD generate_header) != 0) { // maybe header to put + if constexpr ((_Mode & _STD generate_header) != 0) { // maybe header to put if (*_Pstate == 0) { // header to put if (_Last2 - _Mid2 < 3 + _Nput) { break; // not enough room for both @@ -282,9 +278,9 @@ namespace stdext { } virtual int do_max_length() const noexcept override { // return maximum length required for a conversion - if _CONSTEXPR_IF ((_Mode & _STD consume_header) != 0) { + if constexpr ((_Mode & _STD consume_header) != 0) { return 9; // header + max input - } else if _CONSTEXPR_IF ((_Mode & _STD generate_header) != 0) { + } else if constexpr ((_Mode & _STD generate_header) != 0) { return 7; // header + max output } else { return 6; // 6-byte max input sequence, no 3-byte header diff --git a/stl/inc/cvt/xtwo_byte b/stl/inc/cvt/xtwo_byte index 17b21b27ed9..f77fc0dd9fa 100644 --- a/stl/inc/cvt/xtwo_byte +++ b/stl/inc/cvt/xtwo_byte @@ -18,10 +18,6 @@ _STL_DISABLE_CLANG_WARNINGS #pragma push_macro("new") #undef new -#if !_HAS_IF_CONSTEXPR -#pragma warning(disable : 4127) // conditional expression is constant -#endif // !_HAS_IF_CONSTEXPR - namespace stdext { namespace cvt { @@ -57,7 +53,7 @@ namespace stdext { if (_Bytecode < _Table::_Nlow) { _Widecode = _Bytecode; // map byte to same wide value } else if ((_Widecode = _Table::_Btw[_Bytecode - _Table::_Nlow]) == 0) { - if _CONSTEXPR_IF (_Table::_Nbytes < 2) { + if constexpr (_Table::_Nbytes < 2) { return _Mybase::error; // no single-byte mapping } else { if (_Mid1 + 1 == _Last1) { diff --git a/stl/inc/deque b/stl/inc/deque index 729691d1e75..fe0b478bda0 100644 --- a/stl/inc/deque +++ b/stl/inc/deque @@ -690,7 +690,7 @@ public: deque(deque&& _Right, const _Alloc& _Al) : _Mypair(_One_then_variadic_args_t{}, _Al) { _Alproxy_ty _Alproxy(_Getal()); - if _CONSTEXPR_IF (!_Alty_traits::is_always_equal::value) { + if constexpr (!_Alty_traits::is_always_equal::value) { if (_Getal() != _Right._Getal()) { _Container_proxy_ptr12<_Alproxy_ty> _Proxy(_Alproxy, _Get_data()); _Construct(_STD make_move_iterator(_Right._Unchecked_begin()), diff --git a/stl/inc/exception b/stl/inc/exception index 0b0f52e749c..5c9fdcd8cbf 100644 --- a/stl/inc/exception +++ b/stl/inc/exception @@ -353,7 +353,6 @@ struct _With_nested : _Uty, nested_exception { // glue user exception to nested_ : _Uty(_STD forward<_Ty>(_Arg)), nested_exception() {} // store user exception and current_exception() }; -#if _HAS_IF_CONSTEXPR template [[noreturn]] void throw_with_nested(_Ty&& _Arg) { // throw user exception, glued to nested_exception if possible using _Uty = decay_t<_Ty>; @@ -367,29 +366,6 @@ template _THROW(_STD forward<_Ty>(_Arg)); } } -#else // ^^^ _HAS_IF_CONSTEXPR ^^^ // vvv !_HAS_IF_CONSTEXPR vvv -template -[[noreturn]] void _Throw_with_nested(_Ty&& _Arg, true_type) { // throw user exception glued to nested_exception - using _Uty = decay_t<_Ty>; - using _Glued = _With_nested<_Ty, _Uty>; - - _THROW(_Glued(_STD forward<_Ty>(_Arg))); -} - -template -[[noreturn]] void _Throw_with_nested(_Ty&& _Arg, false_type) { // throw user exception by itself - _THROW(_STD forward<_Ty>(_Arg)); -} - -template -[[noreturn]] void throw_with_nested(_Ty&& _Arg) { // throw user exception, glued to nested_exception if possible - using _Uty = decay_t<_Ty>; - - bool_constant && !is_base_of_v && !is_final_v<_Uty>> _Tag; - - _Throw_with_nested(_STD forward<_Ty>(_Arg), _Tag); -} -#endif // _HAS_IF_CONSTEXPR #ifdef _CPPRTTI // FUNCTION TEMPLATE rethrow_if_nested diff --git a/stl/inc/forward_list b/stl/inc/forward_list index c3446e70e32..935574d1004 100644 --- a/stl/inc/forward_list +++ b/stl/inc/forward_list @@ -615,7 +615,7 @@ public: forward_list(forward_list&& _Right, const _Alloc& _Al) noexcept( _Alnode_traits::is_always_equal::value) // strengthened : _Mypair(_One_then_variadic_args_t{}, _Al) { - if _CONSTEXPR_IF (!_Alty_traits::is_always_equal::value) { + if constexpr (!_Alty_traits::is_always_equal::value) { if (_Getal() != _Right._Getal()) { _Flist_insert_after_op2<_Alnode> _Insert_op(_Getal()); _Insert_op._Append_range_unchecked( @@ -1252,7 +1252,7 @@ private: auto& _Right_data = _Right._Mypair._Myval2; #if _ITERATOR_DEBUG_LEVEL != 0 _DEBUG_ORDER_UNWRAPPED(_Right._Unchecked_begin(), _Default_sentinel{}, _Pred); - if _CONSTEXPR_IF (!_Alnode_traits::is_always_equal::value) { + if constexpr (!_Alnode_traits::is_always_equal::value) { _STL_VERIFY(_Getal() == _Right._Getal(), "list allocators incompatible for merge"); } #endif // _ITERATOR_DEBUG_LEVEL != 0 @@ -1273,7 +1273,7 @@ private: #if _ITERATOR_DEBUG_LEVEL == 2 constexpr bool _Noexcept = noexcept(_DEBUG_LT_PRED(_Pred, _My_data._Myhead->_Myval, _Right_data._Myhead->_Myval)); - if _CONSTEXPR_IF (_Noexcept) { + if constexpr (_Noexcept) { // if the comparison is noexcept, we can take all the iterators in one go and avoid quadratic updates of // the iterator chain _Lockit _Lock(_LOCK_DEBUG); @@ -1325,7 +1325,7 @@ private: } #if _ITERATOR_DEBUG_LEVEL == 2 - if _CONSTEXPR_IF (!_Noexcept) { + if constexpr (!_Noexcept) { _Lockit _Lock(_LOCK_DEBUG); for (auto _Next = _First2; _Next != _Run_end; _Next = _Next->_Next) { _Transfer_ownership(_Right, _Next); @@ -1423,7 +1423,7 @@ private: #if _ITERATOR_DEBUG_LEVEL == 0 (void) _Right; #else // ^^^ _ITERATOR_DEBUG_LEVEL == 0 // _ITERATOR_DEBUG_LEVEL != 0 vvv - if _CONSTEXPR_IF (!_Alnode_traits::is_always_equal::value) { + if constexpr (!_Alnode_traits::is_always_equal::value) { _STL_VERIFY(_Getal() == _Right._Getal(), "forward_list containers incompatible for splice_after"); } #endif // _ITERATOR_DEBUG_LEVEL == 0 @@ -1452,7 +1452,7 @@ private: #if _ITERATOR_DEBUG_LEVEL == 0 (void) _Right; #else // ^^^ _ITERATOR_DEBUG_LEVEL == 0 // _ITERATOR_DEBUG_LEVEL != 0 vvv - if _CONSTEXPR_IF (!_Alnode_traits::is_always_equal::value) { + if constexpr (!_Alnode_traits::is_always_equal::value) { _STL_VERIFY(_Getal() == _Right._Getal(), "forward_list containers incompatible for splice_after"); } #endif // _ITERATOR_DEBUG_LEVEL == 0 diff --git a/stl/inc/fstream b/stl/inc/fstream index 6e7482640ca..6556fcd6c35 100644 --- a/stl/inc/fstream +++ b/stl/inc/fstream @@ -548,7 +548,7 @@ protected: #pragma warning(disable : 4127) // conditional expression is constant virtual streamsize __CLR_OR_THIS_CALL xsgetn(_Elem* _Ptr, streamsize _Count) override { // get _Count characters from stream - if _CONSTEXPR_IF (sizeof(_Elem) == 1) { + if constexpr (sizeof(_Elem) == 1) { if (_Count <= 0) { return 0; } @@ -596,7 +596,7 @@ protected: virtual streamsize __CLR_OR_THIS_CALL xsputn(const _Elem* _Ptr, streamsize _Count) override { // put _Count characters to stream - if _CONSTEXPR_IF (sizeof(_Elem) == 1) { + if constexpr (sizeof(_Elem) == 1) { if (_Pcvt) { // if we need a nontrivial codecvt transform, do the default expensive thing return _Mysb::xsputn(_Ptr, _Count); } diff --git a/stl/inc/functional b/stl/inc/functional index 1d8ad65b20e..4a46439d871 100644 --- a/stl/inc/functional +++ b/stl/inc/functional @@ -772,7 +772,6 @@ template _INLINE_VAR constexpr bool _Testable_callable_v = disjunction_v, _Is_specialization<_Ty, function>, is_member_pointer<_Ty>>; -#if _HAS_IF_CONSTEXPR template bool _Test_callable(const _Ty& _Arg) noexcept { // determine whether std::function must store _Arg if constexpr (_Testable_callable_v<_Ty>) { @@ -781,23 +780,6 @@ bool _Test_callable(const _Ty& _Arg) noexcept { // determine whether std::functi return true; } } -#else // ^^^ _HAS_IF_CONSTEXPR // !_HAS_IF_CONSTEXPR vvv -template -bool _Test_callable(true_type, const _Ty& _Arg) noexcept { - // std::function must store non-null testable callable objects - return !!_Arg; -} - -template -bool _Test_callable(false_type, const _Ty&) noexcept { // std::function must store arbitrary callable objects - return true; -} - -template -bool _Test_callable(const _Ty& _Arg) noexcept { // determine whether std::function must store _Arg - return _Test_callable(bool_constant<_Testable_callable_v<_Ty>>{}, _Arg); -} -#endif // _HAS_IF_CONSTEXPR // CLASS TEMPLATE _Func_base template @@ -851,7 +833,7 @@ public: private: virtual _Mybase* _Copy(void* _Where) const override { auto& _Myax = _Mypair._Get_first(); - if _CONSTEXPR_IF (_Is_large<_Func_impl>) { + if constexpr (_Is_large<_Func_impl>) { _Myalty _Rebound(_Myax); _Alloc_construct_ptr<_Myalty> _Constructor{_Rebound}; _Constructor._Allocate(); @@ -865,7 +847,7 @@ private: } virtual _Mybase* _Move(void* _Where) noexcept override { - if _CONSTEXPR_IF (_Is_large<_Func_impl>) { + if constexpr (_Is_large<_Func_impl>) { return nullptr; } else { const auto _Ptr = static_cast<_Func_impl*>(_Where); @@ -917,7 +899,7 @@ public: private: virtual _Mybase* _Copy(void* _Where) const override { - if _CONSTEXPR_IF (_Is_large<_Func_impl_no_alloc>) { + if constexpr (_Is_large<_Func_impl_no_alloc>) { (void) _Where; // TRANSITION, DevCom-1004719 return _Global_new<_Func_impl_no_alloc>(_Callee); } else { @@ -926,7 +908,7 @@ private: } virtual _Mybase* _Move(void* _Where) noexcept override { - if _CONSTEXPR_IF (_Is_large<_Func_impl_no_alloc>) { + if constexpr (_Is_large<_Func_impl_no_alloc>) { (void) _Where; // TRANSITION, DevCom-1004719 return nullptr; } else { @@ -1025,7 +1007,7 @@ protected: } using _Impl = _Func_impl_no_alloc, _Ret, _Types...>; - if _CONSTEXPR_IF (_Is_large<_Impl>) { + if constexpr (_Is_large<_Impl>) { // dynamically allocate _Val _Set(_Global_new<_Impl>(_STD forward<_Fx>(_Val))); } else { @@ -1042,7 +1024,7 @@ protected: } using _Myimpl = _Func_impl, _Alloc, _Ret, _Types...>; - if _CONSTEXPR_IF (_Is_large<_Myimpl>) { + if constexpr (_Is_large<_Myimpl>) { // dynamically allocate _Val using _Alimpl = _Rebind_alloc_t<_Alloc, _Myimpl>; _Alimpl _Al(_Ax); diff --git a/stl/inc/future b/stl/inc/future index 2600a3cac8f..d38072b6692 100644 --- a/stl/inc/future +++ b/stl/inc/future @@ -874,6 +874,9 @@ class future : public _State_manager<_Ty> { using _Mybase = _State_manager<_Ty>; public: + static_assert(!is_array_v<_Ty> && is_object_v<_Ty> && is_destructible_v<_Ty>, + "T in future must meet the Cpp17Destructible requirements (N4878 [futures.unique.future]/4)."); + future() noexcept {} future(future&& _Other) noexcept : _Mybase(_STD move(_Other), true) {} @@ -972,6 +975,9 @@ class shared_future : public _State_manager<_Ty> { using _Mybase = _State_manager<_Ty>; public: + static_assert(!is_array_v<_Ty> && is_object_v<_Ty> && is_destructible_v<_Ty>, + "T in shared_future must meet the Cpp17Destructible requirements (N4878 [futures.shared.future]/4)."); + shared_future() noexcept {} shared_future(const shared_future& _Other) noexcept : _Mybase(_Other) {} @@ -1139,6 +1145,9 @@ private: template class promise { // class that defines an asynchronous provider that holds a value public: + static_assert(!is_array_v<_Ty> && is_object_v<_Ty> && is_destructible_v<_Ty>, + "T in promise must meet the Cpp17Destructible requirements (N4878 [futures.promise]/1)."); + promise() : _MyPromise(new _Associated_state<_Ty>) {} template diff --git a/stl/inc/header-units.json b/stl/inc/header-units.json new file mode 100644 index 00000000000..cb1ef9efeb5 --- /dev/null +++ b/stl/inc/header-units.json @@ -0,0 +1,149 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +{ + "Version": "1.0", + "BuildAsHeaderUnits": [ + // "__msvc_all_public_headers.hpp", // for testing, not production + "__msvc_system_error_abi.hpp", + "algorithm", + "any", + "array", + "atomic", + "barrier", + "bit", + "bitset", + // "cassert", // design is permanently incompatible with header units + // "ccomplex", // removed in C++20 + "cctype", + "cerrno", + "cfenv", + "cfloat", + "charconv", + "chrono", + "cinttypes", + // "ciso646", // removed in C++20 + "climits", + "clocale", + "cmath", + "codecvt", + "compare", + "complex", + "concepts", + "condition_variable", + "coroutine", + "csetjmp", + "csignal", + // "cstdalign", // removed in C++20 + "cstdarg", + // "cstdbool", // removed in C++20 + "cstddef", + "cstdint", + "cstdio", + "cstdlib", + "cstring", + // "ctgmath", // removed in C++20 + "ctime", + "cuchar", + "cwchar", + "cwctype", + "deque", + "exception", + "execution", + "filesystem", + "forward_list", + "fstream", + "functional", + "future", + // "hash_map", // non-Standard, will be removed soon + // "hash_set", // non-Standard, will be removed soon + "initializer_list", + "iomanip", + "ios", + "iosfwd", + "iostream", + "iso646.h", + "istream", + "iterator", + "latch", + "limits", + "list", + "locale", + "map", + "memory", + "memory_resource", + "mutex", + "new", + "numbers", + "numeric", + "optional", + "ostream", + "queue", + "random", + "ranges", + "ratio", + "regex", + "scoped_allocator", + "semaphore", + "set", + "shared_mutex", + "span", + "sstream", + "stack", + "stdexcept", + "stop_token", + "streambuf", + "string", + "string_view", + "strstream", + "system_error", + "thread", + "tuple", + "type_traits", + "typeindex", + "typeinfo", + "unordered_map", + "unordered_set", + "use_ansi.h", + "utility", + "valarray", + "variant", + "vector", + "version", + "xatomic.h", + "xatomic_wait.h", + "xbit_ops.h", + "xcall_once.h", + "xcharconv.h", + "xcharconv_ryu.h", + "xcharconv_ryu_tables.h", + "xerrc.h", + "xfacet", + "xfilesystem_abi.h", + "xhash", + "xiosbase", + // "xkeycheck.h", // internal header, provides no machinery, scans for macroized keywords only + "xlocale", + "xlocbuf", + "xlocinfo", + "xlocinfo.h", + "xlocmes", + "xlocmon", + "xlocnum", + "xloctime", + "xmemory", + "xnode_handle.h", + "xpolymorphic_allocator.h", + "xsmf_control.h", + "xstddef", + "xstring", + "xthreads.h", + "xtimec.h", + "xtr1common", + "xtree", + "xutility", + "ymath.h", + "yvals.h", + "yvals_core.h" + ] +} diff --git a/stl/inc/limits b/stl/inc/limits index 01bb53bab0b..bfe6ee02843 100644 --- a/stl/inc/limits +++ b/stl/inc/limits @@ -1058,13 +1058,18 @@ _NODISCARD int _Checked_x86_x64_countr_zero(const _Ty _Val) noexcept { constexpr _Ty _Max = (numeric_limits<_Ty>::max)(); #ifndef __AVX2__ - const bool _Definitely_have_tzcnt = __isa_available >= __ISA_AVAILABLE_AVX2; - if (!_Definitely_have_tzcnt && _Val == 0) { - return _Digits; + // Because the widening done below will always give a non-0 value, checking for tzcnt + // is not required for 8-bit and 16-bit since the only difference in behavior between + // bsf and tzcnt is when the value is 0. + if constexpr (_Digits > 16) { + const bool _Definitely_have_tzcnt = __isa_available >= __ISA_AVAILABLE_AVX2; + if (!_Definitely_have_tzcnt && _Val == 0) { + return _Digits; + } } #endif // __AVX2__ - if _CONSTEXPR_IF (_Digits <= 32) { + if constexpr (_Digits <= 32) { // Intended widening to int. This operation means that a narrow 0 will widen // to 0xFFFF....FFFF0... instead of 0. We need this to avoid counting all the zeros // of the wider type. diff --git a/stl/inc/list b/stl/inc/list index 5e98c59e3c4..c8d81b1897e 100644 --- a/stl/inc/list +++ b/stl/inc/list @@ -762,10 +762,6 @@ private: friend class _Hash; template friend bool _Hash_equal(const _Hash<_Traits>&, const _Hash<_Traits>&); -#if !_HAS_IF_CONSTEXPR - template - friend bool _Hash_equal_elements(const _Hash<_Traits>& _Left, const _Hash<_Traits>& _Right, false_type); -#endif // _HAS_IF_CONSTEXPR using _Alty = _Rebind_alloc_t<_Alloc, _Ty>; using _Alty_traits = allocator_traits<_Alty>; @@ -895,7 +891,7 @@ public: } list(list&& _Right, const _Alloc& _Al) : _Mypair(_One_then_variadic_args_t{}, _Al) { - if _CONSTEXPR_IF (!_Alnode_traits::is_always_equal::value) { + if constexpr (!_Alnode_traits::is_always_equal::value) { if (_Getal() != _Right._Getal()) { _Construct_range_unchecked(_STD make_move_iterator(_Right._Unchecked_begin()), _STD make_move_iterator(_Right._Unchecked_end())); @@ -1682,7 +1678,7 @@ private: #if _ITERATOR_DEBUG_LEVEL != 0 _DEBUG_ORDER_UNWRAPPED(_Right._Unchecked_begin(), _Right._Unchecked_end(), _Pred); - if _CONSTEXPR_IF (!_Alnode_traits::is_always_equal::value) { + if constexpr (!_Alnode_traits::is_always_equal::value) { _STL_VERIFY(_Getal() == _Right._Getal(), "list allocators incompatible for merge"); } #endif // _ITERATOR_DEBUG_LEVEL != 0 @@ -1739,7 +1735,7 @@ private: // splice _Right [_First, _Last) before _Where; returns _Last if (this != _STD addressof(_Right)) { // splicing from another list, adjust counts #if _ITERATOR_DEBUG_LEVEL != 0 - if _CONSTEXPR_IF (!_Alnode_traits::is_always_equal::value) { + if constexpr (!_Alnode_traits::is_always_equal::value) { _STL_VERIFY(_Getal() == _Right._Getal(), "list allocators incompatible for splice"); } #endif // _ITERATOR_DEBUG_LEVEL != 0 diff --git a/stl/inc/memory b/stl/inc/memory index e9050c26eee..beac884f890 100644 --- a/stl/inc/memory +++ b/stl/inc/memory @@ -126,7 +126,6 @@ namespace ranges { #endif // __cpp_lib_concepts // FUNCTION TEMPLATE uninitialized_copy_n -#if _HAS_IF_CONSTEXPR template _NoThrowFwdIt uninitialized_copy_n(const _InIt _First, const _Diff _Count_raw, _NoThrowFwdIt _Dest) { // copy [_First, _First + _Count) to [_Dest, ...) @@ -152,40 +151,6 @@ _NoThrowFwdIt uninitialized_copy_n(const _InIt _First, const _Diff _Count_raw, _ _Seek_wrapped(_Dest, _UDest); return _Dest; } -#else // ^^^ _HAS_IF_CONSTEXPR / !_HAS_IF_CONSTEXPR vvv -template -_NoThrowFwdIt _Uninitialized_copy_n_unchecked2(_InIt _First, _Diff _Count, const _NoThrowFwdIt _Dest, - false_type) { // copy [_First, _First + _Count) to [_Dest, ...), no special optimization - _Uninitialized_backout<_NoThrowFwdIt> _Backout{_Dest}; - - for (; _Count > 0; --_Count, (void) ++_First) { - _Backout._Emplace_back(*_First); - } - - return _Backout._Release(); -} - -template -_NoThrowFwdIt _Uninitialized_copy_n_unchecked2(const _InIt _First, const _Diff _Count, const _NoThrowFwdIt _Dest, - true_type) { // copy [_First, _First + _Count) to [_Dest, ...), memmove optimization - return _Copy_memmove(_First, _First + _Count, _Dest); -} - -template -_NoThrowFwdIt uninitialized_copy_n(const _InIt _First, const _Diff _Count_raw, _NoThrowFwdIt _Dest) { - // copy [_First, _First + _Count) to [_Dest, ...)] - _Algorithm_int_t<_Diff> _Count = _Count_raw; - if (_Count <= 0) { - return _Dest; - } - - auto _UFirst = _Get_unwrapped_n(_First, _Count); - auto _UDest = _Get_unwrapped_n(_Dest, _Count); - _Seek_wrapped(_Dest, _Uninitialized_copy_n_unchecked2(_UFirst, _Count, _UDest, - bool_constant<_Ptr_copy_cat::_Really_trivial>{})); - return _Dest; -} -#endif // _HAS_IF_CONSTEXPR #ifdef __cpp_lib_concepts namespace ranges { @@ -455,7 +420,6 @@ namespace ranges { #endif // __cpp_lib_concepts // FUNCTION TEMPLATE uninitialized_fill_n -#if _HAS_IF_CONSTEXPR template _NoThrowFwdIt uninitialized_fill_n(_NoThrowFwdIt _First, const _Diff _Count_raw, const _Tval& _Val) { // copy _Count copies of _Val to raw _First @@ -489,41 +453,6 @@ _NoThrowFwdIt uninitialized_fill_n(_NoThrowFwdIt _First, const _Diff _Count_raw, _Seek_wrapped(_First, _UFirst); return _First; } -#else // ^^^ _HAS_IF_CONSTEXPR // !_HAS_IF_CONSTEXPR vvv -template -_NoThrowFwdIt _Uninitialized_fill_n_unchecked1( - const _NoThrowFwdIt _First, _Diff _Count, const _Tval& _Val, false_type) { - // copy _Count copies of _Val to raw _First, no special optimization - _Uninitialized_backout<_NoThrowFwdIt> _Backout{_First}; - for (; _Count > 0; --_Count) { - _Backout._Emplace_back(_Val); - } - - return _Backout._Release(); -} - -template -_NoThrowFwdIt _Uninitialized_fill_n_unchecked1( - const _NoThrowFwdIt _First, const _Diff _Count, const _Tval& _Val, true_type) { - // copy _Count copies of _Val to raw _First, memset optimization - _Fill_memset(_First, _Val, _Count); - return _First + _Count; -} - -template -_NoThrowFwdIt uninitialized_fill_n(_NoThrowFwdIt _First, const _Diff _Count_raw, const _Tval& _Val) { - // copy _Count copies of _Val to raw _First - _Algorithm_int_t<_Diff> _Count = _Count_raw; - if (_Count <= 0) { - return _First; - } - - auto _UFirst = _Get_unwrapped_n(_STD move(_First), _Count); - _Seek_wrapped(_First, _Uninitialized_fill_n_unchecked1(_STD move(_UFirst), _Count, _Val, - bool_constant<_Fill_memset_is_safe<_Unwrapped_t<_NoThrowFwdIt>, _Tval>>{})); - return _First; -} -#endif // _HAS_IF_CONSTEXPR #ifdef __cpp_lib_concepts namespace ranges { @@ -567,22 +496,7 @@ namespace ranges { }; inline constexpr _Uninitialized_fill_n_fn uninitialized_fill_n{_Not_quite_object::_Construct_tag{}}; -} // namespace ranges -#endif // __cpp_lib_concepts -// FUNCTION TEMPLATE construct_at -#if _HAS_CXX20 -template -_CONSTEXPR20_DYNALLOC auto construct_at(_Ty* const _Location, _Types&&... _Args) noexcept( - noexcept(::new (const_cast(static_cast(_Location))) - _Ty(_STD forward<_Types>(_Args)...))) // strengthened - -> decltype( - ::new (const_cast(static_cast(_Location))) _Ty(_STD forward<_Types>(_Args)...)) { - return ::new (const_cast(static_cast(_Location))) _Ty(_STD forward<_Types>(_Args)...); -} - -#ifdef __cpp_lib_concepts -namespace ranges { // VARIABLE ranges::construct_at class _Construct_at_fn : private _Not_quite_object { public: @@ -603,26 +517,7 @@ namespace ranges { }; inline constexpr _Construct_at_fn construct_at{_Not_quite_object::_Construct_tag{}}; -} // namespace ranges -#endif // __cpp_lib_concepts -#endif // _HAS_CXX20 -#if _HAS_CXX17 -// FUNCTION TEMPLATE destroy_at -template -_CONSTEXPR20_DYNALLOC void destroy_at(_Ty* const _Location) noexcept /* strengthened */ { -#if _HAS_CXX20 - if constexpr (is_array_v<_Ty>) { - _Destroy_range(_STD begin(*_Location), _STD end(*_Location)); - } else -#endif // _HAS_CXX20 - { - _Location->~_Ty(); - } -} - -#ifdef __cpp_lib_concepts -namespace ranges { // VARIABLE ranges::destroy_at // clang-format off template <_No_throw_input_iterator _It, _No_throw_sentinel_for<_It> _Se> @@ -648,9 +543,11 @@ namespace ranges { } // namespace ranges #endif // __cpp_lib_concepts +#if _HAS_CXX17 // FUNCTION TEMPLATE destroy template -void destroy(const _NoThrowFwdIt _First, const _NoThrowFwdIt _Last) { // destroy all elements in [_First, _Last) +_CONSTEXPR20_DYNALLOC void destroy(const _NoThrowFwdIt _First, const _NoThrowFwdIt _Last) { + // destroy all elements in [_First, _Last) _Adl_verify_range(_First, _Last); _Destroy_range(_Get_unwrapped(_First), _Get_unwrapped(_Last)); } @@ -677,7 +574,7 @@ namespace ranges { // clang-format off template <_No_throw_input_iterator _It, _No_throw_sentinel_for<_It> _Se> requires destructible> - /* _CONSTEXPR20_DYNALLOC */ _It operator()(_It _First, _Se _Last) const noexcept { + _CONSTEXPR20_DYNALLOC _It operator()(_It _First, _Se _Last) const noexcept { // clang-format on _Adl_verify_range(_First, _Last); _Seek_wrapped(_First, @@ -688,7 +585,7 @@ namespace ranges { // clang-format off template <_No_throw_input_range _Rng> requires destructible> - /* _CONSTEXPR20_DYNALLOC */ borrowed_iterator_t<_Rng> operator()(_Rng&& _Range) const noexcept { + _CONSTEXPR20_DYNALLOC borrowed_iterator_t<_Rng> operator()(_Rng&& _Range) const noexcept { // clang-format on auto _First = _RANGES begin(_Range); _Seek_wrapped(_First, _RANGES _Destroy_unchecked(_Get_unwrapped(_STD move(_First)), _Uend(_Range))); @@ -702,7 +599,7 @@ namespace ranges { // FUNCTION TEMPLATE destroy_n template -_NoThrowFwdIt destroy_n(_NoThrowFwdIt _First, const _Diff _Count_raw) { +_CONSTEXPR20_DYNALLOC _NoThrowFwdIt destroy_n(_NoThrowFwdIt _First, const _Diff _Count_raw) { // destroy all elements in [_First, _First + _Count) _Algorithm_int_t<_Diff> _Count = _Count_raw; if (_Count <= 0) { @@ -732,8 +629,9 @@ namespace ranges { // clang-format off template <_No_throw_input_iterator _It> requires destructible> - /* _CONSTEXPR20_DYNALLOC */ _It operator()(_It _First, const iter_difference_t<_It> _Count) const noexcept { + _CONSTEXPR20_DYNALLOC _It operator()(_It _First, const iter_difference_t<_It> _Count_raw) const noexcept { // clang-format on + _Algorithm_int_t> _Count = _Count_raw; if (_Count <= 0) { return _First; } @@ -1386,21 +1284,6 @@ struct _Can_enable_shared<_Yty, void_t> // is_convertible is necessary to verify unambiguous inheritance }; -#if !_HAS_IF_CONSTEXPR -template -void _Enable_shared_from_this1(const shared_ptr<_Other>& _This, _Yty* _Ptr, true_type) noexcept { - // enable shared_from_this - if (_Ptr && _Ptr->_Wptr.expired()) { - _Ptr->_Wptr = shared_ptr>(_This, const_cast*>(_Ptr)); - } -} - -template -void _Enable_shared_from_this1(const shared_ptr<_Other>&, _Yty*, false_type) noexcept { - // don't enable shared_from_this -} -#endif // !_HAS_IF_CONSTEXPR - // CLASS TEMPLATE _Ptr_base struct _Exception_ptr_access; @@ -1676,7 +1559,6 @@ public: _SP_convertible<_Ux, _Ty>>, int> = 0> explicit shared_ptr(_Ux* _Px) { // construct shared_ptr object that owns _Px -#if _HAS_IF_CONSTEXPR if constexpr (is_array_v<_Ty>) { _Setpd(_Px, default_delete<_Ux[]>{}); } else { @@ -1684,9 +1566,6 @@ public: _Set_ptr_rep_and_enable_shared(_Owner._Ptr, new _Ref_count<_Ux>(_Owner._Ptr)); _Owner._Ptr = nullptr; } -#else // ^^^ _HAS_IF_CONSTEXPR // !_HAS_IF_CONSTEXPR vvv - _Setp(_Px, is_array<_Ty>{}); -#endif // _HAS_IF_CONSTEXPR } template - void _Setp(_Ux* _Px, true_type) { // take ownership of _Px - _Setpd(_Px, default_delete<_Ux[]>{}); - } - - template - void _Setp(_Ux* const _Px, false_type) { // take ownership of _Px - _Temporary_owner<_Ux> _Owner(_Px); - _Set_ptr_rep_and_enable_shared(_Owner._Ptr, new _Ref_count<_Ux>(_Owner._Ptr)); - _Owner._Ptr = nullptr; - } -#endif // !_HAS_IF_CONSTEXPR - template void _Setpd(const _UxptrOrNullptr _Px, _Dx _Dt) { // take ownership of _Px, deleter _Dt _Temporary_owner_del<_UxptrOrNullptr, _Dx> _Owner(_Px, _Dt); @@ -1956,17 +1821,11 @@ private: void _Set_ptr_rep_and_enable_shared(_Ux* const _Px, _Ref_count_base* const _Rx) noexcept { // take ownership of _Px this->_Ptr = _Px; this->_Rep = _Rx; -#if _HAS_IF_CONSTEXPR if constexpr (conjunction_v>, negation>, _Can_enable_shared<_Ux>>) { if (_Px && _Px->_Wptr.expired()) { _Px->_Wptr = shared_ptr>(*this, const_cast*>(_Px)); } } -#else // ^^^ _HAS_IF_CONSTEXPR // !_HAS_IF_CONSTEXPR vvv - _Enable_shared_from_this1(*this, _Px, - bool_constant< - conjunction_v>, negation>, _Can_enable_shared<_Ux>>>{}); -#endif // _HAS_IF_CONSTEXPR } void _Set_ptr_rep_and_enable_shared(nullptr_t, _Ref_count_base* const _Rx) noexcept { // take ownership of nullptr @@ -2223,10 +2082,10 @@ struct _Alignas_storage_unit { alignas(_Align) char _Space[_Align]; }; -enum class _Check_overflow : bool { _No, _Yes }; +enum class _Check_overflow : bool { _Nope, _Yes }; template -_NODISCARD size_t _Calculate_bytes_for_flexible_array(const size_t _Count) noexcept(_Check == _Check_overflow::_No) { +_NODISCARD size_t _Calculate_bytes_for_flexible_array(const size_t _Count) noexcept(_Check == _Check_overflow::_Nope) { constexpr size_t _Align = alignof(_Refc); size_t _Bytes = sizeof(_Refc); // contains storage for one element @@ -2832,7 +2691,7 @@ private: _Rebind_alloc_t<_Alloc, _Storage> _Al(this->_Get_val()); const size_t _Bytes = - _Calculate_bytes_for_flexible_array<_Ref_count_unbounded_array_alloc, _Check_overflow::_No>(_Size); + _Calculate_bytes_for_flexible_array<_Ref_count_unbounded_array_alloc, _Check_overflow::_Nope>(_Size); const size_t _Storage_units = _Bytes / sizeof(_Storage); this->~_Ref_count_unbounded_array_alloc(); @@ -3257,13 +3116,8 @@ protected: ~enable_shared_from_this() = default; private: -#if _HAS_IF_CONSTEXPR template friend class shared_ptr; -#else // ^^^ _HAS_IF_CONSTEXPR // !_HAS_IF_CONSTEXPR vvv - template - friend void _Enable_shared_from_this1(const shared_ptr<_Other>& _This, _Yty* _Ptr, true_type) noexcept; -#endif // _HAS_IF_CONSTEXPR mutable weak_ptr<_Ty> _Wptr; }; diff --git a/stl/inc/random b/stl/inc/random index a0a9d74b0de..405f47898a4 100644 --- a/stl/inc/random +++ b/stl/inc/random @@ -281,12 +281,6 @@ _CRTIMP2_PURE void __CLRCALL_PURE_OR_CDECL _MP_Add(_MP_arr, uint64_t) noexcept; _CRTIMP2_PURE void __CLRCALL_PURE_OR_CDECL _MP_Mul(_MP_arr, uint64_t, uint64_t) noexcept; _CRTIMP2_PURE void __CLRCALL_PURE_OR_CDECL _MP_Rem(_MP_arr, uint64_t) noexcept; -#if !_HAS_IF_CONSTEXPR -#pragma warning(push) -#pragma warning(disable : 4309) // static_cast: truncation of constant value -#pragma warning(disable : 4724) // potential mod by 0 -#endif // !_HAS_IF_CONSTEXPR - template _NODISCARD _Uint _Next_linear_congruential_value(_Uint _Prev) noexcept { // Choose intermediate type: @@ -298,20 +292,20 @@ _NODISCARD _Uint _Next_linear_congruential_value(_Uint _Prev) noexcept { // Divide by _Ax: // _Cx <= numeric_limits::max() // && (_Mx - 1) <= (numeric_limits::max() - _Cx) / _Ax - if _CONSTEXPR_IF (_Ax == 0) { // degenerate case; avoid divide by 0 + if constexpr (_Ax == 0) { // degenerate case; avoid divide by 0 return static_cast<_Uint>(_Cx); // relies on _Mx == 0 || _Cx <= _Mx, N4741 [rand.eng.lcong]/3 - } else if _CONSTEXPR_IF (_Mx == 0) { + } else if constexpr (_Mx == 0) { // N4762 [rand.eng.lcong]/2: "If the template parameter m is 0, the modulus m // used throughout this subclause [rand.eng.lcong] is // numeric_limits::max() plus 1." That is: Just do the multiply // and let normal unsigned modulo take care of it return static_cast<_Uint>(static_cast<_Uint>(_Ax * _Prev) + _Cx); - } else if _CONSTEXPR_IF (_Cx <= UINT_MAX && static_cast<_Uint>(_Mx - 1) <= (UINT_MAX - _Cx) / _Ax) { + } else if constexpr (_Cx <= UINT_MAX && static_cast<_Uint>(_Mx - 1) <= (UINT_MAX - _Cx) / _Ax) { // unsigned int is sufficient to store intermediate calculation const auto _Mul = static_cast(_Prev) * static_cast(_Ax) + static_cast(_Cx); return static_cast<_Uint>(_Mul % _Mx); - } else if _CONSTEXPR_IF (_Cx <= ULLONG_MAX && static_cast<_Uint>(_Mx - 1) <= (ULLONG_MAX - _Cx) / _Ax) { + } else if constexpr (_Cx <= ULLONG_MAX && static_cast<_Uint>(_Mx - 1) <= (ULLONG_MAX - _Cx) / _Ax) { // unsigned long long is sufficient to store intermediate calculation const auto _Mul = static_cast(_Prev) * _Ax + _Cx; return static_cast<_Uint>(_Mul % _Mx); @@ -324,10 +318,6 @@ _NODISCARD _Uint _Next_linear_congruential_value(_Uint _Prev) noexcept { } } -#if !_HAS_IF_CONSTEXPR -#pragma warning(pop) -#endif // !_HAS_IF_CONSTEXPR - template _NODISCARD constexpr unsigned int _Seed_seq_to_uint(_Seed_seq& _Seq) { unsigned int _Arr[4]{}; @@ -345,18 +335,13 @@ _NODISCARD constexpr unsigned long long _Seed_seq_to_ull(_Seed_seq& _Seq) { return _Result; } -#if !_HAS_IF_CONSTEXPR -#pragma warning(push) -#pragma warning(disable : 4724) // potential mod by 0 -#endif // !_HAS_IF_CONSTEXPR - template _NODISCARD constexpr _Uint _Get_linear_congruential_seed(_Uint _Sx) noexcept { // N4741 [rand.eng.lcong]/5 - if _CONSTEXPR_IF (_Mx != 0) { + if constexpr (_Mx != 0) { _Sx %= _Mx; } - if _CONSTEXPR_IF (_Cx == 0) { + if constexpr (_Cx == 0) { if (_Sx == 0) { _Sx = _Uint{1}; } @@ -368,13 +353,13 @@ _NODISCARD constexpr _Uint _Get_linear_congruential_seed(_Uint _Sx) noexcept { / template _NODISCARD _Uint _Get_linear_congruential_seed_from_seq(_Seed_seq& _Seq) { // N4741 [rand.eng.lcong]/6 _Uint _Sx; - if _CONSTEXPR_IF (_Mx == 0) { - if _CONSTEXPR_IF (sizeof(_Uint) <= sizeof(unsigned int)) { + if constexpr (_Mx == 0) { + if constexpr (sizeof(_Uint) <= sizeof(unsigned int)) { _Sx = static_cast<_Uint>(_Seed_seq_to_uint(_Seq)); } else { _Sx = static_cast<_Uint>(_Seed_seq_to_ull(_Seq)); } - } else if _CONSTEXPR_IF (_Mx <= UINT_MAX) { + } else if constexpr (_Mx <= UINT_MAX) { _Sx = static_cast<_Uint>(_Seed_seq_to_uint(_Seq) % _Mx); } else { _Sx = static_cast<_Uint>(_Seed_seq_to_ull(_Seq) % _Mx); @@ -383,10 +368,6 @@ _NODISCARD _Uint _Get_linear_congruential_seed_from_seq(_Seed_seq& _Seq) { // N4 return _Get_linear_congruential_seed<_Uint, _Cx, _Mx>(_Sx); } -#if !_HAS_IF_CONSTEXPR -#pragma warning(pop) -#endif // !_HAS_IF_CONSTEXPR - template class linear_congruential_engine { // a linear congruential generator random engine public: @@ -795,7 +776,7 @@ struct _Swc_traits { // traits for subtract_with_carry generator static int _Get_wc() { // compute number of 32-bit words per element int _Kx; - if _CONSTEXPR_IF (_Mx == 0) { + if constexpr (_Mx == 0) { _Kx = (8 * sizeof(_Ty) + 31) / 32; } else { // compute number of 32-bit words required unsigned long long _Val = 1ULL << 32; @@ -831,7 +812,7 @@ struct _Swc_traits { // traits for subtract_with_carry generator #pragma warning(push) #pragma warning(disable : 4724) // potential mod by 0 static _Cy_t _Reduce(_Ty* _Ax) { // reduce values to allowed range - if _CONSTEXPR_IF (_Mx != 0) { + if constexpr (_Mx != 0) { for (size_t _Ix = 0; _Ix < _Nw; ++_Ix) { _Ax[_Ix] = _Ax[_Ix] % _Mx; } @@ -925,7 +906,7 @@ public: } constexpr bool _Mod_non_zero = _Traits::_Mod != 0; - if _CONSTEXPR_IF (_Mod_non_zero) { + if constexpr (_Mod_non_zero) { this->_Ax[_Ix] %= _Traits::_Mod; } } @@ -1847,7 +1828,7 @@ private: } static _Uty _Adjust(_Uty _Uval) { // convert signed ranges to unsigned ranges and vice versa - if _CONSTEXPR_IF (is_signed_v<_Ty>) { + if constexpr (is_signed_v<_Ty>) { const _Uty _Adjuster = (static_cast<_Uty>(-1) >> 1) + 1; // 2^(N-1) if (_Uval < _Adjuster) { @@ -2044,7 +2025,7 @@ _NODISCARD _Flt _Float_upper_bound(_Ty _Val) { constexpr auto _Flt_digits = numeric_limits<_Flt>::digits; using _Ty_32or64 = conditional_t<_Ty_digits <= 32, uint32_t, uint64_t>; - if _CONSTEXPR_IF (_Ty_digits <= _Flt_digits) { + if constexpr (_Ty_digits <= _Flt_digits) { return static_cast<_Flt>(_Val) + _Flt{1}; } else { #pragma warning(push) diff --git a/stl/inc/regex b/stl/inc/regex index 3bbc4ed3006..5b748309cb6 100644 --- a/stl/inc/regex +++ b/stl/inc/regex @@ -1215,7 +1215,7 @@ basic_ostream<_Elem, _Traits>& operator<<(basic_ostream<_Elem, _Traits>& _Ostr, } // FORWARD DECLARATIONS -template >> +template >> class match_results; template diff --git a/stl/inc/sstream b/stl/inc/sstream index e5c6235cf2f..90ce15f8ea0 100644 --- a/stl/inc/sstream +++ b/stl/inc/sstream @@ -29,6 +29,10 @@ public: using _Mystr = basic_string<_Elem, _Traits, _Alloc>; using _Mysize_type = typename _Mystr::size_type; +#if _HAS_CXX20 + using _Mystr_view = basic_string_view<_Elem, _Traits>; +#endif // _HAS_CXX20 + basic_stringbuf() : _Seekhigh(nullptr), _Mystate(_Getstate(ios_base::in | ios_base::out)), _Al() {} explicit basic_stringbuf(ios_base::openmode _Mode) : _Seekhigh(nullptr), _Mystate(_Getstate(_Mode)), _Al() {} @@ -38,6 +42,37 @@ public: _Init(_Str.c_str(), _Str.size(), _Getstate(_Mode)); } +#if _HAS_CXX20 + explicit basic_stringbuf(const _Alloc& _Al_) : basic_stringbuf(ios_base::in | ios_base::out, _Al_) {} + + basic_stringbuf(ios_base::openmode _Mode, const _Alloc& _Al_) + : _Seekhigh(nullptr), _Mystate(_Getstate(_Mode)), _Al(_Al_) {} + + explicit basic_stringbuf(_Mystr&& _Str, ios_base::openmode _Mode = ios_base::in | ios_base::out) + : _Al(_STD move(_Str._Getal())) { + _Init_string_inplace(_STD move(_Str), _Getstate(_Mode)); + } + + template + basic_stringbuf(const basic_string<_Elem, _Traits, _Alloc2>& _Str, ios_base::openmode _Mode, const _Alloc& _Al_) + : _Al(_Al_) { + _Init(_Str.c_str(), _Str.size(), _Getstate(_Mode)); + } + + template + basic_stringbuf(const basic_string<_Elem, _Traits, _Alloc2>& _Str, const _Alloc& _Al_) + : basic_stringbuf(_Str, ios_base::in | ios_base::out, _Al_) {} + + template , int> = 0> + explicit basic_stringbuf( + const basic_string<_Elem, _Traits, _Alloc2>& _Str, ios_base::openmode _Mode = ios_base::in | ios_base::out) + : basic_stringbuf(_Str, _Mode, _Alloc{}) {} + + basic_stringbuf(basic_stringbuf&& _Right, const _Alloc& _Al_) : _Al(_Al_) { + _Assign_rv(_STD move(_Right)); + } +#endif // _HAS_CXX20 + basic_stringbuf(basic_stringbuf&& _Right) { _Assign_rv(_STD move(_Right)); } @@ -54,12 +89,18 @@ public: } } - void swap(basic_stringbuf& _Right) { + void swap(basic_stringbuf& _Right) noexcept /* strengthened */ { if (this != _STD addressof(_Right)) { + if constexpr (!allocator_traits<_Alloc>::propagate_on_container_swap::value) { + _STL_ASSERT( + _Al == _Right._Al, "The allocators of basic_stringbuf should propagate or be equal on swap."); + } + _Mysb::swap(_Right); _STD swap(_Seekhigh, _Right._Seekhigh); _STD swap(_Mystate, _Right._Mystate); - _Swap_adl(_Al, _Right._Al); + // The same as basic_string::swap + _Pocs(_Al, _Right._Al); } } @@ -71,27 +112,53 @@ public: } enum { // constants for bits in stream state - _Allocated = 1, // set if character array storage has been allocated, eback() points to allocated storage - _Constant = 2, // set if character array nonmutable - _Noread = 4, // set if character array cannot be read - _Append = 8, // set if all writes are appends - _Atend = 16 // set if initial writes are appends + _Allocated = 1, // set if character array storage has been allocated, eback() points to allocated storage + _Constant = 2, // set if character array nonmutable + _Noread = 4, // set if character array cannot be read + _Append = 8, // set if all writes are appends + _Atend = 16, // set if initial writes are appends + _From_rvalue = 32 // set if character array is released from an rvalue of basic_string }; using int_type = typename _Traits::int_type; using pos_type = typename _Traits::pos_type; using off_type = typename _Traits::off_type; - _NODISCARD _Mystr str() const { - _Mystr _Result(_Al); - if (!(_Mystate & _Constant) && _Mysb::pptr()) { // writable, make string from write buffer + struct _Buffer_view { + _Elem* _Ptr; + _Mysize_type _Size; + _Mysize_type _Res; + }; + + _NODISCARD _Buffer_view _Get_buffer_view() const noexcept { + _Buffer_view _Result{}; + if ((!(_Mystate & _Constant) || (_Mystate & _From_rvalue)) && _Mysb::pptr()) { + // writable, make string view from write buffer const auto _Base = _Mysb::pbase(); - _Result.assign(_Base, static_cast<_Mysize_type>((_STD max)(_Mysb::pptr(), _Seekhigh) - _Base)); - } else if (!(_Mystate & _Noread) && _Mysb::gptr()) { // readable, make string from read buffer + _Result._Ptr = _Base; + _Result._Size = static_cast<_Mysize_type>((_STD max)(_Mysb::pptr(), _Seekhigh) - _Base); + _Result._Res = static_cast<_Mysize_type>(_Mysb::epptr() - _Base); + } else if (!(_Mystate & _Noread) && _Mysb::gptr()) { + // readable, make string view from read buffer const auto _Base = _Mysb::eback(); - _Result.assign(_Base, static_cast<_Mysize_type>(_Mysb::egptr() - _Base)); + _Result._Ptr = _Base; + _Result._Size = static_cast<_Mysize_type>(_Mysb::egptr() - _Base); + _Result._Res = _Result._Size; } + return _Result; + } +#if _HAS_CXX20 + _NODISCARD _Mystr str() const& +#else + _NODISCARD _Mystr str() const +#endif // _HAS_CXX20 + { + _Mystr _Result(_Al); + const auto _View = _Get_buffer_view(); + if (_View._Ptr) { + _Result.assign(_View._Ptr, _View._Size); + } return _Result; } @@ -100,6 +167,72 @@ public: _Init(_Newstr.c_str(), _Newstr.size(), _Mystate); } +#if _HAS_CXX20 + template <_Allocator _Alloc2> + _NODISCARD basic_string<_Elem, _Traits, _Alloc2> str(const _Alloc2& _Al) const { + return basic_string<_Elem, _Traits, _Alloc2>{view(), _Al}; + } + + // The buffer cannot be moved to a string directly, because + // the buffer may already be full, and the terminating char is not '\0'. + // In that case, copy the string as usual. + _NODISCARD _Mystr str() && { + _Mystr _Result{_String_constructor_rvalue_allocator_tag{}, _STD move(_Al)}; + const auto _View = _Get_buffer_view(); + // _Size cannot be larger than _Res, but it could be equal, + // because basic_stringbuf doesn't allocate for the terminating '\0'. + if (_View._Size == _View._Res) { + // the buffer is full + _Result.assign(_View._Ptr, _View._Size); + } else { + _Traits::assign(_View._Ptr[_View._Size], _Elem()); + if (_Result._Move_assign_from_buffer(_View._Ptr, _View._Size, _View._Res)) { + _Mystate &= ~_Allocated; + } + } + _Tidy(); + return _Result; + } + + _NODISCARD _Mystr_view view() const noexcept { + const auto _View = _Get_buffer_view(); + return _Mystr_view{_View._Ptr, _View._Size}; + } + + template , int> = 0> + void str(const basic_string<_Elem, _Traits, _Alloc2>& _Newstr) { + _Tidy(); + _Init(_Newstr.c_str(), _Newstr.size(), _Mystate); + } + + void _Str(_Mystr&& _Newstr, _Equal_allocators) { + _Tidy(); + _Pocma(_Al, _Newstr._Getal()); + _Init_string_inplace(_STD move(_Newstr), _Mystate); + } + + void _Str(_Mystr&& _Newstr, _Propagate_allocators) { + _Str(_STD move(_Newstr), _Equal_allocators{}); + } + + void _Str(_Mystr&& _Newstr, _No_propagate_allocators) { + if (_Al == _Newstr._Getal()) { + _Str(_STD move(_Newstr), _Equal_allocators{}); + } else { + _Tidy(); + _Init(_Newstr.c_str(), _Newstr.size(), _Mystate); + } + } + + void str(_Mystr&& _Newstr) { + _Str(_STD move(_Newstr), _Choose_pocma<_Alloc>{}); + } + + _NODISCARD allocator_type get_allocator() const noexcept { + return _Al; + } +#endif // _HAS_CXX20 + protected: virtual int_type overflow(int_type _Meta = _Traits::eof()) { // put an element to stream if (_Mystate & _Constant) { @@ -205,7 +338,7 @@ protected: off_type _Off, ios_base::seekdir _Way, ios_base::openmode _Mode = ios_base::in | ios_base::out) { // change position by _Off, according to _Way, _Mode const auto _Gptr_old = _Mysb::gptr(); - const auto _Pptr_old = _Mysb::pptr(); + const auto _Pptr_old = (_Mystate & _Constant) ? nullptr : _Mysb::pptr(); if (_Pptr_old && _Seekhigh < _Pptr_old) { // update high-water pointer _Seekhigh = _Pptr_old; } @@ -267,7 +400,7 @@ protected: // change position to _Pos, according to _Mode const auto _Off = static_cast(_Pos); const auto _Gptr_old = _Mysb::gptr(); - const auto _Pptr_old = _Mysb::pptr(); + const auto _Pptr_old = (_Mystate & _Constant) ? nullptr : _Mysb::pptr(); if (_Pptr_old && _Seekhigh < _Pptr_old) { // update high-water pointer _Seekhigh = _Pptr_old; } @@ -297,6 +430,8 @@ protected: protected: void _Init(const _Elem* _Ptr, _Mysize_type _Count, int _State) { // initialize buffer to [_Ptr, _Ptr + _Count), set state + _State &= ~_From_rvalue; + if (_Count > INT_MAX) { // TRANSITION, VSO-485517 _Xbad_alloc(); } @@ -328,6 +463,34 @@ protected: _Mystate = _State; } +#if _HAS_CXX20 + void _Init_string_inplace(_Mystr&& _Str, int _State) { + _State |= _From_rvalue; + + auto [_Ptr, _Size, _Res] = _Str._Release_to_buffer(_Al); + _Elem* const _Pnew = _Unfancy(_Ptr); + if (_Res != 0 && (_State & (_Noread | _Constant)) != (_Noread | _Constant)) { + // finite buffer that can be read or written, set it up + _Seekhigh = _Pnew + _Size; + auto _End_buffer = _Pnew + _Res; + + _Mysb::setp(_Pnew, (_State & (_Atend | _Append)) ? _Seekhigh : _Pnew, _End_buffer); + + if (_State & _Noread) { // maintain "_Allocated == eback() points to buffer base" invariant + _Mysb::setg(_Pnew, nullptr, _Pnew); + } else { + _Mysb::setg(_Pnew, _Pnew, _Seekhigh); + } + + _State |= _Allocated; + } else { + _Seekhigh = nullptr; + } + + _Mystate = _State; + } +#endif // _HAS_CXX20 + void _Tidy() noexcept { // discard any allocated buffer and clear pointers if (_Mystate & _Allocated) { _Al.deallocate(_Ptr_traits::pointer_to(*_Mysb::eback()), @@ -369,13 +532,15 @@ private: return _State; } + // TRANSITION, ABI, see GH-938 _Elem* _Seekhigh; // the high-water pointer in character array int _Mystate; // the stream state allocator_type _Al; // the allocator object }; template -void swap(basic_stringbuf<_Elem, _Traits, _Alloc>& _Left, basic_stringbuf<_Elem, _Traits, _Alloc>& _Right) { +void swap(basic_stringbuf<_Elem, _Traits, _Alloc>& _Left, basic_stringbuf<_Elem, _Traits, _Alloc>& _Right) noexcept +/* strengthened */ { _Left.swap(_Right); } @@ -388,6 +553,10 @@ public: using _Mysb = basic_stringbuf<_Elem, _Traits, _Alloc>; using _Mystr = basic_string<_Elem, _Traits, _Alloc>; +#if _HAS_CXX20 + using _Mystr_view = basic_string_view<_Elem, _Traits>; +#endif // _HAS_CXX20 + basic_istringstream() : _Mybase(_STD addressof(_Stringbuffer)), _Stringbuffer(ios_base::in) {} explicit basic_istringstream(ios_base::openmode _Mode) @@ -396,6 +565,27 @@ public: explicit basic_istringstream(const _Mystr& _Str, ios_base::openmode _Mode = ios_base::in) : _Mybase(_STD addressof(_Stringbuffer)), _Stringbuffer(_Str, _Mode | ios_base::in) {} +#if _HAS_CXX20 + basic_istringstream(ios_base::openmode _Mode, const _Alloc& _Al) + : _Mybase(_STD addressof(_Stringbuffer)), _Stringbuffer(_Mode | ios_base::in, _Al) {} + + explicit basic_istringstream(_Mystr&& _Str, ios_base::openmode _Mode = ios_base::in) + : _Mybase(_STD addressof(_Stringbuffer)), _Stringbuffer(_STD move(_Str), _Mode | ios_base::in) {} + + template + basic_istringstream(const basic_string<_Elem, _Traits, _Alloc2>& _Str, const _Alloc& _Al) + : _Mybase(_STD addressof(_Stringbuffer)), _Stringbuffer(_Str, ios_base::in, _Al) {} + + template + basic_istringstream(const basic_string<_Elem, _Traits, _Alloc2>& _Str, ios_base::openmode _Mode, const _Alloc& _Al) + : _Mybase(_STD addressof(_Stringbuffer)), _Stringbuffer(_Str, _Mode | ios_base::in, _Al) {} + + template , int> = 0> + explicit basic_istringstream( + const basic_string<_Elem, _Traits, _Alloc2>& _Str, ios_base::openmode _Mode = ios_base::in) + : _Mybase(_STD addressof(_Stringbuffer)), _Stringbuffer(_Str, _Mode | ios_base::in) {} +#endif // _HAS_CXX20 + basic_istringstream(basic_istringstream&& _Right) : _Mybase(_STD addressof(_Stringbuffer)) { _Assign_rv(_STD move(_Right)); } @@ -428,7 +618,12 @@ public: return const_cast<_Mysb*>(_STD addressof(_Stringbuffer)); } - _NODISCARD _Mystr str() const { +#if _HAS_CXX20 + _NODISCARD _Mystr str() const& +#else + _NODISCARD _Mystr str() const +#endif // _HAS_CXX20 + { return _Stringbuffer.str(); } @@ -436,6 +631,30 @@ public: _Stringbuffer.str(_Newstr); } +#if _HAS_CXX20 + template <_Allocator _Alloc2> + _NODISCARD basic_string<_Elem, _Traits, _Alloc2> str(const _Alloc2& _Al) const { + return _Stringbuffer.str(_Al); + } + + _NODISCARD _Mystr str() && { + return _STD move(_Stringbuffer).str(); + } + + _NODISCARD _Mystr_view view() const noexcept { + return _Stringbuffer.view(); + } + + template , int> = 0> + void str(const basic_string<_Elem, _Traits, _Alloc2>& _Newstr) { + _Stringbuffer.str(_Newstr); + } + + void str(_Mystr&& _Newstr) { + _Stringbuffer.str(_STD move(_Newstr)); + } +#endif // _HAS_CXX20 + private: _Mysb _Stringbuffer; }; @@ -454,6 +673,10 @@ public: using _Mysb = basic_stringbuf<_Elem, _Traits, _Alloc>; using _Mystr = basic_string<_Elem, _Traits, _Alloc>; +#if _HAS_CXX20 + using _Mystr_view = basic_string_view<_Elem, _Traits>; +#endif // _HAS_CXX20 + basic_ostringstream() : _Mybase(_STD addressof(_Stringbuffer)), _Stringbuffer(ios_base::out) {} explicit basic_ostringstream(ios_base::openmode _Mode) @@ -462,6 +685,27 @@ public: explicit basic_ostringstream(const _Mystr& _Str, ios_base::openmode _Mode = ios_base::out) : _Mybase(_STD addressof(_Stringbuffer)), _Stringbuffer(_Str, _Mode | ios_base::out) {} +#if _HAS_CXX20 + basic_ostringstream(ios_base::openmode _Mode, const _Alloc& _Al) + : _Mybase(_STD addressof(_Stringbuffer)), _Stringbuffer(_Mode | ios_base::out, _Al) {} + + explicit basic_ostringstream(_Mystr&& _Str, ios_base::openmode _Mode = ios_base::out) + : _Mybase(_STD addressof(_Stringbuffer)), _Stringbuffer(_STD move(_Str), _Mode | ios_base::out) {} + + template + basic_ostringstream(const basic_string<_Elem, _Traits, _Alloc2>& _Str, const _Alloc& _Al) + : _Mybase(_STD addressof(_Stringbuffer)), _Stringbuffer(_Str, ios_base::out, _Al) {} + + template + basic_ostringstream(const basic_string<_Elem, _Traits, _Alloc2>& _Str, ios_base::openmode _Mode, const _Alloc& _Al) + : _Mybase(_STD addressof(_Stringbuffer)), _Stringbuffer(_Str, _Mode | ios_base::out, _Al) {} + + template , int> = 0> + explicit basic_ostringstream( + const basic_string<_Elem, _Traits, _Alloc2>& _Str, ios_base::openmode _Mode = ios_base::out) + : _Mybase(_STD addressof(_Stringbuffer)), _Stringbuffer(_Str, _Mode | ios_base::out) {} +#endif // _HAS_CXX20 + basic_ostringstream(basic_ostringstream&& _Right) : _Mybase(_STD addressof(_Stringbuffer)) { _Assign_rv(_STD move(_Right)); } @@ -494,7 +738,12 @@ public: return const_cast<_Mysb*>(_STD addressof(_Stringbuffer)); } - _NODISCARD _Mystr str() const { +#if _HAS_CXX20 + _NODISCARD _Mystr str() const& +#else + _NODISCARD _Mystr str() const +#endif // _HAS_CXX20 + { return _Stringbuffer.str(); } @@ -502,6 +751,30 @@ public: _Stringbuffer.str(_Newstr); } +#if _HAS_CXX20 + template <_Allocator _Alloc2> + _NODISCARD basic_string<_Elem, _Traits, _Alloc2> str(const _Alloc2& _Al) const { + return _Stringbuffer.str(_Al); + } + + _NODISCARD _Mystr str() && { + return _STD move(_Stringbuffer).str(); + } + + _NODISCARD _Mystr_view view() const noexcept { + return _Stringbuffer.view(); + } + + template , int> = 0> + void str(const basic_string<_Elem, _Traits, _Alloc2>& _Newstr) { + _Stringbuffer.str(_Newstr); + } + + void str(_Mystr&& _Newstr) { + _Stringbuffer.str(_STD move(_Newstr)); + } +#endif // _HAS_CXX20 + private: _Mysb _Stringbuffer; }; @@ -526,6 +799,10 @@ public: using _Mysb = basic_stringbuf<_Elem, _Traits, _Alloc>; using _Mystr = basic_string<_Elem, _Traits, _Alloc>; +#if _HAS_CXX20 + using _Mystr_view = basic_string_view<_Elem, _Traits>; +#endif // _HAS_CXX20 + basic_stringstream() : _Mybase(_STD addressof(_Stringbuffer)), _Stringbuffer(ios_base::in | ios_base::out) {} explicit basic_stringstream(ios_base::openmode _Mode) @@ -534,6 +811,27 @@ public: explicit basic_stringstream(const _Mystr& _Str, ios_base::openmode _Mode = ios_base::in | ios_base::out) : _Mybase(_STD addressof(_Stringbuffer)), _Stringbuffer(_Str, _Mode) {} +#if _HAS_CXX20 + basic_stringstream(ios_base::openmode _Mode, const _Alloc& _Al) + : _Mybase(_STD addressof(_Stringbuffer)), _Stringbuffer(_Mode, _Al) {} + + explicit basic_stringstream(_Mystr&& _Str, ios_base::openmode _Mode = ios_base::in | ios_base::out) + : _Mybase(_STD addressof(_Stringbuffer)), _Stringbuffer(_STD move(_Str), _Mode) {} + + template + basic_stringstream(const basic_string<_Elem, _Traits, _Alloc2>& _Str, const _Alloc& _Al) + : _Mybase(_STD addressof(_Stringbuffer)), _Stringbuffer(_Str, ios_base::in | ios_base::out, _Al) {} + + template + basic_stringstream(const basic_string<_Elem, _Traits, _Alloc2>& _Str, ios_base::openmode _Mode, const _Alloc& _Al) + : _Mybase(_STD addressof(_Stringbuffer)), _Stringbuffer(_Str, _Mode, _Al) {} + + template , int> = 0> + explicit basic_stringstream( + const basic_string<_Elem, _Traits, _Alloc2>& _Str, ios_base::openmode _Mode = ios_base::in | ios_base::out) + : _Mybase(_STD addressof(_Stringbuffer)), _Stringbuffer(_Str, _Mode) {} +#endif // _HAS_CXX20 + basic_stringstream(basic_stringstream&& _Right) : _Mybase(_STD addressof(_Stringbuffer)) { _Assign_rv(_STD move(_Right)); } @@ -566,7 +864,12 @@ public: return const_cast<_Mysb*>(_STD addressof(_Stringbuffer)); } - _NODISCARD _Mystr str() const { +#if _HAS_CXX20 + _NODISCARD _Mystr str() const& +#else + _NODISCARD _Mystr str() const +#endif // _HAS_CXX20 + { return _Stringbuffer.str(); } @@ -574,6 +877,30 @@ public: _Stringbuffer.str(_Newstr); } +#if _HAS_CXX20 + template <_Allocator _Alloc2> + _NODISCARD basic_string<_Elem, _Traits, _Alloc2> str(const _Alloc2& _Al) const { + return _Stringbuffer.str(_Al); + } + + _NODISCARD _Mystr str() && { + return _STD move(_Stringbuffer).str(); + } + + _NODISCARD _Mystr_view view() const noexcept { + return _Stringbuffer.view(); + } + + template , int> = 0> + void str(const basic_string<_Elem, _Traits, _Alloc2>& _Newstr) { + _Stringbuffer.str(_Newstr); + } + + void str(_Mystr&& _Newstr) { + _Stringbuffer.str(_STD move(_Newstr)); + } +#endif // _HAS_CXX20 + private: _Mysb _Stringbuffer; }; diff --git a/stl/inc/string b/stl/inc/string index 72d3cebb2d8..c680e0c2d32 100644 --- a/stl/inc/string +++ b/stl/inc/string @@ -458,7 +458,7 @@ _Elem* _UIntegral_to_buff(_Elem* _RNext, _UTy _UVal) { // format _UVal into buff #else // ^^^ _WIN64 ^^^ // vvv !_WIN64 vvv constexpr bool _Big_uty = sizeof(_UTy) > 4; - if _CONSTEXPR_IF (_Big_uty) { // For 64-bit numbers, work in chunks to avoid 64-bit divisions. + if constexpr (_Big_uty) { // For 64-bit numbers, work in chunks to avoid 64-bit divisions. while (_UVal > 0xFFFFFFFFU) { auto _UVal_chunk = static_cast(_UVal % 1000000000); _UVal /= 1000000000; diff --git a/stl/inc/type_traits b/stl/inc/type_traits index e978fe15e20..c1a030758bb 100644 --- a/stl/inc/type_traits +++ b/stl/inc/type_traits @@ -1591,7 +1591,6 @@ _CONSTEXPR17 auto invoke(_Callable&& _Obj, _Ty1&& _Arg1, _Types2&&... _Args2) no static_cast<_Callable&&>(_Obj), static_cast<_Ty1&&>(_Arg1), static_cast<_Types2&&>(_Args2)...))) -> decltype(_Invoker1<_Callable, _Ty1>::_Call( static_cast<_Callable&&>(_Obj), static_cast<_Ty1&&>(_Arg1), static_cast<_Types2&&>(_Args2)...)) { -#if _HAS_IF_CONSTEXPR if constexpr (_Invoker1<_Callable, _Ty1>::_Strategy == _Invoker_strategy::_Functor) { return static_cast<_Callable&&>(_Obj)(static_cast<_Ty1&&>(_Arg1), static_cast<_Types2&&>(_Args2)...); } else if constexpr (_Invoker1<_Callable, _Ty1>::_Strategy == _Invoker_strategy::_Pmf_object) { @@ -1608,10 +1607,6 @@ _CONSTEXPR17 auto invoke(_Callable&& _Obj, _Ty1&& _Arg1, _Types2&&... _Args2) no static_assert(_Invoker1<_Callable, _Ty1>::_Strategy == _Invoker_strategy::_Pmd_pointer, "bug in invoke"); return (*static_cast<_Ty1&&>(_Arg1)).*_Obj; } -#else // ^^^ _HAS_IF_CONSTEXPR // !_HAS_IF_CONSTEXPR vvv - return _Invoker1<_Callable, _Ty1>::_Call( - static_cast<_Callable&&>(_Obj), static_cast<_Ty1&&>(_Arg1), static_cast<_Types2&&>(_Args2)...); -#endif // _HAS_IF_CONSTEXPR } #pragma warning(pop) // TRANSITION, DevCom-936696 diff --git a/stl/inc/vector b/stl/inc/vector index 38298bfeb57..252601aae62 100644 --- a/stl/inc/vector +++ b/stl/inc/vector @@ -561,7 +561,7 @@ private: } void _Move_construct(vector& _Right, false_type) { // move from _Right, possibly moving its contents - if _CONSTEXPR_IF (!_Alty_traits::is_always_equal::value) { + if constexpr (!_Alty_traits::is_always_equal::value) { if (_Getal() != _Right._Getal()) { const auto& _Right_data = _Right._Mypair._Myval2; const pointer _Rightfirst = _Right_data._Myfirst; @@ -635,7 +635,6 @@ private: _My_data._Orphan_all(); const auto _Oldcapacity = static_cast(_My_data._Myend - _Myfirst); -#if _HAS_IF_CONSTEXPR if constexpr (conjunction_v::_Trivially_copyable>, _Uses_default_construct<_Alty, _Ty*, _Ty>, _Uses_default_destroy<_Alty, _Ty*>>) { if (_Newsize > _Oldcapacity) { @@ -643,9 +642,7 @@ private: } _Mylast = _Refancy(_Copy_memmove(_Unfancy(_First), _Unfancy(_Last), _Unfancy(_Myfirst))); - } else -#endif // _HAS_IF_CONSTEXPR - { + } else { auto _Oldsize = static_cast(_Mylast - _Myfirst); if (_Newsize > _Oldsize) { @@ -1107,7 +1104,6 @@ private: _My_data._Orphan_all(); -#if _HAS_IF_CONSTEXPR if constexpr (conjunction_v::_Trivially_copyable>, _Uses_default_construct<_Alty, _Ty*, decltype(*_First)>, _Uses_default_destroy<_Alty, _Ty*>>) { @@ -1117,9 +1113,7 @@ private: } _Mylast = _Refancy(_Copy_memmove(_First, _Last, _Unfancy(_Myfirst))); - } else -#endif // _HAS_IF_CONSTEXPR - { + } else { auto _Oldsize = static_cast(_Mylast - _Myfirst); if (_Newsize > _Oldsize) { @@ -1775,13 +1769,10 @@ _NODISCARD bool operator==(const vector<_Ty, _Alloc>& _Left, const vector<_Ty, _ return false; } -#if _HAS_IF_CONSTEXPR if constexpr (is_same_v<_Ty, bool>) { return _STD equal( _Left._Myvec._Unchecked_begin(), _Left._Myvec._Unchecked_end(), _Right._Myvec._Unchecked_begin()); - } else -#endif // _HAS_IF_CONSTEXPR - { + } else { return _STD equal(_Left._Unchecked_begin(), _Left._Unchecked_end(), _Right._Unchecked_begin()); } } @@ -1793,7 +1784,6 @@ _NODISCARD bool operator!=(const vector<_Ty, _Alloc>& _Left, const vector<_Ty, _ } #endif // !_HAS_CXX20 -#if _HAS_IF_CONSTEXPR // Optimize vector lexicographical comparisons. // There are several endianness/ordering issues to consider here. @@ -1835,7 +1825,6 @@ struct _Vbase_compare_three_way { #endif // __cpp_lib_concepts } }; -#endif // _HAS_IF_CONSTEXPR #ifdef __cpp_lib_concepts template @@ -1865,7 +1854,6 @@ _NODISCARD _Synth_three_way_result<_Ty> operator<=>( #else // __cpp_lib_concepts template _NODISCARD bool operator<(const vector<_Ty, _Alloc>& _Left, const vector<_Ty, _Alloc>& _Right) { -#if _HAS_IF_CONSTEXPR if constexpr (is_same_v<_Ty, bool>) { // This optimization works because vector "trims" its underlying storage by zeroing out unused bits. auto _First = _Left._Myvec._Unchecked_begin(); @@ -1885,9 +1873,7 @@ _NODISCARD bool operator<(const vector<_Ty, _Alloc>& _Left, const vector<_Ty, _A } return _Left.size() < _Right.size(); - } else -#endif // _HAS_IF_CONSTEXPR - { + } else { return _STD lexicographical_compare( _Left._Unchecked_begin(), _Left._Unchecked_end(), _Right._Unchecked_begin(), _Right._Unchecked_end()); } @@ -2446,7 +2432,7 @@ public: vector(vector&& _Right, const _Alloc& _Al) noexcept(is_nothrow_constructible_v<_Mybase, _Mybase, const _Alloc&>) : _Mybase(_STD move(_Right), _Al) { - if _CONSTEXPR_IF (!_Alvbase_traits::is_always_equal::value) { + if constexpr (!_Alvbase_traits::is_always_equal::value) { if (this->_Getal() != _Right._Getal()) { return; } @@ -2993,7 +2979,6 @@ namespace pmr { } // namespace pmr #endif // _HAS_CXX17 -#if _HAS_IF_CONSTEXPR // VARIABLE TEMPLATE _Is_vb_iterator template _INLINE_VAR constexpr bool _Is_vb_iterator<_Vb_iterator<_Alloc>, _RequiresMutable> = true; @@ -3050,7 +3035,6 @@ _CONSTEXPR20 void _Fill_vbool(_FwdIt _First, _FwdIt _Last, const _Ty& _Val) { *_VbFirst = (*_VbFirst & _LastDestMask) | (_FillVal & _LastSourceMask); } } -#endif // _HAS_IF_CONSTEXPR _STD_END #pragma pop_macro("new") diff --git a/stl/inc/xhash b/stl/inc/xhash index 476b8c4938d..21f0901e804 100644 --- a/stl/inc/xhash +++ b/stl/inc/xhash @@ -34,7 +34,6 @@ namespace stdext { using _STD size_t; // FUNCTION TEMPLATE hash_value -#if _HAS_IF_CONSTEXPR template _NODISCARD size_t hash_value(const _Kty& _Keyval) noexcept { if constexpr (_STD is_pointer_v<_Kty> || _STD is_null_pointer_v<_Kty>) { @@ -43,22 +42,6 @@ namespace stdext { return static_cast(_Keyval) ^ 0xdeadbeefu; } } -#else // ^^^ _HAS_IF_CONSTEXPR / !_HAS_IF_CONSTEXPR vvv - template - _NODISCARD size_t _Hash_value(_STD true_type, const _Kty& _Keyval) noexcept { - return reinterpret_cast(_Keyval) ^ 0xdeadbeefu; - } - - template - _NODISCARD size_t _Hash_value(_STD false_type, const _Kty& _Keyval) noexcept { - return static_cast(_Keyval) ^ 0xdeadbeefu; - } - - template - _NODISCARD size_t hash_value(const _Kty& _Keyval) noexcept { - return _Hash_value(_STD disjunction<_STD is_pointer<_Kty>, _STD is_null_pointer<_Kty>>{}, _Keyval); - } -#endif // _HAS_IF_CONSTEXPR template _NODISCARD size_t hash_value(const basic_string<_Elem, _Traits, _Alloc>& _Str) noexcept { @@ -375,14 +358,6 @@ public: static constexpr size_type _Min_buckets = 8; // must be a positive power of 2 static constexpr bool _Multi = _Traits::_Multi; -#if !_HAS_IF_CONSTEXPR - template - friend bool _Hash_equal_elements(const _Hash<_TraitsT>& _Left, const _Hash<_TraitsT>& _Right, false_type); - - template - friend bool _Hash_equal_elements(const _Hash<_TraitsT>& _Left, const _Hash<_TraitsT>& _Right, true_type); -#endif // !_HAS_IF_CONSTEXPR - template friend bool _Hash_equal(const _Hash<_TraitsT>& _Left, const _Hash<_TraitsT>& _Right); @@ -436,7 +411,7 @@ private: public: _Hash(_Hash&& _Right, const allocator_type& _Al) : _Traitsobj(_Right._Traitsobj), _List(_Al), _Vec(_Al) { // construct hash table by moving _Right, allocator - if _CONSTEXPR_IF (_Alnode_traits::is_always_equal::value) { + if constexpr (_Alnode_traits::is_always_equal::value) { _Move_construct_equal_alloc(_Right); } else if (_List._Getal() == _Right._List._Getal()) { _Move_construct_equal_alloc(_Right); @@ -587,7 +562,6 @@ public: return *this; } -#if _HAS_IF_CONSTEXPR template conditional_t<_Multi, iterator, pair> emplace(_Valtys&&... _Vals) { // try to insert value_type(_Vals...) @@ -640,70 +614,7 @@ public: _List._Make_iter(_Insert_new_node_before(_Hashval, _Target._Insert_before, _Newnode._Release())), true}; } } -#else // ^^^ _HAS_IF_CONSTEXPR // !_HAS_IF_CONSTEXPR vvv - template - iterator _Choose_emplace(integral_constant, _Valtys&&... _Vals) { - _Check_max_size(); - _List_node_emplace_op2<_Alnode> _Newnode(_List._Getal(), _STD forward<_Valtys>(_Vals)...); - const auto& _Keyval = _Traits::_Kfn(_Newnode._Ptr->_Myval); - const auto _Hashval = _Traitsobj(_Keyval); - if (_Check_rehash_required_1()) { - _Rehash_for_1(); - } - - const auto _Target = _Find_last(_Keyval, _Hashval); - return _List._Make_iter(_Insert_new_node_before(_Hashval, _Target._Insert_before, _Newnode._Release())); - } - - template - pair _Choose_emplace(integral_constant, _Valtys&&... _Vals) { - using _In_place_key_extractor = typename _Traits::template _In_place_key_extractor<_Remove_cvref_t<_Valtys>...>; - const auto& _Keyval = _In_place_key_extractor::_Extract(_Vals...); - const auto _Hashval = _Traitsobj(_Keyval); - auto _Target = _Find_last(_Keyval, _Hashval); - if (_Target._Duplicate) { - return {_List._Make_iter(_Target._Duplicate), false}; - } - - _Check_max_size(); - // invalidates _Keyval: - _List_node_emplace_op2<_Alnode> _Newnode(_List._Getal(), _STD forward<_Valtys>(_Vals)...); - if (_Check_rehash_required_1()) { - _Rehash_for_1(); - _Target = _Find_last(_Traits::_Kfn(_Newnode._Ptr->_Myval), _Hashval); - } - - return {_List._Make_iter(_Insert_new_node_before(_Hashval, _Target._Insert_before, _Newnode._Release())), true}; - } - - template - pair _Choose_emplace(integral_constant, _Valtys&&... _Vals) { - _List_node_emplace_op2<_Alnode> _Newnode(_List._Getal(), _STD forward<_Valtys>(_Vals)...); - const auto& _Keyval = _Traits::_Kfn(_Newnode._Ptr->_Myval); - const auto _Hashval = _Traitsobj(_Keyval); - auto _Target = _Find_last(_Keyval, _Hashval); - if (_Target._Duplicate) { - return {_List._Make_iter(_Target._Duplicate), false}; - } - - _Check_max_size(); - if (_Check_rehash_required_1()) { - _Rehash_for_1(); - _Target = _Find_last(_Traits::_Kfn(_Newnode._Ptr->_Myval), _Hashval); - } - - return {_List._Make_iter(_Insert_new_node_before(_Hashval, _Target._Insert_before, _Newnode._Release())), true}; - } - - template - conditional_t<_Multi, iterator, pair> emplace(_Valtys&&... _Vals) { - constexpr int _Choice = - _Multi ? 2 : _Traits::template _In_place_key_extractor<_Remove_cvref_t<_Valtys>...>::_Extractable; - return _Choose_emplace(integral_constant{}, _STD forward<_Valtys>(_Vals)...); - } -#endif // _HAS_IF_CONSTEXPR -#if _HAS_IF_CONSTEXPR template iterator emplace_hint(const_iterator _Hint, _Valtys&&... _Vals) { // try to insert value_type(_Vals...) using _In_place_key_extractor = typename _Traits::template _In_place_key_extractor<_Remove_cvref_t<_Valtys>...>; @@ -753,68 +664,6 @@ public: return _List._Make_iter(_Insert_new_node_before(_Hashval, _Target._Insert_before, _Newnode._Release())); } } -#else // ^^^ _HAS_IF_CONSTEXPR // !_HAS_IF_CONSTEXPR vvv - template - iterator _Choose_emplace_hint(integral_constant, const _Nodeptr _Hint, _Valtys&&... _Vals) { - _Check_max_size(); - _List_node_emplace_op2<_Alnode> _Newnode(_List._Getal(), _STD forward<_Valtys>(_Vals)...); - const auto& _Keyval = _Traits::_Kfn(_Newnode._Ptr->_Myval); - const auto _Hashval = _Traitsobj(_Keyval); - if (_Check_rehash_required_1()) { - _Rehash_for_1(); - } - - const auto _Target = _Find_hint(_Hint, _Keyval, _Hashval); - return _List._Make_iter(_Insert_new_node_before(_Hashval, _Target._Insert_before, _Newnode._Release())); - } - - template - iterator _Choose_emplace_hint(integral_constant, const _Nodeptr _Hint, _Valtys&&... _Vals) { - using _In_place_key_extractor = typename _Traits::template _In_place_key_extractor<_Remove_cvref_t<_Valtys>...>; - const auto& _Keyval = _In_place_key_extractor::_Extract(_Vals...); - const auto _Hashval = _Traitsobj(_Keyval); - auto _Target = _Find_hint(_Hint, _Keyval, _Hashval); - if (_Target._Duplicate) { - return _List._Make_iter(_Target._Duplicate); - } - - _Check_max_size(); - // invalidates _Keyval: - _List_node_emplace_op2<_Alnode> _Newnode(_List._Getal(), _STD forward<_Valtys>(_Vals)...); - if (_Check_rehash_required_1()) { - _Rehash_for_1(); - _Target = _Find_hint(_Hint, _Traits::_Kfn(_Newnode._Ptr->_Myval), _Hashval); - } - - return _List._Make_iter(_Insert_new_node_before(_Hashval, _Target._Insert_before, _Newnode._Release())); - } - - template - iterator _Choose_emplace_hint(integral_constant, const _Nodeptr _Hint, _Valtys&&... _Vals) { - _List_node_emplace_op2<_Alnode> _Newnode(_List._Getal(), _STD forward<_Valtys>(_Vals)...); - const auto& _Keyval = _Traits::_Kfn(_Newnode._Ptr->_Myval); - const auto _Hashval = _Traitsobj(_Keyval); - auto _Target = _Find_hint(_Hint, _Keyval, _Hashval); - if (_Target._Duplicate) { - return _List._Make_iter(_Target._Duplicate); - } - - _Check_max_size(); - if (_Check_rehash_required_1()) { - _Rehash_for_1(); - _Target = _Find_hint(_Hint, _Traits::_Kfn(_Newnode._Ptr->_Myval), _Hashval); - } - - return _List._Make_iter(_Insert_new_node_before(_Hashval, _Target._Insert_before, _Newnode._Release())); - } - - template - iterator emplace_hint(const_iterator _Hint, _Valtys&&... _Vals) { - constexpr int _Choice = - _Multi ? 2 : _Traits::template _In_place_key_extractor<_Remove_cvref_t<_Valtys>...>::_Extractable; - return _Choose_emplace_hint(integral_constant{}, _Hint._Ptr, _STD forward<_Valtys>(_Vals)...); - } -#endif // _HAS_IF_CONSTEXPR protected: template @@ -1232,7 +1081,7 @@ public: _Nothrow_hash<_Traits, key_type> // && (!_Multi || _Nothrow_compare<_Traits, key_type, key_type>) ) /* strengthened */ { const size_t _Hashval = _Traitsobj(_Keyval); - if _CONSTEXPR_IF (_Multi) { + if constexpr (_Multi) { const auto _Where = _Equal_range(_Keyval, _Hashval); _Unchecked_erase(_Where._First._Ptr, _Where._Last._Ptr); return _Where._Distance; @@ -1261,7 +1110,7 @@ public: return; } - if _CONSTEXPR_IF (_Nothrow_hash<_Traits, key_type>) { + if constexpr (_Nothrow_hash<_Traits, key_type>) { // In testing, hash{}(size_t{}) takes about 14 times as much time as assigning a pointer, or // ~7-8 times as much as clearing a bucket. Therefore, if we would need to assign over more than 8 times // as many buckets as elements, remove element-by-element. @@ -1291,7 +1140,7 @@ private: const _Nodeptr _Bucket_hi = _Vec._Mypair._Myval2._Myfirst[(_Bucket << 1) + 1]._Ptr; for (;;) { if (!_Traitsobj(_Traits::_Kfn(_Where->_Myval), _Keyval)) { - if _CONSTEXPR_IF (!_Traits::_Standard) { + if constexpr (!_Traits::_Standard) { if (_Traitsobj(_Keyval, _Traits::_Kfn(_Where->_Myval))) { return _End; } @@ -1310,7 +1159,7 @@ private: template _Nodeptr _Find(const _Keyty& _Keyval, const size_t _Hashval) const { - if _CONSTEXPR_IF (_Traits::_Multi) { + if constexpr (_Traits::_Multi) { return _Find_first(_Keyval, _Hashval); } else { // use _Find_last for unique containers to avoid increase in code size of instantiating _Find_first @@ -1344,7 +1193,7 @@ public: template _NODISCARD size_type count(typename _Traits::template _Deduce_key<_Keyty> _Keyval) const { const size_t _Hashval = _Traitsobj(_Keyval); - if _CONSTEXPR_IF (_Multi) { + if constexpr (_Multi) { return _Equal_range(_Keyval, _Hashval)._Distance; } else { return static_cast(_Find_last(_Keyval, _Hashval)._Duplicate); @@ -1405,14 +1254,14 @@ private: } } - if _CONSTEXPR_IF (!_Traits::_Standard) { + if constexpr (!_Traits::_Standard) { if (_Traitsobj(_Keyval, _Traits::_Kfn(*_Where))) { return {_End, _End, 0}; } } const _Unchecked_const_iterator _First = _Where; - if _CONSTEXPR_IF (_Multi) { + if constexpr (_Multi) { size_type _Distance = 0; for (;;) { ++_Distance; @@ -1662,7 +1511,7 @@ protected: for (;;) { // Search backwards to maintain sorted [_Bucket_lo, _Bucket_hi] when !_Standard if (!_Traitsobj(_Keyval, _Traits::_Kfn(_Where->_Myval))) { - if _CONSTEXPR_IF (!_Traits::_Standard) { + if constexpr (!_Traits::_Standard) { if (_Traitsobj(_Traits::_Kfn(_Where->_Myval), _Keyval)) { return {_Where->_Next, _Nodeptr{}}; } @@ -1685,7 +1534,7 @@ protected: // if _Hint points to an element equivalent to _Keyval, returns _Hint; otherwise, // returns _Find_last(_Keyval, _Hashval) if (_Hint != _List._Mypair._Myval2._Myhead && !_Traitsobj(_Traits::_Kfn(_Hint->_Myval), _Keyval)) { - if _CONSTEXPR_IF (!_Traits::_Standard) { + if constexpr (!_Traits::_Standard) { if (_Traitsobj(_Keyval, _Traits::_Kfn(_Hint->_Myval))) { return _Find_last(_Keyval, _Hashval); } @@ -1928,7 +1777,7 @@ protected: } _Unchecked_const_iterator _Left_stop_at; - if _CONSTEXPR_IF (_Traits::_Standard) { + if constexpr (_Traits::_Standard) { _Left_stop_at = _Unchecked_end(); } else { // check the first elements for equivalence when !_Standard @@ -2036,13 +1885,13 @@ public: const _Unchecked_const_iterator _Bucket_hi = _Vec._Mypair._Myval2._Myfirst[(_Bucket << 1) + 1]; if (_Where != _End) { // check that the bucket is sorted for legacy hash_meow: - if _CONSTEXPR_IF (!_Traits::_Standard) { + if constexpr (!_Traits::_Standard) { if (_Where != _Bucket_hi) { auto _SFirst = _Where; auto _SNext = _Where; for (;;) { ++_SNext; - if _CONSTEXPR_IF (_Traits::_Multi) { + if constexpr (_Traits::_Multi) { _STL_INTERNAL_CHECK(!_Traitsobj(_Traits::_Kfn(*_SNext), _Traits::_Kfn(*_SFirst))); } else { _STL_INTERNAL_CHECK(_Traitsobj(_Traits::_Kfn(*_SFirst), _Traits::_Kfn(*_SNext))); @@ -2091,34 +1940,12 @@ template using _Is_hasher = negation, _Is_allocator<_Hasher>>>; #endif // _HAS_CXX17 -#if !_HAS_IF_CONSTEXPR -template -_NODISCARD bool _Hash_equal_elements(const _Hash<_Traits>& _Left, const _Hash<_Traits>& _Right, false_type) { - for (const auto& _LVal : _Left) { - // look for element with equivalent key - const auto& _Keyval = _Traits::_Kfn(_LVal); - const auto _Next2 = _Right._Find_last(_Keyval, _Right._Traitsobj(_Keyval))._Duplicate; - if (!(static_cast(_Next2) && _Traits::_Nonkfn(_LVal) == _Traits::_Nonkfn(_Next2->_Myval))) { - return false; - } - } - - return true; -} - -template -_NODISCARD bool _Hash_equal_elements(const _Hash<_Traits>& _Left, const _Hash<_Traits>& _Right, true_type) { - return _Left._Multi_equal(_Right); -} -#endif // !_HAS_IF_CONSTEXPR - template _NODISCARD bool _Hash_equal(const _Hash<_Traits>& _Left, const _Hash<_Traits>& _Right) { if (_Left.size() != _Right.size()) { return false; } -#if _HAS_IF_CONSTEXPR if constexpr (_Traits::_Multi) { return _Left._Multi_equal(_Right); } else { @@ -2133,9 +1960,6 @@ _NODISCARD bool _Hash_equal(const _Hash<_Traits>& _Left, const _Hash<_Traits>& _ } return true; -#else // ^^^ _HAS_IF_CONSTEXPR ^^^ / vvv !_HAS_IF_CONSTEXPR vvv - return _Hash_equal_elements(_Left, _Right, bool_constant<_Traits::_Multi>{}); -#endif // _HAS_IF_CONSTEXPR } _STD_END diff --git a/stl/inc/xlocale b/stl/inc/xlocale index 0922ab47730..fcdbf63bb17 100644 --- a/stl/inc/xlocale +++ b/stl/inc/xlocale @@ -732,7 +732,7 @@ protected: _Elem* _First2, _Elem* _Last2, _Elem*& _Mid2) const { // convert bytes [_First1, _Last1) to [_First2, _Last2) _Mid1 = _First1; _Mid2 = _First2; - if _CONSTEXPR_IF (is_same_v<_Byte, _Elem>) { + if constexpr (is_same_v<_Byte, _Elem>) { return noconv; // convert nothing } else { // types differ, copy one for one @@ -751,7 +751,7 @@ protected: _Byte* _First2, _Byte* _Last2, _Byte*& _Mid2) const { // convert [_First1, _Last1) to bytes [_First2, _Last2) _Mid1 = _First1; _Mid2 = _First2; - if _CONSTEXPR_IF (is_same_v<_Byte, _Elem>) { + if constexpr (is_same_v<_Byte, _Elem>) { return noconv; // convert nothing } else { // types differ, copy one for one @@ -3242,8 +3242,11 @@ protected: }; // FUNCTION TEMPLATE _Getloctxt -template -int __CRTDECL _Getloctxt(_InIt& _First, _InIt& _Last, size_t _Numfields, const _Elem* _Ptr) { +enum class _Case_sensitive : bool { _Nope, _Yes }; + +template +int __CRTDECL _Getloctxt( + _InIt& _First, _InIt& _Last, size_t _Numfields, const _Elem* _Ptr, const _Case_sensitive _Matching) { // find field at _Ptr that matches longest in [_First, _Last) for (size_t _Off = 0; _Ptr[_Off] != _Elem{}; ++_Off) { if (_Ptr[_Off] == _Ptr[0]) { @@ -3271,7 +3274,10 @@ int __CRTDECL _Getloctxt(_InIt& _First, _InIt& _Last, size_t _Numfields, const _ || _Ptr[_Off] == _Elem{}) { // matched all of field, save as possible answer _Str[_Field] = static_cast(_Column < 127 ? _Column : 127); // save skip count if small enough _Ans = static_cast(_Field); // save answer - } else if (_First == _Last || _CType.tolower(_Ptr[_Off]) != _CType.tolower(static_cast<_Elem>(*_First))) { + } else if (_First == _Last + || (_Matching == _Case_sensitive::_Yes + ? _Ptr[_Off] != *_First + : _CType.tolower(_Ptr[_Off]) != _CType.tolower(static_cast<_Elem>(*_First)))) { _Str[_Field] = static_cast(_Column < 127 ? _Column : 127); // no match, just save skip count } else { _Prefix = true; // still a valid prefix diff --git a/stl/inc/xlocnum b/stl/inc/xlocnum index 89d33a7d02f..2643b4cbe56 100644 --- a/stl/inc/xlocnum +++ b/stl/inc/xlocnum @@ -369,7 +369,7 @@ protected: _Str += _Punct_fac.falsename(); _Str.push_back(_Elem{}); _Str += _Punct_fac.truename(); // construct "\0false\0true" - switch (_Getloctxt(_First, _Last, 2, _Str.c_str())) { + switch (_Getloctxt(_First, _Last, 2, _Str.c_str(), _Case_sensitive::_Yes)) { case 0: _Val = false; break; diff --git a/stl/inc/xloctime b/stl/inc/xloctime index 55cb9f0df2d..d812c1b5743 100644 --- a/stl/inc/xloctime +++ b/stl/inc/xloctime @@ -326,7 +326,7 @@ protected: virtual _InIt __CLR_OR_THIS_CALL do_get_weekday(_InIt _First, _InIt _Last, ios_base&, ios_base::iostate& _State, tm* _Pt) const { // get weekday from [_First, _Last) into _Pt - int _Num = _Getloctxt(_First, _Last, 0, _Days); + int _Num = _Getloctxt(_First, _Last, 0, _Days, _Case_sensitive::_Nope); if (_Num < 0) { _State |= ios_base::failbit; } else { @@ -338,7 +338,7 @@ protected: virtual _InIt __CLR_OR_THIS_CALL do_get_monthname(_InIt _First, _InIt _Last, ios_base&, ios_base::iostate& _State, tm* _Pt) const { // get month from [_First, _Last) into _Pt - int _Num = _Getloctxt(_First, _Last, 0, _Months); + int _Num = _Getloctxt(_First, _Last, 0, _Months, _Case_sensitive::_Nope); if (_Num < 0) { _State |= ios_base::failbit; @@ -444,7 +444,7 @@ protected: break; case 'p': - _Ans = _Getloctxt(_First, _Last, 0, ":AM:am:PM:pm"); + _Ans = _Getloctxt(_First, _Last, 0, ":AM:am:PM:pm", _Case_sensitive::_Nope); if (_Ans < 0) { _State |= ios_base::failbit; } else if (1 < _Ans) { diff --git a/stl/inc/xmemory b/stl/inc/xmemory index b1d8bfd0807..38209d5c9cd 100644 --- a/stl/inc/xmemory +++ b/stl/inc/xmemory @@ -55,7 +55,7 @@ template _NODISCARD constexpr size_t _Get_size_of_n(const size_t _Count) { constexpr bool _Overflow_is_possible = _Ty_size > 1; - if _CONSTEXPR_IF (_Overflow_is_possible) { + if constexpr (_Overflow_is_possible) { constexpr size_t _Max_possible = static_cast(-1) / _Ty_size; if (_Count > _Max_possible) { _Throw_bad_array_new_length(); // multiply overflow @@ -73,13 +73,30 @@ _INLINE_VAR constexpr size_t _New_alignof = (_STD max)(alignof(_Ty), // STRUCT _Default_allocate_traits struct _Default_allocate_traits { - __declspec(allocator) static void* _Allocate(const size_t _Bytes) { + __declspec(allocator) static +#ifdef __clang__ // Clang and MSVC implement P0784R7 differently; see GH-1532 + _CONSTEXPR20_DYNALLOC +#endif // __clang__ + void* _Allocate(const size_t _Bytes) { return ::operator new(_Bytes); } #ifdef __cpp_aligned_new - __declspec(allocator) static void* _Allocate_aligned(const size_t _Bytes, const size_t _Align) { - return ::operator new (_Bytes, align_val_t{_Align}); + __declspec(allocator) static +#ifdef __clang__ // Clang and MSVC implement P0784R7 differently; see GH-1532 + _CONSTEXPR20_DYNALLOC +#endif // __clang__ + void* _Allocate_aligned(const size_t _Bytes, const size_t _Align) { +#ifdef __clang__ // Clang and MSVC implement P0784R7 differently; see GH-1532 +#ifdef __cpp_lib_constexpr_dynamic_alloc + if (_STD is_constant_evaluated()) { + return ::operator new(_Bytes); + } else +#endif // __cpp_lib_constexpr_dynamic_alloc +#endif // __clang__ + { + return ::operator new (_Bytes, align_val_t{_Align}); + } } #endif // __cpp_aligned_new }; @@ -157,34 +174,46 @@ inline void _Adjust_manually_vector_aligned(void*& _Ptr, size_t& _Bytes) { #ifdef __cpp_aligned_new template __STDCPP_DEFAULT_NEW_ALIGNMENT__), int> = 0> -__declspec(allocator) void* _Allocate(const size_t _Bytes) { +__declspec(allocator) _CONSTEXPR20_DYNALLOC void* _Allocate(const size_t _Bytes) { // allocate _Bytes when __cpp_aligned_new && _Align > __STDCPP_DEFAULT_NEW_ALIGNMENT__ if (_Bytes == 0) { return nullptr; } - size_t _Passed_align = _Align; +#ifdef __cpp_lib_constexpr_dynamic_alloc // TRANSITION, GH-1532 + if (_STD is_constant_evaluated()) { + return _Traits::_Allocate(_Bytes); + } else +#endif // __cpp_lib_constexpr_dynamic_alloc + { + size_t _Passed_align = _Align; #if defined(_M_IX86) || defined(_M_X64) - if (_Bytes >= _Big_allocation_threshold) { - // boost the alignment of big allocations to help autovectorization - _Passed_align = (_STD max)(_Align, _Big_allocation_alignment); - } + if (_Bytes >= _Big_allocation_threshold) { + // boost the alignment of big allocations to help autovectorization + _Passed_align = (_STD max)(_Align, _Big_allocation_alignment); + } #endif // defined(_M_IX86) || defined(_M_X64) - - return _Traits::_Allocate_aligned(_Bytes, _Passed_align); + return _Traits::_Allocate_aligned(_Bytes, _Passed_align); + } } template __STDCPP_DEFAULT_NEW_ALIGNMENT__), int> = 0> -void _Deallocate(void* _Ptr, const size_t _Bytes) noexcept { +_CONSTEXPR20_DYNALLOC void _Deallocate(void* _Ptr, const size_t _Bytes) noexcept { // deallocate storage allocated by _Allocate when __cpp_aligned_new && _Align > __STDCPP_DEFAULT_NEW_ALIGNMENT__ - size_t _Passed_align = _Align; +#ifdef __cpp_lib_constexpr_dynamic_alloc // TRANSITION, GH-1532 + if (_STD is_constant_evaluated()) { + ::operator delete(_Ptr); + } else +#endif // __cpp_lib_constexpr_dynamic_alloc + { + size_t _Passed_align = _Align; #if defined(_M_IX86) || defined(_M_X64) - if (_Bytes >= _Big_allocation_threshold) { // boost the alignment of big allocations to help autovectorization - _Passed_align = (_STD max)(_Align, _Big_allocation_alignment); - } + if (_Bytes >= _Big_allocation_threshold) { // boost the alignment of big allocations to help autovectorization + _Passed_align = (_STD max)(_Align, _Big_allocation_alignment); + } #endif // defined(_M_IX86) || defined(_M_X64) - - ::operator delete (_Ptr, _Bytes, align_val_t{_Passed_align}); + ::operator delete (_Ptr, _Bytes, align_val_t{_Passed_align}); + } } #define _HAS_ALIGNED_NEW 1 @@ -194,11 +223,16 @@ void _Deallocate(void* _Ptr, const size_t _Bytes) noexcept { template = 0> -__declspec(allocator) void* _Allocate(const size_t _Bytes) { +__declspec(allocator) _CONSTEXPR20_DYNALLOC void* _Allocate(const size_t _Bytes) { // allocate _Bytes when !_HAS_ALIGNED_NEW || _Align <= __STDCPP_DEFAULT_NEW_ALIGNMENT__ #if defined(_M_IX86) || defined(_M_X64) - if (_Bytes >= _Big_allocation_threshold) { // boost the alignment of big allocations to help autovectorization - return _Allocate_manually_vector_aligned<_Traits>(_Bytes); +#ifdef __cpp_lib_constexpr_dynamic_alloc // TRANSITION, GH-1532 + if (!_STD is_constant_evaluated()) +#endif // __cpp_lib_constexpr_dynamic_alloc + { + if (_Bytes >= _Big_allocation_threshold) { // boost the alignment of big allocations to help autovectorization + return _Allocate_manually_vector_aligned<_Traits>(_Bytes); + } } #endif // defined(_M_IX86) || defined(_M_X64) @@ -210,15 +244,21 @@ __declspec(allocator) void* _Allocate(const size_t _Bytes) { } template = 0> -void _Deallocate(void* _Ptr, size_t _Bytes) noexcept { +_CONSTEXPR20_DYNALLOC void _Deallocate(void* _Ptr, size_t _Bytes) noexcept { // deallocate storage allocated by _Allocate when !_HAS_ALIGNED_NEW || _Align <= __STDCPP_DEFAULT_NEW_ALIGNMENT__ +#ifdef __cpp_lib_constexpr_dynamic_alloc // TRANSITION, GH-1532 + if (_STD is_constant_evaluated()) { + ::operator delete(_Ptr); + } else +#endif // __cpp_lib_constexpr_dynamic_alloc + { #if defined(_M_IX86) || defined(_M_X64) - if (_Bytes >= _Big_allocation_threshold) { // boost the alignment of big allocations to help autovectorization - _Adjust_manually_vector_aligned(_Ptr, _Bytes); - } + if (_Bytes >= _Big_allocation_threshold) { // boost the alignment of big allocations to help autovectorization + _Adjust_manually_vector_aligned(_Ptr, _Bytes); + } #endif // defined(_M_IX86) || defined(_M_X64) - - ::operator delete(_Ptr, _Bytes); + ::operator delete(_Ptr, _Bytes); + } } #undef _HAS_ALIGNED_NEW @@ -261,15 +301,27 @@ _CONSTEXPR20_DYNALLOC void _Destroy_range(_NoThrowFwdIt _First, _NoThrowSentinel template _CONSTEXPR20_DYNALLOC void _Destroy_in_place(_Ty& _Obj) noexcept { -#if _HAS_IF_CONSTEXPR if constexpr (is_array_v<_Ty>) { _Destroy_range(_Obj, _Obj + extent_v<_Ty>); + } else { + _Obj.~_Ty(); + } +} + +#if _HAS_CXX17 +// FUNCTION TEMPLATE destroy_at +template +_CONSTEXPR20_DYNALLOC void destroy_at(_Ty* const _Location) noexcept /* strengthened */ { +#if _HAS_CXX20 + if constexpr (is_array_v<_Ty>) { + _Destroy_range(_STD begin(*_Location), _STD end(*_Location)); } else -#endif // _HAS_IF_CONSTEXPR +#endif // _HAS_CXX20 { - _Obj.~_Ty(); + _Location->~_Ty(); } } +#endif // _HAS_CXX17 // FUNCTION TEMPLATE _Const_cast template @@ -519,12 +571,12 @@ struct _Normal_allocator_traits { // defines traits for allocators template using rebind_traits = allocator_traits>; - _NODISCARD static __declspec(allocator) pointer allocate(_Alloc& _Al, _CRT_GUARDOVERFLOW const size_type _Count) { + _NODISCARD static _CONSTEXPR20_DYNALLOC __declspec(allocator) pointer + allocate(_Alloc& _Al, _CRT_GUARDOVERFLOW const size_type _Count) { return _Al.allocate(_Count); } -#if _HAS_IF_CONSTEXPR - _NODISCARD static __declspec(allocator) pointer + _NODISCARD static _CONSTEXPR20_DYNALLOC __declspec(allocator) pointer allocate(_Alloc& _Al, _CRT_GUARDOVERFLOW const size_type _Count, const const_void_pointer _Hint) { if constexpr (_Has_allocate_hint<_Alloc, size_type, const_void_pointer>::value) { return _Al.allocate(_Count, _Hint); @@ -532,124 +584,53 @@ struct _Normal_allocator_traits { // defines traits for allocators return _Al.allocate(_Count); } } -#else // ^^^ _HAS_IF_CONSTEXPR ^^^ // vvv !_HAS_IF_CONSTEXPR vvv - static __declspec(allocator) pointer - _Allocate1(_Alloc& _Al, _CRT_GUARDOVERFLOW const size_type _Count, const const_void_pointer _Hint, true_type) { - return _Al.allocate(_Count, _Hint); - } - - static __declspec(allocator) pointer - _Allocate1(_Alloc& _Al, _CRT_GUARDOVERFLOW const size_type _Count, const_void_pointer, false_type) { - return _Al.allocate(_Count); - } - - _NODISCARD static __declspec(allocator) pointer - allocate(_Alloc& _Al, _CRT_GUARDOVERFLOW const size_type _Count, const const_void_pointer _Hint) { - return _Allocate1(_Al, _Count, _Hint, _Has_allocate_hint<_Alloc, size_type, const_void_pointer>{}); - } -#endif // _HAS_IF_CONSTEXPR - static void deallocate(_Alloc& _Al, pointer _Ptr, size_type _Count) { + static _CONSTEXPR20_DYNALLOC void deallocate(_Alloc& _Al, pointer _Ptr, size_type _Count) { _Al.deallocate(_Ptr, _Count); } -#if _HAS_IF_CONSTEXPR template - static void construct(_Alloc& _Al, _Ty* _Ptr, _Types&&... _Args) { + static _CONSTEXPR20_DYNALLOC void construct(_Alloc& _Al, _Ty* _Ptr, _Types&&... _Args) { if constexpr (_Uses_default_construct<_Alloc, _Ty*, _Types...>::value) { (void) _Al; // TRANSITION, DevCom-1004719 +#ifdef __cpp_lib_constexpr_dynamic_alloc + _STD construct_at(_Ptr, _STD forward<_Types>(_Args)...); +#else // __cpp_lib_constexpr_dynamic_alloc ::new (static_cast(_Ptr)) _Ty(_STD forward<_Types>(_Args)...); +#endif // __cpp_lib_constexpr_dynamic_alloc } else { _Al.construct(_Ptr, _STD forward<_Types>(_Args)...); } } -#else // ^^^ _HAS_IF_CONSTEXPR ^^^ // vvv !_HAS_IF_CONSTEXPR vvv - template - static void _Construct1(true_type, _Alloc&, _Ty* _Ptr, _Types&&... _Args) { - ::new (static_cast(_Ptr)) _Ty(_STD forward<_Types>(_Args)...); - } - template - static void _Construct1(false_type, _Alloc& _Al, _Ty* _Ptr, _Types&&... _Args) { - _Al.construct(_Ptr, _STD forward<_Types>(_Args)...); - } - - template - static void construct(_Alloc& _Al, _Ty* _Ptr, _Types&&... _Args) { - _Construct1(typename _Uses_default_construct<_Alloc, _Ty*, _Types...>::type{}, _Al, _Ptr, - _STD forward<_Types>(_Args)...); - } -#endif // _HAS_IF_CONSTEXPR - -#if _HAS_IF_CONSTEXPR template - static void destroy(_Alloc& _Al, _Ty* _Ptr) { + static _CONSTEXPR20_DYNALLOC void destroy(_Alloc& _Al, _Ty* _Ptr) { if constexpr (_Uses_default_destroy<_Alloc, _Ty*>::value) { +#ifdef __cpp_lib_constexpr_dynamic_alloc + _STD destroy_at(_Ptr); +#else // __cpp_lib_constexpr_dynamic_alloc _Ptr->~_Ty(); +#endif // __cpp_lib_constexpr_dynamic_alloc } else { _Al.destroy(_Ptr); } } -#else // ^^^ _HAS_IF_CONSTEXPR ^^^ // vvv !_HAS_IF_CONSTEXPR vvv - template - static void _Destroy1(_Alloc&, _Ty* _Ptr, true_type) { - _Ptr->~_Ty(); - } - - template - static void _Destroy1(_Alloc& _Al, _Ty* _Ptr, false_type) { - _Al.destroy(_Ptr); - } - - template - static void destroy(_Alloc& _Al, _Ty* _Ptr) { - _Destroy1(_Al, _Ptr, _Uses_default_destroy_t<_Alloc, _Ty*>()); - } -#endif // _HAS_IF_CONSTEXPR -#if _HAS_IF_CONSTEXPR - _NODISCARD static size_type max_size(const _Alloc& _Al) noexcept { + _NODISCARD static _CONSTEXPR20_DYNALLOC size_type max_size(const _Alloc& _Al) noexcept { if constexpr (_Has_max_size<_Alloc>::value) { return _Al.max_size(); } else { return (numeric_limits::max)() / sizeof(value_type); } } -#else // ^^^ _HAS_IF_CONSTEXPR ^^^ // vvv !_HAS_IF_CONSTEXPR vvv - static size_type _Max_size1(const _Alloc& _Al, true_type) noexcept { - return _Al.max_size(); - } - - static size_type _Max_size1(const _Alloc&, false_type) noexcept { - return (numeric_limits::max)() / sizeof(value_type); - } - _NODISCARD static size_type max_size(const _Alloc& _Al) noexcept { - return _Max_size1(_Al, _Has_max_size<_Alloc>{}); - } -#endif // _HAS_IF_CONSTEXPR - -#if _HAS_IF_CONSTEXPR - _NODISCARD static _Alloc select_on_container_copy_construction(const _Alloc& _Al) { + _NODISCARD static _CONSTEXPR20_DYNALLOC _Alloc select_on_container_copy_construction(const _Alloc& _Al) { if constexpr (_Has_select_on_container_copy_construction<_Alloc>::value) { return _Al.select_on_container_copy_construction(); } else { return _Al; } } -#else // ^^^ _HAS_IF_CONSTEXPR ^^^ // vvv !_HAS_IF_CONSTEXPR vvv - static _Alloc _Select_on_container_copy_construction1(const _Alloc& _Al, true_type) { - return _Al.select_on_container_copy_construction(); - } - - static _Alloc _Select_on_container_copy_construction1(const _Alloc& _Al, false_type) { - return _Al; - } - - _NODISCARD static _Alloc select_on_container_copy_construction(const _Alloc& _Al) { - return _Select_on_container_copy_construction1(_Al, _Has_select_on_container_copy_construction<_Alloc>{}); - } -#endif // _HAS_IF_CONSTEXPR }; _STL_RESTORE_DEPRECATED_WARNING @@ -677,35 +658,73 @@ struct _Default_allocator_traits { // traits for std::allocator template using rebind_traits = allocator_traits>; - _NODISCARD static __declspec(allocator) pointer allocate(_Alloc&, _CRT_GUARDOVERFLOW const size_type _Count) { - return static_cast(_Allocate<_New_alignof>(_Get_size_of_n(_Count))); + _NODISCARD static _CONSTEXPR20_DYNALLOC __declspec(allocator) pointer + allocate(_Alloc& _Al, _CRT_GUARDOVERFLOW const size_type _Count) { +#ifdef __cpp_lib_constexpr_dynamic_alloc // TRANSITION, GH-1532 + if (_STD is_constant_evaluated()) { + return _Al.allocate(_Count); + } else +#endif // __cpp_lib_constexpr_dynamic_alloc + { + (void) _Al; + return static_cast( + _Allocate<_New_alignof>(_Get_size_of_n(_Count))); + } } - _NODISCARD static __declspec(allocator) pointer - allocate(_Alloc&, _CRT_GUARDOVERFLOW const size_type _Count, const_void_pointer) { - return static_cast(_Allocate<_New_alignof>(_Get_size_of_n(_Count))); + _NODISCARD static _CONSTEXPR20_DYNALLOC __declspec(allocator) pointer + allocate(_Alloc& _Al, _CRT_GUARDOVERFLOW const size_type _Count, const_void_pointer) { +#ifdef __cpp_lib_constexpr_dynamic_alloc // TRANSITION, GH-1532 + if (_STD is_constant_evaluated()) { + return _Al.allocate(_Count); + } else +#endif // __cpp_lib_constexpr_dynamic_alloc + { + (void) _Al; + return static_cast( + _Allocate<_New_alignof>(_Get_size_of_n(_Count))); + } } - static void deallocate(_Alloc&, const pointer _Ptr, const size_type _Count) { + static _CONSTEXPR20_DYNALLOC void deallocate(_Alloc& _Al, const pointer _Ptr, const size_type _Count) { // no overflow check on the following multiply; we assume _Allocate did that check - _Deallocate<_New_alignof>(_Ptr, sizeof(value_type) * _Count); +#ifdef __cpp_lib_constexpr_dynamic_alloc // TRANSITION, GH-1532 + if (_STD is_constant_evaluated()) { + _Al.deallocate(_Ptr, _Count); + } else +#endif // __cpp_lib_constexpr_dynamic_alloc + { + (void) _Al; + _Deallocate<_New_alignof>(_Ptr, sizeof(value_type) * _Count); + } } template - static void construct(_Alloc&, _Objty* const _Ptr, _Types&&... _Args) { - ::new (const_cast(static_cast(_Ptr))) _Objty(_STD forward<_Types>(_Args)...); + static _CONSTEXPR20_DYNALLOC void construct(_Alloc&, _Objty* const _Ptr, _Types&&... _Args) { +#ifdef __cpp_lib_constexpr_dynamic_alloc + if (_STD is_constant_evaluated()) { + _STD construct_at(_Ptr, _STD forward<_Types>(_Args)...); + } else +#endif // __cpp_lib_constexpr_dynamic_alloc + { + ::new (_Voidify_iter(_Ptr)) _Objty(_STD forward<_Types>(_Args)...); + } } template - static void destroy(_Alloc&, _Uty* const _Ptr) { + static _CONSTEXPR20_DYNALLOC void destroy(_Alloc&, _Uty* const _Ptr) { +#ifdef __cpp_lib_constexpr_dynamic_alloc + _STD destroy_at(_Ptr); +#else // __cpp_lib_constexpr_dynamic_alloc _Ptr->~_Uty(); +#endif // __cpp_lib_constexpr_dynamic_alloc } - _NODISCARD static size_type max_size(const _Alloc&) noexcept { + _NODISCARD static _CONSTEXPR20_DYNALLOC size_type max_size(const _Alloc&) noexcept { return static_cast(-1) / sizeof(value_type); } - _NODISCARD static _Alloc select_on_container_copy_construction(const _Alloc& _Al) { + _NODISCARD static _CONSTEXPR20_DYNALLOC _Alloc select_on_container_copy_construction(const _Alloc& _Al) { return _Al; } }; @@ -799,13 +818,15 @@ public: constexpr allocator(const allocator&) noexcept = default; template constexpr allocator(const allocator<_Other>&) noexcept {} + _CONSTEXPR20_DYNALLOC ~allocator() = default; + _CONSTEXPR20_DYNALLOC allocator& operator=(const allocator&) = default; - void deallocate(_Ty* const _Ptr, const size_t _Count) { + _CONSTEXPR20_DYNALLOC void deallocate(_Ty* const _Ptr, const size_t _Count) { // no overflow check on the following multiply; we assume _Allocate did that check _Deallocate<_New_alignof<_Ty>>(_Ptr, sizeof(_Ty) * _Count); } - _NODISCARD __declspec(allocator) _Ty* allocate(_CRT_GUARDOVERFLOW const size_t _Count) { + _NODISCARD _CONSTEXPR20_DYNALLOC __declspec(allocator) _Ty* allocate(_CRT_GUARDOVERFLOW const size_t _Count) { return static_cast<_Ty*>(_Allocate<_New_alignof<_Ty>>(_Get_size_of_n(_Count))); } @@ -850,12 +871,12 @@ public: }; template -_NODISCARD bool operator==(const allocator<_Ty>&, const allocator<_Other>&) noexcept { +_NODISCARD _CONSTEXPR20_DYNALLOC bool operator==(const allocator<_Ty>&, const allocator<_Other>&) noexcept { return true; } template -_NODISCARD bool operator!=(const allocator<_Ty>&, const allocator<_Other>&) noexcept { +_NODISCARD _CONSTEXPR20_DYNALLOC bool operator!=(const allocator<_Ty>&, const allocator<_Other>&) noexcept { return false; } @@ -875,54 +896,22 @@ template using _Alloc_size_t = typename allocator_traits<_Alloc>::size_type; // FUNCTION TEMPLATE _Pocca -#if _HAS_IF_CONSTEXPR template void _Pocca(_Alloc& _Left, const _Alloc& _Right) noexcept { if constexpr (allocator_traits<_Alloc>::propagate_on_container_copy_assignment::value) { _Left = _Right; } } -#else // ^^^ _HAS_IF_CONSTEXPR ^^^ // vvv !_HAS_IF_CONSTEXPR vvv -template -void _Pocca(_Alloc& _Left, const _Alloc& _Right, true_type) noexcept { - _Left = _Right; -} - -template -void _Pocca(_Alloc&, const _Alloc&, false_type) noexcept {} - -template -void _Pocca(_Alloc& _Left, const _Alloc& _Right) noexcept { - _Pocca(_Left, _Right, typename allocator_traits<_Alloc>::propagate_on_container_copy_assignment{}); -} -#endif // _HAS_IF_CONSTEXPR // FUNCTION TEMPLATE _Pocma -#if _HAS_IF_CONSTEXPR template void _Pocma(_Alloc& _Left, _Alloc& _Right) noexcept { // (maybe) propagate on container move assignment if constexpr (allocator_traits<_Alloc>::propagate_on_container_move_assignment::value) { _Left = _STD move(_Right); } } -#else // ^^^ _HAS_IF_CONSTEXPR ^^^ // vvv !_HAS_IF_CONSTEXPR vvv -template -void _Pocma(_Alloc& _Left, _Alloc& _Right, true_type) noexcept { - _Left = _STD move(_Right); -} - -template -void _Pocma(_Alloc&, _Alloc&, false_type) noexcept {} - -template -void _Pocma(_Alloc& _Left, _Alloc& _Right) noexcept { - typename allocator_traits<_Alloc>::propagate_on_container_move_assignment _Tag; - _Pocma(_Left, _Right, _Tag); -} -#endif // _HAS_IF_CONSTEXPR // FUNCTION TEMPLATE _Pocs -#if _HAS_IF_CONSTEXPR template void _Pocs(_Alloc& _Left, _Alloc& _Right) noexcept { if constexpr (allocator_traits<_Alloc>::propagate_on_container_swap::value) { @@ -931,32 +920,13 @@ void _Pocs(_Alloc& _Left, _Alloc& _Right) noexcept { _STL_ASSERT(_Left == _Right, "containers incompatible for swap"); } } -#else // ^^^ _HAS_IF_CONSTEXPR ^^^ // vvv !_HAS_IF_CONSTEXPR vvv -template -void _Pocs(_Alloc& _Left, _Alloc& _Right, true_type) noexcept { - _Swap_adl(_Left, _Right); -} - -template -void _Pocs(_Alloc& _Left, _Alloc& _Right, false_type) noexcept { - _STL_ASSERT(_Left == _Right, "containers incompatible for swap"); - (void) _Left; - (void) _Right; -} - -template -void _Pocs(_Alloc& _Left, _Alloc& _Right) noexcept { - typename allocator_traits<_Alloc>::propagate_on_container_swap _Tag; - _Pocs(_Left, _Right, _Tag); -} -#endif // _HAS_IF_CONSTEXPR // FUNCTION TEMPLATE _Destroy_range WITH ALLOC template void _Destroy_range(_Alloc_ptr_t<_Alloc> _First, const _Alloc_ptr_t<_Alloc> _Last, _Alloc& _Al) noexcept { // note that this is an optimization for debug mode codegen; in release mode the BE removes all of this using _Ty = typename _Alloc::value_type; - if _CONSTEXPR_IF (!conjunction_v, _Uses_default_destroy<_Alloc, _Ty*>>) { + if constexpr (!conjunction_v, _Uses_default_destroy<_Alloc, _Ty*>>) { for (; _First != _Last; ++_First) { allocator_traits<_Alloc>::destroy(_Al, _Unfancy(_First)); } @@ -967,7 +937,7 @@ void _Destroy_range(_Alloc_ptr_t<_Alloc> _First, const _Alloc_ptr_t<_Alloc> _Las template _CONSTEXPR20_DYNALLOC void _Destroy_range(_NoThrowFwdIt _First, const _NoThrowSentinel _Last) noexcept { // note that this is an optimization for debug mode codegen; in release mode the BE removes all of this - if _CONSTEXPR_IF (!is_trivially_destructible_v<_Iter_value_t<_NoThrowFwdIt>>) { + if constexpr (!is_trivially_destructible_v<_Iter_value_t<_NoThrowFwdIt>>) { for (; _First != _Last; ++_First) { _Destroy_in_place(*_First); } @@ -992,7 +962,6 @@ _NODISCARD constexpr size_t _Convert_size(const size_t _Len) noexcept { } // FUNCTION TEMPLATE _Deallocate_plain -#if _HAS_IF_CONSTEXPR template void _Deallocate_plain(_Alloc& _Al, typename _Alloc::value_type* const _Ptr) noexcept { // deallocate a plain pointer using an allocator @@ -1004,21 +973,6 @@ void _Deallocate_plain(_Alloc& _Al, typename _Alloc::value_type* const _Ptr) noe _Alloc_traits::deallocate(_Al, _Ptr_traits::pointer_to(*_Ptr), 1); } } -#else // ^^^ _HAS_IF_CONSTEXPR ^^^ // vvv !_HAS_IF_CONSTEXPR vvv -template , typename _Alloc::value_type*>, int> = 0> -void _Deallocate_plain(_Alloc& _Al, typename _Alloc::value_type* const _Ptr) noexcept { - // deallocate a plain pointer using an allocator, non-fancy pointers special case - allocator_traits<_Alloc>::deallocate(_Al, _Ptr, 1); -} - -template , typename _Alloc::value_type*>, int> = 0> -void _Deallocate_plain(_Alloc& _Al, typename _Alloc::value_type* const _Ptr) noexcept { - // deallocate a plain pointer using an allocator - using _Alloc_traits = allocator_traits<_Alloc>; - using _Ptr_traits = pointer_traits<_Alloc_ptr_t<_Alloc>>; - _Alloc_traits::deallocate(_Al, _Ptr_traits::pointer_to(*_Ptr), 1); -} -#endif // _HAS_IF_CONSTEXPR // FUNCTION TEMPLATE _Delete_plain_internal template @@ -1470,7 +1424,6 @@ namespace ranges { #endif // __cpp_lib_concepts // FUNCTION TEMPLATE _Uninitialized_move_unchecked -#if _HAS_IF_CONSTEXPR template _NoThrowFwdIt _Uninitialized_move_unchecked(_InIt _First, const _InIt _Last, _NoThrowFwdIt _Dest) { // move [_First, _Last) to raw [_Dest, ...) @@ -1485,32 +1438,6 @@ _NoThrowFwdIt _Uninitialized_move_unchecked(_InIt _First, const _InIt _Last, _No return _Backout._Release(); } } -#else // ^^^ _HAS_IF_CONSTEXPR ^^^ // vvv !_HAS_IF_CONSTEXPR vvv -template -_NoThrowFwdIt _Uninitialized_move_unchecked1(_InIt _First, const _InIt _Last, const _NoThrowFwdIt _Dest, false_type) { - // move [_First, _Last) to raw [_Dest, ...), no special optimization - _Uninitialized_backout<_NoThrowFwdIt> _Backout{_Dest}; - for (; _First != _Last; ++_First) { - _Backout._Emplace_back(_STD move(*_First)); - } - - return _Backout._Release(); -} - -template -_NoThrowFwdIt _Uninitialized_move_unchecked1( - const _InIt _First, const _InIt _Last, const _NoThrowFwdIt _Dest, true_type) { - // move [_First, _Last) to raw [_Dest, ...), memmove optimization - return _Copy_memmove(_First, _Last, _Dest); -} - -template -_NoThrowFwdIt _Uninitialized_move_unchecked(_InIt _First, const _InIt _Last, _NoThrowFwdIt _Dest) { - // move [_First, _Last) to raw [_Dest, ...), choose optimization - return _Uninitialized_move_unchecked1( - _First, _Last, _Dest, bool_constant<_Ptr_move_cat<_InIt, _NoThrowFwdIt>::_Really_trivial>{}); -} -#endif // _HAS_IF_CONSTEXPR // STRUCT TEMPLATE _Uninitialized_backout_al template @@ -1546,7 +1473,6 @@ private: }; // FUNCTION TEMPLATE _Uninitialized_copy WITH ALLOCATOR -#if _HAS_IF_CONSTEXPR template _Alloc_ptr_t<_Alloc> _Uninitialized_copy( const _InIt _First, const _InIt _Last, _Alloc_ptr_t<_Alloc> _Dest, _Alloc& _Al) { @@ -1572,46 +1498,8 @@ _Alloc_ptr_t<_Alloc> _Uninitialized_copy( return _Dest; } -#else // ^^^ _HAS_IF_CONSTEXPR ^^^ // vvv !_HAS_IF_CONSTEXPR vvv -template -_Alloc_ptr_t<_Alloc> _Uninitialized_copy_al_unchecked( - _InIt _First, const _InIt _Last, const _Alloc_ptr_t<_Alloc> _Dest, _Alloc& _Al, false_type) { - // copy [_First, _Last) to raw _Dest, using _Al, no special optimization - _Uninitialized_backout_al<_Alloc> _Backout{_Dest, _Al}; - for (; _First != _Last; ++_First) { - _Backout._Emplace_back(*_First); - } - - return _Backout._Release(); -} - -template -_Alloc_ptr_t<_Alloc> _Uninitialized_copy_al_unchecked( - const _InIt _First, const _InIt _Last, const _Alloc_ptr_t<_Alloc> _Dest, _Alloc&, true_type) { - // copy [_First, _Last) to raw _Dest, using default _Alloc construct, memmove optimization - return _Copy_memmove(_First, _Last, _Unfancy(_Dest)); -} - -template -_Alloc_ptr_t<_Alloc> _Uninitialized_copy( - const _InIt _First, const _InIt _Last, _Alloc_ptr_t<_Alloc> _Dest, _Alloc& _Al) { - // copy [_First, _Last) to raw _Dest, using _Al - // note: only called internally from elsewhere in the STL - - // clang-format off - auto _UFirst = _Get_unwrapped(_First); - const auto _ULast = _Get_unwrapped(_Last); - // clang-format on - - using _Ptrval = typename _Alloc::value_type*; - return _Uninitialized_copy_al_unchecked(_UFirst, _ULast, _Dest, _Al, - bool_constant::_Really_trivial>, - _Uses_default_construct<_Alloc, _Ptrval, decltype(*_UFirst)>>>{}); -} -#endif // _HAS_IF_CONSTEXPR // FUNCTION TEMPLATE uninitialized_copy -#if _HAS_IF_CONSTEXPR template _NoThrowFwdIt uninitialized_copy(const _InIt _First, const _InIt _Last, _NoThrowFwdIt _Dest) { // copy [_First, _Last) to raw [_Dest, ...) @@ -1633,40 +1521,8 @@ _NoThrowFwdIt uninitialized_copy(const _InIt _First, const _InIt _Last, _NoThrow _Seek_wrapped(_Dest, _UDest); return _Dest; } -#else // ^^^ _HAS_IF_CONSTEXPR / !_HAS_IF_CONSTEXPR vvv -template -_NoThrowFwdIt _Uninitialized_copy_unchecked(_InIt _First, const _InIt _Last, const _NoThrowFwdIt _Dest, false_type) { - // copy [_First, _Last) to raw [_Dest, ...), no special optimization - _Uninitialized_backout<_NoThrowFwdIt> _Backout{_Dest}; - for (; _First != _Last; ++_First) { - _Backout._Emplace_back(*_First); - } - - return _Backout._Release(); -} - -template -_NoThrowFwdIt _Uninitialized_copy_unchecked( - const _InIt _First, const _InIt _Last, const _NoThrowFwdIt _Dest, true_type) { - // copy [_First, _Last) to raw [_Dest, ...), memmove optimization - return _Copy_memmove(_First, _Last, _Dest); -} - -template -_NoThrowFwdIt uninitialized_copy(const _InIt _First, const _InIt _Last, _NoThrowFwdIt _Dest) { - // copy [_First, _Last) to raw [_Dest, ...) - _Adl_verify_range(_First, _Last); - auto _UFirst = _Get_unwrapped(_First); - const auto _ULast = _Get_unwrapped(_Last); - auto _UDest = _Get_unwrapped_n(_Dest, _Idl_distance<_InIt>(_UFirst, _ULast)); - _Seek_wrapped(_Dest, _Uninitialized_copy_unchecked(_UFirst, _ULast, _UDest, - bool_constant<_Ptr_copy_cat::_Really_trivial>{})); - return _Dest; -} -#endif // _HAS_IF_CONSTEXPR // FUNCTION TEMPLATE _Uninitialized_move WITH ALLOCATOR -#if _HAS_IF_CONSTEXPR template _Alloc_ptr_t<_Alloc> _Uninitialized_move( const _InIt _First, const _InIt _Last, _Alloc_ptr_t<_Alloc> _Dest, _Alloc& _Al) { @@ -1688,50 +1544,8 @@ _Alloc_ptr_t<_Alloc> _Uninitialized_move( return _Backout._Release(); } } -#else // ^^^ _HAS_IF_CONSTEXPR ^^^ // vvv !_HAS_IF_CONSTEXPR vvv -template -_Alloc_ptr_t<_Alloc> _Uninitialized_move_al_unchecked( - _InIt _First, const _InIt _Last, _Alloc_ptr_t<_Alloc> _Dest, _Alloc& _Al, false_type) { - // move [_First, _Last) to raw _Dest, using _Al, no special optimization - _Uninitialized_backout_al<_Alloc> _Backout{_Dest, _Al}; - for (; _First != _Last; ++_First) { - _Backout._Emplace_back(_STD move(*_First)); - } - - return _Backout._Release(); -} - -template -_Alloc_ptr_t<_Alloc> _Uninitialized_move_al_unchecked( - const _InIt _First, const _InIt _Last, _Alloc_ptr_t<_Alloc> _Dest, _Alloc&, true_type) { - // move [_First, _Last) to raw _Dest, using default _Alloc construct, memmove optimization - _Copy_memmove(_First, _Last, _Unfancy(_Dest)); - return _Dest + (_Last - _First); -} - -template -_Alloc_ptr_t<_Alloc> _Uninitialized_move( - const _InIt _First, const _InIt _Last, _Alloc_ptr_t<_Alloc> _Dest, _Alloc& _Al) { - // move [_First, _Last) to raw _Dest, using _Al - // note: only called internally from elsewhere in the STL - - // clang-format off - auto _UFirst = _Get_unwrapped(_First); - const auto _ULast = _Get_unwrapped(_Last); - auto _UDest = _Get_unwrapped_n(_Dest, _Idl_distance<_InIt>(_UFirst, _ULast)); - // clang-format on - - using _Ptrval = typename _Alloc::value_type*; - _Seek_wrapped( - _Dest, _Uninitialized_move_al_unchecked(_UFirst, _ULast, _UDest, _Al, - bool_constant < _Ptr_move_cat::_Really_trivial - && _Uses_default_construct<_Alloc, _Ptrval, decltype(_STD move(*_UFirst))>::value > {})); - return _Dest; -} -#endif // _HAS_IF_CONSTEXPR // FUNCTION TEMPLATE _Uninitialized_fill_n WITH ALLOCATOR -#if _HAS_IF_CONSTEXPR template _Alloc_ptr_t<_Alloc> _Uninitialized_fill_n( _Alloc_ptr_t<_Alloc> _First, _Alloc_size_t<_Alloc> _Count, const typename _Alloc::value_type& _Val, _Alloc& _Al) { @@ -1755,39 +1569,8 @@ _Alloc_ptr_t<_Alloc> _Uninitialized_fill_n( return _Backout._Release(); } } -#else // ^^^ _HAS_IF_CONSTEXPR // !_HAS_IF_CONSTEXPR vvv -template -_Alloc_ptr_t<_Alloc> _Uninit_alloc_fill_n1(_Alloc_ptr_t<_Alloc> _First, _Alloc_size_t<_Alloc> _Count, - const typename _Alloc::value_type& _Val, _Alloc& _Al, false_type) { - // copy _Count copies of _Val to raw _First, using _Al, no special optimization - _Uninitialized_backout_al<_Alloc> _Backout{_First, _Al}; - for (; 0 < _Count; --_Count) { - _Backout._Emplace_back(_Val); - } - - return _Backout._Release(); -} - -template -_Alloc_ptr_t<_Alloc> _Uninit_alloc_fill_n1(_Alloc_ptr_t<_Alloc> _First, _Alloc_size_t<_Alloc> _Count, - const typename _Alloc::value_type& _Val, _Alloc&, true_type) { - // copy _Count copies of _Val to raw _First, using default _Alloc construct, memset optimization - _Fill_memset(_Unfancy(_First), _Val, _Count); - return _First + _Count; -} - -template -_Alloc_ptr_t<_Alloc> _Uninitialized_fill_n(_Alloc_ptr_t<_Alloc> _First, const _Alloc_size_t<_Alloc> _Count, - const typename _Alloc::value_type& _Val, _Alloc& _Al) { - // copy _Count copies of _Val to raw _First, using _Al - using _Ty = typename _Alloc::value_type; - return _Uninit_alloc_fill_n1(_First, _Count, _Val, _Al, - bool_constant < _Fill_memset_is_safe<_Ty*, _Ty> && _Uses_default_construct<_Alloc, _Ty*, _Ty>::value > {}); -} -#endif // _HAS_IF_CONSTEXPR // FUNCTION TEMPLATE uninitialized_fill -#if _HAS_IF_CONSTEXPR template void uninitialized_fill(const _NoThrowFwdIt _First, const _NoThrowFwdIt _Last, const _Tval& _Val) { // copy _Val throughout raw [_First, _Last) @@ -1811,35 +1594,6 @@ void uninitialized_fill(const _NoThrowFwdIt _First, const _NoThrowFwdIt _Last, c _Backout._Release(); } } -#else // ^^^ _HAS_IF_CONSTEXPR // !_HAS_IF_CONSTEXPR vvv -template -void _Uninitialized_fill_unchecked( - const _NoThrowFwdIt _First, const _NoThrowFwdIt _Last, const _Tval& _Val, false_type) { - // copy _Val throughout raw [_First, _Last), no special optimization - _Uninitialized_backout<_NoThrowFwdIt> _Backout{_First}; - while (_Backout._Last != _Last) { - _Backout._Emplace_back(_Val); - } - - _Backout._Release(); -} - -template -void _Uninitialized_fill_unchecked( - const _NoThrowFwdIt _First, const _NoThrowFwdIt _Last, const _Tval& _Val, true_type) { - // copy _Val throughout raw [_First, _Last), memset optimization - _Fill_memset(_First, _Val, static_cast(_Last - _First)); -} - -template -void uninitialized_fill(const _NoThrowFwdIt _First, const _NoThrowFwdIt _Last, const _Tval& _Val) { - // copy _Val throughout raw [_First, _Last) - _Adl_verify_range(_First, _Last); - const auto _UFirst = _Get_unwrapped(_First); - _Uninitialized_fill_unchecked(_UFirst, _Get_unwrapped(_Last), _Val, - bool_constant<_Fill_memset_is_safe<_Unwrapped_t, _Tval>>{}); -} -#endif // _HAS_IF_CONSTEXPR // FUNCTION TEMPLATE _Uninitialized_value_construct_n WITH ALLOCATOR template @@ -1855,7 +1609,6 @@ _Ptr _Zero_range(const _Ptr _First, const _Ptr _Last) { // fill [_First, _Last) return _Last; } -#if _HAS_IF_CONSTEXPR template _Alloc_ptr_t<_Alloc> _Uninitialized_value_construct_n( _Alloc_ptr_t<_Alloc> _First, _Alloc_size_t<_Alloc> _Count, _Alloc& _Al) { @@ -1874,39 +1627,7 @@ _Alloc_ptr_t<_Alloc> _Uninitialized_value_construct_n( return _Backout._Release(); } } -#else // ^^^ _HAS_IF_CONSTEXPR // !_HAS_IF_CONSTEXPR vvv -template -_Alloc_ptr_t<_Alloc> _Uninitialized_value_construct_n1( - _Alloc_ptr_t<_Alloc> _First, _Alloc_size_t<_Alloc> _Count, _Alloc& _Al, false_type) { - // value-initialize _Count objects to raw _First, using _Al, no special optimization - _Uninitialized_backout_al<_Alloc> _Backout{_First, _Al}; - for (; 0 < _Count; --_Count) { - _Backout._Emplace_back(); - } - - return _Backout._Release(); -} - -template -_Alloc_ptr_t<_Alloc> _Uninitialized_value_construct_n1( - _Alloc_ptr_t<_Alloc> _First, _Alloc_size_t<_Alloc> _Count, _Alloc&, true_type) { - // value-initialize _Count objects to raw _First, using default _Alloc construct, all-bits-zero type - auto _PFirst = _Unfancy(_First); - _Zero_range(_PFirst, _PFirst + _Count); - return _First + _Count; -} -template -_Alloc_ptr_t<_Alloc> _Uninitialized_value_construct_n( - _Alloc_ptr_t<_Alloc> _First, _Alloc_size_t<_Alloc> _Count, _Alloc& _Al) { - // value-initialize _Count objects to raw _First, using _Al - using _Ptrty = typename _Alloc::value_type*; - return _Uninitialized_value_construct_n1(_First, _Count, _Al, - bool_constant < _Use_memset_value_construct_v<_Ptrty> && _Uses_default_construct<_Alloc, _Ptrty>::value > {}); -} -#endif // _HAS_IF_CONSTEXPR - -#if _HAS_IF_CONSTEXPR template _NoThrowFwdIt _Uninitialized_value_construct_n_unchecked1(_NoThrowFwdIt _UFirst, _Diff _Count) { // value-initialize all elements in [_UFirst, _UFirst + _Count_raw) @@ -1922,26 +1643,6 @@ _NoThrowFwdIt _Uninitialized_value_construct_n_unchecked1(_NoThrowFwdIt _UFirst, return _Backout._Release(); } } -#else // ^^^ _HAS_IF_CONSTEXPR // !_HAS_IF_CONSTEXPR vvv -template -_NoThrowFwdIt _Uninitialized_value_construct_n_unchecked2(_NoThrowFwdIt _UFirst, _Diff _Count, false_type) { - _Uninitialized_backout<_NoThrowFwdIt> _Backout{_UFirst}; - for (; 0 < _Count; --_Count) { - _Backout._Emplace_back(); - } - - return _Backout._Release(); -} -template -_NoThrowFwdIt _Uninitialized_value_construct_n_unchecked2(_NoThrowFwdIt _UFirst, _Diff _Count, true_type) { - return _Zero_range(_UFirst, _UFirst + _Count); -} -template -_NoThrowFwdIt _Uninitialized_value_construct_n_unchecked1(_NoThrowFwdIt _UFirst, _Diff _Count) { - return _Uninitialized_value_construct_n_unchecked2( - _UFirst, _Count, bool_constant<_Use_memset_value_construct_v<_NoThrowFwdIt>>{}); -} -#endif // _HAS_IF_CONSTEXPR #if _HAS_DEPRECATED_TEMPORARY_BUFFER // FUNCTION TEMPLATE get_temporary_buffer @@ -2034,7 +1735,7 @@ struct _Alloc_temporary { template _NODISCARD constexpr bool _Allocators_equal(const _Alloc& _Lhs, const _Alloc& _Rhs) noexcept { - if _CONSTEXPR_IF (allocator_traits<_Alloc>::is_always_equal::value) { + if constexpr (allocator_traits<_Alloc>::is_always_equal::value) { return true; } else { return _Lhs == _Rhs; diff --git a/stl/inc/xstring b/stl/inc/xstring index 5c6503dc590..80355987c2c 100644 --- a/stl/inc/xstring +++ b/stl/inc/xstring @@ -2272,6 +2272,11 @@ struct _String_constructor_concat_tag { explicit _String_constructor_concat_tag() = default; }; +struct _String_constructor_rvalue_allocator_tag { + // tag to select constructors used by basic_stringbuf's rvalue str() + explicit _String_constructor_rvalue_allocator_tag() = default; +}; + [[noreturn]] inline void _Xlen_string() { _Xlength_error("string too long"); } @@ -2280,6 +2285,7 @@ template , class _Alloc = alloca class basic_string { // null-terminated transparent array of elements private: friend _Tidy_deallocate_guard; + friend basic_stringbuf<_Elem, _Traits, _Alloc>; using _Alty = _Rebind_alloc_t<_Alloc, _Elem>; using _Alty_traits = allocator_traits<_Alty>; @@ -2504,7 +2510,7 @@ public: : _Mypair(_One_then_variadic_args_t{}, _Al) { auto&& _Alproxy = _GET_PROXY_ALLOCATOR(_Alty, _Getal()); _Container_proxy_ptr<_Alty> _Proxy(_Alproxy, _Mypair._Myval2); - if _CONSTEXPR_IF (!_Alty_traits::is_always_equal::value) { + if constexpr (!_Alty_traits::is_always_equal::value) { if (_Getal() != _Right._Getal()) { _Construct_lv_contents(_Right); _Proxy._Release(); @@ -2633,6 +2639,14 @@ public: } #endif // _HAS_CXX17 +#if _HAS_CXX20 + basic_string(_String_constructor_rvalue_allocator_tag, _Alloc&& _Al) + : _Mypair(_One_then_variadic_args_t{}, _STD move(_Al)) { + _Mypair._Myval2._Alloc_proxy(_GET_PROXY_ALLOCATOR(_Alty, _Getal())); + _Tidy_init(); + } +#endif // _HAS_CXX20 + private: void _Move_assign(basic_string& _Right, _Equal_allocators) noexcept { _Tidy_deallocate(); @@ -2662,6 +2676,51 @@ private: } public: +#if _HAS_CXX20 + bool _Move_assign_from_buffer(_Elem* const _Right, const size_type _Size, const size_type _Res) { + // Move assign from a buffer, used by basic_stringbuf; returns _Large_string_engaged() + _Tidy_deallocate(); + pointer _Fancy_right = _Refancy(_Right); + auto& _My_data = _Mypair._Myval2; + _My_data._Mysize = _Size; + _My_data._Myres = _Res - 1; + if (_My_data._Large_string_engaged()) { + _Construct_in_place(_My_data._Bx._Ptr, _Fancy_right); + return true; + } else { + _Traits::copy(_My_data._Bx._Buf, _Right, _Res); + _My_data._Myres = _BUF_SIZE - 1; + return false; + } + } + + // No instance of this type can exist where an exception may be thrown. + struct _Released_buffer { + pointer _Ptr; + size_type _Size; + size_type _Res; + }; + + _NODISCARD _Released_buffer _Release_to_buffer(_Alloc& _Al) { + // Release to a buffer, or allocate a new one if in small string mode + _Released_buffer _Result; + auto& _My_data = _Mypair._Myval2; + _Result._Size = _My_data._Mysize; + if (_My_data._Large_string_engaged()) { + _Result._Ptr = _My_data._Bx._Ptr; + _Result._Res = _My_data._Myres + 1; + } else { + // use _BUF_SIZE + 1 to avoid SSO, if the buffer is assigned back + _Result._Ptr = _Al.allocate(_BUF_SIZE + 1); + _Traits::copy(_Unfancy(_Result._Ptr), _My_data._Bx._Buf, _BUF_SIZE); + _Result._Res = _BUF_SIZE + 1; + } + _My_data._Orphan_all(); + _Tidy_init(); + return _Result; + } +#endif // _HAS_CXX20 + basic_string& operator=(basic_string&& _Right) noexcept(noexcept(_Move_assign(_Right, _Choose_pocma<_Alty>{}))) { if (this != _STD addressof(_Right)) { _Move_assign(_Right, _Choose_pocma<_Alty>{}); @@ -2814,7 +2873,7 @@ private: void _Copy_assign_val_from_small(const basic_string& _Right) { // TRANSITION, VSO-761321; inline into only caller when that's fixed _Tidy_deallocate(); - if _CONSTEXPR_IF (_Can_memcpy_val) { + if constexpr (_Can_memcpy_val) { _Memcpy_val_from(_Right); } else { _Traits::copy( @@ -2980,7 +3039,6 @@ public: _Count, _Ch); } -#if _HAS_IF_CONSTEXPR template , int> = 0> basic_string& append(const _Iter _First, const _Iter _Last) { // append [_First, _Last), input iterators _Adl_verify_range(_First, _Last); @@ -2993,25 +3051,6 @@ public: return append(_Right._Mypair._Myval2._Myptr(), _Right._Mypair._Myval2._Mysize); } } -#else // ^^^ _HAS_IF_CONSTEXPR // !_HAS_IF_CONSTEXPR vvv - template - basic_string& _Append_range(const _Iter _UFirst, const _Iter _ULast, true_type) { - return append(_UFirst, _Convert_size(static_cast(_ULast - _UFirst))); - } - - template - basic_string& _Append_range(const _Iter _UFirst, const _Iter _ULast, false_type) { - const basic_string _Right(_UFirst, _ULast, get_allocator()); - return append(_Right._Mypair._Myval2._Myptr(), _Right._Mypair._Myval2._Mysize); - } - - template , int> = 0> - basic_string& append(const _Iter _First, const _Iter _Last) { // append [_First, _Last), input iterators { - _Adl_verify_range(_First, _Last); - const auto _UFirst = _Get_unwrapped(_First); - return _Append_range(_UFirst, _Get_unwrapped(_Last), _Is_elem_cptr{}); - } -#endif // _HAS_IF_CONSTEXPR basic_string& assign(const basic_string& _Right) { *this = _Right; @@ -3081,7 +3120,6 @@ public: _Ch); } -#if _HAS_IF_CONSTEXPR template , int> = 0> basic_string& assign(const _Iter _First, const _Iter _Last) { _Adl_verify_range(_First, _Last); @@ -3100,31 +3138,6 @@ public: } } } -#else // ^^^ _HAS_IF_CONSTEXPR // !_HAS_IF_CONSTEXPR vvv - template - basic_string& _Assign_range(const _Iter _UFirst, const _Iter _ULast, true_type) { - return assign(_UFirst, _Convert_size(static_cast(_ULast - _UFirst))); - } - - template - basic_string& _Assign_range(const _Iter _UFirst, const _Iter _ULast, false_type) { - basic_string _Right(_UFirst, _ULast, get_allocator()); - if (_Mypair._Myval2._Myres < _Right._Mypair._Myval2._Myres) { - _Mypair._Myval2._Orphan_all(); - _Swap_data(_Right, bool_constant<_Can_memcpy_val>{}); - return *this; - } else { - return assign(_Right._Mypair._Myval2._Myptr(), _Right._Mypair._Myval2._Mysize); - } - } - - template , int> = 0> - basic_string& assign(const _Iter _First, const _Iter _Last) { - _Adl_verify_range(_First, _Last); - const auto _UFirst = _Get_unwrapped(_First); - return _Assign_range(_UFirst, _Get_unwrapped(_Last), _Is_elem_cptr{}); - } -#endif // _HAS_IF_CONSTEXPR basic_string& insert(const size_type _Off, const basic_string& _Right) { // insert _Right at _Off return insert(_Off, _Right._Mypair._Myval2._Myptr(), _Right._Mypair._Myval2._Mysize); @@ -3239,7 +3252,6 @@ public: return begin() + static_cast(_Off); } -#if _HAS_IF_CONSTEXPR template , int> = 0> iterator insert(const const_iterator _Where, const _Iter _First, const _Iter _Last) { // insert [_First, _Last) at _Where, input iterators @@ -3259,31 +3271,6 @@ public: return begin() + static_cast(_Off); } -#else // ^^^ _HAS_IF_CONSTEXPR // !_HAS_IF_CONSTEXPR vvv - template - void _Insert_range(const size_type _Off, const _Iter _UFirst, const _Iter _ULast, true_type) { - insert(_Off, _UFirst, _Convert_size(static_cast(_ULast - _UFirst))); - } - - template - void _Insert_range(const size_type _Off, const _Iter _UFirst, const _Iter _ULast, false_type) { - const basic_string _Right(_UFirst, _ULast, get_allocator()); - insert(_Off, _Right._Mypair._Myval2._Myptr(), _Right._Mypair._Myval2._Mysize); - } - - template , int> = 0> - iterator insert(const const_iterator _Where, const _Iter _First, const _Iter _Last) { - // insert [_First, _Last) at _Where, input iterators -#if _ITERATOR_DEBUG_LEVEL != 0 - _STL_VERIFY(_Where._Getcont() == _STD addressof(_Mypair._Myval2), "string iterator incompatible"); -#endif // _ITERATOR_DEBUG_LEVEL != 0 - const auto _Off = static_cast(_Unfancy(_Where._Ptr) - _Mypair._Myval2._Myptr()); - _Adl_verify_range(_First, _Last); - const auto _UFirst = _Get_unwrapped(_First); - _Insert_range(_Off, _UFirst, _Get_unwrapped(_Last), _Is_elem_cptr{}); - return begin() + static_cast(_Off); - } -#endif // _HAS_IF_CONSTEXPR basic_string& erase(const size_type _Off = 0) { // erase elements [_Off, ...) _Mypair._Myval2._Check_offset(_Off); @@ -3514,7 +3501,6 @@ public: static_cast(_Last._Ptr - _First._Ptr), _Count, _Ch); } -#if _HAS_IF_CONSTEXPR template , int> = 0> basic_string& replace( const const_iterator _First, const const_iterator _Last, const _Iter _First2, const _Iter _Last2) { @@ -3535,37 +3521,6 @@ public: return replace(_Off, _Length, _Right._Mypair._Myval2._Myptr(), _Right._Mypair._Myval2._Mysize); } } -#else // ^^^ _HAS_IF_CONSTEXPR // !_HAS_IF_CONSTEXPR vvv - template - basic_string& _Replace_range( - const size_type _Off, const size_type _Length, const _Ptr _UFirst2, const _Ptr _ULast2, true_type) { - // replace [_First, _Last) with [_First2, _Last2), pointers - return replace(_Off, _Length, _UFirst2, _Convert_size(static_cast(_ULast2 - _UFirst2))); - } - - template - basic_string& _Replace_range( - const size_type _Off, const size_type _Length, const _Iter _First2, const _Iter _Last2, false_type) { - // replace [_First, _Last) with [_First2, _Last2), input iterators - const basic_string _Right(_First2, _Last2, get_allocator()); - return replace(_Off, _Length, _Right._Mypair._Myval2._Myptr(), _Right._Mypair._Myval2._Mysize); - } - - template , int> = 0> - basic_string& replace( - const const_iterator _First, const const_iterator _Last, const _Iter _First2, const _Iter _Last2) { - // replace [_First, _Last) with [_First2, _Last2), input iterators - _Adl_verify_range(_First, _Last); -#if _ITERATOR_DEBUG_LEVEL != 0 - _STL_VERIFY(_First._Getcont() == _STD addressof(_Mypair._Myval2), "string iterators incompatible"); -#endif // _ITERATOR_DEBUG_LEVEL != 0 - _Adl_verify_range(_First2, _Last2); - const auto _UFirst2 = _Get_unwrapped(_First2); - const auto _ULast2 = _Get_unwrapped(_Last2); - return _Replace_range(static_cast(_Unfancy(_First._Ptr) - _Mypair._Myval2._Myptr()), - static_cast(_Last._Ptr - _First._Ptr), _UFirst2, _ULast2, _Is_elem_cptr{}); - } -#endif // _HAS_IF_CONSTEXPR _NODISCARD iterator begin() noexcept { return iterator(_Refancy(_Mypair._Myval2._Myptr()), _STD addressof(_Mypair._Myval2)); diff --git a/stl/inc/xtree b/stl/inc/xtree index 1b22fb347dc..aba7f46baee 100644 --- a/stl/inc/xtree +++ b/stl/inc/xtree @@ -927,7 +927,7 @@ public: _Tree(_Tree&& _Right, const allocator_type& _Al) : _Mypair(_One_then_variadic_args_t{}, _Right.key_comp(), // intentionally copy comparator, see LWG-2227 _One_then_variadic_args_t{}, _Al) { - if _CONSTEXPR_IF (!_Alnode_traits::is_always_equal::value) { + if constexpr (!_Alnode_traits::is_always_equal::value) { if (_Getal() != _Right._Getal()) { _Different_allocator_move_construct(_STD move(_Right)); return; @@ -997,7 +997,6 @@ private: } protected: -#if _HAS_IF_CONSTEXPR template pair<_Nodeptr, bool> _Emplace(_Valtys&&... _Vals) { using _In_place_key_extractor = typename _Traits::template _In_place_key_extractor<_Remove_cvref_t<_Valtys>...>; @@ -1033,61 +1032,6 @@ protected: return {_Scary->_Insert_node(_Loc._Location, _Inserted), true}; } -#else // ^^^ _HAS_IF_CONSTEXPR // !_HAS_IF_CONSTEXPR vvv - - template - pair<_Nodeptr, bool> _Emplace1(true_type, _Valtys&&... _Vals) { // _Emplace for extractable - using _In_place_key_extractor = typename _Traits::template _In_place_key_extractor<_Remove_cvref_t<_Valtys>...>; - const auto _Scary = _Get_scary(); - _Tree_find_result<_Nodeptr> _Loc; - _Nodeptr _Inserted; - const auto& _Keyval = _In_place_key_extractor::_Extract(_Vals...); - _Loc = _Find_lower_bound(_Keyval); - if (_Lower_bound_duplicate(_Loc._Bound, _Keyval)) { - return {_Loc._Bound, false}; - } - - _Check_grow_by_1(); - _Inserted = _Tree_temp_node<_Alnode>(_Getal(), _Scary->_Myhead, _STD forward<_Valtys>(_Vals)...)._Release(); - - // nothrow hereafter - return {_Scary->_Insert_node(_Loc._Location, _Inserted), true}; - } - - template - pair<_Nodeptr, bool> _Emplace1(false_type, _Valtys&&... _Vals) { // _Emplace for unextractable - const auto _Scary = _Get_scary(); - _Tree_find_result<_Nodeptr> _Loc; - _Nodeptr _Inserted; - { - _Tree_temp_node<_Alnode> _Newnode(_Getal(), _Scary->_Myhead, _STD forward<_Valtys>(_Vals)...); - const auto& _Keyval = _Traits::_Kfn(_Newnode._Ptr->_Myval); - if _CONSTEXPR_IF (_Multi) { // duplicate check if unique - _Loc = _Find_upper_bound(_Keyval); - } else { - _Loc = _Find_lower_bound(_Keyval); - if (_Lower_bound_duplicate(_Loc._Bound, _Keyval)) { - return {_Loc._Bound, false}; - } - } - - _Check_grow_by_1(); - // nothrow hereafter - _Inserted = _Newnode._Release(); - } - - return {_Scary->_Insert_node(_Loc._Location, _Inserted), true}; - } - - template - pair<_Nodeptr, bool> _Emplace(_Valtys&&... _Vals) { - return _Emplace1( - bool_constant < !_Multi - && _Traits::template _In_place_key_extractor<_Remove_cvref_t<_Valtys>...>::_Extractable > {}, - _STD forward<_Valtys>(_Vals)...); - } - -#endif // _HAS_IF_CONSTEXPR public: template @@ -1097,7 +1041,6 @@ public: } protected: -#if _HAS_IF_CONSTEXPR template _Nodeptr _Emplace_hint(const _Nodeptr _Hint, _Valtys&&... _Vals) { using _In_place_key_extractor = typename _Traits::template _In_place_key_extractor<_Remove_cvref_t<_Valtys>...>; @@ -1129,52 +1072,6 @@ protected: return _Scary->_Insert_node(_Loc._Location, _Inserted); } -#else // ^^^ _HAS_IF_CONSTEXPR // !_HAS_IF_CONSTEXPR vvv - template - _Nodeptr _Emplace_hint1(true_type, const _Nodeptr _Hint, _Valtys&&... _Vals) { - using _In_place_key_extractor = typename _Traits::template _In_place_key_extractor<_Remove_cvref_t<_Valtys>...>; - const auto _Scary = _Get_scary(); - const auto _Loc = _Find_hint(_Hint, _In_place_key_extractor::_Extract(_Vals...)); - if (_Loc._Duplicate) { - return _Loc._Location._Parent; - } - - _Check_grow_by_1(); - const auto _Inserted = - _Tree_temp_node<_Alnode>(_Getal(), _Scary->_Myhead, _STD forward<_Valtys>(_Vals)...)._Release(); - // nothrow hereafter - - return _Scary->_Insert_node(_Loc._Location, _Inserted); - } - - template - _Nodeptr _Emplace_hint1(false_type, const _Nodeptr _Hint, _Valtys&&... _Vals) { - const auto _Scary = _Get_scary(); - _Tree_find_hint_result<_Nodeptr> _Loc; - _Nodeptr _Inserted; - { - _Tree_temp_node<_Alnode> _Newnode(_Getal(), _Scary->_Myhead, _STD forward<_Valtys>(_Vals)...); - _Loc = _Find_hint(_Hint, _Traits::_Kfn(_Newnode._Ptr->_Myval)); - if (_Loc._Duplicate) { - return _Loc._Location._Parent; - } - - _Check_grow_by_1(); - // nothrow hereafter - _Inserted = _Newnode._Release(); - } - - return _Scary->_Insert_node(_Loc._Location, _Inserted); - } - - template - _Nodeptr _Emplace_hint(const _Nodeptr _Hint, _Valtys&&... _Vals) { - return _Emplace_hint1( - bool_constant < !_Multi - && _Traits::template _In_place_key_extractor<_Remove_cvref_t<_Valtys>...>::_Extractable > {}, - _Hint, _STD forward<_Valtys>(_Vals)...); - } -#endif // _HAS_IF_CONSTEXPR public: template @@ -1494,7 +1391,7 @@ public: #endif // _HAS_CXX20 _NODISCARD size_type count(const key_type& _Keyval) const { - if _CONSTEXPR_IF (_Multi) { + if constexpr (_Multi) { const auto _Ans = _Eqrange(_Keyval); return static_cast(_STD distance( _Unchecked_const_iterator(_Ans.first, nullptr), _Unchecked_const_iterator(_Ans.second, nullptr))); @@ -1585,7 +1482,7 @@ protected: _Tree_find_hint_result<_Nodeptr> _Find_hint(const _Nodeptr _Hint, const _Keyty& _Keyval) const { const auto& _Comp = _Getcomp(); const auto _Head = _Get_scary()->_Myhead; - if _CONSTEXPR_IF (_Multi) { // insert even if duplicate + if constexpr (_Multi) { // insert even if duplicate if (_Hint->_Isnil) { // insert at end if greater than or equal to last element if (_Head->_Parent->_Isnil || !_DEBUG_LT_PRED(_Comp, _Keyval, _Traits::_Kfn(_Head->_Right->_Myval))) { diff --git a/stl/inc/xutility b/stl/inc/xutility index a613a5f8548..9f1c687ad01 100644 --- a/stl/inc/xutility +++ b/stl/inc/xutility @@ -121,17 +121,24 @@ struct _Get_rebind_alias<_Ty, _Other, void_t -_NODISCARD void* _Voidify_iter(_Iter _It) noexcept { -#if _HAS_IF_CONSTEXPR +_NODISCARD constexpr void* _Voidify_iter(_Iter _It) noexcept { if constexpr (is_pointer_v<_Iter>) { return const_cast(static_cast(_It)); - } else -#endif // _HAS_IF_CONSTEXPR - { + } else { return const_cast(static_cast(_STD addressof(*_It))); } } +// FUNCTION TEMPLATE construct_at +#if _HAS_CXX20 +template +_CONSTEXPR20_DYNALLOC auto construct_at(_Ty* const _Location, _Types&&... _Args) noexcept( + noexcept(::new (_Voidify_iter(_Location)) _Ty(_STD forward<_Types>(_Args)...))) // strengthened + -> decltype(::new (_Voidify_iter(_Location)) _Ty(_STD forward<_Types>(_Args)...)) { + return ::new (_Voidify_iter(_Location)) _Ty(_STD forward<_Types>(_Args)...); +} +#endif // _HAS_CXX20 + // FUNCTION TEMPLATE _Construct_in_place template void _Construct_in_place(_Ty& _Obj, _Types&&... _Args) noexcept(is_nothrow_constructible_v<_Ty, _Types...>) { @@ -219,12 +226,9 @@ template struct _Ref_fn { // pass function object by value as a reference template constexpr decltype(auto) operator()(_Args&&... _Vals) { // forward function call operator -#if _HAS_IF_CONSTEXPR if constexpr (is_member_pointer_v<_Fx>) { return _STD invoke(_Fn, _STD forward<_Args>(_Vals)...); - } else -#endif // _HAS_IF_CONSTEXPR - { + } else { return _Fn(_STD forward<_Args>(_Vals)...); } } @@ -1269,7 +1273,6 @@ _INLINE_VAR constexpr bool _Range_verifiable_v<_Iter, _Sentinel, void_t(), _STD declval()))>> = _Allow_inheriting_unwrap_v<_Iter>; -#if _HAS_IF_CONSTEXPR template constexpr void _Adl_verify_range(const _Iter& _First, const _Sentinel& _Last) { // check that [_First, _Last) forms an iterator range @@ -1277,24 +1280,6 @@ constexpr void _Adl_verify_range(const _Iter& _First, const _Sentinel& _Last) { _Verify_range(_First, _Last); } } -#else // ^^^ _HAS_IF_CONSTEXPR / !_HAS_IF_CONSTEXPR vvv -template -constexpr void _Adl_verify_range1(const _Iter& _First, const _Sentinel& _Last, true_type) { - // check that [_First, _Last) forms an iterator range - _Verify_range(_First, _Last); -} - -template -constexpr void _Adl_verify_range1(const _Iter&, const _Sentinel&, false_type) { - // (don't) check that [_First, _Last) forms an iterator range -} - -template -constexpr void _Adl_verify_range(const _Iter& _First, const _Sentinel& _Last) { - // check that [_First, _Last) forms an iterator range - _Adl_verify_range1(_First, _Last, bool_constant<_Range_verifiable_v<_Iter, _Sentinel>>{}); -} -#endif // _HAS_IF_CONSTEXPR // FUNCTION TEMPLATE _Get_unwrapped template @@ -1305,7 +1290,6 @@ _INLINE_VAR constexpr bool _Unwrappable_v<_Iter, void_t&>()._Seek_to(_STD declval<_Iter>()._Unwrapped()))>> = _Allow_inheriting_unwrap_v<_Remove_cvref_t<_Iter>>; -#if _HAS_IF_CONSTEXPR template _NODISCARD constexpr decltype(auto) _Get_unwrapped(_Iter&& _It) { // unwrap an iterator previously subjected to _Adl_verify_range or otherwise validated @@ -1317,24 +1301,6 @@ _NODISCARD constexpr decltype(auto) _Get_unwrapped(_Iter&& _It) { return static_cast<_Iter&&>(_It); } } -#else // ^^^ _HAS_IF_CONSTEXPR / !_HAS_IF_CONSTEXPR vvv -template , int> = 0> -_NODISCARD constexpr decltype(auto) _Get_unwrapped(_Iter&& _It) { - // unwrap an iterator previously subjected to _Adl_verify_range or otherwise validated - return static_cast<_Iter&&>(_It)._Unwrapped(); -} - -template , int> = 0> -_NODISCARD constexpr _Iter&& _Get_unwrapped(_Iter&& _It) { - // (don't) unwrap an iterator previously subjected to _Adl_verify_range or otherwise validated - return static_cast<_Iter&&>(_It); -} - -template -_NODISCARD constexpr _Ty* _Get_unwrapped(_Ty* const _Ptr) { // special case already-unwrapped pointers - return _Ptr; -} -#endif // _HAS_IF_CONSTEXPR template using _Unwrapped_t = _Remove_cvref_t()))>; @@ -1352,7 +1318,6 @@ template _INLINE_VAR constexpr bool _Unwrappable_for_unverified_v = _Unwrappable_v<_Iter>&& _Do_unwrap_when_unverified_v<_Remove_cvref_t<_Iter>>; -#if _HAS_IF_CONSTEXPR template _NODISCARD constexpr decltype(auto) _Get_unwrapped_unverified(_Iter&& _It) { // unwrap an iterator not previously subjected to _Adl_verify_range @@ -1364,24 +1329,6 @@ _NODISCARD constexpr decltype(auto) _Get_unwrapped_unverified(_Iter&& _It) { return static_cast<_Iter&&>(_It); } } -#else // ^^^_HAS_IF_CONSTEXPR / !_HAS_IF_CONSTEXPR vvv -template , int> = 0> -_NODISCARD constexpr decltype(auto) _Get_unwrapped_unverified(_Iter&& _It) { - // unwrap an iterator not previously subjected to _Adl_verify_range - return static_cast<_Iter&&>(_It)._Unwrapped(); -} - -template , int> = 0> -_NODISCARD constexpr _Iter&& _Get_unwrapped_unverified(_Iter&& _It) { - // (don't) unwrap an iterator not previously subjected to _Adl_verify_range - return static_cast<_Iter&&>(_It); -} - -template -_NODISCARD constexpr _Ty* _Get_unwrapped_unverified(_Ty* const _Ptr) { // special case already-unwrapped pointers - return _Ptr; -} -#endif // _HAS_IF_CONSTEXPR template using _Unwrapped_unverified_t = _Remove_cvref_t()))>; @@ -1411,7 +1358,6 @@ template _INLINE_VAR constexpr bool _Unwrappable_for_offset_v = _Unwrappable_v<_Iter>&& _Offset_verifiable_v<_Remove_cvref_t<_Iter>>; -#if _HAS_IF_CONSTEXPR template _NODISCARD constexpr decltype(auto) _Get_unwrapped_n(_Iter&& _It, const _Diff _Off) { if constexpr (is_pointer_v>) { @@ -1437,48 +1383,6 @@ _NODISCARD constexpr decltype(auto) _Get_unwrapped_n(_Iter&& _It, const _Diff _O return static_cast<_Iter&&>(_It); } } -#else // ^^^ _HAS_IF_CONSTEXPR / !_HAS_IF_CONSTEXPR vvv -template && is_integral_v<_Diff>, int> = 0> -_NODISCARD constexpr decltype(auto) _Get_unwrapped_n(_Iter&& _It, const _Diff _Off) { - // ask an iterator to assert that the iterator moved _Off positions is valid, and unwrap - using _IDiff = _Iter_diff_t<_Remove_cvref_t<_Iter>>; - using _CDiff = common_type_t<_Diff, _IDiff>; - const auto _COff = static_cast<_CDiff>(_Off); - - _STL_ASSERT(_COff <= static_cast<_CDiff>(_Max_possible_v<_IDiff>) - && (is_unsigned_v<_Diff> || static_cast<_CDiff>(_Min_possible_v<_IDiff>) <= _COff), - "integer overflow"); - (void) _COff; - - _It._Verify_offset(static_cast<_IDiff>(_Off)); - return static_cast<_Iter&&>(_It)._Unwrapped(); -} - -template // - && ((!_Unwrappable_for_offset_v<_Iter> && is_integral_v<_Diff>) || is_same_v<_Diff, _Distance_unknown>), - int> = 0> -_NODISCARD constexpr decltype(auto) _Get_unwrapped_n(_Iter&& _It, _Diff) { - // iterator doesn't support offset-based asserts, or offset unknown; defer to unverified unwrap - return static_cast<_Iter&&>(_It)._Unwrapped(); -} - -template // - && ((!_Unwrappable_for_offset_v<_Iter> && is_integral_v<_Diff>) || is_same_v<_Diff, _Distance_unknown>), - int> = 0> -_NODISCARD constexpr _Iter&& _Get_unwrapped_n(_Iter&& _It, _Diff) { - // pass through iterator that doesn't participate in checking - return static_cast<_Iter&&>(_It); -} - -template || is_integral_v<_Diff>, int> = 0> -_NODISCARD constexpr _Ty* _Get_unwrapped_n(_Ty* const _Src, _Diff) { - return _Src; -} -#endif // _HAS_IF_CONSTEXPR // FUNCTION TEMPLATE _Seek_wrapped template @@ -1489,7 +1393,6 @@ _INLINE_VAR constexpr bool _Wrapped_seekable_v<_Iter, _UIter, void_t()._Seek_to(_STD declval<_UIter>()))>> = true; -#if _HAS_IF_CONSTEXPR template constexpr void _Seek_wrapped(_Iter& _It, _UIter&& _UIt) { if constexpr (_Wrapped_seekable_v<_Iter, _UIter>) { @@ -1498,22 +1401,6 @@ constexpr void _Seek_wrapped(_Iter& _It, _UIter&& _UIt) { _It = _STD forward<_UIter>(_UIt); } } -#else // ^^^ _HAS_IF_CONSTEXPR / !_HAS_IF_CONSTEXPR vvv -template , int> = 0> -constexpr void _Seek_wrapped(_Iter& _It, _UIter&& _UIt) { - _It._Seek_to(_STD forward<_UIter>(_UIt)); -} - -template , int> = 0> -constexpr void _Seek_wrapped(_Iter& _It, _UIter&& _UIt) { - _It = _STD forward<_UIter>(_UIt); -} - -template -constexpr void _Seek_wrapped(_Ty*& _It, _Ty* const _UIt) { - _It = _UIt; -} -#endif // _HAS_IF_CONSTEXPR #if _HAS_CXX17 // STRUCT TEMPLATE _Is_allocator @@ -1554,8 +1441,12 @@ using _Enable_if_execution_policy_t = typename remove_reference_t<_ExPo>::_Stand #endif // _HAS_CXX17 +#if _HAS_CXX20 +template +concept _Allocator = _Is_allocator<_Ty>::value; +#endif // _HAS_CXX20 + // FUNCTION TEMPLATE _Idl_distance -#if _HAS_IF_CONSTEXPR template _NODISCARD constexpr auto _Idl_distance(const _Iter& _First, const _Iter& _Last) { // tries to get the distance between _First and _Last if they are random-access iterators @@ -1565,26 +1456,6 @@ _NODISCARD constexpr auto _Idl_distance(const _Iter& _First, const _Iter& _Last) return _Distance_unknown{}; } } -#else // ^^^ _HAS_IF_CONSTEXPR / !_HAS_IF_CONSTEXPR vvv -template -_NODISCARD constexpr _Distance_unknown _Idl_distance1(const _Iter&, const _Iter&, input_iterator_tag) { - // _Idl_distance for non-random-access iterators - return {}; -} - -template -_NODISCARD constexpr _Iter_diff_t<_Checked> _Idl_distance1( - const _Iter& _First, const _Iter& _Last, random_access_iterator_tag) { - // _Idl_distance for random-access iterators - return static_cast<_Iter_diff_t<_Checked>>(_Last - _First); -} - -template -_NODISCARD constexpr auto _Idl_distance(const _Iter& _First, const _Iter& _Last) { - // tries to get the distance between _First and _Last if they are random-access iterators - return _Idl_distance1<_Checked>(_First, _Last, _Iter_cat_t<_Iter>{}); -} -#endif // _HAS_IF_CONSTEXPR // STRUCT TEMPLATE _Unwrap_enum AND ALIAS template > @@ -1635,7 +1506,6 @@ constexpr bool _Debug_lt_pred(_Pr&& _Pred, _Ty1&& _Left, _Ty2&& _Right) noexcept } // FUNCTION TEMPLATE _Debug_order_unchecked -#if _HAS_IF_CONSTEXPR template constexpr void _Debug_order_unchecked(_InIt _First, _Sentinel _Last, _Pr&& _Pred) { // test if range is ordered by predicate @@ -1647,31 +1517,8 @@ constexpr void _Debug_order_unchecked(_InIt _First, _Sentinel _Last, _Pr&& _Pred } } } -#else // ^^^ _HAS_IF_CONSTEXPR / !_HAS_IF_CONSTEXPR vvv -template -constexpr void _Debug_order_unchecked2(_InIt, _Sentinel, _Pr&, input_iterator_tag) { - // (don't) test if range is ordered by predicate, input iterators -} - -template -constexpr void _Debug_order_unchecked2(_FwdIt _First, _Sentinel _Last, _Pr& _Pred, forward_iterator_tag) { - // test if range is ordered by predicate, forward iterators - if (_First != _Last) { - for (_FwdIt _Next = _First; ++_Next != _Last; _First = _Next) { - _STL_VERIFY(!static_cast(_Pred(*_Next, *_First)), "sequence not ordered"); - } - } -} - -template -constexpr void _Debug_order_unchecked(_InIt _First, _Sentinel _Last, _Pr&& _Pred) { - // test if range is ordered by predicate - _Debug_order_unchecked2(_First, _Last, _Pred, _Iter_cat_t<_InIt>{}); -} -#endif // _HAS_IF_CONSTEXPR // FUNCTION TEMPLATE _Debug_order_set_unchecked -#if _HAS_IF_CONSTEXPR template constexpr void _Debug_order_set_unchecked(_InIt _First, _InIt _Last, _Pr&& _Pred) { // test if range is ordered by predicate @@ -1679,41 +1526,10 @@ constexpr void _Debug_order_set_unchecked(_InIt _First, _InIt _Last, _Pr&& _Pred _Debug_order_unchecked(_First, _Last, _Pred); } } -#else // ^^^ _HAS_IF_CONSTEXPR / !_HAS_IF_CONSTEXPR vvv -template -struct _Priority_tag : _Priority_tag<_Value - 1> { // priority tag for tag dispatch - explicit _Priority_tag() = default; -}; - -template <> -struct _Priority_tag<0> { // base case priority tag for tag dispatch - explicit _Priority_tag() = default; -}; - -template -void _Debug_order_set_unchecked2(_InIt, _InIt, _Pr&, input_iterator_tag, _Priority_tag<0>) { - // (don't) test if range is ordered by predicate, input iterators or different types -} - -template -constexpr void _Debug_order_set_unchecked2( - _FwdIt _First, _FwdIt _Last, _Pr& _Pred, forward_iterator_tag, _Priority_tag<1>) { - // test if range is ordered by predicate, forward iterators and same types - _Debug_order_unchecked2(_First, _Last, _Pred, forward_iterator_tag{}); -} - -template -constexpr void _Debug_order_set_unchecked(_InIt _First, _InIt _Last, _Pr&& _Pred) { - // test if range is ordered by predicate - _Debug_order_set_unchecked2(_First, _Last, _Pred, _Iter_cat_t<_InIt>{}, - _Priority_tag, _Iter_value_t<_InIt>>>{}); -} -#endif // _HAS_IF_CONSTEXPR #endif // _ITERATOR_DEBUG_LEVEL < 2 // MORE ITERATOR STUFF (from ) // FUNCTION TEMPLATE advance -#if _HAS_IF_CONSTEXPR template _CONSTEXPR17 void advance(_InIt& _Where, _Diff _Off) { // increment iterator by offset if constexpr (_Is_random_iter_v<_InIt>) { @@ -1741,59 +1557,8 @@ _CONSTEXPR17 void advance(_InIt& _Where, _Diff _Off) { // increment iterator by } } } -#else // ^^^ _HAS_IF_CONSTEXPR / !_HAS_IF_CONSTEXPR vvv -template -_CONSTEXPR17 void _Advance1(_InIt& _Where, _Diff _Off, input_iterator_tag) { - // increment iterator by offset, input iterators - _STL_ASSERT(_Off >= 0, "negative advance of non-bidirectional iterator"); - - decltype(auto) _UWhere = _Get_unwrapped_n(_STD move(_Where), _Off); - constexpr bool _Need_rewrap = !is_reference_v; - - for (; 0 < _Off; --_Off) { - ++_UWhere; - } - - if (_Need_rewrap) { - _Seek_wrapped(_Where, _STD move(_UWhere)); - } -} - -template -_CONSTEXPR17 void _Advance1(_BidIt& _Where, _Diff _Off, bidirectional_iterator_tag) { - // increment iterator by offset, bidirectional iterators - decltype(auto) _UWhere = _Get_unwrapped_n(_STD move(_Where), _Off); - constexpr bool _Need_rewrap = !is_reference_v; - - for (; 0 < _Off; --_Off) { - ++_UWhere; - } - - for (; _Off < 0; ++_Off) { - --_UWhere; - } - - if (_Need_rewrap) { - _Seek_wrapped(_Where, _STD move(_UWhere)); - } -} - -template -_CONSTEXPR17 void _Advance1(_RanIt& _Where, _Diff _Off, random_access_iterator_tag) { - // increment iterator by offset, random-access iterators - _Where += _Off; -} - -template -_CONSTEXPR17 void advance(_InIt& _Where, _Diff _Off) { - // increment iterator by offset, arbitrary iterators - // we remove_const_t before _Iter_cat_t for better diagnostics if the user passes an iterator that is const - _Advance1(_Where, _Off, _Iter_cat_t>{}); -} -#endif // _HAS_IF_CONSTEXPR // FUNCTION TEMPLATE distance -#if _HAS_IF_CONSTEXPR template _NODISCARD _CONSTEXPR17 _Iter_diff_t<_InIt> distance(_InIt _First, _InIt _Last) { if constexpr (_Is_random_iter_v<_InIt>) { @@ -1810,32 +1575,6 @@ _NODISCARD _CONSTEXPR17 _Iter_diff_t<_InIt> distance(_InIt _First, _InIt _Last) return _Off; } } -#else // ^^^ _HAS_IF_CONSTEXPR / !_HAS_IF_CONSTEXPR vvv -template -_CONSTEXPR17 _Iter_diff_t<_InIt> _Distance1(_InIt _First, _InIt _Last, input_iterator_tag) { - // return distance between iterators; input - _Adl_verify_range(_First, _Last); - auto _UFirst = _Get_unwrapped(_First); - const auto _ULast = _Get_unwrapped(_Last); - _Iter_diff_t<_InIt> _Off = 0; - for (; _UFirst != _ULast; ++_UFirst) { - ++_Off; - } - - return _Off; -} - -template -_CONSTEXPR17 _Iter_diff_t<_RanIt> _Distance1(_RanIt _First, _RanIt _Last, random_access_iterator_tag) { - // return distance between iterators; random-access - return _Last - _First; -} - -template -_NODISCARD _CONSTEXPR17 _Iter_diff_t<_InIt> distance(_InIt _First, _InIt _Last) { - return _Distance1(_First, _Last, _Iter_cat_t<_InIt>{}); -} -#endif // _HAS_IF_CONSTEXPR // FUNCTION TEMPLATE _Next_iter template @@ -1868,18 +1607,6 @@ _NODISCARD _CONSTEXPR17 _BidIt prev(_BidIt _First, _Iter_diff_t<_BidIt> _Off = 1 } // CLASS TEMPLATE reverse_iterator -#if !_HAS_IF_CONSTEXPR -template -_NODISCARD constexpr _Iter _Operator_arrow(true_type, _Iter _Target) { - return _Target; -} - -template -_NODISCARD constexpr decltype(auto) _Operator_arrow(false_type, _Iter& _Target) { - return _Target.operator->(); -} -#endif // !_HAS_IF_CONSTEXPR - template class reverse_iterator { public: @@ -1953,15 +1680,11 @@ public: _NODISCARD _CONSTEXPR17 pointer operator->() const { _BidIt _Tmp = current; --_Tmp; -#if _HAS_IF_CONSTEXPR if constexpr (is_pointer_v<_BidIt>) { return _Tmp; } else { return _Tmp.operator->(); } -#else // ^^^ _HAS_IF_CONSTEXPR / !_HAS_IF_CONSTEXPR vvv - return _Operator_arrow(is_pointer<_BidIt>{}, _Tmp); -#endif // _HAS_IF_CONSTEXPR } #endif // __cpp_lib_concepts @@ -4382,7 +4105,6 @@ _OutIt _Copy_memcpy_common(_InIt _IFirst, _InIt _ILast, _OutIt _OFirst, _OutIt _ return reinterpret_cast<_OutIt>(_OFirst_ch + _Count); } -#if _HAS_IF_CONSTEXPR // VARIABLE TEMPLATE _Is_vb_iterator template _INLINE_VAR constexpr bool _Is_vb_iterator = false; @@ -4406,30 +4128,6 @@ _CONSTEXPR20 _OutIt _Copy_unchecked(_InIt _First, _InIt _Last, _OutIt _Dest) { return _Dest; } -#else // ^^^ _HAS_IF_CONSTEXPR / !_HAS_IF_CONSTEXPR vvv -template -_OutIt _Copy_unchecked1(_InIt _First, _InIt _Last, _OutIt _Dest, false_type) { - // copy [_First, _Last) to [_Dest, ...), arbitrary iterators - for (; _First != _Last; ++_Dest, (void) ++_First) { - *_Dest = *_First; - } - - return _Dest; -} - -template -_OutIt _Copy_unchecked1(_InIt _First, _InIt _Last, _OutIt _Dest, true_type) { - // copy [_First, _Last) to [_Dest, ...), pointers to trivially copyable - return _Copy_memmove(_First, _Last, _Dest); -} - -template -_OutIt _Copy_unchecked(_InIt _First, _InIt _Last, _OutIt _Dest) { - // copy [_First, _Last) to [_Dest, ...) - // note: _Copy_unchecked has callers other than the copy family - return _Copy_unchecked1(_First, _Last, _Dest, bool_constant<_Ptr_copy_cat<_InIt, _OutIt>::_Trivially_copyable>{}); -} -#endif // _HAS_IF_CONSTEXPR template _CONSTEXPR20 _OutIt copy(_InIt _First, _InIt _Last, _OutIt _Dest) { // copy [_First, _Last) to [_Dest, ...) @@ -4453,7 +4151,6 @@ _FwdIt2 copy(_ExPo&&, _FwdIt1 _First, _FwdIt1 _Last, _FwdIt2 _Dest) noexcept /* #endif // _HAS_CXX17 // FUNCTION TEMPLATE copy_n -#if _HAS_IF_CONSTEXPR template _CONSTEXPR20 _OutIt copy_n(_InIt _First, _Diff _Count_raw, _OutIt _Dest) { // copy [_First, _First + _Count) to [_Dest, ...) @@ -4490,46 +4187,6 @@ _CONSTEXPR20 _OutIt copy_n(_InIt _First, _Diff _Count_raw, _OutIt _Dest) { return _Dest; } -#else // ^^^ _HAS_IF_CONSTEXPR / !_HAS_IF_CONSTEXPR vvv -template -_OutIt _Copy_n_unchecked4(_InIt _First, _Diff _Count, _OutIt _Dest, false_type) { - // copy [_First, _First + _Count) to [_Dest, ...), no special optimization - // pre: 0 < _Count - for (;;) { - *_Dest = *_First; - ++_Dest; - --_Count; - if (_Count == 0) { // note that we avoid an extra ++_First here to allow istream_iterator to work, - // see LWG-2471 - return _Dest; - } - - ++_First; - } -} - -template -_OutIt _Copy_n_unchecked4(_InIt _First, _Diff _Count, _OutIt _Dest, true_type) { - // copy [_First, _First + _Count) to [_Dest, ...), memmove optimization - // pre: 0 < _Count - return _Copy_memmove(_First, _First + _Count, _Dest); -} - -template -_OutIt copy_n(_InIt _First, _Diff _Count_raw, _OutIt _Dest) { // copy [_First, _First + _Count) to [_Dest, ...) - const _Algorithm_int_t<_Diff> _Count = _Count_raw; - if (0 < _Count) { - auto _UFirst = _Get_unwrapped_n(_First, _Count); - auto _UDest = _Get_unwrapped_n(_Dest, _Count); - _Seek_wrapped( - _Dest, _Copy_n_unchecked4(_UFirst, _Count, _UDest, - bool_constant<_Ptr_copy_cat::_Trivially_copyable>{})); - } - - return _Dest; -} -#endif // _HAS_IF_CONSTEXPR - #if _HAS_CXX17 template = 0> _FwdIt2 copy_n(_ExPo&&, _FwdIt1 _First, _Diff _Count_raw, _FwdIt2 _Dest) noexcept /* terminates */ { @@ -4557,7 +4214,6 @@ _BidIt2 _Copy_backward_memmove(move_iterator<_BidIt1> _First, move_iterator<_Bid return _Copy_backward_memmove(_First.base(), _Last.base(), _Dest); } -#if _HAS_IF_CONSTEXPR template _NODISCARD _CONSTEXPR20 _BidIt2 _Copy_backward_unchecked(_BidIt1 _First, _BidIt1 _Last, _BidIt2 _Dest) { // copy [_First, _Last) backwards to [..., _Dest) @@ -4587,34 +4243,6 @@ _CONSTEXPR20 _BidIt2 copy_backward(_BidIt1 _First, _BidIt1 _Last, _BidIt2 _Dest) _Seek_wrapped(_Dest, _Copy_backward_unchecked(_UFirst, _ULast, _UDest)); return _Dest; } -#else // ^^^ _HAS_IF_CONSTEXPR / !_HAS_IF_CONSTEXPR vvv -template -_BidIt2 _Copy_backward_unchecked(_BidIt1 _First, _BidIt1 _Last, _BidIt2 _Dest, false_type) { - // copy [_First, _Last) backwards to [..., _Dest), no special optimization - while (_First != _Last) { - *--_Dest = *--_Last; - } - - return _Dest; -} - -template -_BidIt2 _Copy_backward_unchecked(_BidIt1 _First, _BidIt1 _Last, _BidIt2 _Dest, true_type) { - // copy [_First, _Last) backwards to [..., _Dest), memmove optimization - return _Copy_backward_memmove(_First, _Last, _Dest); -} - -template -_BidIt2 copy_backward(_BidIt1 _First, _BidIt1 _Last, _BidIt2 _Dest) { // copy [_First, _Last) backwards to [..., _Dest) - _Adl_verify_range(_First, _Last); - auto _UFirst = _Get_unwrapped(_First); - const auto _ULast = _Get_unwrapped(_Last); - auto _UDest = _Get_unwrapped_n(_Dest, -_Idl_distance<_BidIt1>(_UFirst, _ULast)); - _Seek_wrapped(_Dest, _Copy_backward_unchecked(_UFirst, _ULast, _UDest, - bool_constant<_Ptr_copy_cat::_Trivially_copyable>{})); - return _Dest; -} -#endif // _HAS_IF_CONSTEXPR #if _HAS_CXX17 template = 0> @@ -4626,7 +4254,6 @@ _BidIt2 copy_backward(_ExPo&&, _BidIt1 _First, _BidIt1 _Last, _BidIt2 _Dest) noe #endif // _HAS_CXX17 // FUNCTION TEMPLATE move -#if _HAS_IF_CONSTEXPR template _CONSTEXPR20 _OutIt _Move_unchecked(_InIt _First, _InIt _Last, _OutIt _Dest) { // move [_First, _Last) to [_Dest, ...) @@ -4646,30 +4273,6 @@ _CONSTEXPR20 _OutIt _Move_unchecked(_InIt _First, _InIt _Last, _OutIt _Dest) { return _Dest; } -#else // ^^^ _HAS_IF_CONSTEXPR / !_HAS_IF_CONSTEXPR vvv -template -_OutIt _Move_unchecked1(_InIt _First, _InIt _Last, _OutIt _Dest, false_type) { - // move [_First, _Last) to [_Dest, ...), no special optimization - for (; _First != _Last; ++_Dest, (void) ++_First) { - *_Dest = _STD move(*_First); - } - - return _Dest; -} - -template -_OutIt _Move_unchecked1(_InIt _First, _InIt _Last, _OutIt _Dest, true_type) { - // move [_First, _Last) to [_Dest, ...), memmove optimization - return _Copy_memmove(_First, _Last, _Dest); -} - -template -_OutIt _Move_unchecked(_InIt _First, _InIt _Last, _OutIt _Dest) { - // move [_First, _Last) to [_Dest, ...), choose optimization - // note: _Move_unchecked has callers other than the move family - return _Move_unchecked1(_First, _Last, _Dest, bool_constant<_Ptr_move_cat<_InIt, _OutIt>::_Trivially_copyable>{}); -} -#endif // _HAS_IF_CONSTEXPR template _CONSTEXPR20 _OutIt move(_InIt _First, _InIt _Last, _OutIt _Dest) { @@ -4694,7 +4297,6 @@ _FwdIt2 move(_ExPo&&, _FwdIt1 _First, _FwdIt1 _Last, _FwdIt2 _Dest) noexcept /* #endif // _HAS_CXX17 // FUNCTION TEMPLATE move_backward -#if _HAS_IF_CONSTEXPR template _CONSTEXPR20 _BidIt2 _Move_backward_unchecked(_BidIt1 _First, _BidIt1 _Last, _BidIt2 _Dest) { // move [_First, _Last) backwards to [..., _Dest) @@ -4714,31 +4316,6 @@ _CONSTEXPR20 _BidIt2 _Move_backward_unchecked(_BidIt1 _First, _BidIt1 _Last, _Bi return _Dest; } -#else // ^^^ _HAS_IF_CONSTEXPR / !_HAS_IF_CONSTEXPR vvv -template -_BidIt2 _Move_backward_unchecked1(_BidIt1 _First, _BidIt1 _Last, _BidIt2 _Dest, false_type) { - // move [_First, _Last) backwards to [..., _Dest), no special optimization - while (_First != _Last) { - *--_Dest = _STD move(*--_Last); - } - - return _Dest; -} - -template -_BidIt2 _Move_backward_unchecked1(_BidIt1 _First, _BidIt1 _Last, _BidIt2 _Dest, true_type) { - // move [_First, _Last) backwards to [..., _Dest), memmove optimization - return _Copy_backward_memmove(_First, _Last, _Dest); -} - -template -_BidIt2 _Move_backward_unchecked(_BidIt1 _First, _BidIt1 _Last, _BidIt2 _Dest) { - // move [_First, _Last) backwards to [..., _Dest), choose optimization - // note: _Move_backward_unchecked has callers other than the move_backward family - return _Move_backward_unchecked1( - _First, _Last, _Dest, bool_constant<_Ptr_move_cat<_BidIt1, _BidIt2>::_Trivially_copyable>{}); -} -#endif // _HAS_IF_CONSTEXPR template _CONSTEXPR20 _BidIt2 move_backward(_BidIt1 _First, _BidIt1 _Last, _BidIt2 _Dest) { @@ -4789,11 +4366,12 @@ struct _Is_character_or_byte_or_bool : true_type {}; template <> struct _Is_character_or_byte_or_bool : true_type {}; -// _Fill_memset_is_safe determines if _FwdIt and _Ty are eligible for memset optimization in fill +// _Fill_memset_is_safe determines if _FwdIt and _Ty are eligible for memset optimization in fill. +// Need to explicitly test for volatile because _Unwrap_enum_t discards qualifiers. template > _INLINE_VAR constexpr bool _Fill_memset_is_safe = conjunction_v, _Is_character_or_byte_or_bool<_Unwrap_enum_t>>>, - is_assignable<_Iter_ref_t<_FwdIt>, const _Ty&>>; + negation>>>, is_assignable<_Iter_ref_t<_FwdIt>, const _Ty&>>; template _INLINE_VAR constexpr bool _Fill_memset_is_safe<_FwdIt, _Ty, false> = false; @@ -4825,7 +4403,6 @@ _NODISCARD bool _Is_all_bits_zero(const _Ty& _Val) { return _CSTD memcmp(&_Val, &_Zero, sizeof(_Ty)) == 0; } -#if _HAS_IF_CONSTEXPR template _CONSTEXPR20 void fill(const _FwdIt _First, const _FwdIt _Last, const _Ty& _Val) { // copy _Val through [_First, _Last) @@ -4855,28 +4432,6 @@ _CONSTEXPR20 void fill(const _FwdIt _First, const _FwdIt _Last, const _Ty& _Val) } } } -#else // ^^^ _HAS_IF_CONSTEXPR // !_HAS_IF_CONSTEXPR vvv -template -void _Fill_unchecked1(_FwdIt _First, _FwdIt _Last, const _Ty& _Val, false_type) { - // copy _Val through [_First, _Last), no special optimization - for (; _First != _Last; ++_First) { - *_First = _Val; - } -} - -template -void _Fill_unchecked1(_FwdIt _First, _FwdIt _Last, const _Ty& _Val, true_type) { - // copy _Val through [_First, _Last), memset optimization - _Fill_memset(_First, _Val, static_cast(_Last - _First)); -} - -template -void fill(_FwdIt _First, _FwdIt _Last, const _Ty& _Val) { // copy _Val through [_First, _Last) - _Adl_verify_range(_First, _Last); - _Fill_unchecked1(_Get_unwrapped(_First), _Get_unwrapped(_Last), _Val, - bool_constant<_Fill_memset_is_safe<_Unwrapped_t, _Ty>>{}); -} -#endif // _HAS_IF_CONSTEXPR #if _HAS_CXX17 template = 0> @@ -4889,7 +4444,6 @@ void fill(_ExPo&&, _FwdIt _First, _FwdIt _Last, const _Ty& _Val) noexcept /* ter #endif // _HAS_CXX17 // FUNCTION TEMPLATE fill_n -#if _HAS_IF_CONSTEXPR template _CONSTEXPR20 _OutIt fill_n(_OutIt _Dest, const _Diff _Count_raw, const _Ty& _Val) { // copy _Val _Count times through [_Dest, ...) @@ -4928,38 +4482,6 @@ _CONSTEXPR20 _OutIt fill_n(_OutIt _Dest, const _Diff _Count_raw, const _Ty& _Val return _Dest; } -#else // ^^^ _HAS_IF_CONSTEXPR // !_HAS_IF_CONSTEXPR vvv -template -_OutIt _Fill_n_unchecked2(_OutIt _Dest, _Diff _Count, const _Ty& _Val, false_type) { - // copy _Val _Count times through [_Dest, ...), no special optimization - for (; 0 < _Count; --_Count, (void) ++_Dest) { - *_Dest = _Val; - } - - return _Dest; -} - -template -_OutIt _Fill_n_unchecked2(_OutIt _Dest, _Diff _Count, const _Ty& _Val, true_type) { - // copy _Val _Count times through [_Dest, ...), memset optimization - _Fill_memset(_Dest, _Val, static_cast(_Count)); - return _Dest + _Count; -} - -template -_OutIt fill_n(_OutIt _Dest, const _Diff _Count_raw, const _Ty& _Val) { - // copy _Val _Count times through [_Dest, ...) - const _Algorithm_int_t<_Diff> _Count = _Count_raw; - if (0 < _Count) { - auto _UDest = _Get_unwrapped_n(_Dest, _Count); - _Seek_wrapped(_Dest, - _Fill_n_unchecked2(_UDest, _Count, _Val, bool_constant<_Fill_memset_is_safe>{})); - } - - return _Dest; -} -#endif // _HAS_IF_CONSTEXPR - #if _HAS_CXX17 template = 0> _FwdIt fill_n(_ExPo&&, _FwdIt _Dest, _Diff _Count_raw, const _Ty& _Val) noexcept /* terminates */ { @@ -5044,10 +4566,22 @@ _INLINE_VAR constexpr bool _Can_memcmp_elements_with_pred = _Can_memcmp_elements template _INLINE_VAR constexpr bool _Iterators_are_contiguous = contiguous_iterator<_Iter1> // && contiguous_iterator<_Iter2>; + +template +_NODISCARD constexpr _Target* _To_pointer(const _Iter& _It) noexcept { + _STL_INTERNAL_STATIC_ASSERT(contiguous_iterator<_Iter>); + return reinterpret_cast<_Target*>(_STD to_address(_It)); +} #else // ^^^ defined(__cpp_lib_concepts) ^^^ / vvv !defined(__cpp_lib_concepts) vvv // When concepts aren't available, we can detect pointers. (Iterators should be unwrapped before using this.) template _INLINE_VAR constexpr bool _Iterators_are_contiguous = conjunction_v, is_pointer<_Iter2>>; + +template +_NODISCARD constexpr _Target* _To_pointer(const _Iter& _It) noexcept { + _STL_INTERNAL_STATIC_ASSERT(is_pointer_v<_Iter>); + return reinterpret_cast<_Target*>(_It); +} #endif // ^^^ !defined(__cpp_lib_concepts) ^^^ // _Equal_memcmp_is_safe<_Iter1, _Iter2, _Pr> reports whether we can activate the memcmp optimization @@ -5062,7 +4596,6 @@ template _INLINE_VAR constexpr bool _Equal_memcmp_is_safe = _Equal_memcmp_is_safe_helper, remove_const_t<_Iter2>, _Pr>; -#if _HAS_IF_CONSTEXPR template _NODISCARD _CONSTEXPR20 bool equal(const _InIt1 _First1, const _InIt1 _Last1, const _InIt2 _First2, _Pr _Pred) { // compare [_First1, _Last1) to [_First2, ...) @@ -5075,9 +4608,9 @@ _NODISCARD _CONSTEXPR20 bool equal(const _InIt1 _First1, const _InIt1 _Last1, co if (!_STD is_constant_evaluated()) #endif // __cpp_lib_is_constant_evaluated { - const auto _First1_ch = reinterpret_cast(_UFirst1); - const auto _First2_ch = reinterpret_cast(_UFirst2); - const auto _Count = static_cast(reinterpret_cast(_ULast1) - _First1_ch); + const auto _First1_ch = _To_pointer(_UFirst1); + const auto _First2_ch = _To_pointer(_UFirst2); + const auto _Count = static_cast(_To_pointer(_ULast1) - _First1_ch); return _CSTD memcmp(_First1_ch, _First2_ch, _Count) == 0; } } @@ -5090,38 +4623,6 @@ _NODISCARD _CONSTEXPR20 bool equal(const _InIt1 _First1, const _InIt1 _Last1, co return true; } -#else // ^^^ _HAS_IF_CONSTEXPR / !_HAS_IF_CONSTEXPR vvv -template , int> = 0> -bool _Equal_unchecked(_InIt1 _First1, const _InIt1 _Last1, _InIt2 _First2, _Pr _Pred) { - // compare [_First1, _Last1) to [_First2, ...), no special optimization - for (; _First1 != _Last1; ++_First1, (void) ++_First2) { - if (!_Pred(*_First1, *_First2)) { - return false; - } - } - - return true; -} - -template , int> = 0> -bool _Equal_unchecked(const _InIt1 _First1, const _InIt1 _Last1, const _InIt2 _First2, _Pr) { - // compare [_First1, _Last1) to [_First2, ...), memcmp optimization - const auto _First1_ch = reinterpret_cast(_First1); - const auto _First2_ch = reinterpret_cast(_First2); - const auto _Count = static_cast(reinterpret_cast(_Last1) - _First1_ch); - return _CSTD memcmp(_First1_ch, _First2_ch, _Count) == 0; -} - -template -_NODISCARD bool equal(const _InIt1 _First1, const _InIt1 _Last1, const _InIt2 _First2, _Pr _Pred) { - // compare [_First1, _Last1) to [_First2, ...) - _Adl_verify_range(_First1, _Last1); - const auto _UFirst1 = _Get_unwrapped(_First1); - const auto _ULast1 = _Get_unwrapped(_Last1); - const auto _UFirst2 = _Get_unwrapped_n(_First2, _Idl_distance<_InIt1>(_UFirst1, _ULast1)); - return _Equal_unchecked(_UFirst1, _ULast1, _UFirst2, _Pass_fn(_Pred)); -} -#endif // _HAS_IF_CONSTEXPR #if _HAS_CXX17 template = 0> @@ -5144,7 +4645,6 @@ _NODISCARD bool equal(_ExPo&& _Exec, const _FwdIt1 _First1, const _FwdIt1 _Last1 } #endif // _HAS_CXX17 -#if _HAS_IF_CONSTEXPR template _NODISCARD _CONSTEXPR20 bool equal( const _InIt1 _First1, const _InIt1 _Last1, const _InIt2 _First2, const _InIt2 _Last2, _Pr _Pred) { @@ -5180,49 +4680,6 @@ _NODISCARD _CONSTEXPR20 bool equal( } } } -#else // ^^^ _HAS_IF_CONSTEXPR / !_HAS_IF_CONSTEXPR vvv -template -bool _Equal_unchecked(_InIt1 _First1, const _InIt1 _Last1, _InIt2 _First2, const _InIt2 _Last2, _Pr _Pred, - input_iterator_tag, input_iterator_tag) { - // compare [_First1, _Last1) to [_First2, _Last2), arbitrary iterators - for (;;) { - if (_First1 == _Last1) { - return _First2 == _Last2; - } - - if (_First2 == _Last2) { - return false; - } - - if (!_Pred(*_First1, *_First2)) { - return false; - } - - ++_First1; - ++_First2; - } -} - -template -bool _Equal_unchecked(const _InIt1 _First1, const _InIt1 _Last1, const _InIt2 _First2, const _InIt2 _Last2, _Pr _Pred, - random_access_iterator_tag, random_access_iterator_tag) { - // compare [_First1, _Last1) to [_First2, _Last2), random-access iterators - if (_Last1 - _First1 != _Last2 - _First2) { - return false; - } - - return _Equal_unchecked(_First1, _Last1, _First2, _Pred); -} - -template -_NODISCARD bool equal(const _InIt1 _First1, const _InIt1 _Last1, const _InIt2 _First2, const _InIt2 _Last2, _Pr _Pred) { - // compare [_First1, _Last1) to [_First2, _Last2) - _Adl_verify_range(_First1, _Last1); - _Adl_verify_range(_First2, _Last2); - return _Equal_unchecked(_Get_unwrapped(_First1), _Get_unwrapped(_Last1), _Get_unwrapped(_First2), - _Get_unwrapped(_Last2), _Pass_fn(_Pred), _Iter_cat_t<_InIt1>{}, _Iter_cat_t<_InIt2>{}); -} -#endif // _HAS_IF_CONSTEXPR #if _HAS_CXX17 template = 0> @@ -5578,33 +5035,12 @@ _NODISCARD constexpr _Iter_diff_t<_InIt> _Count_pr(_InIt _First, const _InIt _La return _Count; } -#if !_HAS_IF_CONSTEXPR -template -void _Trim_matching_suffixes(_FwdIt1&, _FwdIt2&, _Pr, forward_iterator_tag, forward_iterator_tag) { - // trim matching suffixes, forward iterators (do nothing) -} - -template -void _Trim_matching_suffixes( - _FwdIt1& _Last1, _FwdIt2& _Last2, _Pr _Pred, bidirectional_iterator_tag, bidirectional_iterator_tag) { - // trim matching suffixes, bidirectional iterators - // assumptions: same lengths, non-empty, !_Pred(*_First1, *_First2) - do { // find last inequality - --_Last1; - --_Last2; - } while (_Pred(*_Last1, *_Last2)); - ++_Last1; - ++_Last2; -} -#endif // !_HAS_IF_CONSTEXPR - template _NODISCARD _CONSTEXPR20 bool _Check_match_counts( const _FwdIt1 _First1, _FwdIt1 _Last1, const _FwdIt2 _First2, _FwdIt2 _Last2, _Pr _Pred) { // test if [_First1, _Last1) == permuted [_First2, _Last2), after matching prefix removal _STL_INTERNAL_CHECK(!_Pred(*_First1, *_First2)); _STL_INTERNAL_CHECK(_STD distance(_First1, _Last1) == _STD distance(_First2, _Last2)); -#if _HAS_IF_CONSTEXPR if constexpr (_Is_bidi_iter_v<_FwdIt1> && _Is_bidi_iter_v<_FwdIt2>) { do { // find last inequality --_Last1; @@ -5613,9 +5049,7 @@ _NODISCARD _CONSTEXPR20 bool _Check_match_counts( ++_Last1; ++_Last2; } -#else // ^^^ _HAS_IF_CONSTEXPR // !_HAS_IF_CONSTEXPR vvv - _Trim_matching_suffixes(_Last1, _Last2, _Pred, _Iter_cat_t<_FwdIt1>{}, _Iter_cat_t<_FwdIt2>{}); -#endif // _HAS_IF_CONSTEXPR + for (_FwdIt1 _Next1 = _First1; _Next1 != _Last1; ++_Next1) { if (_Next1 == _Find_pr(_First1, _Next1, *_Next1, _Pred)) { // new value, compare match counts _Iter_diff_t<_FwdIt2> _Count2 = _Count_pr(_First2, _Last2, *_Next1, _Pred); @@ -5640,7 +5074,7 @@ _CONSTEXPR20 void reverse(const _BidIt _First, const _BidIt _Last) { // reverse _Adl_verify_range(_First, _Last); auto _UFirst = _Get_unwrapped(_First); auto _ULast = _Get_unwrapped(_Last); -#if _HAS_IF_CONSTEXPR && _USE_STD_VECTOR_ALGORITHMS +#if _USE_STD_VECTOR_ALGORITHMS using _Elem = remove_pointer_t; constexpr bool _Allow_vectorization = conjunction_v, _Is_trivially_swappable<_Elem>, negation>>; @@ -5665,7 +5099,7 @@ _CONSTEXPR20 void reverse(const _BidIt _First, const _BidIt _Last) { // reverse return; } } -#endif // _HAS_IF_CONSTEXPR && _USE_STD_VECTOR_ALGORITHMS +#endif // _USE_STD_VECTOR_ALGORITHMS for (; _UFirst != _ULast && _UFirst != --_ULast; ++_UFirst) { _STD iter_swap(_UFirst, _ULast); @@ -5693,7 +5127,6 @@ constexpr pair<_BidIt, _BidIt> _Reverse_until_sentinel_unchecked(_BidIt _First, return pair<_BidIt, _BidIt>(_First, _Last); } -#if _HAS_IF_CONSTEXPR template _CONSTEXPR20 _FwdIt rotate(_FwdIt _First, _FwdIt _Mid, _FwdIt _Last) { // exchange the ranges [_First, _Mid) and [_Mid, _Last) @@ -5749,72 +5182,6 @@ _CONSTEXPR20 _FwdIt rotate(_FwdIt _First, _FwdIt _Mid, _FwdIt _Last) { return _First; } -#else // ^^^ _HAS_IF_CONSTEXPR / !_HAS_IF_CONSTEXPR vvv -template -_FwdIt _Rotate_unchecked1(_FwdIt _First, _FwdIt _Mid, _FwdIt _Last, forward_iterator_tag) { - // rotate [_First, _Last) left by distance(_First, _Mid) positions, forward iterators - for (_FwdIt _Next = _Mid, _Res = _Last;;) { // swap [_First, ...) into place - _STD iter_swap(_First, _Next); - if (++_First == _Mid) { // quit if done, else define next interval - if (++_Next == _Last) { - return _Res == _Last ? _Mid : _Res; - } else { - _Mid = _Next; // mark end of next interval - } - } else if (++_Next == _Last) { // wrap to last end - if (_Res == _Last) { - _Res = _First; - } - - _Next = _Mid; - } - } -} - -template -_BidIt _Rotate_unchecked1(_BidIt _First, _BidIt _Mid, _BidIt _Last, bidirectional_iterator_tag) { - // rotate [_First, _Last) left by distance(_First, _Mid) positions, bidirectional iterators - _STD reverse(_First, _Mid); - _STD reverse(_Mid, _Last); - auto _Tmp = _Reverse_until_sentinel_unchecked(_First, _Mid, _Last); - _STD reverse(_Tmp.first, _Tmp.second); - return _Mid != _Tmp.first ? _Tmp.first : _Tmp.second; -} - -template -_RanIt _Rotate_unchecked1(_RanIt _First, _RanIt _Mid, _RanIt _Last, random_access_iterator_tag) { - // rotate [_First, _Last) left by distance(_First, _Mid) positions, random-access iterators - _STD reverse(_First, _Mid); - _STD reverse(_Mid, _Last); - _STD reverse(_First, _Last); - return _First + (_Last - _Mid); -} - -template -_FwdIt _Rotate_unchecked(_FwdIt _First, _FwdIt _Mid, _FwdIt _Last) { - // rotate [_First, _Last) left by distance(_First, _Mid) positions - if (_First == _Mid) { - return _Last; - } - - if (_Mid == _Last) { - return _First; - } - - return _Rotate_unchecked1(_First, _Mid, _Last, _Iter_cat_t<_FwdIt>{}); -} - -template -_FwdIt rotate(_FwdIt _First, _FwdIt _Mid, _FwdIt _Last) { - // exchange the ranges [_First, _Mid) and [_Mid, _Last) - // that is, rotates [_First, _Last) left by distance(_First, _Mid) positions - // returns the iterator pointing at *_First's new home - _Adl_verify_range(_First, _Mid); - _Adl_verify_range(_Mid, _Last); - _Seek_wrapped(_First, _Rotate_unchecked(_Get_unwrapped(_First), _Get_unwrapped(_Mid), _Get_unwrapped(_Last))); - return _First; -} -#endif // _HAS_IF_CONSTEXPR #if _HAS_CXX17 template = 0> diff --git a/stl/inc/yvals_core.h b/stl/inc/yvals_core.h index c99f468a540..e37d8daf036 100644 --- a/stl/inc/yvals_core.h +++ b/stl/inc/yvals_core.h @@ -140,6 +140,7 @@ // P0339R6 polymorphic_allocator<> // P0356R5 bind_front() // P0357R3 Supporting Incomplete Types In reference_wrapper +// P0408R7 Efficient Access To basic_stringbuf's Buffer // P0415R1 constexpr For (Again) // P0439R0 enum class memory_order // P0457R2 starts_with()/ends_with() For basic_string/basic_string_view @@ -166,6 +167,7 @@ // P0758R1 is_nothrow_convertible // P0768R1 Library Support For The Spaceship Comparison Operator <=> // P0769R2 shift_left(), shift_right() +// P0784R7 Library Support For More constexpr Containers // P0811R3 midpoint(), lerp() // P0879R0 constexpr For Swapping Functions // P0887R1 type_identity @@ -371,15 +373,6 @@ #define _MSVC_KNOWN_SEMANTICS #endif -// Controls whether the STL uses "if constexpr" internally in C++14 mode -#ifndef _HAS_IF_CONSTEXPR -#ifdef __CUDACC__ -#define _HAS_IF_CONSTEXPR 0 -#else // __CUDACC__ -#define _HAS_IF_CONSTEXPR 1 -#endif // __CUDACC__ -#endif // _HAS_IF_CONSTEXPR - // Controls whether the STL uses "conditional explicit" internally #ifndef _HAS_CONDITIONAL_EXPLICIT #ifdef __cpp_conditional_explicit @@ -400,11 +393,11 @@ #endif // _HAS_EXCEPTIONS // warning C4984: 'if constexpr' is a C++17 language extension -#if !_HAS_CXX17 && _HAS_IF_CONSTEXPR +#if !_HAS_CXX17 #define _STL_DISABLED_WARNING_C4984 4984 -#else // !_HAS_CXX17 && _HAS_IF_CONSTEXPR +#else // !_HAS_CXX17 #define _STL_DISABLED_WARNING_C4984 -#endif // !_HAS_CXX17 && _HAS_IF_CONSTEXPR +#endif // !_HAS_CXX17 // warning C5053: support for 'explicit()' in C++17 and earlier is a vendor extension #if !_HAS_CXX20 && _HAS_CONDITIONAL_EXPLICIT @@ -510,10 +503,16 @@ #define _CPPLIB_VER 650 #define _MSVC_STL_VERSION 142 -#define _MSVC_STL_UPDATE 202011L +#define _MSVC_STL_UPDATE 202101L #ifndef _ALLOW_COMPILER_AND_STL_VERSION_MISMATCH -#ifdef __EDG__ +#ifdef __CUDACC__ +#if __CUDACC_VER_MAJOR__ < 10 \ + || (__CUDACC_VER_MAJOR__ == 10 \ + && (__CUDACC_VER_MINOR__ < 1 || (__CUDACC_VER_MINOR__ == 1 && __CUDACC_VER_BUILD__ < 243))) +#error STL1002: Unexpected compiler version, expected CUDA 10.1 Update 2 or newer. +#endif // ^^^ old CUDA ^^^ +#elif defined(__EDG__) // not attempting to detect __EDG_VERSION__ being less than expected #elif defined(__clang__) #if __clang_major__ < 11 @@ -553,13 +552,6 @@ #define _CONSTEXPR20 inline #endif // ^^^ inline (not constexpr) in C++17 and earlier ^^^ -// Functions that became constexpr in C++20 via P0784R7 -#if _HAS_CXX20 && defined(__cpp_constexpr_dynamic_alloc) -#define _CONSTEXPR20_DYNALLOC constexpr -#else -#define _CONSTEXPR20_DYNALLOC inline -#endif - // P0607R0 Inline Variables For The STL #if _HAS_CXX17 #define _INLINE_VAR inline @@ -644,12 +636,6 @@ #define _STL_OPTIMIZE_SYSTEM_ERROR_OPERATORS 1 #endif // _STL_OPTIMIZE_SYSTEM_ERROR_OPERATORS -#if _HAS_IF_CONSTEXPR -#define _CONSTEXPR_IF constexpr -#else // _HAS_IF_CONSTEXPR -#define _CONSTEXPR_IF -#endif // _HAS_IF_CONSTEXPR - #ifdef __cpp_consteval #define _CONSTEVAL consteval #else // ^^^ supports consteval / no consteval vvv @@ -1194,8 +1180,14 @@ #define __cpp_lib_concepts 201907L #endif // !defined(__EDG__) || defined(__INTELLISENSE__) -#define __cpp_lib_constexpr_algorithms 201806L -#define __cpp_lib_constexpr_complex 201711L +#define __cpp_lib_constexpr_algorithms 201806L +#define __cpp_lib_constexpr_complex 201711L + +#if defined(__cpp_constexpr_dynamic_alloc) \ + && defined(__clang__) // TRANSITION, MSVC support for constexpr dynamic allocation +#define __cpp_lib_constexpr_dynamic_alloc 201907L +#endif // defined(__cpp_constexpr_dynamic_alloc) && defined(__clang__) + #define __cpp_lib_constexpr_functional 201907L #define __cpp_lib_constexpr_iterator 201811L #define __cpp_lib_constexpr_memory 201811L @@ -1264,6 +1256,13 @@ #define __cpp_lib_experimental_erase_if 201411L #define __cpp_lib_experimental_filesystem 201406L +// Functions that became constexpr in C++20 via P0784R7 +#ifdef __cpp_lib_constexpr_dynamic_alloc +#define _CONSTEXPR20_DYNALLOC constexpr +#else +#define _CONSTEXPR20_DYNALLOC inline +#endif + #ifdef _RTC_CONVERSION_CHECKS_ENABLED #ifndef _ALLOW_RTCc_IN_STL #error /RTCc rejects conformant code, so it is not supported by the C++ Standard Library. Either remove this \ diff --git a/tests/libcxx/expected_results.txt b/tests/libcxx/expected_results.txt index 3996fe4e0ed..8961a1cc341 100644 --- a/tests/libcxx/expected_results.txt +++ b/tests/libcxx/expected_results.txt @@ -493,19 +493,18 @@ std/utilities/variant/variant.variant/variant.ctor/conv.pass.cpp FAIL std/utilities/variant/variant.variant/variant.ctor/T.pass.cpp FAIL # C++20 P0784R7 "More constexpr containers" -std/utilities/memory/allocator.traits/allocator.traits.members/allocate.pass.cpp FAIL -std/utilities/memory/allocator.traits/allocator.traits.members/allocate_hint.pass.cpp FAIL +std/utilities/memory/allocator.traits/allocator.traits.members/allocate.pass.cpp:0 FAIL +std/utilities/memory/allocator.traits/allocator.traits.members/allocate_hint.pass.cpp:0 FAIL std/utilities/memory/allocator.traits/allocator.traits.members/construct.pass.cpp FAIL -std/utilities/memory/allocator.traits/allocator.traits.members/deallocate.pass.cpp FAIL +std/utilities/memory/allocator.traits/allocator.traits.members/deallocate.pass.cpp:0 FAIL std/utilities/memory/allocator.traits/allocator.traits.members/destroy.pass.cpp FAIL -std/utilities/memory/allocator.traits/allocator.traits.members/max_size.pass.cpp FAIL -std/utilities/memory/allocator.traits/allocator.traits.members/select_on_container_copy_construction.pass.cpp FAIL -std/utilities/memory/default.allocator/allocator.globals/eq.pass.cpp FAIL -std/utilities/memory/default.allocator/allocator.members/allocate.pass.cpp:1 FAIL +std/utilities/memory/allocator.traits/allocator.traits.members/max_size.pass.cpp:0 FAIL +std/utilities/memory/allocator.traits/allocator.traits.members/select_on_container_copy_construction.pass.cpp:0 FAIL +std/utilities/memory/default.allocator/allocator.globals/eq.pass.cpp:0 FAIL std/utilities/memory/specialized.algorithms/specialized.construct/construct_at.pass.cpp FAIL -std/utilities/memory/specialized.algorithms/specialized.destroy/destroy.pass.cpp FAIL -std/utilities/memory/specialized.algorithms/specialized.destroy/destroy_at.pass.cpp FAIL -std/utilities/memory/specialized.algorithms/specialized.destroy/destroy_n.pass.cpp FAIL +std/utilities/memory/specialized.algorithms/specialized.destroy/destroy.pass.cpp:0 FAIL +std/utilities/memory/specialized.algorithms/specialized.destroy/destroy_at.pass.cpp:0 FAIL +std/utilities/memory/specialized.algorithms/specialized.destroy/destroy_n.pass.cpp:0 FAIL # C++20 P0896R4 "" std/language.support/support.limits/support.limits.general/algorithm.version.pass.cpp FAIL diff --git a/tests/libcxx/skipped_tests.txt b/tests/libcxx/skipped_tests.txt index b5172f6cdba..61b46acc242 100644 --- a/tests/libcxx/skipped_tests.txt +++ b/tests/libcxx/skipped_tests.txt @@ -501,7 +501,6 @@ utilities\memory\allocator.traits\allocator.traits.members\destroy.pass.cpp utilities\memory\allocator.traits\allocator.traits.members\max_size.pass.cpp utilities\memory\allocator.traits\allocator.traits.members\select_on_container_copy_construction.pass.cpp utilities\memory\default.allocator\allocator.globals\eq.pass.cpp -utilities\memory\default.allocator\allocator.members\allocate.pass.cpp utilities\memory\specialized.algorithms\specialized.construct\construct_at.pass.cpp utilities\memory\specialized.algorithms\specialized.destroy\destroy.pass.cpp utilities\memory\specialized.algorithms\specialized.destroy\destroy_at.pass.cpp diff --git a/tests/std/test.lst b/tests/std/test.lst index d6321fa752d..e1d4e28a8c8 100644 --- a/tests/std/test.lst +++ b/tests/std/test.lst @@ -172,6 +172,7 @@ tests\GH_001103_countl_zero_correctness tests\GH_001105_custom_streambuf_throws tests\GH_001123_random_cast_out_of_range tests\GH_001411_core_headers +tests\GH_001541_case_sensitive_boolalpha tests\LWG2597_complex_branch_cut tests\LWG3018_shared_ptr_function tests\P0019R8_atomic_ref @@ -228,6 +229,7 @@ tests\P0339R6_polymorphic_allocator tests\P0355R7_calendars_and_time_zones_io tests\P0356R5_bind_front tests\P0357R3_supporting_incomplete_types_in_reference_wrapper +tests\P0408R7_efficient_access_to_stringbuf_buffer tests\P0414R2_shared_ptr_for_arrays tests\P0415R1_constexpr_complex tests\P0426R1_constexpr_char_traits diff --git a/tests/std/tests/GH_001541_case_sensitive_boolalpha/env.lst b/tests/std/tests/GH_001541_case_sensitive_boolalpha/env.lst new file mode 100644 index 00000000000..19f025bd0e6 --- /dev/null +++ b/tests/std/tests/GH_001541_case_sensitive_boolalpha/env.lst @@ -0,0 +1,4 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\usual_matrix.lst diff --git a/tests/std/tests/GH_001541_case_sensitive_boolalpha/test.cpp b/tests/std/tests/GH_001541_case_sensitive_boolalpha/test.cpp new file mode 100644 index 00000000000..42cdbdc11d5 --- /dev/null +++ b/tests/std/tests/GH_001541_case_sensitive_boolalpha/test.cpp @@ -0,0 +1,41 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +using namespace std; + +enum class Parse { Success, Failure }; + +struct TestCase { + const char* str; + ios_base::fmtflags flags; + Parse expected; + bool result; +}; + +// clang-format off +constexpr TestCase test_cases[] = { + {"0", ios_base::fmtflags{}, Parse::Success, false}, + {"1", ios_base::fmtflags{}, Parse::Success, true }, + {"2", ios_base::fmtflags{}, Parse::Failure, true }, // N4868 [facet.num.get.virtuals]/6 + {"WOOF", ios_base::fmtflags{}, Parse::Failure, false}, // N4868 [facet.num.get.virtuals]/3.6 + {"false", ios_base::boolalpha, Parse::Success, false}, + {"true", ios_base::boolalpha, Parse::Success, true }, + {"WOOF", ios_base::boolalpha, Parse::Failure, false}, // N4868 [facet.num.get.virtuals]/7 + {"FALSE", ios_base::boolalpha, Parse::Failure, false}, // GH-1541 + {"TRUE", ios_base::boolalpha, Parse::Failure, false}, // GH-1541 +}; +// clang-format on + +int main() { + for (const auto& test : test_cases) { + bool val = !test.result; + istringstream iss(test.str); + iss.setf(test.flags); + iss >> val; + assert(iss.fail() == (test.expected == Parse::Failure)); + assert(val == test.result); + } +} diff --git a/tests/std/tests/P0220R1_optional/test.cpp b/tests/std/tests/P0220R1_optional/test.cpp index a7bb292e541..ec0b2904315 100644 --- a/tests/std/tests/P0220R1_optional/test.cpp +++ b/tests/std/tests/P0220R1_optional/test.cpp @@ -5495,13 +5495,17 @@ constexpr int test() { optional opt(in_place, 2); Y y(3); +#ifndef __EDG__ // TRANSITION, VSO-1268140 assert(std::move(opt).value_or(y) == 2); assert(*opt == 0); +#endif // ^^^ no workaround ^^^ } { optional opt(in_place, 2); +#ifndef __EDG__ // TRANSITION, VSO-1268140 assert(std::move(opt).value_or(Y(3)) == 2); assert(*opt == 0); +#endif // ^^^ no workaround ^^^ } { optional opt; diff --git a/tests/std/tests/P0408R7_efficient_access_to_stringbuf_buffer/env.lst b/tests/std/tests/P0408R7_efficient_access_to_stringbuf_buffer/env.lst new file mode 100644 index 00000000000..e5b00aee0d4 --- /dev/null +++ b/tests/std/tests/P0408R7_efficient_access_to_stringbuf_buffer/env.lst @@ -0,0 +1,4 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\usual_latest_winsdk_matrix.lst diff --git a/tests/std/tests/P0408R7_efficient_access_to_stringbuf_buffer/test.cpp b/tests/std/tests/P0408R7_efficient_access_to_stringbuf_buffer/test.cpp new file mode 100644 index 00000000000..84d4474aa25 --- /dev/null +++ b/tests/std/tests/P0408R7_efficient_access_to_stringbuf_buffer/test.cpp @@ -0,0 +1,302 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace std; + +constexpr char empty_string[] = ""; +constexpr char small_string[] = "a"; +constexpr char large_string[] = + "This is a long long long long long long long long string to avoid small string optimization."; + +template +struct test_rvalue { + void operator()(const string& init_value) { + string buffer{init_value}; + size_t res = buffer.capacity(); + Stream stream{move(buffer)}; + assert(stream.view() == init_value); + assert(stream.str() == init_value); + assert(stream.view() == init_value); + assert(stream.rdbuf()->get_allocator() == init_value.get_allocator()); + // Move out the buffer, the underlying buffer should be empty. + buffer = move(stream).str(); + if (buffer == large_string) { + // stream doesn't actually have space for a null-terminator + assert(buffer.capacity() == res); + } else { + assert(buffer.capacity() == res + 1); + } + assert(buffer == init_value); + assert(stream.view().empty()); + assert(stream.str().empty()); + // Move in the buffer string + stream.str(move(buffer)); + assert(stream.view() == init_value); + assert(stream.str() == init_value); + assert(stream.rdbuf()->get_allocator() == init_value.get_allocator()); + // Move to another stream + Stream stream2 = move(stream); + assert(stream.view().empty()); + assert(stream2.view() == init_value); + } +}; + +template +struct test_allocator { + void operator()(const pmr::string& init_value) { + Stream stream{init_value}; + assert(stream.view() == init_value); + assert(stream.str(init_value.get_allocator()) == init_value); + assert(stream.str() == string_view{init_value}); + assert(move(stream).str() == string_view{init_value}); + assert(stream.view().empty()); + stream.str(init_value); + assert(stream.view() == init_value); + assert(stream.str(init_value.get_allocator()) == init_value); + assert(stream.str() == string_view{init_value}); + } +}; + +template +struct test_pmr_allocator { + pmr::polymorphic_allocator alloc; + + void operator()(const pmr::string& init_value) { + Stream stream{init_value, alloc}; + assert(stream.rdbuf()->get_allocator() != init_value.get_allocator()); + { + pmr::string new_str = stream.str(init_value.get_allocator()); + assert(new_str == init_value); + assert(new_str.get_allocator() == init_value.get_allocator()); + } + { + pmr::string new_str = stream.str(); + assert(new_str == init_value); + assert(new_str.get_allocator() != init_value.get_allocator()); + } + stream.str(init_value); + assert(stream.rdbuf()->get_allocator() != init_value.get_allocator()); + { + pmr::string new_str = stream.str(init_value.get_allocator()); + assert(new_str == init_value); + assert(new_str.get_allocator() == init_value.get_allocator()); + } + { + pmr::string new_str = stream.str(); + assert(new_str == init_value); + assert(new_str.get_allocator() != init_value.get_allocator()); + } + Stream stream2{init_value, init_value.get_allocator()}; + assert(stream2.rdbuf()->get_allocator() == init_value.get_allocator()); + } +}; + +template +void run_test_util() { + Test test{}; + test(empty_string); + test(small_string); + test(large_string); +} + +template