diff --git a/README.md b/README.md index 40546698950..27fc8769080 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ which ships as part of the MSVC toolset and the Visual Studio IDE. * Our [Status Chart][] displays our overall progress over time. * Join our [Discord server][]. -[![Build Status](https://dev.azure.com/vclibs/STL/_apis/build/status/microsoft.STL?branchName=master)][Pipelines] +[![Build Status](https://dev.azure.com/vclibs/STL/_apis/build/status/microsoft.STL?branchName=main)][Pipelines] # What This Repo Is Useful For @@ -57,12 +57,12 @@ issue. The [bug tag][] and [enhancement tag][] are being populated. # Goals -We're implementing the latest C++ Working Draft, currently [N4868][], which will eventually become the next C++ -International Standard, C++20. The terms Working Draft (WD) and Working Paper (WP) are interchangeable; we often +We're implementing the latest C++ Working Draft, currently [N4878][], which will eventually become the next C++ +International Standard. The terms Working Draft (WD) and Working Paper (WP) are interchangeable; we often informally refer to these drafts as "the Standard" while being aware of the difference. (There are other relevant Standards; for example, supporting `/std:c++14` and `/std:c++17` involves understanding how the C++14 and C++17 Standards differ from the Working Paper, and we often need to refer to the C Standard Library and ECMAScript regular -expression specifications.) +expression specifications.) We're currently prioritizing C++20 features before starting any work on C++23. Our primary goals are conformance, performance, usability, and compatibility. @@ -405,10 +405,10 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception [LWG issues]: https://cplusplus.github.io/LWG/lwg-toc.html [LWG tag]: https://github.com/microsoft/STL/issues?q=is%3Aopen+is%3Aissue+label%3ALWG [Microsoft Open Source Code of Conduct]: https://opensource.microsoft.com/codeofconduct/ -[N4868]: https://wg21.link/n4868 +[N4878]: https://wg21.link/n4878 [NOTICE.txt]: NOTICE.txt [Ninja]: https://ninja-build.org -[Pipelines]: https://dev.azure.com/vclibs/STL/_build/latest?definitionId=4&branchName=master +[Pipelines]: https://dev.azure.com/vclibs/STL/_build/latest?definitionId=4&branchName=main [Python]: https://www.python.org/downloads/windows/ [Roadmap]: https://github.com/microsoft/STL/wiki/Roadmap [Status Chart]: https://microsoft.github.io/STL/ diff --git a/azure-devops/checkout-sources.yml b/azure-devops/checkout-sources.yml new file mode 100644 index 00000000000..916f72572fa --- /dev/null +++ b/azure-devops/checkout-sources.yml @@ -0,0 +1,71 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +parameters: +- name: vcpkgSHAVar + type: string + default: vcpkgSHA +- name: llvmSHAVar + type: string + default: llvmSHA +steps: +- checkout: self + clean: true + submodules: false +- task: PowerShell@2 + displayName: 'Get submodule SHAs' + timeoutInMinutes: 1 + inputs: + targetType: inline + script: | + cd $(Build.SourcesDirectory) + $regexSubmoduleSHA = '^[ \-+]([0-9a-f]+) .*$' + $llvmSHA = git submodule status --cached llvm-project | %{$_ -replace $regexSubmoduleSHA, '$1'} + Write-Host "##vso[task.setvariable variable=${{ parameters.llvmSHAVar }};]$llvmSHA" + $vcpkgSHA = git submodule status --cached vcpkg | %{$_ -replace $regexSubmoduleSHA, '$1'} + Write-Host "##vso[task.setvariable variable=${{ parameters.vcpkgSHAVar }};]$vcpkgSHA" +- script: | + cd $(Build.SourcesDirectory) + if not exist "llvm-project" ( + mkdir llvm-project + ) + cd llvm-project + + if not exist ".git" ( + del /S /Q * + git init + ) + + git remote get-url llvm + if errorlevel 1 ( + git remote add llvm https://github.com/llvm/llvm-project.git + git config --local extensions.partialClone llvm + ) + + git fetch --filter=tree:0 --depth=1 llvm $(${{ parameters.llvmSHAVar }}) + git sparse-checkout init --cone + git sparse-checkout set libcxx/test libcxx/utils/libcxx llvm/utils/lit + git reset --quiet --hard FETCH_HEAD + git clean --quiet -x -d -f + displayName: "Checkout LLVM source" +- script: | + cd $(Build.SourcesDirectory) + if not exist "vcpkg" ( + mkdir vcpkg + ) + cd vcpkg + + if not exist ".git" ( + del /S /Q * + git init + ) + + git remote get-url vcpkg + if errorlevel 1 ( + git remote add vcpkg https://github.com/Microsoft/vcpkg.git + git config --local extensions.partialClone vcpkg + ) + + git fetch --filter=tree:0 --depth=1 vcpkg $(${{ parameters.vcpkgSHAVar }}) + git checkout -f FETCH_HEAD + displayName: "Checkout vcpkg source" diff --git a/azure-devops/cmake-configure-build.yml b/azure-devops/cmake-configure-build.yml new file mode 100644 index 00000000000..02e1cd93fa4 --- /dev/null +++ b/azure-devops/cmake-configure-build.yml @@ -0,0 +1,52 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +parameters: +- name: hostArch + type: string +- name: targetArch + type: string +- name: vcpkgLocationVar + type: string + default: vcpkgLocation +- name: targetPlatform + type: string +- name: buildOutputLocationVar + type: string + default: buildOutputLocation +- name: cmakeAdditionalFlags + type: string + default: '' +steps: +- task: PowerShell@2 + displayName: 'Get Test Parallelism' + timeoutInMinutes: 1 + inputs: + targetType: inline + script: | + $testParallelism = $env:NUMBER_OF_PROCESSORS - 2 + Write-Host "##vso[task.setvariable variable=testParallelism;]$testParallelism" +- script: | + if exist "$(${{ parameters.buildOutputLocationVar }})" ( + rmdir /S /Q "$(${{ parameters.buildOutputLocationVar }})" + ) + call "%PROGRAMFILES(X86)%\Microsoft Visual Studio\2019\Preview\Common7\Tools\VsDevCmd.bat" ^ + -host_arch=${{ parameters.hostArch }} -arch=${{ parameters.targetArch }} -no_logo + cmake ${{ parameters.cmakeAdditionalFlags}} -G Ninja ^ + -DCMAKE_TOOLCHAIN_FILE=$(${{ parameters.vcpkgLocationVar }})\scripts\buildsystems\vcpkg.cmake ^ + -DVCPKG_TARGET_TRIPLET=${{ parameters.targetPlatform }}-windows ^ + -DCMAKE_CXX_COMPILER=cl ^ + -DCMAKE_BUILD_TYPE=Release ^ + -DLIT_FLAGS=$(litFlags) ^ + -DCMAKE_CXX_FLAGS=/analyze:autolog- ^ + -S $(Build.SourcesDirectory) -B $(${{ parameters.buildOutputLocationVar }}) + displayName: 'Configure the STL' + timeoutInMinutes: 2 + env: { TMP: $(tmpDir), TEMP: $(tmpDir) } +- script: | + call "%PROGRAMFILES(X86)%\Microsoft Visual Studio\2019\Preview\Common7\Tools\VsDevCmd.bat" ^ + -host_arch=${{ parameters.hostArch }} -arch=${{ parameters.targetArch }} -no_logo + cmake --build $(${{ parameters.buildOutputLocationVar }}) + displayName: 'Build the STL' + timeoutInMinutes: 10 + env: { TMP: $(tmpDir), TEMP: $(tmpDir) } diff --git a/azure-devops/cross-build.yml b/azure-devops/cross-build.yml new file mode 100644 index 00000000000..1bcae239d5b --- /dev/null +++ b/azure-devops/cross-build.yml @@ -0,0 +1,51 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +parameters: +- name: hostArch + type: string + default: amd64 +- name: targetPlatform + type: string +- name: vsDevCmdArch + type: string +- name: buildOutputLocationVar + type: string + default: buildOutputLocation +- name: numShards + type: number + default: 8 +jobs: +- job: '${{ parameters.targetPlatform }}' + variables: + fixedFlags: '--timeout=240;--shuffle' + parallelismFlag: '-j$(testParallelism)' + xmlOutputFlag: '--xunit-xml-output=$(${{ parameters.buildOutputLocationVar }})/test-results.xml' + shardFlags: '--num-shards=$(System.TotalJobsInPhase);--run-shard=$(System.JobPositionInPhase)' + litFlags: '$(fixedFlags);$(parallelismFlag);$(xmlOutputFlag);$(shardFlags)' + strategy: + parallel: ${{ parameters.numShards }} + timeoutInMinutes: 360 + steps: + - script: | + if exist "$(tmpDir)" (rmdir /S /Q $(tmpDir)) + mkdir $(tmpDir) + displayName: 'Setup TMP Directory' + + - template: checkout-sources.yml + - template: vcpkg-dependencies.yml + parameters: + targetPlatform: ${{ parameters.targetPlatform }} + - template: cmake-configure-build.yml + parameters: + targetPlatform: ${{ parameters.targetPlatform }} + hostArch: ${{ parameters.hostArch }} + targetArch: ${{ parameters.vsDevCmdArch }} + cmakeAdditionalFlags: '-DTESTS_BUILD_ONLY=ON' + - template: run-tests.yml + parameters: + hostArch: ${{ parameters.hostArch }} + targetPlatform: ${{ parameters.targetPlatform }} + targetArch: ${{ parameters.vsDevCmdArch }} + displayName: 'Build Tests' + publishArtifact: true diff --git a/azure-devops/native-build-test.yml b/azure-devops/native-build-test.yml new file mode 100644 index 00000000000..17fa03732ae --- /dev/null +++ b/azure-devops/native-build-test.yml @@ -0,0 +1,45 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +parameters: +- name: targetPlatform + type: string +- name: vsDevCmdArch + type: string +- name: buildOutputLocationVar + type: string + default: buildOutputLocation +- name: numShards + type: number + default: 8 +jobs: +- job: '${{ parameters.targetPlatform }}' + variables: + fixedFlags: '--timeout=240;--shuffle' + parallelismFlag: '-j$(testParallelism)' + xmlOutputFlag: '--xunit-xml-output=$(${{ parameters.buildOutputLocationVar }})/test-results.xml' + shardFlags: '--num-shards=$(System.TotalJobsInPhase);--run-shard=$(System.JobPositionInPhase)' + litFlags: '$(fixedFlags);$(parallelismFlag);$(xmlOutputFlag);$(shardFlags)' + strategy: + parallel: ${{ parameters.numShards }} + timeoutInMinutes: 360 + steps: + - script: | + if exist "$(tmpDir)" (rmdir /S /Q $(tmpDir)) + mkdir $(tmpDir) + displayName: 'Setup TMP Directory' + + - template: checkout-sources.yml + - template: vcpkg-dependencies.yml + parameters: + targetPlatform: ${{ parameters.targetPlatform }} + - template: cmake-configure-build.yml + parameters: + targetPlatform: ${{ parameters.targetPlatform }} + targetArch: ${{ parameters.vsDevCmdArch }} + hostArch: ${{ parameters.vsDevCmdArch }} + - template: run-tests.yml + parameters: + hostArch: ${{ parameters.vsDevCmdArch }} + targetPlatform: ${{ parameters.targetPlatform }} + targetArch: ${{ parameters.vsDevCmdArch }} diff --git a/azure-devops/run-build.yml b/azure-devops/run-build.yml deleted file mode 100644 index 767b5c77bfe..00000000000 --- a/azure-devops/run-build.yml +++ /dev/null @@ -1,130 +0,0 @@ -# Copyright (c) Microsoft Corporation. -# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - -jobs: -- job: '${{ parameters.targetPlatform }}_${{ parameters.shardNum }}' - timeoutInMinutes: 360 - - variables: - buildOutputLocation: 'D:\build\${{ parameters.targetPlatform }}' - litFlags: '-j$(testParallelism);--timeout=240;--shuffle;--xunit-xml-output=$(buildOutputLocation)/test-results.xml' - shardFlags: '--num-shards=${{ parameters.numShards }};--run-shard=${{ parameters.shardNum }}' - vcpkgLocation: '$(Build.SourcesDirectory)/vcpkg' - steps: - - script: | - if exist "$(tmpDir)" ( - rmdir /S /Q $(tmpDir) - ) - mkdir $(tmpDir) - displayName: 'Setup TMP Directory' - - checkout: self - clean: true - submodules: false - - task: PowerShell@2 - displayName: 'Get submodule SHAs' - timeoutInMinutes: 1 - inputs: - targetType: inline - script: | - cd $(Build.SourcesDirectory) - $regexSubmoduleSHA = '^[ \-+]([0-9a-f]+) .*$' - $llvmSHA = git submodule status --cached llvm-project | %{$_ -replace $regexSubmoduleSHA, '$1'} - Write-Host "##vso[task.setvariable variable=llvmSHA;]$llvmSHA" - $vcpkgSHA = git submodule status --cached vcpkg | %{$_ -replace $regexSubmoduleSHA, '$1'} - Write-Host "##vso[task.setvariable variable=vcpkgSHA;]$vcpkgSHA" - - script: | - cd $(Build.SourcesDirectory) - if not exist "llvm-project" ( - mkdir llvm-project - ) - cd llvm-project - git init - git remote add llvm https://github.com/llvm/llvm-project - git config --local extensions.partialClone llvm - git fetch --filter=tree:0 --depth=1 llvm $(llvmSHA) - git reset --quiet $(llvmSHA) - git sparse-checkout init --cone - git sparse-checkout set libcxx/test libcxx/utils/libcxx llvm/utils/lit - displayName: "Checkout LLVM source" - - script: | - cd $(Build.SourcesDirectory) - if not exist "vcpkg" ( - mkdir vcpkg - ) - cd vcpkg - git init - git remote add vcpkg https://github.com/Microsoft/vcpkg - git config --local extensions.partialClone vcpkg - git fetch --filter=tree:0 --depth=1 vcpkg $(vcpkgSHA) - git checkout $(vcpkgSHA) - displayName: "Checkout vcpkg source" - - task: Cache@2 - displayName: vcpkg/installed Caching - timeoutInMinutes: 10 - inputs: - key: '"${{ parameters.targetPlatform }}" | "$(vcpkgSHA)" | "2020-03-01.01"' - path: '$(vcpkgLocation)/installed' - cacheHitVar: CACHE_RESTORED - - task: run-vcpkg@0 - displayName: 'Run vcpkg to Install boost-build' - condition: and(ne(variables.CACHE_RESTORED, 'true'), contains('${{ parameters.targetPlatform }}', 'arm')) - timeoutInMinutes: 10 - inputs: - doNotUpdateVcpkg: true - vcpkgArguments: 'boost-build' - vcpkgDirectory: '$(vcpkgLocation)' - vcpkgTriplet: 'x86-windows' - env: { TMP: $(tmpDir), TEMP: $(tmpDir) } - - task: run-vcpkg@0 - displayName: 'Run vcpkg to Install boost-math' - condition: ne(variables.CACHE_RESTORED, 'true') - timeoutInMinutes: 10 - inputs: - doNotUpdateVcpkg: true - vcpkgArguments: 'boost-math' - vcpkgDirectory: '$(vcpkgLocation)' - vcpkgTriplet: '${{ parameters.targetPlatform }}-windows' - env: { TMP: $(tmpDir), TEMP: $(tmpDir) } - - task: PowerShell@2 - displayName: 'Get Test Parallelism' - timeoutInMinutes: 1 - inputs: - targetType: inline - script: | - $testParallelism = $env:NUMBER_OF_PROCESSORS - 2 - Write-Host "##vso[task.setvariable variable=testParallelism;]$testParallelism" - - script: | - if exist "$(buildOutputLocation)" ( - rmdir /S /Q "$(buildOutputLocation)" - ) - call "%PROGRAMFILES(X86)%\Microsoft Visual Studio\2019\Preview\Common7\Tools\VsDevCmd.bat" ^ - -host_arch=amd64 -arch=${{ parameters.vsDevCmdArch }} -no_logo - cmake -G Ninja -DCMAKE_TOOLCHAIN_FILE=$(vcpkgLocation)\scripts\buildsystems\vcpkg.cmake ^ - -DVCPKG_TARGET_TRIPLET=${{ parameters.targetPlatform }}-windows -DCMAKE_CXX_COMPILER=cl ^ - -DCMAKE_BUILD_TYPE=Release -DLIT_FLAGS=$(litFlags);$(shardFlags) ^ - -DCMAKE_CXX_FLAGS=/analyze:autolog- ^ - -S $(Build.SourcesDirectory) -B $(buildOutputLocation) - cmake --build $(buildOutputLocation) - displayName: 'Build the STL' - timeoutInMinutes: 10 - env: { TMP: $(tmpDir), TEMP: $(tmpDir) } - - task: CmdLine@2 - displayName: 'Run Tests' - timeoutInMinutes: 120 - condition: and(succeeded(), in('${{ parameters.targetPlatform }}', 'x64', 'x86')) - inputs: - workingDirectory: $(buildOutputLocation) - script: | - call "%PROGRAMFILES(X86)%\Microsoft Visual Studio\2019\Preview\Common7\Tools\VsDevCmd.bat" ^ - -host_arch=${{ parameters.vsDevCmdArch }} -arch=${{ parameters.vsDevCmdArch }} -no_logo - ctest -V - env: { TMP: $(tmpDir), TEMP: $(tmpDir) } - - task: PublishTestResults@2 - displayName: 'Publish Tests' - timeoutInMinutes: 10 - condition: and(succeededOrFailed(), in('${{ parameters.targetPlatform }}', 'x64', 'x86')) - inputs: - searchFolder: $(buildOutputLocation) - testResultsFormat: JUnit - testResultsFiles: '**/test-results.xml' - testRunTitle: 'test-${{ parameters.targetPlatform }}-${{ parameters.shardNum }}' diff --git a/azure-devops/run-tests.yml b/azure-devops/run-tests.yml new file mode 100644 index 00000000000..a247bfc43c4 --- /dev/null +++ b/azure-devops/run-tests.yml @@ -0,0 +1,48 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +parameters: +- name: buildOutputLocationVar + type: string + default: buildOutputLocation +- name: targetPlatform + type: string +- name: hostArch + type: string +- name: targetArch + type: string +- name: displayName + type: string + default: 'Run Tests' +- name: publishArtifact + type: boolean + default: false +steps: +- task: CmdLine@2 + displayName: ${{ parameters.displayName }} + timeoutInMinutes: 120 + condition: succeeded() + inputs: + workingDirectory: $(${{ parameters.buildOutputLocationVar }}) + script: | + call "%PROGRAMFILES(X86)%\Microsoft Visual Studio\2019\Preview\Common7\Tools\VsDevCmd.bat" ^ + -host_arch=${{ parameters.hostArch }} -arch=${{ parameters.targetArch }} -no_logo + ctest -V + env: { TMP: $(tmpDir), TEMP: $(tmpDir) } +- task: PublishTestResults@2 + displayName: 'Publish Tests' + timeoutInMinutes: 10 + condition: succeededOrFailed() + inputs: + searchFolder: $(${{ parameters.buildOutputLocationVar }}) + testResultsFormat: JUnit + testResultsFiles: '**/test-results.xml' + testRunTitle: 'test-${{ parameters.targetPlatform }}-$(System.JobPositionInPhase)' +- publish: $(${{ parameters.buildOutPutLocationVar }})/out + artifact: '${{ parameters.targetPlatform }}-$(System.JobPositionInPhase)-libs-$(System.JobId)' + condition: ${{ parameters.publishArtifact }} + displayName: 'Publish Libs and Headers Artifact' +- publish: $(${{ parameters.buildOutPutLocationVar }})/tests + artifact: '${{ parameters.targetPlatform }}-$(System.JobPositionInPhase)-tests-$(System.JobId)' + condition: ${{ parameters.publishArtifact }} + displayName: 'Publish Tests Artifact' diff --git a/azure-devops/vcpkg-dependencies.yml b/azure-devops/vcpkg-dependencies.yml new file mode 100644 index 00000000000..bd22c161de1 --- /dev/null +++ b/azure-devops/vcpkg-dependencies.yml @@ -0,0 +1,38 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +parameters: +- name: targetPlatform + type: string +- name: vcpkgLocationVar + type: string + default: vcpkgLocation +- name: vcpkgSHAVar + type: string + default: vcpkgSHA +steps: +- task: Cache@2 + displayName: vcpkg/installed Caching + timeoutInMinutes: 10 + inputs: + key: '"${{ parameters.targetPlatform }}" | "$(${{ parameters.vcpkgSHAVar }})" | "2020-03-01.01"' + path: '$(${{ parameters.vcpkgLocationVar }})/installed' + cacheHitVar: CACHE_RESTORED +- task: run-vcpkg@0 + displayName: 'Run vcpkg to Install boost-build' + condition: ne(variables.CACHE_RESTORED, 'true') + timeoutInMinutes: 10 + inputs: + doNotUpdateVcpkg: true + vcpkgArguments: 'boost-build' + vcpkgDirectory: '$(${{ parameters.vcpkgLocationVar }})' + vcpkgTriplet: 'x86-windows' +- task: run-vcpkg@0 + displayName: 'Run vcpkg to Install boost-math' + condition: ne(variables.CACHE_RESTORED, 'true') + timeoutInMinutes: 10 + inputs: + doNotUpdateVcpkg: true + vcpkgArguments: 'boost-math' + vcpkgDirectory: '$(${{ parameters.vcpkgLocationVar }})' + vcpkgTriplet: '${{ parameters.targetPlatform }}-windows' diff --git a/azure-pipelines.yml b/azure-pipelines.yml index f342d73784b..1451cb51321 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -5,6 +5,8 @@ variables: tmpDir: 'D:\Temp' + buildOutputLocation: 'D:\build' + vcpkgLocation: '$(Build.SourcesDirectory)/vcpkg' pool: 'StlBuild-2021-01-20-2' @@ -56,131 +58,39 @@ stages: failOnStandardError: true arguments: '$(buildOutputLocation)/validate/validate.exe' env: { TMP: $(tmpDir), TEMP: $(tmpDir) } - - stage: Build_And_Test + + - stage: Build_And_Test_x86 + dependsOn: Code_Format displayName: 'Build and Test' jobs: - - template: azure-devops/run-build.yml - parameters: - targetPlatform: x86 - vsDevCmdArch: x86 - numShards: 8 - shardNum: 1 - - - template: azure-devops/run-build.yml - parameters: - targetPlatform: x86 - vsDevCmdArch: x86 - numShards: 8 - shardNum: 2 - - - template: azure-devops/run-build.yml - parameters: - targetPlatform: x86 - vsDevCmdArch: x86 - numShards: 8 - shardNum: 3 - - - template: azure-devops/run-build.yml + - template: azure-devops/native-build-test.yml parameters: targetPlatform: x86 vsDevCmdArch: x86 - numShards: 8 - shardNum: 4 - - template: azure-devops/run-build.yml - parameters: - targetPlatform: x86 - vsDevCmdArch: x86 - numShards: 8 - shardNum: 5 - - - template: azure-devops/run-build.yml - parameters: - targetPlatform: x86 - vsDevCmdArch: x86 - numShards: 8 - shardNum: 6 - - - template: azure-devops/run-build.yml - parameters: - targetPlatform: x86 - vsDevCmdArch: x86 - numShards: 8 - shardNum: 7 - - - template: azure-devops/run-build.yml - parameters: - targetPlatform: x86 - vsDevCmdArch: x86 - numShards: 8 - shardNum: 8 - - - template: azure-devops/run-build.yml - parameters: - targetPlatform: x64 - vsDevCmdArch: amd64 - numShards: 8 - shardNum: 1 - - - template: azure-devops/run-build.yml - parameters: - targetPlatform: x64 - vsDevCmdArch: amd64 - numShards: 8 - shardNum: 2 - - - template: azure-devops/run-build.yml - parameters: - targetPlatform: x64 - vsDevCmdArch: amd64 - numShards: 8 - shardNum: 3 - - - template: azure-devops/run-build.yml - parameters: - targetPlatform: x64 - vsDevCmdArch: amd64 - numShards: 8 - shardNum: 4 - - - template: azure-devops/run-build.yml - parameters: - targetPlatform: x64 - vsDevCmdArch: amd64 - numShards: 8 - shardNum: 5 - - - template: azure-devops/run-build.yml - parameters: - targetPlatform: x64 - vsDevCmdArch: amd64 - numShards: 8 - shardNum: 6 - - - template: azure-devops/run-build.yml - parameters: - targetPlatform: x64 - vsDevCmdArch: amd64 - numShards: 8 - shardNum: 7 - - - template: azure-devops/run-build.yml + - stage: Build_And_Test_x64 + dependsOn: Code_Format + displayName: 'Build and Test' + jobs: + - template: azure-devops/native-build-test.yml parameters: targetPlatform: x64 vsDevCmdArch: amd64 - numShards: 8 - shardNum: 8 - - template: azure-devops/run-build.yml + - stage: Build_ARM + dependsOn: Code_Format + displayName: 'Build' + jobs: + - template: azure-devops/cross-build.yml parameters: targetPlatform: arm vsDevCmdArch: arm - numShards: 1 - shardNum: 1 - - template: azure-devops/run-build.yml + - stage: Build_ARM64 + dependsOn: Code_Format + displayName: 'Build' + jobs: + - template: azure-devops/cross-build.yml parameters: targetPlatform: arm64 vsDevCmdArch: arm64 - numShards: 1 - shardNum: 1 diff --git a/docs/cgmanifest.json b/docs/cgmanifest.json index 89ca6e7b688..6e1b6634269 100644 --- a/docs/cgmanifest.json +++ b/docs/cgmanifest.json @@ -14,7 +14,7 @@ "type": "git", "git": { "repositoryUrl": "https://github.com/microsoft/STL.git", - "commitHash": "c70b7a830eda523a69934ba949ac700da2c0dfd2" + "commitHash": "355f8f560ecbde3a8832a5893ce7b4da7840549d" } } }, diff --git a/llvm-project b/llvm-project index a668ad92d5e..60575179041 160000 --- a/llvm-project +++ b/llvm-project @@ -1 +1 @@ -Subproject commit a668ad92d5e2161e07e1a435a19ea5072f52a989 +Subproject commit 605751790418ca4fb1df1e94dfbac34cfcc1b96f diff --git a/stl/inc/algorithm b/stl/inc/algorithm index 8eb7c131ae2..be003e41cf8 100644 --- a/stl/inc/algorithm +++ b/stl/inc/algorithm @@ -41,6 +41,9 @@ _STD_BEGIN // COMMON SORT PARAMETERS _INLINE_VAR constexpr int _ISORT_MAX = 32; // maximum size for insertion sort +template +_INLINE_VAR constexpr auto _Isort_max = _Iter_diff_t<_It>{_ISORT_MAX}; + // STRUCT TEMPLATE _Optimistic_temporary_buffer template constexpr ptrdiff_t _Temporary_buffer_size(const _Diff _Value) noexcept { @@ -1697,6 +1700,19 @@ namespace ranges { using move_result = in_out_result<_In, _Out>; // VARIABLE ranges::move + // clang-format off + template _Se, weakly_incrementable _Out> + requires indirectly_movable<_It, _Out> + constexpr move_result<_It, _Out> _Move_unchecked(_It _First, const _Se _Last, _Out _Result) { + // clang-format on + + for (; _First != _Last; ++_First, (void) ++_Result) { + *_Result = _RANGES iter_move(_First); + } + + return {_STD move(_First), _STD move(_Result)}; + } + class _Move_fn : private _Not_quite_object { public: using _Not_quite_object::_Not_quite_object; @@ -1705,39 +1721,27 @@ namespace ranges { template _Se, weakly_incrementable _Out> requires indirectly_movable<_It, _Out> constexpr move_result<_It, _Out> operator()(_It _First, _Se _Last, _Out _Result) const { + // clang-format on _Adl_verify_range(_First, _Last); - auto _UResult = _Move_unchecked( + auto _UResult = _RANGES _Move_unchecked( _Get_unwrapped(_STD move(_First)), _Get_unwrapped(_STD move(_Last)), _STD move(_Result)); _Seek_wrapped(_First, _STD move(_UResult.in)); return {_STD move(_First), _STD move(_UResult.out)}; } + // clang-format off template requires indirectly_movable, _Out> constexpr move_result, _Out> operator()(_Rng&& _Range, _Out _Result) const { - auto _First = _RANGES begin(_Range); - auto _UResult = _Move_unchecked(_Get_unwrapped(_STD move(_First)), _Uend(_Range), _STD move(_Result)); + // clang-format on + auto _First = _RANGES begin(_Range); + auto _UResult = + _RANGES _Move_unchecked(_Get_unwrapped(_STD move(_First)), _Uend(_Range), _STD move(_Result)); _Seek_wrapped(_First, _STD move(_UResult.in)); return {_STD move(_First), _STD move(_UResult.out)}; } - // clang-format on - - private: - template - _NODISCARD static constexpr move_result<_It, _Out> _Move_unchecked(_It _First, const _Se _Last, _Out _Result) { - _STL_INTERNAL_STATIC_ASSERT(input_iterator<_It>); - _STL_INTERNAL_STATIC_ASSERT(sentinel_for<_Se, _It>); - _STL_INTERNAL_STATIC_ASSERT(weakly_incrementable<_Out>); - _STL_INTERNAL_STATIC_ASSERT(indirectly_movable<_It, _Out>); - - for (; _First != _Last; ++_First, (void) ++_Result) { - *_Result = _RANGES iter_move(_First); - } - - return {_STD move(_First), _STD move(_Result)}; - } }; inline constexpr _Move_fn move{_Not_quite_object::_Construct_tag{}}; @@ -1751,7 +1755,7 @@ namespace ranges { // concept-constrained for strict enforcement as it is used by several algorithms template requires indirectly_movable<_It1, _It2> - _NODISCARD constexpr _It2 _Move_backward_common(const _It1 _First, _It1 _Last, _It2 _Result) { + constexpr _It2 _Move_backward_common(const _It1 _First, _It1 _Last, _It2 _Result) { if constexpr (_Ptr_move_cat<_It1, _It2>::_Trivially_copyable) { if (!_STD is_constant_evaluated()) { return _Copy_backward_memmove(_First, _Last, _Result); @@ -4617,74 +4621,71 @@ namespace ranges { #ifdef __cpp_lib_concepts namespace ranges { // VARIABLE ranges::rotate - class _Rotate_fn : private _Not_quite_object { - public: - using _Not_quite_object::_Not_quite_object; + template + _NODISCARD constexpr subrange<_It> _Reverse_until_mid_unchecked(_It _First, const _It _Mid, _It _Last) { + // reverse until either _First or _Last hits _Mid + _STL_INTERNAL_CHECK(_First != _Mid); + _STL_INTERNAL_CHECK(_Mid != _Last); - template _Se> - constexpr subrange<_It> operator()(_It _First, _It _Mid, _Se _Last) const { - _Adl_verify_range(_First, _Mid); - _Adl_verify_range(_Mid, _Last); - auto _UResult = _Rotate_unchecked( - _Get_unwrapped(_STD move(_First)), _Get_unwrapped(_STD move(_Mid)), _Get_unwrapped(_STD move(_Last))); + do { + _RANGES iter_swap(_First, --_Last); + } while (++_First != _Mid && _Last != _Mid); - return _Rewrap_subrange>(_First, _STD move(_UResult)); - } + return {_STD move(_First), _STD move(_Last)}; + } - // clang-format off - template - requires permutable> - constexpr borrowed_subrange_t<_Rng> operator()(_Rng&& _Range, iterator_t<_Rng> _Mid) const { - // clang-format on - _Adl_verify_range(_RANGES begin(_Range), _Mid); - _Adl_verify_range(_Mid, _RANGES end(_Range)); - auto _UResult = _Rotate_unchecked(_Ubegin(_Range), _Get_unwrapped(_STD move(_Mid)), _Uend(_Range)); + template _Se> + _NODISCARD constexpr subrange<_It> _Rotate_unchecked(_It _First, _It _Mid, _Se _Last) { + // Exchange the ranges [_First, _Mid) and [_Mid, _Last) + // that is, rotates [_First, _Last) left by distance(_First, _Mid) positions - return _Rewrap_subrange>(_Mid, _STD move(_UResult)); + if (_First == _Mid) { + auto _Final = _Get_final_iterator_unwrapped<_It>(_Mid, _STD move(_Last)); + return {_Final, _Final}; } - private: - template - _NODISCARD static constexpr subrange<_It> _Rotate_unchecked(_It _First, _It _Mid, _Se _Last) { - // Exchange the ranges [_First, _Mid) and [_Mid, _Last) - // that is, rotates [_First, _Last) left by distance(_First, _Mid) positions - _STL_INTERNAL_STATIC_ASSERT(permutable<_It>); - _STL_INTERNAL_STATIC_ASSERT(sentinel_for<_Se, _It>); - - if (_First == _Mid) { - auto _Final = _Get_final_iterator_unwrapped<_It>(_Mid, _STD move(_Last)); - return {_Final, _Final}; - } + if (_Mid == _Last) { + return {_STD move(_First), _STD move(_Mid)}; + } - if (_Mid == _Last) { - return {_STD move(_First), _STD move(_Mid)}; - } + if constexpr (bidirectional_iterator<_It>) { + _Reverse_common(_First, _Mid); + auto _Final = _Get_final_iterator_unwrapped<_It>(_Mid, _STD move(_Last)); + _Reverse_common(_Mid, _Final); - if constexpr (bidirectional_iterator<_It>) { - _Reverse_common(_First, _Mid); - auto _Final = _Get_final_iterator_unwrapped<_It>(_Mid, _STD move(_Last)); - _Reverse_common(_Mid, _Final); + if constexpr (random_access_iterator<_It>) { + _Reverse_common(_First, _Final); + _First += _Final - _Mid; - if constexpr (random_access_iterator<_It>) { - _Reverse_common(_First, _Final); - _First += _Final - _Mid; + return {_STD move(_First), _STD move(_Final)}; + } else { + const auto _Result = _RANGES _Reverse_until_mid_unchecked(_STD move(_First), _Mid, _Final); + auto _Mid_first = _Result.begin(); + auto _Mid_last = _Result.end(); + _Reverse_common(_Mid_first, _Mid_last); - return {_STD move(_First), _STD move(_Final)}; + if (_Mid_first == _Mid) { + return {_STD move(_Mid_last), _STD move(_Final)}; } else { - const auto _Result = _Reverse_until_mid_unchecked(_STD move(_First), _Mid, _Final); - auto _Mid_first = _Result.begin(); - auto _Mid_last = _Result.end(); - _Reverse_common(_Mid_first, _Mid_last); - - if (_Mid_first == _Mid) { - return {_STD move(_Mid_last), _STD move(_Final)}; - } else { - return {_STD move(_Mid_first), _STD move(_Final)}; - } + return {_STD move(_Mid_first), _STD move(_Final)}; } - } else { - auto _Next = _Mid; - do { // rotate the first cycle + } + } else { + auto _Next = _Mid; + do { // rotate the first cycle + _RANGES iter_swap(_First, _Next); + ++_First; + ++_Next; + if (_First == _Mid) { + _Mid = _Next; + } + } while (_Next != _Last); + + auto _Begin = _First; + + while (_Mid != _Last) { // rotate subsequent cycles + _Next = _Mid; + do { _RANGES iter_swap(_First, _Next); ++_First; ++_Next; @@ -4692,36 +4693,35 @@ namespace ranges { _Mid = _Next; } } while (_Next != _Last); - - auto _Begin = _First; - - while (_Mid != _Last) { // rotate subsequent cycles - _Next = _Mid; - do { - _RANGES iter_swap(_First, _Next); - ++_First; - ++_Next; - if (_First == _Mid) { - _Mid = _Next; - } - } while (_Next != _Last); - } - return {_STD move(_Begin), _STD move(_Mid)}; } + return {_STD move(_Begin), _STD move(_Mid)}; } + } - template - _NODISCARD static constexpr subrange<_It> _Reverse_until_mid_unchecked(_It _First, const _It _Mid, _It _Last) { - // reverse until either _First or _Last hits _Mid - _STL_INTERNAL_STATIC_ASSERT(permutable<_It>); - _STL_INTERNAL_CHECK(_First != _Mid); - _STL_INTERNAL_CHECK(_Mid != _Last); + class _Rotate_fn : private _Not_quite_object { + public: + using _Not_quite_object::_Not_quite_object; - do { - _RANGES iter_swap(_First, --_Last); - } while (++_First != _Mid && _Last != _Mid); + template _Se> + constexpr subrange<_It> operator()(_It _First, _It _Mid, _Se _Last) const { + _Adl_verify_range(_First, _Mid); + _Adl_verify_range(_Mid, _Last); + auto _UResult = _RANGES _Rotate_unchecked( + _Get_unwrapped(_STD move(_First)), _Get_unwrapped(_STD move(_Mid)), _Get_unwrapped(_STD move(_Last))); + + return _Rewrap_subrange>(_First, _STD move(_UResult)); + } + + // clang-format off + template + requires permutable> + constexpr borrowed_subrange_t<_Rng> operator()(_Rng&& _Range, iterator_t<_Rng> _Mid) const { + // clang-format on + _Adl_verify_range(_RANGES begin(_Range), _Mid); + _Adl_verify_range(_Mid, _RANGES end(_Range)); + auto _UResult = _RANGES _Rotate_unchecked(_Ubegin(_Range), _Get_unwrapped(_STD move(_Mid)), _Uend(_Range)); - return {_STD move(_First), _STD move(_Last)}; + return _Rewrap_subrange>(_Mid, _STD move(_UResult)); } }; @@ -5537,7 +5537,7 @@ template _BidIt _Stable_partition_unchecked(_BidIt _First, _BidIt _Last, _Pr _Pred) { // partition preserving order of equivalents for (;;) { - if (_First == _Last) { // the input range range is true (already partitioned) + if (_First == _Last) { // the input range is true (already partitioned) return _First; } @@ -5583,6 +5583,209 @@ _BidIt stable_partition(_ExPo&&, _BidIt _First, _BidIt _Last, _Pr _Pred) noexcep } #endif // _HAS_CXX17 +#ifdef __cpp_lib_concepts +namespace ranges { + // VARIABLE ranges::stable_partition + template + _It _Buffered_rotate_common(const _It _First, const _It _Mid, const _It _Last, const iter_difference_t<_It> _Count1, + const iter_difference_t<_It> _Count2, iter_value_t<_It>* const _Temp_ptr, const ptrdiff_t _Capacity) { + // rotate [_First, _Last) using temp buffer + _STL_INTERNAL_CHECK(_Count1 == _RANGES distance(_First, _Mid)); + _STL_INTERNAL_CHECK(_Count2 == _RANGES distance(_Mid, _Last)); + + if (_Count1 == 0) { + return _Last; + } + + if (_Count2 == 0) { + return _First; + } + + if (_Count1 <= _Count2 && _Count1 <= _Capacity) { // buffer left range, then move parts + _Uninitialized_backout*> _Backout{ + _Temp_ptr, _RANGES _Uninitialized_move_unchecked(_First, _Mid, _Temp_ptr, _Temp_ptr + _Count1).out}; + const _It _New_mid = _RANGES _Move_unchecked(_STD move(_Mid), _STD move(_Last), _STD move(_First)).out; + _RANGES _Move_unchecked(_Backout._First, _Backout._Last, _New_mid); + return _New_mid; + } + + if (_Count2 <= _Capacity) { // buffer right range, then move parts + _Uninitialized_backout*> _Backout{ + _Temp_ptr, _RANGES _Uninitialized_move_unchecked(_Mid, _Last, _Temp_ptr, _Temp_ptr + _Count2).out}; + _RANGES _Move_backward_common(_First, _STD move(_Mid), _STD move(_Last)); + return _RANGES _Move_unchecked(_Backout._First, _Backout._Last, _STD move(_First)).out; + } + + // buffer too small, rotate in place + return _RANGES _Rotate_unchecked(_STD move(_First), _STD move(_Mid), _STD move(_Last)).begin(); + } + + class _Stable_partition_fn : private _Not_quite_object { + public: + using _Not_quite_object::_Not_quite_object; + + // clang-format off + template _Se, class _Pj = identity, + indirect_unary_predicate> _Pr> + requires permutable<_It> + subrange<_It> operator()(_It _First, _Se _Last, _Pr _Pred, _Pj _Proj = {}) const { + // clang-format on + _Adl_verify_range(_First, _Last); + auto _UFirst = _Get_unwrapped(_STD move(_First)); + auto _ULast = _Get_final_iterator_unwrapped<_It>(_UFirst, _STD move(_Last)); + + auto _UResult = + _Stable_partition_common(_STD move(_UFirst), _STD move(_ULast), _Pass_fn(_Pred), _Pass_fn(_Proj)); + return _Rewrap_subrange>(_First, _STD move(_UResult)); + } + + // clang-format off + template , _Pj>> _Pr> + requires permutable> + borrowed_subrange_t<_Rng> operator()(_Rng&& _Range, _Pr _Pred, _Pj _Proj = {}) const { + // clang-format on + auto _ULast = _Get_final_iterator_unwrapped(_Range); + auto _UResult = + _Stable_partition_common(_Ubegin(_Range), _STD move(_ULast), _Pass_fn(_Pred), _Pass_fn(_Proj)); + return _Rewrap_subrange>(_Range, _STD move(_UResult)); + } + + private: + template + _NODISCARD static subrange<_It> _Stable_partition_common(_It _First, _It _Last, _Pr _Pred, _Pj _Proj) { + _STL_INTERNAL_STATIC_ASSERT(bidirectional_iterator<_It>); + _STL_INTERNAL_STATIC_ASSERT(permutable<_It>); + _STL_INTERNAL_STATIC_ASSERT(indirect_unary_predicate<_Pr, projected<_It, _Pj>>); + + // partition preserving order of equivalents + for (;;) { // skip in-place elements at front + if (_First == _Last) { // the input range is true (already partitioned) + return {_STD move(_First), _STD move(_Last)}; + } + + if (!_STD invoke(_Pred, _STD invoke(_Proj, *_First))) { + break; + } + ++_First; + } + + auto _Saved_last = _Last; + do { // skip in-place elements at end + --_Last; + if (_First == _Last) { + return {_STD move(_First), _STD move(_Saved_last)}; + } + } while (!_STD invoke(_Pred, _STD invoke(_Proj, *_Last))); + + const iter_difference_t<_It> _Temp_count = _RANGES distance(_First, _Last); + _Optimistic_temporary_buffer> _Temp_buf{_Temp_count}; + + // _Temp_count + 1 since we work on closed ranges + const auto _Total_count = static_cast>(_Temp_count + 1); + auto _Result = _Stable_partition_common_buffered( + _STD move(_First), _STD move(_Last), _Pred, _Proj, _Total_count, _Temp_buf._Data, _Temp_buf._Capacity); + return {_STD move(_Result.first), _STD move(_Saved_last)}; + } + + template + _NODISCARD static pair<_It, iter_difference_t<_It>> _Stable_partition_common_buffered(_It _First, _It _Last, + _Pr _Pred, _Pj _Proj, const iter_difference_t<_It> _Count, iter_value_t<_It>* const _Temp_ptr, + const ptrdiff_t _Capacity) { + // implement stable_partition of [_First, _Last] (note: closed range) + // note: _Count >= 2 and _First != _Last + _STL_INTERNAL_STATIC_ASSERT(permutable<_It>); + _STL_INTERNAL_STATIC_ASSERT(indirect_unary_predicate<_Pr, projected<_It, _Pj>>); + _STL_INTERNAL_STATIC_ASSERT(bidirectional_iterator<_It>); + _STL_INTERNAL_CHECK(!_STD invoke(_Pred, _STD invoke(_Proj, *_First))); + _STL_INTERNAL_CHECK(_STD invoke(_Pred, _STD invoke(_Proj, *_Last))); + _STL_INTERNAL_CHECK(_Count == _RANGES distance(_First, _Last) + 1); + + using _Diff = iter_difference_t<_It>; + if (_Count - 1 <= _Capacity) { // - 1 since we never need to store *_Last + _Uninitialized_backout*> _Backout{_Temp_ptr}; + _It _Next = _First; + _Backout._Emplace_back(_RANGES iter_move(_First)); + while (++_First != _Last) { + // test each element, moving into the temporary buffer if it's in the false range, or + // assigning backwards if it's in the true range + if (_STD invoke(_Pred, _STD invoke(_Proj, *_First))) { + *_Next = _RANGES iter_move(_First); + ++_Next; + } else { + _Backout._Emplace_back(_RANGES iter_move(_First)); + } + } + + // move the last true element, *_Last, to the end of the true range + *_Next = _RANGES iter_move(_Last); + ++_Next; + // copy back the false range + _RANGES _Move_unchecked(_Backout._First, _Backout._Last, _Next); + const auto _True_distance = static_cast<_Diff>(_Count - (_Backout._Last - _Backout._First)); + return {_STD move(_Next), _True_distance}; + } + + const _Diff _Mid_offset = _Count >> 1; // _Mid_offset >= 1 because _Count >= 2 + const _It _Mid = _RANGES next(_First, _Mid_offset); + // form [_First, _Left) true range, [_Left, _Mid) false range + _It _Left = _Mid; + _Diff _Left_true_count = _Mid_offset; + for (;;) { // skip over the trailing false range before _Mid + --_Left; + --_Left_true_count; + if (_First == _Left) { // the entire left range is false + break; + } + + if (_STD invoke(_Pred, _STD invoke(_Proj, *_Left))) { + // excluded the false range before _Mid, invariants reestablished, recurse + ++_Left_true_count; // to include *_First + const auto _Low = _Stable_partition_common_buffered( + _First, _STD move(_Left), _Pred, _Proj, _Left_true_count, _Temp_ptr, _Capacity); + _Left = _STD move(_Low.first); + _Left_true_count = _Low.second; + break; + } + } + + // form [_Mid, _Right) true range, [_Right, next(_Last)) false range + _It _Right = _Mid; + _Diff _Right_true_count = 0; + for (;;) { // skip over the leading true range after and including _Mid + if (_Right == _Last) { // the entire right range is true + ++_Right; // to include _Last + ++_Right_true_count; + break; + } + + if (!_STD invoke(_Pred, _STD invoke(_Proj, *_Right))) { + // excluded the true range after and including _Mid, invariants reestablished, recurse + const auto _Right_count = static_cast<_Diff>(_Count - _Mid_offset); + const auto _Remaining = static_cast<_Diff>(_Right_count - _Right_true_count); + const auto _High = _Stable_partition_common_buffered( + _STD move(_Right), _Last, _Pred, _Proj, _Remaining, _Temp_ptr, _Capacity); + _Right = _STD move(_High.first); + _Right_true_count += _High.second; + break; + } + + ++_Right; + ++_Right_true_count; + } + + // swap the [_Left, _Mid) false range with the [_Mid, _Right) true range + auto _Partition_point = + _RANGES _Buffered_rotate_common(_STD move(_Left), _STD move(_Mid), _STD move(_Right), + static_cast<_Diff>(_Mid_offset - _Left_true_count), _Right_true_count, _Temp_ptr, _Capacity); + return {_STD move(_Partition_point), static_cast<_Diff>(_Left_true_count + _Right_true_count)}; + } + }; + + inline constexpr _Stable_partition_fn stable_partition{_Not_quite_object::_Construct_tag{}}; +} // namespace ranges +#endif // __cpp_lib_concepts + // FUNCTION TEMPLATE push_heap template _CONSTEXPR20 void _Push_heap_by_index( @@ -6921,50 +7124,392 @@ void inplace_merge(_ExPo&&, _BidIt _First, _BidIt _Mid, _BidIt _Last) noexcept / } #endif // _HAS_CXX17 -// FUNCTION TEMPLATE sort -template -_CONSTEXPR20 _BidIt _Insertion_sort_unchecked(const _BidIt _First, const _BidIt _Last, _Pr _Pred) { - // insertion sort [_First, _Last) - if (_First != _Last) { - for (_BidIt _Mid = _First; ++_Mid != _Last;) { // order next element - _BidIt _Hole = _Mid; - _Iter_value_t<_BidIt> _Val = _STD move(*_Mid); - - if (_DEBUG_LT_PRED(_Pred, _Val, *_First)) { // found new earliest element, move to front - _Move_backward_unchecked(_First, _Mid, ++_Hole); - *_First = _STD move(_Val); - } else { // look for insertion point after first - for (_BidIt _Prev = _Hole; _DEBUG_LT_PRED(_Pred, _Val, *--_Prev); _Hole = _Prev) { - *_Hole = _STD move(*_Prev); // move hole down - } +#ifdef __cpp_lib_concepts +namespace ranges { + // FUNCTION TEMPLATE _Is_sorted_until_unchecked + // clang-format off + template _Se, class _Pr, class _Pj> + requires indirect_strict_weak_order<_Pr, projected<_It, _Pj>> + _NODISCARD constexpr _It _Is_sorted_until_unchecked(_It _First, const _Se _Last, _Pr _Pred, _Pj _Proj) { + // clang-format on + if (_First == _Last) { + return _First; + } - *_Hole = _STD move(_Val); // insert element in hole + for (auto _Prev = _First; ++_First != _Last; ++_Prev) { + if (_STD invoke(_Pred, _STD invoke(_Proj, *_First), _STD invoke(_Proj, *_Prev))) { + break; } } + + return _First; } - return _Last; -} + // VARIABLE ranges::inplace_merge + template + void _Rotate_one_right(_It _First, _It _Mid, _It _Last) { + // exchanges the range [_First, _Mid) with [_Mid, _Last) + _STL_INTERNAL_CHECK(_RANGES next(_Mid) == _Last); + auto _Temp = _RANGES iter_move(_Mid); + _RANGES _Move_backward_common(_First, _STD move(_Mid), _STD move(_Last)); + *_First = _STD move(_Temp); + } -template -_CONSTEXPR20 void _Med3_unchecked(_RanIt _First, _RanIt _Mid, _RanIt _Last, _Pr _Pred) { - // sort median of three elements to middle - if (_DEBUG_LT_PRED(_Pred, *_Mid, *_First)) { - _STD iter_swap(_Mid, _First); + template + void _Rotate_one_left(_It _First, _It _Mid, _It _Last) { + // exchanges the range [_First, _Mid) with [_Mid, _Last) + _STL_INTERNAL_CHECK(_RANGES next(_First) == _Mid); + auto _Temp = _RANGES iter_move(_Mid); + auto _Result = _RANGES _Move_unchecked(_STD move(_Mid), _STD move(_Last), _STD move(_First)); + *_Result.out = _STD move(_Temp); } - if (_DEBUG_LT_PRED(_Pred, *_Last, *_Mid)) { // swap middle and last, then test first again - _STD iter_swap(_Last, _Mid); + // clang-format off + template + requires sortable<_It, _Pr, _Pj> + void _Inplace_merge_buffer_left(_It _First, _It _Mid, _It _Last, iter_value_t<_It>* _Left_first, + const ptrdiff_t _Capacity, _Pr _Pred, _Pj _Proj) { + // clang-format on + // move the range [_First, _Mid) to _Left_first, and merge it with [_Mid, _Last) to _First + // usual invariants apply + using _Ty = iter_value_t<_It>; - if (_DEBUG_LT_PRED(_Pred, *_Mid, *_First)) { - _STD iter_swap(_Mid, _First); - } - } -} + _Ty* _Left_last = _RANGES _Uninitialized_move_unchecked(_First, _Mid, _Left_first, _Left_first + _Capacity).out; + _Uninitialized_backout<_Ty*> _Backout{_Left_first, _Left_last}; -template -_CONSTEXPR20 void _Guess_median_unchecked(_RanIt _First, _RanIt _Mid, _RanIt _Last, _Pr _Pred) { - // sort median element to middle + // We already know that _Backout._Last - 1 is the highest element, so do not compare against it again. + --_Left_last; + + // We already know that _Mid points to the lowest element and that there is more than 1 element left. + *_First = _RANGES iter_move(_Mid); + ++_First; + ++_Mid; + + for (;;) { + if (_STD invoke(_Pred, _STD invoke(_Proj, *_Mid), _STD invoke(_Proj, *_Left_first))) { + *_First = _RANGES iter_move(_Mid); // the lowest element is now in position + ++_First; + ++_Mid; + if (_Mid == _Last) { + // move the remaining left partition + _RANGES _Move_unchecked(_Left_first, _Backout._Last, _First); + return; + } + } else { + *_First = _RANGES iter_move(_Left_first); + ++_First; + ++_Left_first; + if (_Left_first == _Left_last) { + // move the remaining right partition and highest element, since *_Left_first is highest + const auto _Final = _RANGES _Move_unchecked(_Mid, _Last, _First); + *_Final.out = _RANGES iter_move(_Left_first); + return; + } + } + } + } + + // clang-format off + template + requires sortable<_It, _Pr, _Pj> + void _Inplace_merge_buffer_right(_It _First, _It _Mid, _It _Last, iter_value_t<_It>* _Right_first, + const ptrdiff_t _Capacity, _Pr _Pred, _Pj _Proj) { + // clang-format on + // move the range [_Mid, _Last) to _Right_first, and merge it with [_First, _Mid) to _Last + // usual invariants apply + using _Ty = iter_value_t<_It>; + + _Ty* _Right_last = + _RANGES _Uninitialized_move_unchecked(_Mid, _Last, _Right_first, _Right_first + _Capacity).out; + _Uninitialized_backout<_Ty*> _Backout{_Right_first, _Right_last}; + + // We already know that _Mid points to the next highest element and that there is more than 1 element left. + *--_Last = _RANGES iter_move(--_Mid); + + // We already know that _Backout._Last - 1 is the highest element, so do not compare against it again. + --_Mid; + --_Right_last; + for (;;) { + if (_STD invoke(_Pred, _STD invoke(_Proj, *_Right_last), _STD invoke(_Proj, *_Mid))) { + *--_Last = _RANGES iter_move(_Mid); // the lowest element is now in position + if (_First == _Mid) { + ++_Right_last; // to make [_Right_first, _Right_last) a half-open range + _RANGES _Move_backward_common(_Right_first, _Right_last, _STD move(_Last)); + return; + } + --_Mid; + } else { + *--_Last = _RANGES iter_move(_Right_last); + --_Right_last; + if (_Right_first == _Right_last) { // we can't compare with *_Right_first, but we know it is lowest + ++_Mid; // restore half-open range [_First, _Mid) + _RANGES _Move_backward_common(_First, _STD move(_Mid), _STD move(_Last)); + *_First = _RANGES iter_move(_Right_first); + return; + } + } + } + } + + // clang-format off + template + requires sortable<_It, _Pr, _Pj> + void _Buffered_inplace_merge_common(_It _First, _It _Mid, _It _Last, iter_difference_t<_It> _Count1, + iter_difference_t<_It> _Count2, iter_value_t<_It>* _Temp_ptr, ptrdiff_t _Capacity, _Pr _Pred, _Pj _Proj); + // clang-format on + + // clang-format off + template + requires sortable<_It, _Pr, _Pj> + void _Buffered_inplace_merge_divide_and_conquer2(_It _First, _It _Mid, _It _Last, + const iter_difference_t<_It> _Count1, const iter_difference_t<_It> _Count2, iter_value_t<_It>* const _Temp_ptr, + const ptrdiff_t _Capacity, _Pr _Pred, _Pj _Proj, _It _Firstn, _It _Lastn, const iter_difference_t<_It> _Count1n, + const iter_difference_t<_It> _Count2n) { + // clang-format on + // common block of _Buffered_inplace_merge_divide_and_conquer, below + _It _Midn = _RANGES _Buffered_rotate_common(_Firstn, _Mid, _Lastn, + static_cast>(_Count1 - _Count1n), _Count2n, _Temp_ptr, + _Capacity); // rearrange middle + _RANGES _Buffered_inplace_merge_common( + _First, _Firstn, _Midn, _Count1n, _Count2n, _Temp_ptr, _Capacity, _Pred, _Proj); // merge each new part + _RANGES _Buffered_inplace_merge_common(_Midn, _Lastn, _Last, + static_cast>(_Count1 - _Count1n), + static_cast>(_Count2 - _Count2n), _Temp_ptr, _Capacity, _Pred, _Proj); + } + + // clang-format off + template + requires sortable<_It, _Pr, _Pj> + void _Buffered_inplace_merge_divide_and_conquer(_It _First, _It _Mid, _It _Last, + const iter_difference_t<_It> _Count1, const iter_difference_t<_It> _Count2, iter_value_t<_It>* const _Temp_ptr, + const ptrdiff_t _Capacity, _Pr _Pred, _Pj _Proj) { + // clang-format on + // merge sorted [_First, _Mid) with sorted [_Mid, _Last) + // usual invariants apply + if (_Count1 <= _Count2) { + const iter_difference_t<_It> _Count1n = _Count1 >> 1; // shift for codegen + _It _Firstn = _RANGES next(_First, _Count1n); + _It _Lastn = _RANGES _Lower_bound_unchecked(_Mid, _Count1, _STD invoke(_Proj, *_Firstn), _Pred, _Proj); + const auto _Count2n = _RANGES distance(_Mid, _Lastn); + _RANGES _Buffered_inplace_merge_divide_and_conquer2(_STD move(_First), _STD move(_Mid), _STD move(_Last), + _Count1, _Count2, _Temp_ptr, _Capacity, _Pred, _Proj, _STD move(_Firstn), _STD move(_Lastn), _Count1n, + _Count2n); + } else { + const iter_difference_t<_It> _Count2n = _Count2 >> 1; // shift for codegen + _It _Lastn = _RANGES next(_Mid, _Count2n); + _It _Firstn = _RANGES _Upper_bound_unchecked(_First, _Count2, _STD invoke(_Proj, *_Lastn), _Pred, _Proj); + const auto _Count1n = _RANGES distance(_First, _Firstn); + _RANGES _Buffered_inplace_merge_divide_and_conquer2(_STD move(_First), _STD move(_Mid), _STD move(_Last), + _Count1, _Count2, _Temp_ptr, _Capacity, _Pred, _Proj, _STD move(_Firstn), _STD move(_Lastn), _Count1n, + _Count2n); + } + } + + // clang-format off + template + requires sortable<_It, _Pr, _Pj> + void _Buffered_inplace_merge_common(_It _First, _It _Mid, _It _Last, iter_difference_t<_It> _Count1, + iter_difference_t<_It> _Count2, iter_value_t<_It>* const _Temp_ptr, const ptrdiff_t _Capacity, _Pr _Pred, + _Pj _Proj) { + // clang-format on + // merge sorted [_First, _Mid) with sorted [_Mid, _Last) + // usual invariants *do not* apply; only sortedness applies + // establish the usual invariants + if (_First == _Mid || _Mid == _Last) { + return; + } + + // Find first element in [_First, _Mid) that is greater than *_Mid + while (!_STD invoke(_Pred, _STD invoke(_Proj, *_Mid), _STD invoke(_Proj, *_First))) { + --_Count1; + if (++_First == _Mid) { + return; + } + } + + // Find last element in [_Mid, _Last) that is less than *--_Mid + const auto _Highest = _RANGES prev(_Mid); + do { + // Fast early return if there is only one element to be moved + if (_Mid == --_Last) { + // rotate only element remaining in right partition to the beginning, without allocating + _RANGES _Rotate_one_right(_STD move(_First), _STD move(_Mid), _STD move(++_Last)); + return; + } + --_Count2; + } while (!_STD invoke(_Pred, _STD invoke(_Proj, *_Last), _STD invoke(_Proj, *_Highest))); + ++_Last; + ++_Count2; + + if (_Count1 == 1) { + _RANGES _Rotate_one_left(_STD move(_First), _STD move(_Mid), _STD move(_Last)); + return; + } + + if (_Count1 <= _Count2 && _Count1 <= _Capacity) { + _RANGES _Inplace_merge_buffer_left( + _STD move(_First), _STD move(_Mid), _STD move(_Last), _Temp_ptr, _Capacity, _Pred, _Proj); + } else if (_Count2 <= _Capacity) { + _RANGES _Inplace_merge_buffer_right( + _STD move(_First), _STD move(_Mid), _STD move(_Last), _Temp_ptr, _Capacity, _Pred, _Proj); + } else { + _RANGES _Buffered_inplace_merge_divide_and_conquer(_STD move(_First), _STD move(_Mid), _STD move(_Last), + _Count1, _Count2, _Temp_ptr, _Capacity, _Pred, _Proj); + } + } + + class _Inplace_merge_fn : private _Not_quite_object { + public: + using _Not_quite_object::_Not_quite_object; + + // clang-format off + template _Se, class _Pr = ranges::less, class _Pj = identity> + requires sortable<_It, _Pr, _Pj> + _It operator()(_It _First, _It _Mid, _Se _Last, _Pr _Pred = {}, _Pj _Proj = {}) const { + // clang-format on + _Adl_verify_range(_First, _Mid); + _Adl_verify_range(_Mid, _Last); + + auto _UFirst = _Get_unwrapped(_STD move(_First)); + auto _ULast = _Get_final_iterator_unwrapped<_It>(_UFirst, _STD move(_Last)); + _Seek_wrapped(_First, _ULast); + + _Inplace_merge_common(_STD move(_UFirst), _Get_unwrapped(_STD move(_Mid)), _STD move(_ULast), + _Pass_fn(_Pred), _Pass_fn(_Proj)); + return _First; + } + + // clang-format off + template + requires sortable, _Pr, _Pj> + borrowed_iterator_t<_Rng> operator()( + _Rng&& _Range, iterator_t<_Rng> _Mid, _Pr _Pred = {}, _Pj _Proj = {}) const { + // clang-format on + auto _First = _RANGES begin(_Range); + auto _Last = _RANGES end(_Range); + + _Adl_verify_range(_First, _Mid); + _Adl_verify_range(_Mid, _Last); + + auto _UFirst = _Get_unwrapped(_STD move(_First)); + auto _ULast = _Get_final_iterator_unwrapped>(_UFirst, _STD move(_Last)); + _Seek_wrapped(_First, _ULast); + + _Inplace_merge_common(_STD move(_UFirst), _Get_unwrapped(_STD move(_Mid)), _STD move(_ULast), + _Pass_fn(_Pred), _Pass_fn(_Proj)); + return _First; + } + + private: + template + static void _Inplace_merge_common(_It _First, _It _Mid, _It _Last, _Pr _Pred, _Pj _Proj) { + _STL_INTERNAL_STATIC_ASSERT(bidirectional_iterator<_It>); + _STL_INTERNAL_STATIC_ASSERT(sortable<_It, _Pr, _Pj>); + + if (_First == _Mid || _Mid == _Last) { + return; + } +#if _ITERATOR_DEBUG_LEVEL == 2 + _STL_VERIFY(_RANGES _Is_sorted_until_unchecked(_First, _Mid, _Pred, _Proj) == _Mid, + "ranges::inplace_merge requires the range [first, middle) to be sorted"); + _STL_VERIFY(_RANGES _Is_sorted_until_unchecked(_Mid, _Last, _Pred, _Proj) == _Last, + "ranges::inplace_merge requires the range [middle, last) to be sorted"); +#endif //_ITERATOR_DEBUG_LEVEL == 2 + + // Find first element in [_First, _Mid) that is greater than *_Mid + while (!_STD invoke(_Pred, _STD invoke(_Proj, *_Mid), _STD invoke(_Proj, *_First))) { + if (++_First == _Mid) { + return; + } + } + + // Fast early return if there is only one element to be moved + if (_Mid == --_Last) { + // rotate only element remaining in right partition to the beginning, without allocating + _RANGES _Rotate_one_right(_STD move(_First), _STD move(_Mid), _STD move(++_Last)); + return; + } + + // Find last element in [_Mid, _Last) that is less than *--_Mid + const auto _Highest = _RANGES prev(_Mid); + while (!_STD invoke(_Pred, _STD invoke(_Proj, *_Last), _STD invoke(_Proj, *_Highest))) { + if (_Mid == --_Last) { + // rotate only element remaining in right partition to the beginning, without allocating + _RANGES _Rotate_one_right(_STD move(_First), _STD move(_Mid), _STD move(++_Last)); + return; + } + } + ++_Last; + + const iter_difference_t<_It> _Count1 = _RANGES distance(_First, _Mid); + if (_Count1 == 1) { // rotate only element remaining in left partition to the end, without allocating + _RANGES _Rotate_one_left(_STD move(_First), _STD move(_Mid), _STD move(_Last)); + return; + } + + const iter_difference_t<_It> _Count2 = _RANGES distance(_Mid, _Last); + _Optimistic_temporary_buffer> _Temp_buf{(_STD min)(_Count1, _Count2)}; + if (_Count1 <= _Count2 && _Count1 <= _Temp_buf._Capacity) { + _RANGES _Inplace_merge_buffer_left(_STD move(_First), _STD move(_Mid), _STD move(_Last), + _Temp_buf._Data, _Temp_buf._Capacity, _Pred, _Proj); + } else if (_Count2 <= _Temp_buf._Capacity) { + _RANGES _Inplace_merge_buffer_right(_STD move(_First), _STD move(_Mid), _STD move(_Last), + _Temp_buf._Data, _Temp_buf._Capacity, _Pred, _Proj); + } else { + _RANGES _Buffered_inplace_merge_divide_and_conquer(_STD move(_First), _STD move(_Mid), _STD move(_Last), + _Count1, _Count2, _Temp_buf._Data, _Temp_buf._Capacity, _Pred, _Proj); + } + } + }; + + inline constexpr _Inplace_merge_fn inplace_merge{_Not_quite_object::_Construct_tag{}}; +} // namespace ranges +#endif // __cpp_lib_concepts + +// FUNCTION TEMPLATE sort +template +_CONSTEXPR20 _BidIt _Insertion_sort_unchecked(const _BidIt _First, const _BidIt _Last, _Pr _Pred) { + // insertion sort [_First, _Last) + if (_First != _Last) { + for (_BidIt _Mid = _First; ++_Mid != _Last;) { // order next element + _BidIt _Hole = _Mid; + _Iter_value_t<_BidIt> _Val = _STD move(*_Mid); + + if (_DEBUG_LT_PRED(_Pred, _Val, *_First)) { // found new earliest element, move to front + _Move_backward_unchecked(_First, _Mid, ++_Hole); + *_First = _STD move(_Val); + } else { // look for insertion point after first + for (_BidIt _Prev = _Hole; _DEBUG_LT_PRED(_Pred, _Val, *--_Prev); _Hole = _Prev) { + *_Hole = _STD move(*_Prev); // move hole down + } + + *_Hole = _STD move(_Val); // insert element in hole + } + } + } + + return _Last; +} + +template +_CONSTEXPR20 void _Med3_unchecked(_RanIt _First, _RanIt _Mid, _RanIt _Last, _Pr _Pred) { + // sort median of three elements to middle + if (_DEBUG_LT_PRED(_Pred, *_Mid, *_First)) { + _STD iter_swap(_Mid, _First); + } + + if (_DEBUG_LT_PRED(_Pred, *_Last, *_Mid)) { // swap middle and last, then test first again + _STD iter_swap(_Last, _Mid); + + if (_DEBUG_LT_PRED(_Pred, *_Mid, *_First)) { + _STD iter_swap(_Mid, _First); + } + } +} + +template +_CONSTEXPR20 void _Guess_median_unchecked(_RanIt _First, _RanIt _Mid, _RanIt _Last, _Pr _Pred) { + // sort median element to middle using _Diff = _Iter_diff_t<_RanIt>; const _Diff _Count = _Last - _First; if (40 < _Count) { // Tukey's ninther @@ -7108,12 +7653,12 @@ namespace ranges { // clang-format off template requires sortable<_It, _Pr, _Pj> - constexpr void _Insertion_sort_common(const _It _First, const _It _Last, _Pr _Pred, _Pj _Proj) { + constexpr _It _Insertion_sort_common(const _It _First, const _It _Last, _Pr _Pred, _Pj _Proj) { // clang-format on // insertion sort [_First, _Last) if (_First == _Last) { // empty range is sorted - return; + return _Last; } for (auto _Mid = _First; ++_Mid != _Last;) { // order next element @@ -7133,6 +7678,7 @@ namespace ranges { *_Hole = _STD move(_Val); // insert element in hole } + return _Last; } // clang-format off @@ -7381,16 +7927,16 @@ _OutIt _Merge_move(_InIt _First, const _InIt _Mid, const _InIt _Last, _OutIt _De } template -void _Uninitialized_chunked_merge_unchecked(_BidIt _First, const _BidIt _Last, _Ty* _Dest, - const _Iter_diff_t<_BidIt> _Chunk, _Iter_diff_t<_BidIt> _Count, _Pr _Pred) { - // move to uninitialized merging adjacent chunks of distance _Chunk +void _Uninitialized_chunked_merge_unchecked2( + _BidIt _First, const _BidIt _Last, _Ty* _Dest, _Iter_diff_t<_BidIt> _Count, _Pr _Pred) { + // move to uninitialized merging adjacent chunks of distance _Isort_max<_BidIt> // pre: _Count == distance(_First, _Last) // pre: _Chunk > 0 _Uninitialized_backout<_Ty*> _Backout{_Dest}; - while (_Chunk < _Count) { - _Count -= _Chunk; - const _BidIt _Mid1 = _STD next(_First, _Chunk); - const auto _Chunk2 = (_STD min)(_Chunk, _Count); + while (_Count > _Isort_max<_BidIt>) { + _Count -= _Isort_max<_BidIt>; + const _BidIt _Mid1 = _STD next(_First, _Isort_max<_BidIt>); + const auto _Chunk2 = (_STD min)(_Isort_max<_BidIt>, _Count); _Count -= _Chunk2; const _BidIt _Mid2 = _STD next(_Mid1, _Chunk2); _Backout._Last = _Uninitialized_merge_move(_First, _Mid1, _Mid2, _Backout._Last, _Pred); @@ -7422,10 +7968,10 @@ void _Chunked_merge_unchecked(_BidIt _First, const _BidIt _Last, _OutIt _Dest, c template void _Insertion_sort_isort_max_chunks(_BidIt _First, const _BidIt _Last, _Iter_diff_t<_BidIt> _Count, _Pr _Pred) { - // insertion sort every chunk of distance _ISORT_MAX in [_First, _Last) + // insertion sort every chunk of distance _Isort_max<_BidIt> in [_First, _Last) // pre: _Count == distance(_First, _Last) - for (; _ISORT_MAX < _Count; _Count -= _ISORT_MAX) { // sort chunks - _First = _Insertion_sort_unchecked(_First, _STD next(_First, _ISORT_MAX), _Pred); + for (; _Isort_max<_BidIt> < _Count; _Count -= _Isort_max<_BidIt>) { // sort chunks + _First = _Insertion_sort_unchecked(_First, _STD next(_First, _Isort_max<_BidIt>), _Pred); } _Insertion_sort_unchecked(_First, _Last, _Pred); // sort partial last chunk @@ -7439,14 +7985,14 @@ void _Buffered_merge_sort_unchecked(const _BidIt _First, const _BidIt _Last, con // pre: _Count <= capacity of buffer at _Temp_ptr; also allows safe narrowing to ptrdiff_t _Insertion_sort_isort_max_chunks(_First, _Last, _Count, _Pred); // merge adjacent pairs of chunks to and from temp buffer - auto _Chunk = static_cast<_Iter_diff_t<_BidIt>>(_ISORT_MAX); - if (_Count <= _Chunk) { + if (_Count <= _Isort_max<_BidIt>) { return; } // do the first merge, constructing elements in the temporary buffer - _Uninitialized_chunked_merge_unchecked(_First, _Last, _Temp_ptr, _Chunk, _Count, _Pred); + _Uninitialized_chunked_merge_unchecked2(_First, _Last, _Temp_ptr, _Count, _Pred); _Uninitialized_backout<_Iter_value_t<_BidIt>*> _Backout{_Temp_ptr, _Temp_ptr + _Count}; + auto _Chunk = _Isort_max<_BidIt>; for (;;) { // unconditionally merge elements back into the source buffer _Chunk <<= 1; @@ -7470,7 +8016,7 @@ void _Stable_sort_unchecked(const _BidIt _First, const _BidIt _Last, const _Iter if (_Count <= _ISORT_MAX) { _Insertion_sort_unchecked(_First, _Last, _Pred); // small } else { // sort halves and merge - const auto _Half_count = static_cast<_Diff>(_Count / 2); + const auto _Half_count = static_cast<_Diff>(_Count >> 1); // shift for codegen const auto _Half_count_ceil = static_cast<_Diff>(_Count - _Half_count); const _BidIt _Mid = _STD next(_First, _Half_count_ceil); if (_Half_count_ceil <= _Capacity) { // temp buffer big enough, sort each half using buffer @@ -7520,6 +8066,265 @@ void stable_sort(_ExPo&& _Exec, _BidIt _First, _BidIt _Last) noexcept /* termina } #endif // _HAS_CXX17 + +#ifdef __cpp_lib_concepts +namespace ranges { + // VARIABLE ranges::stable_sort + class _Stable_sort_fn : private _Not_quite_object { + public: + using _Not_quite_object::_Not_quite_object; + + // clang-format off + template _Se, class _Pr = ranges::less, class _Pj = identity> + requires sortable<_It, _Pr, _Pj> + _It operator()(_It _First, _Se _Last, _Pr _Pred = {}, _Pj _Proj = {}) const { + // clang-format on + _Adl_verify_range(_First, _Last); + auto _UFirst = _Get_unwrapped(_STD move(_First)); + auto _ULast = _Get_final_iterator_unwrapped<_It>(_UFirst, _STD move(_Last)); + _Seek_wrapped(_First, _ULast); + + const auto _Count = _ULast - _UFirst; + _Stable_sort_common(_STD move(_UFirst), _STD move(_ULast), _Count, _Pass_fn(_Pred), _Pass_fn(_Proj)); + return _First; + } + + // clang-format off + template + requires sortable, _Pr, _Pj> + borrowed_iterator_t<_Rng> operator()(_Rng&& _Range, _Pr _Pred = {}, _Pj _Proj = {}) const { + // clang-format on + auto _UFirst = _Ubegin(_Range); + auto _ULast = _Get_final_iterator_unwrapped(_Range); + + const auto _Count = _ULast - _UFirst; + _Stable_sort_common(_STD move(_UFirst), _ULast, _Count, _Pass_fn(_Pred), _Pass_fn(_Proj)); + return _Rewrap_iterator(_Range, _STD move(_ULast)); + } + + private: + template + static void _Stable_sort_common( + _It _First, _It _Last, const iter_difference_t<_It> _Count, _Pr _Pred, _Pj _Proj) { + // sort [_First, _Last) with respect to _Pred and _Proj + _STL_INTERNAL_STATIC_ASSERT(random_access_iterator<_It>); + _STL_INTERNAL_STATIC_ASSERT(sortable<_It, _Pr, _Pj>); + _STL_INTERNAL_CHECK(_RANGES distance(_First, _Last) == _Count); + + if (_Count <= _Isort_max<_It>) { + _RANGES _Insertion_sort_common(_STD move(_First), _STD move(_Last), _Pred, _Proj); + return; + } + + _Optimistic_temporary_buffer<_Iter_value_t<_It>> _Temp_buf{_Count - _Count / 2}; + _Stable_sort_common_buffered( + _STD move(_First), _STD move(_Last), _Count, _Temp_buf._Data, _Temp_buf._Capacity, _Pred, _Proj); + } + + template + static void _Stable_sort_common_buffered(_It _First, _It _Last, const iter_difference_t<_It> _Count, + iter_value_t<_It>* const _Temp_ptr, const ptrdiff_t _Capacity, _Pr _Pred, _Pj _Proj) { + // sort [_First, _Last) with respect to _Pred and _Proj + _STL_INTERNAL_STATIC_ASSERT(random_access_iterator<_It>); + _STL_INTERNAL_STATIC_ASSERT(sortable<_It, _Pr, _Pj>); + _STL_INTERNAL_CHECK(_RANGES distance(_First, _Last) == _Count); + // Pre: _Temp_ptr points to empty storage for _Capacity objects + + if (_Count <= _Isort_max<_It>) { + _RANGES _Insertion_sort_common(_STD move(_First), _STD move(_Last), _Pred, _Proj); + } else { // sort halves and merge + const iter_difference_t<_It> _Half_count = _Count >> 1; // shift for codegen + const iter_difference_t<_It> _Half_count_ceil = _Count - _Half_count; + const _It _Mid = _First + _Half_count_ceil; + if (_Half_count_ceil <= _Capacity) { // temp buffer big enough, sort each half using buffer + _Buffered_merge_sort_common(_First, _Mid, _Half_count_ceil, _Temp_ptr, _Pred, _Proj); + _Buffered_merge_sort_common(_Mid, _Last, _Half_count, _Temp_ptr, _Pred, _Proj); + } else { // temp buffer not big enough, divide and conquer + _Stable_sort_common_buffered(_First, _Mid, _Half_count_ceil, _Temp_ptr, _Capacity, _Pred, _Proj); + _Stable_sort_common_buffered(_Mid, _Last, _Half_count, _Temp_ptr, _Capacity, _Pred, _Proj); + } + // merge halves + _RANGES _Buffered_inplace_merge_common(_STD move(_First), _STD move(_Mid), _STD move(_Last), + _Half_count_ceil, _Half_count, _Temp_ptr, _Capacity, _Pred, _Proj); + } + } + + template + static void _Buffered_merge_sort_common(const _It _First, const _It _Last, const iter_difference_t<_It> _Count, + iter_value_t<_It>* const _Temp_ptr, _Pr _Pred, _Pj _Proj) { + // sort using temp buffer for merges + // pre: _Count <= capacity of buffer at _Temp_ptr; also allows safe narrowing to ptrdiff_t + _STL_INTERNAL_STATIC_ASSERT(random_access_iterator<_It>); + _STL_INTERNAL_STATIC_ASSERT(sortable<_It, _Pr, _Pj>); + _STL_INTERNAL_CHECK(_Last - _First == _Count); + + _Insertion_sort_isort_max_chunks(_First, _Last, _Count, _Pred, _Proj); + // merge adjacent pairs of chunks to and from temp buffer + if (_Count <= _Isort_max<_It>) { + return; + } + + // do the first merge, constructing elements in the temporary buffer + _Uninitialized_chunked_merge_common(_First, _Last, _Temp_ptr, _Count, _Pred, _Proj); + _Uninitialized_backout*> _Backout{_Temp_ptr, _Temp_ptr + _Count}; + iter_difference_t<_It> _Chunk_size = _Isort_max<_It>; + for (;;) { + // unconditionally merge elements back into the source buffer + _Chunk_size <<= 1; + _Chunked_merge_common(_Temp_ptr, _Temp_ptr + _Count, _First, _Chunk_size, _Count, _Pred, _Proj); + _Chunk_size <<= 1; + if (_Count <= _Chunk_size) { // if the input would be a single chunk, it's already sorted and we're done + return; + } + + // more merges necessary; merge to temporary buffer + _Chunked_merge_common(_First, _Last, _Temp_ptr, _Chunk_size, _Count, _Pred, _Proj); + } + } + + template + static void _Insertion_sort_isort_max_chunks( + _It _First, _It _Last, iter_difference_t<_It> _Count, _Pr _Pred, _Pj _Proj) { + // insertion sort every chunk of distance _Isort_max<_It> in [_First, _Last) + _STL_INTERNAL_STATIC_ASSERT(random_access_iterator<_It>); + _STL_INTERNAL_STATIC_ASSERT(sortable<_It, _Pr, _Pj>); + _STL_INTERNAL_CHECK(_RANGES distance(_First, _Last) == _Count); + + for (; _Isort_max<_It> < _Count; _Count -= _Isort_max<_It>) { // sort chunks + _First = _RANGES _Insertion_sort_common(_First, _First + _Isort_max<_It>, _Pred, _Proj); + } + + // sort partial last chunk + _RANGES _Insertion_sort_common(_STD move(_First), _STD move(_Last), _Pred, _Proj); + } + + template + static void _Uninitialized_chunked_merge_common(_It _First, const _It _Last, iter_value_t<_It>* const _Dest, + iter_difference_t<_It> _Count, _Pr _Pred, _Pj _Proj) { + // move to uninitialized merging adjacent chunks of distance _Isort_max<_It> + _STL_INTERNAL_STATIC_ASSERT(random_access_iterator<_It>); + _STL_INTERNAL_STATIC_ASSERT(sortable<_It, _Pr, _Pj>); + _STL_INTERNAL_STATIC_ASSERT(constructible_from, iter_rvalue_reference_t<_It>>); + _STL_INTERNAL_CHECK(_RANGES distance(_First, _Last) == _Count); + + _Uninitialized_backout*> _Backout{_Dest}; + const auto _Backout_end = _Dest + _Count; + while (_Isort_max<_It> < _Count) { + _Count -= _Isort_max<_It>; + const auto _Chunk2 = (_STD min)(_Isort_max<_It>, _Count); + _Count -= _Chunk2; + + auto _Mid1 = _First + _Isort_max<_It>; + auto _Last1 = _Mid1 + _Chunk2; + auto _Last2 = _Backout._Last + _Isort_max<_It> + _Chunk2; + _Backout._Last = _Uninitialized_merge_move( + _STD move(_First), _STD move(_Mid1), _Last1, _Backout._Last, _Last2, _Pred, _Proj); + _First = _STD move(_Last1); + } + + // move partial last chunk + _RANGES _Uninitialized_move_unchecked(_STD move(_First), _STD move(_Last), _Backout._Last, _Backout_end); + _Backout._Release(); + } + + template + _NODISCARD static iter_value_t<_It>* _Uninitialized_merge_move(_It _First, _It _Mid, _It _Last, + iter_value_t<_It>* const _Dest, iter_value_t<_It>* const _Dest_last, _Pr _Pred, _Pj _Proj) { + // move merging ranges to uninitialized storage + _STL_INTERNAL_STATIC_ASSERT(sortable<_It, _Pr, _Pj>); + _STL_INTERNAL_STATIC_ASSERT(constructible_from, iter_rvalue_reference_t<_It>>); + _STL_INTERNAL_CHECK(_First != _Mid); + _STL_INTERNAL_CHECK(_Mid != _Last); + _STL_INTERNAL_CHECK(_RANGES distance(_First, _Last) <= _RANGES distance(_Dest, _Dest_last)); + + _Uninitialized_backout*> _Backout{_Dest}; + _It _Next = _Mid; + for (;;) { + if (_STD invoke(_Pred, _STD invoke(_Proj, *_Next), _STD invoke(_Proj, *_First))) { + _Backout._Emplace_back(_RANGES iter_move(_Next)); + ++_Next; + + if (_Next == _Last) { + _Backout._Last = _RANGES _Uninitialized_move_unchecked( + _STD move(_First), _STD move(_Mid), _Backout._Last, _Dest_last) + .out; + return _Backout._Release(); + } + } else { + _Backout._Emplace_back(_RANGES iter_move(_First)); + ++_First; + + if (_First == _Mid) { + _Backout._Last = _RANGES _Uninitialized_move_unchecked( + _STD move(_Next), _STD move(_Last), _Backout._Last, _Dest_last) + .out; + return _Backout._Release(); + } + } + } + } + + template + _NODISCARD static _OutIt _Merge_move_common( + _InIt _First, _InIt _Mid, _InIt _Last, _OutIt _Dest, _Pr _Pred, _Pj _Proj) { + // move merging adjacent ranges [_First, _Mid) and [_Mid, _Last) to _Dest + _STL_INTERNAL_STATIC_ASSERT(sortable<_InIt, _Pr, _Pj>); + _STL_INTERNAL_STATIC_ASSERT(indirectly_movable<_InIt, _OutIt>); + _STL_INTERNAL_CHECK(_First != _Mid); + _STL_INTERNAL_CHECK(_Mid != _Last); + + _InIt _Next = _Mid; + for (;;) { + if (_STD invoke(_Pred, _STD invoke(_Proj, *_Next), _STD invoke(_Proj, *_First))) { + *_Dest = _RANGES iter_move(_Next); + ++_Dest; + ++_Next; + + if (_Next == _Last) { + return _RANGES _Move_unchecked(_STD move(_First), _STD move(_Mid), _STD move(_Dest)).out; + } + } else { + *_Dest = _RANGES iter_move(_First); + ++_Dest; + ++_First; + + if (_First == _Mid) { + return _RANGES _Move_unchecked(_STD move(_Next), _STD move(_Last), _STD move(_Dest)).out; + } + } + } + } + + template + static void _Chunked_merge_common(_It1 _First, const _It1 _Last, _It2 _Dest, + const iter_difference_t<_It1> _Chunk_size, iter_difference_t<_It1> _Count, _Pr _Pred, _Pj _Proj) { + // move merging adjacent chunks of distance _Chunk_size + _STL_INTERNAL_STATIC_ASSERT(random_access_iterator<_It1>); + _STL_INTERNAL_STATIC_ASSERT(sortable<_It1, _Pr, _Pj>); + _STL_INTERNAL_STATIC_ASSERT(indirectly_movable<_It1, _It2>); + _STL_INTERNAL_CHECK(_Last - _First == _Count); + _STL_INTERNAL_CHECK(_Chunk_size > 0); + + while (_Chunk_size < _Count) { + _Count -= _Chunk_size; + const auto _Right_chunk_size = (_STD min)(_Chunk_size, _Count); + _Count -= _Right_chunk_size; + + auto _Mid1 = _First + _Chunk_size; + auto _Last1 = _Mid1 + _Right_chunk_size; + _Dest = _Merge_move_common(_STD move(_First), _STD move(_Mid1), _Last1, _Dest, _Pred, _Proj); + _First = _STD move(_Last1); + } + + // copy partial last chunk + _RANGES _Move_unchecked(_STD move(_First), _STD move(_Last), _STD move(_Dest)); + } + }; + + inline constexpr _Stable_sort_fn stable_sort{_Not_quite_object::_Construct_tag{}}; +} // namespace ranges +#endif // __cpp_lib_concepts + // FUNCTION TEMPLATE partial_sort template _CONSTEXPR20 void partial_sort(_RanIt _First, _RanIt _Mid, _RanIt _Last, _Pr _Pred) { @@ -7917,7 +8722,7 @@ namespace ranges { } // sort any remainder - _Insertion_sort_common(_STD move(_First), _STD move(_Last), _STD move(_Pred), _STD move(_Proj)); + _Insertion_sort_common(_STD move(_First), _STD move(_Last), _Pred, _Proj); } }; @@ -9533,26 +10338,6 @@ _NODISCARD bool is_sorted(_ExPo&& _Exec, _FwdIt _First, _FwdIt _Last) noexcept / #ifdef __cpp_lib_concepts namespace ranges { - // FUNCTION TEMPLATE _Is_sorted_until_unchecked - template - _NODISCARD constexpr _It _Is_sorted_until_unchecked(_It _First, const _Se _Last, _Pr _Pred, _Pj _Proj) { - _STL_INTERNAL_STATIC_ASSERT(forward_iterator<_It>); - _STL_INTERNAL_STATIC_ASSERT(sentinel_for<_Se, _It>); - _STL_INTERNAL_STATIC_ASSERT(indirect_strict_weak_order<_Pr, projected<_It, _Pj>>); - - if (_First == _Last) { - return _First; - } - - for (auto _Prev = _First; ++_First != _Last; ++_Prev) { - if (_STD invoke(_Pred, _STD invoke(_Proj, *_First), _STD invoke(_Proj, *_Prev))) { - break; - } - } - - return _First; - } - // VARIABLE ranges::is_sorted class _Is_sorted_fn : private _Not_quite_object { public: diff --git a/stl/inc/atomic b/stl/inc/atomic index 5e229aefe28..3300bf34674 100644 --- a/stl/inc/atomic +++ b/stl/inc/atomic @@ -75,6 +75,84 @@ extern "C" _NODISCARD char __stdcall __std_atomic_has_cmpxchg16b() noexcept; #define _ATOMIC_HAS_DCAS 0 #endif // _STD_ATOMIC_ALWAYS_USE_CMPXCHG16B == 1 || !defined(_M_X64) || defined(_M_ARM64EC) +#if defined(_M_ARM64) && defined(__clang__) && __clang_major__ == 11 // TRANSITION, LLVM 12 +inline unsigned char _InterlockedCompareExchange128( + __int64 volatile* _Destination, __int64 _Val_high, __int64 _Val_low, __int64* _Comparand) { + auto _Dest = reinterpret_cast<__int128 volatile*>(_Destination); + auto _Cmp = reinterpret_cast<__int128*>(_Comparand); + __int128 _Val; + reinterpret_cast<__int64*>(&_Val)[0] = _Val_low; + reinterpret_cast<__int64*>(&_Val)[1] = _Val_high; + + __int128 _Stored; + do { + if (_Stored = __builtin_arm_ldaex(_Dest); _Stored != *_Cmp) { + *_Cmp = _Stored; + return 0; + } + } while (__builtin_arm_stlex(_Val, _Dest)); + + return 1; +} + +inline unsigned char _InterlockedCompareExchange128_acq( + __int64 volatile* _Destination, __int64 _Val_high, __int64 _Val_low, __int64* _Comparand) { + auto _Dest = reinterpret_cast<__int128 volatile*>(_Destination); + auto _Cmp = reinterpret_cast<__int128*>(_Comparand); + __int128 _Val; + reinterpret_cast<__int64*>(&_Val)[0] = _Val_low; + reinterpret_cast<__int64*>(&_Val)[1] = _Val_high; + + __int128 _Stored; + do { + if (_Stored = __builtin_arm_ldaex(_Dest); _Stored != *_Cmp) { + *_Cmp = _Stored; + return 0; + } + } while (__builtin_arm_strex(_Val, _Dest)); + + return 1; +} + +inline unsigned char _InterlockedCompareExchange128_nf( + __int64 volatile* _Destination, __int64 _Val_high, __int64 _Val_low, __int64* _Comparand) { + auto _Dest = reinterpret_cast<__int128 volatile*>(_Destination); + auto _Cmp = reinterpret_cast<__int128*>(_Comparand); + __int128 _Val; + reinterpret_cast<__int64*>(&_Val)[0] = _Val_low; + reinterpret_cast<__int64*>(&_Val)[1] = _Val_high; + + __int128 _Stored; + do { + if (_Stored = __builtin_arm_ldrex(_Dest); _Stored != *_Cmp) { + *_Cmp = _Stored; + return 0; + } + } while (__builtin_arm_strex(_Val, _Dest)); + + return 1; +} + +inline unsigned char _InterlockedCompareExchange128_rel( + __int64 volatile* _Destination, __int64 _Val_high, __int64 _Val_low, __int64* _Comparand) { + auto _Dest = reinterpret_cast<__int128 volatile*>(_Destination); + auto _Cmp = reinterpret_cast<__int128*>(_Comparand); + __int128 _Val; + reinterpret_cast<__int64*>(&_Val)[0] = _Val_low; + reinterpret_cast<__int64*>(&_Val)[1] = _Val_high; + + __int128 _Stored; + do { + if (_Stored = __builtin_arm_ldaex(_Dest); _Stored != *_Cmp) { + *_Cmp = _Stored; + return 0; + } + } while (__builtin_arm_stlex(_Val, _Dest)); + + return 1; +} +#endif // ^^^ ARM64 && LLVM 11 workaround ^^^ + // MACRO _ATOMIC_CHOOSE_INTRINSIC #if defined(_M_IX86) || (defined(_M_X64) && !defined(_M_ARM64EC)) #define _ATOMIC_CHOOSE_INTRINSIC(_Order, _Result, _Intrinsic, ...) \ @@ -414,24 +492,45 @@ void _Atomic_wait_direct( } #endif // _HAS_CXX20 -#if 1 // TRANSITION, ABI +#if 1 // TRANSITION, ABI, GH-1151 inline void _Atomic_lock_acquire(long& _Spinlock) noexcept { - while (_InterlockedExchange(&_Spinlock, 1)) { - _YIELD_PROCESSOR(); +#if defined(_M_IX86) || (defined(_M_X64) && !defined(_M_ARM64EC)) + // Algorithm from Intel(R) 64 and IA-32 Architectures Optimization Reference Manual, May 2020 + // Example 2-4. Contended Locks with Increasing Back-off Example - Improved Version, page 2-22 + // The code in mentioned manual is covered by the 0BSD license. + int _Current_backoff = 1; + const int _Max_backoff = 64; + while (_InterlockedExchange(&_Spinlock, 1) != 0) { + while (__iso_volatile_load32(&reinterpret_cast(_Spinlock)) != 0) { + for (int _Count_down = _Current_backoff; _Count_down != 0; --_Count_down) { + _mm_pause(); + } + _Current_backoff = _Current_backoff < _Max_backoff ? _Current_backoff << 1 : _Max_backoff; + } } +#elif defined(_M_ARM) || defined(_M_ARM64) || defined(_M_ARM64EC) + while (_InterlockedExchange(&_Spinlock, 1) != 0) { // TRANSITION, GH-1133: _InterlockedExchange_acq + while (__iso_volatile_load32(&reinterpret_cast(_Spinlock)) != 0) { + __yield(); + } + } +#else // ^^^ defined(_M_ARM) || defined(_M_ARM64) || defined(_M_ARM64EC) ^^^ +#error Unsupported hardware +#endif } inline void _Atomic_lock_release(long& _Spinlock) noexcept { -#if defined(_M_ARM) || defined(_M_ARM64) +#if defined(_M_IX86) || (defined(_M_X64) && !defined(_M_ARM64EC)) + _InterlockedExchange(&_Spinlock, 0); // TRANSITION, GH-1133: same as ARM +#elif defined(_M_ARM) || defined(_M_ARM64) || defined(_M_ARM64EC) _Memory_barrier(); __iso_volatile_store32(reinterpret_cast(&_Spinlock), 0); - _Memory_barrier(); -#else // ^^^ ARM32/ARM64 hardware / x86/x64 hardware vvv - _InterlockedExchange(&_Spinlock, 0); -#endif // hardware + _Memory_barrier(); // TRANSITION, GH-1133: remove +#else // ^^^ defined(_M_ARM) || defined(_M_ARM64) || defined(_M_ARM64EC) ^^^ +#error Unsupported hardware +#endif } - inline void _Atomic_lock_acquire(_Smtx_t* _Spinlock) noexcept { _Smtx_lock_exclusive(_Spinlock); } @@ -471,18 +570,6 @@ bool __stdcall _Atomic_wait_compare_non_lock_free( #ifdef _WIN64 inline bool __stdcall _Atomic_wait_compare_16_bytes(const void* _Storage, void* _Comparand, size_t, void*) noexcept { -#if defined(__clang__) && defined(_M_ARM64) // TRANSITION, Clang 12 - const auto _Dest = static_cast<__int128*>(const_cast(_Storage)); - const auto _Cmp = static_cast(_Comparand); - - do { - if (__builtin_arm_ldrex(_Dest) != *_Cmp) { - return false; - } - } while (__builtin_arm_strex(*_Cmp, _Dest)); - - return true; -#else // ^^^ workaround / no workaround vvv const auto _Dest = static_cast(const_cast(_Storage)); const auto _Cmp = static_cast(_Comparand); alignas(16) long long _Tmp[2] = {_Cmp[0], _Cmp[1]}; @@ -491,7 +578,6 @@ inline bool __stdcall _Atomic_wait_compare_16_bytes(const void* _Storage, void* #else // ^^^ _M_X64 / ARM64 vvv return _InterlockedCompareExchange128_nf(_Dest, _Tmp[1], _Tmp[0], _Tmp) != 0; #endif // ^^^ ARM64 ^^^ -#endif // TRANSITION, Clang 12 } #endif // _WIN64 #endif // _HAS_CXX20 diff --git a/stl/inc/bit b/stl/inc/bit index d933364942c..56e6cdcb37f 100644 --- a/stl/inc/bit +++ b/stl/inc/bit @@ -211,6 +211,24 @@ _NODISCARD int _Checked_x86_x64_popcount(const _Ty _Val) noexcept { #if defined(_M_ARM) || defined(_M_ARM64) +#ifdef __clang__ // TRANSITION, GH-1586 +_NODISCARD constexpr int _Clang_arm_arm64_countl_zero(const unsigned short _Val) { + return __builtin_clzs(_Val); +} + +_NODISCARD constexpr int _Clang_arm_arm64_countl_zero(const unsigned int _Val) { + return __builtin_clz(_Val); +} + +_NODISCARD constexpr int _Clang_arm_arm64_countl_zero(const unsigned long _Val) { + return __builtin_clzl(_Val); +} + +_NODISCARD constexpr int _Clang_arm_arm64_countl_zero(const unsigned long long _Val) { + return __builtin_clzll(_Val); +} +#endif // TRANSITION, GH-1586 + template _NODISCARD int _Checked_arm_arm64_countl_zero(const _Ty _Val) noexcept { constexpr int _Digits = numeric_limits<_Ty>::digits; @@ -218,11 +236,20 @@ _NODISCARD int _Checked_arm_arm64_countl_zero(const _Ty _Val) noexcept { return _Digits; } +#ifdef __clang__ // TRANSITION, GH-1586 + if constexpr (is_same_v, unsigned char>) { + return _Clang_arm_arm64_countl_zero(static_cast(_Val)) + - (numeric_limits::digits - _Digits); + } else { + return _Clang_arm_arm64_countl_zero(_Val); + } +#else // ^^^ workaround / no workaround vvv if constexpr (_Digits <= 32) { - return _CountLeadingZeros(_Val); + return static_cast(_CountLeadingZeros(_Val)); } else { - return _CountLeadingZeros64(_Val); + return static_cast(_CountLeadingZeros64(_Val)); } +#endif // TRANSITION, GH-1586 } #endif // defined(_M_ARM) || defined(_M_ARM64) diff --git a/stl/inc/chrono b/stl/inc/chrono index d53e2873cb6..7927b883277 100644 --- a/stl/inc/chrono +++ b/stl/inc/chrono @@ -15,6 +15,10 @@ #include #include +#if _HAS_CXX20 +#include +#endif // _HAS_CXX20 + #pragma pack(push, _CRT_PACKING) #pragma warning(push, _STL_WARNING_LEVEL) #pragma warning(disable : _STL_DISABLED_WARNINGS) @@ -50,6 +54,23 @@ namespace chrono { } }; +#if _HAS_CXX20 + template + concept _Is_clock = requires { + typename _Clock::rep; + typename _Clock::period; + typename _Clock::duration; + typename _Clock::time_point; + _Clock::is_steady; + _Clock::now(); + }; + + template + struct is_clock : bool_constant<_Is_clock<_Clock>> {}; + template + inline constexpr bool is_clock_v = _Is_clock<_Clock>; +#endif // _HAS_CXX20 + // CLASS TEMPLATE duration template > class duration; @@ -89,7 +110,7 @@ namespace chrono { int> = 0> constexpr duration(const duration<_Rep2, _Period2>& _Dur) noexcept( is_arithmetic_v<_Rep>&& is_arithmetic_v<_Rep2>) // strengthened - : _MyRep(chrono::duration_cast(_Dur).count()) {} + : _MyRep(_CHRONO duration_cast(_Dur).count()) {} _NODISCARD constexpr _Rep count() const noexcept(is_arithmetic_v<_Rep>) /* strengthened */ { return _MyRep; @@ -196,6 +217,23 @@ namespace chrono { return _MyDur; } +#if _HAS_CXX20 + constexpr time_point& operator++() noexcept(is_arithmetic_v) /* strengthened */ { + ++_MyDur; + return *this; + } + constexpr time_point operator++(int) noexcept(is_arithmetic_v) /* strengthened */ { + return time_point{_MyDur++}; + } + constexpr time_point& operator--() noexcept(is_arithmetic_v) /* strengthened */ { + --_MyDur; + return *this; + } + constexpr time_point operator--(int) noexcept(is_arithmetic_v) /* strengthened */ { + return time_point{_MyDur--}; + } +#endif // _HAS_CXX20 + _CONSTEXPR17 time_point& operator+=(const _Duration& _Dur) noexcept(is_arithmetic_v) /* strengthened */ { _MyDur += _Dur; return *this; @@ -225,16 +263,16 @@ struct _Lcm : integral_constant::value) * _Bx> { // STRUCT TEMPLATE common_type SPECIALIZATIONS template -struct common_type, - chrono::duration<_Rep2, _Period2>> { // common type of two durations - using type = chrono::duration, +struct common_type<_CHRONO duration<_Rep1, _Period1>, + _CHRONO duration<_Rep2, _Period2>> { // common type of two durations + using type = _CHRONO duration, ratio<_Gcd<_Period1::num, _Period2::num>::value, _Lcm<_Period1::den, _Period2::den>::value>>; }; template -struct common_type, - chrono::time_point<_Clock, _Duration2>> { // common type of two time points - using type = chrono::time_point<_Clock, common_type_t<_Duration1, _Duration2>>; +struct common_type<_CHRONO time_point<_Clock, _Duration1>, + _CHRONO time_point<_Clock, _Duration2>> { // common type of two time points + using type = _CHRONO time_point<_Clock, common_type_t<_Duration1, _Duration2>>; }; namespace chrono { @@ -405,7 +443,7 @@ namespace chrono { is_arithmetic_v<_Rep>&& is_arithmetic_v) /* strengthened */ { // convert duration to another duration; round towards negative infinity // i.e. the greatest integral result such that the result <= _Dur - const _To _Casted{chrono::duration_cast<_To>(_Dur)}; + const _To _Casted{_CHRONO duration_cast<_To>(_Dur)}; if (_Casted > _Dur) { return _To{_Casted.count() - static_cast(1)}; } @@ -419,7 +457,7 @@ namespace chrono { is_arithmetic_v<_Rep>&& is_arithmetic_v) /* strengthened */ { // convert duration to another duration; round towards positive infinity // i.e. the least integral result such that _Dur <= the result - const _To _Casted{chrono::duration_cast<_To>(_Dur)}; + const _To _Casted{_CHRONO duration_cast<_To>(_Dur)}; if (_Casted < _Dur) { return _To{_Casted.count() + static_cast(1)}; } @@ -439,7 +477,7 @@ namespace chrono { _NODISCARD constexpr _To round(const duration<_Rep, _Period>& _Dur) noexcept( is_arithmetic_v<_Rep>&& is_arithmetic_v) /* strengthened */ { // convert duration to another duration, round to nearest, ties to even - const _To _Floored{chrono::floor<_To>(_Dur)}; + const _To _Floored{_CHRONO floor<_To>(_Dur)}; const _To _Ceiled{_Floored + _To{1}}; const auto _Floor_adjustment = _Dur - _Floored; const auto _Ceil_adjustment = _Ceiled - _Dur; @@ -466,6 +504,12 @@ namespace chrono { using seconds = duration; using minutes = duration>; using hours = duration>; +#if _HAS_CXX20 + using days = duration, hours::period>>; + using weeks = duration, days::period>>; + using years = duration, days::period>>; + using months = duration>>; +#endif // _HAS_CXX20 // time_point ARITHMETIC template @@ -546,7 +590,7 @@ namespace chrono { _NODISCARD constexpr time_point<_Clock, _To> time_point_cast(const time_point<_Clock, _Duration>& _Time) noexcept( is_arithmetic_v&& is_arithmetic_v) /* strengthened */ { // change the duration type of a time_point; truncate - return time_point<_Clock, _To>(chrono::duration_cast<_To>(_Time.time_since_epoch())); + return time_point<_Clock, _To>(_CHRONO duration_cast<_To>(_Time.time_since_epoch())); } // FUNCTION TEMPLATE floor (for time_point instances) @@ -554,7 +598,7 @@ namespace chrono { _NODISCARD constexpr time_point<_Clock, _To> floor(const time_point<_Clock, _Duration>& _Time) noexcept( is_arithmetic_v&& is_arithmetic_v) /* strengthened */ { // change the duration type of a time_point; round towards negative infinity - return time_point<_Clock, _To>(chrono::floor<_To>(_Time.time_since_epoch())); + return time_point<_Clock, _To>(_CHRONO floor<_To>(_Time.time_since_epoch())); } // FUNCTION TEMPLATE ceil (for time_point instances) @@ -562,7 +606,7 @@ namespace chrono { _NODISCARD constexpr time_point<_Clock, _To> ceil(const time_point<_Clock, _Duration>& _Time) noexcept( is_arithmetic_v&& is_arithmetic_v) /* strengthened */ { // change the duration type of a time_point; round towards positive infinity - return time_point<_Clock, _To>(chrono::ceil<_To>(_Time.time_since_epoch())); + return time_point<_Clock, _To>(_CHRONO ceil<_To>(_Time.time_since_epoch())); } // FUNCTION TEMPLATE round (for time_point instances) @@ -571,15 +615,15 @@ namespace chrono { _NODISCARD constexpr time_point<_Clock, _To> round(const time_point<_Clock, _Duration>& _Time) noexcept( is_arithmetic_v&& is_arithmetic_v) /* strengthened */ { // change the duration type of a time_point; round to nearest, ties to even - return time_point<_Clock, _To>(chrono::round<_To>(_Time.time_since_epoch())); + return time_point<_Clock, _To>(_CHRONO round<_To>(_Time.time_since_epoch())); } // CLOCKS struct system_clock { // wraps GetSystemTimePreciseAsFileTime/GetSystemTimeAsFileTime using rep = long long; using period = ratio<1, 10'000'000>; // 100 nanoseconds - using duration = chrono::duration; - using time_point = chrono::time_point; + using duration = _CHRONO duration; + using time_point = _CHRONO time_point; static constexpr bool is_steady = false; _NODISCARD static time_point now() noexcept { // get current time @@ -595,11 +639,19 @@ namespace chrono { } }; +#if _HAS_CXX20 + // sys_time ALIASES + template + using sys_time = time_point; + using sys_seconds = sys_time; + using sys_days = sys_time; +#endif // _HAS_CXX20 + struct steady_clock { // wraps QueryPerformanceCounter using rep = long long; using period = nano; using duration = nanoseconds; - using time_point = chrono::time_point; + using time_point = _CHRONO time_point; static constexpr bool is_steady = true; _NODISCARD static time_point now() noexcept { // get current time @@ -699,28 +751,1338 @@ namespace chrono { return _Os << _Sstr.str(); } + + struct local_t {}; + + template + using local_time = time_point; + using local_seconds = local_time; + using local_days = local_time; + + struct last_spec { + explicit last_spec() = default; + }; + inline constexpr last_spec last{}; + + class day { + public: + day() = default; + constexpr explicit day(unsigned int _Val) noexcept : _Day{static_cast(_Val)} {} + + constexpr day& operator++() noexcept { + ++_Day; + return *this; + } + constexpr day operator++(int) noexcept { + return day{_Day++}; + } + constexpr day& operator--() noexcept { + --_Day; + return *this; + } + constexpr day operator--(int) noexcept { + return day{_Day--}; + } + + constexpr day& operator+=(const days& _Days) noexcept { + _Day += static_cast(_Days.count()); + return *this; + } + constexpr day& operator-=(const days& _Days) noexcept { + _Day -= static_cast(_Days.count()); + return *this; + } + + _NODISCARD constexpr explicit operator unsigned int() const noexcept { + return _Day; + } + _NODISCARD constexpr bool ok() const noexcept { + return _Day >= 1 && _Day <= 31; + } + + private: + unsigned char _Day; + }; + + _NODISCARD constexpr bool operator==(const day& _Left, const day& _Right) noexcept { + return static_cast(_Left) == static_cast(_Right); + } + _NODISCARD constexpr strong_ordering operator<=>(const day& _Left, const day& _Right) noexcept { + return static_cast(_Left) <=> static_cast(_Right); + } + + _NODISCARD constexpr day operator+(const day& _Left, const days& _Right) noexcept { + return day{static_cast(_Left) + _Right.count()}; + } + _NODISCARD constexpr day operator+(const days& _Left, const day& _Right) noexcept { + return _Right + _Left; + } + _NODISCARD constexpr day operator-(const day& _Left, const days& _Right) noexcept { + return day{static_cast(_Left) - _Right.count()}; + } + _NODISCARD constexpr days operator-(const day& _Left, const day& _Right) noexcept { + return days{ + static_cast(static_cast(_Left)) - static_cast(static_cast(_Right))}; + } + + class month { + public: + month() = default; + constexpr explicit month(unsigned int _Val) noexcept : _Month{static_cast(_Val)} {} + + constexpr month& operator++() noexcept { + *this += months{1}; + return *this; + } + constexpr month operator++(int) noexcept { + month _Temp{*this}; + ++*this; + return _Temp; + } + constexpr month& operator--() noexcept { + *this -= months{1}; + return *this; + } + constexpr month operator--(int) noexcept { + month _Temp{*this}; + --*this; + return _Temp; + } + + constexpr month& operator+=(const months& _Months) noexcept; + constexpr month& operator-=(const months& _Months) noexcept; + + _NODISCARD constexpr explicit operator unsigned int() const noexcept { + return _Month; + } + _NODISCARD constexpr bool ok() const noexcept { + return _Month >= 1 && _Month <= 12; + } + + private: + unsigned char _Month; + }; + + _NODISCARD constexpr bool operator==(const month& _Left, const month& _Right) noexcept { + return static_cast(_Left) == static_cast(_Right); + } + _NODISCARD constexpr strong_ordering operator<=>(const month& _Left, const month& _Right) noexcept { + return static_cast(_Left) <=> static_cast(_Right); + } + + _NODISCARD constexpr month operator+(const month& _Left, const months& _Right) noexcept { + const auto _Mo = static_cast(static_cast(_Left)) + (_Right.count() - 1); + const auto _Div = (_Mo >= 0 ? _Mo : _Mo - 11) / 12; + return month{static_cast(_Mo - _Div * 12 + 1)}; + } + _NODISCARD constexpr month operator+(const months& _Left, const month& _Right) noexcept { + return _Right + _Left; + } + _NODISCARD constexpr month operator-(const month& _Left, const months& _Right) noexcept { + return _Left + -_Right; + } + _NODISCARD constexpr months operator-(const month& _Left, const month& _Right) noexcept { + const auto _Mo = static_cast(_Left) - static_cast(_Right); + return months{_Mo <= 11 ? _Mo : _Mo + 12}; + } + + constexpr month& month::operator+=(const months& _Months) noexcept { + *this = *this + _Months; + return *this; + } + constexpr month& month::operator-=(const months& _Months) noexcept { + *this = *this - _Months; + return *this; + } + + class year { + public: + year() = default; + constexpr explicit year(int _Val) noexcept : _Year{static_cast(_Val)} {} + + constexpr year& operator++() noexcept { + ++_Year; + return *this; + } + constexpr year operator++(int) noexcept { + return year{_Year++}; + } + constexpr year& operator--() noexcept { + --_Year; + return *this; + } + constexpr year operator--(int) noexcept { + return year{_Year--}; + } + + constexpr year& operator+=(const years& _Years) noexcept { +#ifdef __EDG__ // TRANSITION, VSO-1271098 + _Year = static_cast(_Year + _Years.count()); +#else // ^^^ workaround / no workaround vvv + _Year += static_cast(_Years.count()); +#endif // ^^^ no workaround ^^^ + return *this; + } + constexpr year& operator-=(const years& _Years) noexcept { +#ifdef __EDG__ // TRANSITION, VSO-1271098 + _Year = static_cast(_Year - _Years.count()); +#else // ^^^ workaround / no workaround vvv + _Year -= static_cast(_Years.count()); +#endif // ^^^ no workaround ^^^ + return *this; + } + + _NODISCARD constexpr year operator+() const noexcept { + return *this; + } + _NODISCARD constexpr year operator-() const noexcept { + return year{-_Year}; + } + + _NODISCARD constexpr bool is_leap() const noexcept { + return _Year % 4 == 0 && (_Year % 100 != 0 || _Year % 400 == 0); + } + + _NODISCARD constexpr explicit operator int() const noexcept { + return _Year; + } + + _NODISCARD constexpr bool ok() const noexcept { + return _Year_min <= _Year && _Year <= _Year_max; + } + + _NODISCARD static constexpr year(min)() noexcept { + return year{_Year_min}; + } + _NODISCARD static constexpr year(max)() noexcept { + return year{_Year_max}; + } + + private: + short _Year; + static constexpr int _Year_min = -32767; + static constexpr int _Year_max = 32767; + }; + + _NODISCARD constexpr bool operator==(const year& _Left, const year& _Right) noexcept { + return static_cast(_Left) == static_cast(_Right); + } + _NODISCARD constexpr strong_ordering operator<=>(const year& _Left, const year& _Right) noexcept { + return static_cast(_Left) <=> static_cast(_Right); + } + + _NODISCARD constexpr year operator+(const year& _Left, const years& _Right) noexcept { + return year{static_cast(_Left) + _Right.count()}; + } + _NODISCARD constexpr year operator+(const years& _Left, const year& _Right) noexcept { + return _Right + _Left; + } + _NODISCARD constexpr year operator-(const year& _Left, const years& _Right) noexcept { + return _Left + -_Right; + } + _NODISCARD constexpr years operator-(const year& _Left, const year& _Right) noexcept { + return years{static_cast(_Left) - static_cast(_Right)}; + } + + class weekday_indexed; + class weekday_last; + + class weekday { + public: + weekday() = default; + constexpr explicit weekday(unsigned int _Val) noexcept + : _Weekday{static_cast(_Val == 7 ? 0 : _Val)} {} + constexpr weekday(const sys_days& _Sys_day) noexcept + : _Weekday{static_cast(_Weekday_from_days(_Sys_day.time_since_epoch().count()))} {} + constexpr explicit weekday(const local_days& _Local_day) noexcept + : _Weekday{static_cast(_Weekday_from_days(_Local_day.time_since_epoch().count()))} {} + + constexpr weekday& operator++() noexcept { + return *this += days{1}; + } + constexpr weekday operator++(int) noexcept { + weekday _Temp{*this}; + ++*this; + return _Temp; + } + constexpr weekday& operator--() noexcept { + return *this -= days{1}; + } + constexpr weekday operator--(int) noexcept { + weekday _Temp{*this}; + --*this; + return _Temp; + } + + constexpr weekday& operator+=(const days& _Days) noexcept; + constexpr weekday& operator-=(const days& _Days) noexcept; + + _NODISCARD constexpr unsigned int c_encoding() const noexcept { + return _Weekday; + } + _NODISCARD constexpr unsigned int iso_encoding() const noexcept { + return _Weekday == 0u ? 7u : _Weekday; + } + _NODISCARD constexpr bool ok() const noexcept { + return _Weekday <= 6; + } + + _NODISCARD constexpr weekday_indexed operator[](unsigned int _Index) const noexcept; + _NODISCARD constexpr weekday_last operator[](last_spec) const noexcept; + + private: + unsigned char _Weekday; + + // courtesy of Howard Hinnant + // https://howardhinnant.github.io/date_algorithms.html#weekday_from_days + _NODISCARD static constexpr unsigned int _Weekday_from_days(int _Tp) noexcept { + return static_cast(_Tp >= -4 ? (_Tp + 4) % 7 : (_Tp + 5) % 7 + 6); + } + }; + + _NODISCARD constexpr bool operator==(const weekday& _Left, const weekday& _Right) noexcept { + return _Left.c_encoding() == _Right.c_encoding(); + } + + _NODISCARD constexpr weekday operator+(const weekday& _Left, const days& _Right) noexcept { + const auto _Wd = static_cast(_Left.c_encoding()) + _Right.count(); + const auto _Div = (_Wd >= 0 ? _Wd : _Wd - 6) / 7; + return weekday{static_cast(_Wd - _Div * 7)}; + } + _NODISCARD constexpr weekday operator+(const days& _Left, const weekday& _Right) noexcept { + return _Right + _Left; + } + _NODISCARD constexpr weekday operator-(const weekday& _Left, const days& _Right) noexcept { + return _Left + -_Right; + } + _NODISCARD constexpr days operator-(const weekday& _Left, const weekday& _Right) noexcept { + const auto _Wd = _Left.c_encoding() - _Right.c_encoding(); + const auto _Wk = _Wd <= 6 ? _Wd : _Wd + 7; + return days{_Wk}; + } + + constexpr weekday& weekday::operator+=(const days& _Days) noexcept { + *this = *this + _Days; + return *this; + } + constexpr weekday& weekday::operator-=(const days& _Days) noexcept { + *this = *this - _Days; + return *this; + } + + class weekday_indexed { + public: + weekday_indexed() = default; + constexpr weekday_indexed(const weekday& _Wd, unsigned int _Idx) noexcept + : _Weekday{_Wd}, _Index{static_cast(_Idx)} {} + + _NODISCARD constexpr weekday weekday() const noexcept { + return _Weekday; + } + _NODISCARD constexpr unsigned int index() const noexcept { + return _Index; + } + _NODISCARD constexpr bool ok() const noexcept { + return _Weekday.ok() && _Index >= 1 && _Index <= 5; + } + + private: + _CHRONO weekday _Weekday; + unsigned char _Index; + }; + + _NODISCARD constexpr bool operator==(const weekday_indexed& _Left, const weekday_indexed& _Right) noexcept { + return _Left.weekday() == _Right.weekday() && _Left.index() == _Right.index(); + } + + class weekday_last { + public: + constexpr explicit weekday_last(const weekday& _Wd) noexcept : _Weekday{_Wd} {} + + _NODISCARD constexpr weekday weekday() const noexcept { + return _Weekday; + } + _NODISCARD constexpr bool ok() const noexcept { + return _Weekday.ok(); + } + + private: + _CHRONO weekday _Weekday; + }; + + _NODISCARD constexpr bool operator==(const weekday_last& _Left, const weekday_last& _Right) noexcept { + return _Left.weekday() == _Right.weekday(); + } + + _NODISCARD constexpr weekday_indexed weekday::operator[](unsigned int _Index) const noexcept { + return {*this, _Index}; + } + _NODISCARD constexpr weekday_last weekday::operator[](last_spec) const noexcept { + return weekday_last{*this}; + } + + class month_day { + public: + month_day() = default; + constexpr month_day(const month& _Month_, const day& _Day_) noexcept : _Month{_Month_}, _Day{_Day_} {} + + _NODISCARD constexpr month month() const noexcept { + return _Month; + } + _NODISCARD constexpr day day() const noexcept { + return _Day; + } + _NODISCARD constexpr bool ok() const noexcept { + if (!_Month.ok() || !_Day.ok()) { + return false; + } + + const auto _Da = static_cast(_Day); + const auto _Mo = static_cast(_Month); + if (_Mo == 2) { + return _Da <= 29; + } + + if (_Mo == 4 || _Mo == 6 || _Mo == 9 || _Mo == 11) { + return _Da <= 30; + } + return true; + } + + private: + _CHRONO month _Month; + _CHRONO day _Day; + }; + + _NODISCARD constexpr bool operator==(const month_day& _Left, const month_day& _Right) noexcept { + return _Left.month() == _Right.month() && _Left.day() == _Right.day(); + } + _NODISCARD constexpr strong_ordering operator<=>(const month_day& _Left, const month_day& _Right) noexcept { + const auto _Comp = _Left.month() <=> _Right.month(); + if (_Comp != 0) { + return _Comp; + } + + return _Left.day() <=> _Right.day(); + } + + class month_day_last { + public: + constexpr explicit month_day_last(const month& _Month_) noexcept : _Month{_Month_} {} + + _NODISCARD constexpr month month() const noexcept { + return _Month; + } + _NODISCARD constexpr bool ok() const noexcept { + return _Month.ok(); + } + + private: + _CHRONO month _Month; + }; + + _NODISCARD constexpr bool operator==(const month_day_last& _Left, const month_day_last& _Right) noexcept { + return _Left.month() == _Right.month(); + } + _NODISCARD constexpr strong_ordering operator<=>( + const month_day_last& _Left, const month_day_last& _Right) noexcept { + return _Left.month() <=> _Right.month(); + } + + class month_weekday { + public: + constexpr month_weekday(const month& _Month_, const weekday_indexed& _Wdi) noexcept + : _Month{_Month_}, _Weekday_index{_Wdi} {} + + _NODISCARD constexpr month month() const noexcept { + return _Month; + } + _NODISCARD constexpr weekday_indexed weekday_indexed() const noexcept { + return _Weekday_index; + } + + _NODISCARD constexpr bool ok() const noexcept { + return _Month.ok() && _Weekday_index.ok(); + } + + private: + _CHRONO month _Month; + _CHRONO weekday_indexed _Weekday_index; + }; + + _NODISCARD constexpr bool operator==(const month_weekday& _Left, const month_weekday& _Right) noexcept { + return _Left.month() == _Right.month() && _Left.weekday_indexed() == _Right.weekday_indexed(); + } + + class month_weekday_last { + public: + constexpr month_weekday_last(const month& _Month_, const weekday_last& _Wdl) noexcept + : _Month{_Month_}, _Weekday_last{_Wdl} {} + + _NODISCARD constexpr month month() const noexcept { + return _Month; + } + _NODISCARD constexpr weekday_last weekday_last() const noexcept { + return _Weekday_last; + } + _NODISCARD constexpr bool ok() const noexcept { + return _Month.ok() && _Weekday_last.ok(); + } + + private: + _CHRONO month _Month; + _CHRONO weekday_last _Weekday_last; + }; + + _NODISCARD constexpr bool operator==(const month_weekday_last& _Left, const month_weekday_last& _Right) noexcept { + return _Left.month() == _Right.month() && _Left.weekday_last() == _Right.weekday_last(); + } + + class year_month { + public: + year_month() = default; + constexpr year_month(const year& _Year_, const month& _Month_) noexcept : _Year{_Year_}, _Month{_Month_} {} + + _NODISCARD constexpr year year() const noexcept { + return _Year; + } + _NODISCARD constexpr month month() const noexcept { + return _Month; + } + + template + constexpr year_month& operator+=(const months& _Months) noexcept; + template + constexpr year_month& operator-=(const months& _Months) noexcept; + constexpr year_month& operator+=(const years& _Years) noexcept; + constexpr year_month& operator-=(const years& _Years) noexcept; + + _NODISCARD constexpr bool ok() const noexcept { + return _Year.ok() && _Month.ok(); + } + + private: + _CHRONO year _Year; + _CHRONO month _Month; + }; + + _NODISCARD constexpr bool operator==(const year_month& _Left, const year_month& _Right) noexcept { + return _Left.year() == _Right.year() && _Left.month() == _Right.month(); + } + _NODISCARD constexpr strong_ordering operator<=>(const year_month& _Left, const year_month& _Right) noexcept { + const auto _Comp = _Left.year() <=> _Right.year(); + if (_Comp != 0) { + return _Comp; + } + + return _Left.month() <=> _Right.month(); + } + + template + _NODISCARD constexpr year_month operator+(const year_month& _Left, const months& _Right) noexcept { + const auto _Mo = static_cast(static_cast(_Left.month())) + (_Right.count() - 1); + const auto _Div = (_Mo >= 0 ? _Mo : _Mo - 11) / 12; + return year_month{_Left.year() + years{_Div}, month{static_cast(_Mo - _Div * 12 + 1)}}; + } + template + _NODISCARD constexpr year_month operator+(const months& _Left, const year_month& _Right) noexcept { + return _Right + _Left; + } + + template + _NODISCARD constexpr year_month operator-(const year_month& _Left, const months& _Right) noexcept { + return _Left + -_Right; + } + + _NODISCARD constexpr months operator-(const year_month& _Left, const year_month& _Right) noexcept { + return _Left.year() - _Right.year() + + months{static_cast(static_cast(_Left.month())) + - static_cast(static_cast(_Right.month()))}; + } + + _NODISCARD constexpr year_month operator+(const year_month& _Left, const years& _Right) noexcept { + return {year{_Left.year() + _Right}, _Left.month()}; + } + + _NODISCARD constexpr year_month operator+(const years& _Left, const year_month& _Right) noexcept { + return _Right + _Left; + } + + _NODISCARD constexpr year_month operator-(const year_month& _Left, const years& _Right) noexcept { + return _Left + -_Right; + } + + template + constexpr year_month& year_month::operator+=(const months& _Months) noexcept { + *this = *this + _Months; + return *this; + } + template + constexpr year_month& year_month::operator-=(const months& _Months) noexcept { + *this = *this - _Months; + return *this; + } + constexpr year_month& year_month::operator+=(const years& _Years) noexcept { + *this = *this + _Years; + return *this; + } + constexpr year_month& year_month::operator-=(const years& _Years) noexcept { + *this = *this - _Years; + return *this; + } + + inline constexpr day _Last_day_table[] = { + day{31}, day{28}, day{31}, day{30}, day{31}, day{30}, day{31}, day{31}, day{30}, day{31}, day{30}, day{31}}; + + _NODISCARD constexpr day _Last_day(const year& _Year, const month& _Month) { + if (_Month == month{2} && _Year.is_leap()) { + return day{29}; + } + + return _Last_day_table[static_cast(_Month) - 1]; + } + + class year_month_day_last; + + class year_month_day { + public: + year_month_day() = default; + constexpr year_month_day(const year& _Year_, const month& _Month_, const day& _Day_) noexcept + : _Year{_Year_}, _Month{_Month_}, _Day{_Day_} {} + constexpr year_month_day(const year_month_day_last& _Ymdl) noexcept; + constexpr year_month_day(const sys_days& _Sys_days) noexcept + : year_month_day{_Civil_from_days(_Sys_days.time_since_epoch().count())} {} + constexpr explicit year_month_day(const local_days& _Local_days) noexcept + : year_month_day{_Civil_from_days(_Local_days.time_since_epoch().count())} {} + + template + constexpr year_month_day& operator+=(const months& _Months) noexcept; + template + constexpr year_month_day& operator-=(const months& _Months) noexcept; + constexpr year_month_day& operator+=(const years& _Years) noexcept; + constexpr year_month_day& operator-=(const years& _Years) noexcept; + + _NODISCARD constexpr year year() const noexcept { + return _Year; + } + _NODISCARD constexpr month month() const noexcept { + return _Month; + } + _NODISCARD constexpr day day() const noexcept { + return _Day; + } + + _NODISCARD constexpr operator sys_days() const noexcept { + return sys_days{_Days_from_civil()}; + } + _NODISCARD constexpr explicit operator local_days() const noexcept { + return local_days{static_cast(*this).time_since_epoch()}; + } + _NODISCARD constexpr bool ok() const noexcept { + if (!_Year.ok() || !_Month.ok()) { + return false; + } + + return _Day >= _CHRONO day{1} && _Day <= _Last_day(_Year, _Month); + } + + private: + _CHRONO year _Year; + _CHRONO month _Month; + _CHRONO day _Day; + + // courtesy of Howard Hinnant + // https://howardhinnant.github.io/date_algorithms.html#civil_from_days + _NODISCARD static constexpr year_month_day _Civil_from_days(int _Tp) noexcept { + static_assert(numeric_limits::digits >= 18); + static_assert(numeric_limits::digits >= 20); + const int _Zx = _Tp + 719468; // Shift epoch to 0000-03-01 + const int _Era = (_Zx >= 0 ? _Zx : _Zx - 146096) / 146097; + const unsigned int _Day_of_era = static_cast(_Zx - _Era * 146097); // [0, 146096] + const unsigned int _Year_of_era = + (_Day_of_era - _Day_of_era / 1460 + _Day_of_era / 36524 - _Day_of_era / 146096) / 365; // [0, 399] + const int _Year = static_cast(_Year_of_era) + _Era * 400; // Where March is the first month + const unsigned int _Day_of_year = + _Day_of_era - (365 * _Year_of_era + _Year_of_era / 4 - _Year_of_era / 100); // [0, 365] + const unsigned int _Mp = (5 * _Day_of_year + 2) / 153; // [0, 11] + const unsigned int _Day = _Day_of_year - (153 * _Mp + 2) / 5 + 1; // [1, 31] + const unsigned int _Month = _Mp + (_Mp < 10 ? 3 : static_cast(-9)); // [1, 12] + return year_month_day{_CHRONO year{_Year + (_Month <= 2)}, _CHRONO month{_Month}, _CHRONO day{_Day}}; + } + // courtesy of Howard Hinnant + // https://howardhinnant.github.io/date_algorithms.html#days_from_civil + _NODISCARD constexpr days _Days_from_civil() const noexcept { + static_assert(numeric_limits::digits >= 18); + static_assert(numeric_limits::digits >= 20); + const int _Ye = static_cast(_Year) - (_Month <= _CHRONO month{2}); + const unsigned int _Mo = static_cast(_Month); + const int _Era = (_Ye >= 0 ? _Ye : _Ye - 399) / 400; + const unsigned int _Year_of_era = static_cast(_Ye - _Era * 400); // [0, 399] + const unsigned int _Day_of_year = (153 * (_Mo + (_Mo > 2 ? static_cast(-3) : 9)) + 2) / 5 + + static_cast(_Day) - 1; // [0, 365] + const unsigned int _Day_of_era = + _Year_of_era * 365 + _Year_of_era / 4 - _Year_of_era / 100 + _Day_of_year; // [0, 146096] + return days{_Era * 146097 + static_cast(_Day_of_era) - 719468}; + } + }; + + _NODISCARD constexpr bool operator==(const year_month_day& _Left, const year_month_day& _Right) noexcept { + return _Left.year() == _Right.year() && _Left.month() == _Right.month() && _Left.day() == _Right.day(); + } + _NODISCARD constexpr strong_ordering operator<=>( + const year_month_day& _Left, const year_month_day& _Right) noexcept { + auto _Comp = _Left.year() <=> _Right.year(); + if (_Comp != 0) { + return _Comp; + } + + _Comp = _Left.month() <=> _Right.month(); + if (_Comp != 0) { + return _Comp; + } + + return _Left.day() <=> _Right.day(); + } + + template + _NODISCARD constexpr year_month_day operator+(const year_month_day& _Left, const months& _Right) noexcept { + const auto _Ym = year_month{_Left.year(), _Left.month()} + _Right; + return {_Ym.year(), _Ym.month(), _Left.day()}; + } + + template + _NODISCARD constexpr year_month_day operator+(const months& _Left, const year_month_day& _Right) noexcept { + return _Right + _Left; + } + + template + _NODISCARD constexpr year_month_day operator-(const year_month_day& _Left, const months& _Right) noexcept { + return _Left + -_Right; + } + + _NODISCARD constexpr year_month_day operator+(const year_month_day& _Left, const years& _Right) noexcept { + return {_Left.year() + _Right, _Left.month(), _Left.day()}; + } + + _NODISCARD constexpr year_month_day operator+(const years& _Left, const year_month_day& _Right) noexcept { + return _Right + _Left; + } + + _NODISCARD constexpr year_month_day operator-(const year_month_day& _Left, const years& _Right) noexcept { + return _Left + -_Right; + } + + template + constexpr year_month_day& year_month_day::operator+=(const months& _Months) noexcept { + *this = *this + _Months; + return *this; + } + template + constexpr year_month_day& year_month_day::operator-=(const months& _Months) noexcept { + *this = *this - _Months; + return *this; + } + constexpr year_month_day& year_month_day::operator+=(const years& _Years) noexcept { + *this = *this + _Years; + return *this; + } + constexpr year_month_day& year_month_day::operator-=(const years& _Years) noexcept { + *this = *this - _Years; + return *this; + } + + class year_month_day_last { + public: + constexpr year_month_day_last(const year& _Year_, const month_day_last& _Mdl) noexcept + : _Year{_Year_}, _Month_day_last{_Mdl} {} + + template + constexpr year_month_day_last& operator+=(const months& _Months) noexcept; + template + constexpr year_month_day_last& operator-=(const months& _Months) noexcept; + constexpr year_month_day_last& operator+=(const years& _Years) noexcept; + constexpr year_month_day_last& operator-=(const years& _Years) noexcept; + + _NODISCARD constexpr year year() const noexcept { + return _Year; + } + _NODISCARD constexpr month month() const noexcept { + return _Month_day_last.month(); + } + _NODISCARD constexpr month_day_last month_day_last() const noexcept { + return _Month_day_last; + } + _NODISCARD constexpr day day() const noexcept { + return _Last_day(year(), month()); + } + + _NODISCARD constexpr operator sys_days() const noexcept { + return sys_days{year_month_day{year(), month(), day()}}; + } + _NODISCARD constexpr explicit operator local_days() const noexcept { + return local_days{static_cast(*this).time_since_epoch()}; + } + _NODISCARD constexpr bool ok() const noexcept { + return _Year.ok() && _Month_day_last.ok(); + } + + private: + _CHRONO year _Year; + _CHRONO month_day_last _Month_day_last; + }; + + _NODISCARD constexpr bool operator==(const year_month_day_last& _Left, const year_month_day_last& _Right) noexcept { + return _Left.year() == _Right.year() && _Left.month_day_last() == _Right.month_day_last(); + } + _NODISCARD constexpr strong_ordering operator<=>( + const year_month_day_last& _Left, const year_month_day_last& _Right) noexcept { + const auto _Comp = _Left.year() <=> _Right.year(); + if (_Comp != 0) { + return _Comp; + } + + return _Left.month_day_last() <=> _Right.month_day_last(); + } + + template + _NODISCARD constexpr year_month_day_last operator+( + const year_month_day_last& _Left, const months& _Right) noexcept { + const auto _Ym = year_month{_Left.year(), _Left.month()} + _Right; + return {_Ym.year(), month_day_last{_Ym.month()}}; + } + template + _NODISCARD constexpr year_month_day_last operator+( + const months& _Left, const year_month_day_last& _Right) noexcept { + return _Right + _Left; + } + + template + _NODISCARD constexpr year_month_day_last operator-( + const year_month_day_last& _Left, const months& _Right) noexcept { + return _Left + -_Right; + } + + _NODISCARD constexpr year_month_day_last operator+(const year_month_day_last& _Left, const years& _Right) noexcept { + return {_Left.year() + _Right, _Left.month_day_last()}; + } + _NODISCARD constexpr year_month_day_last operator+(const years& _Left, const year_month_day_last& _Right) noexcept { + return _Right + _Left; + } + _NODISCARD constexpr year_month_day_last operator-(const year_month_day_last& _Left, const years& _Right) noexcept { + return _Left + -_Right; + } + + template + constexpr year_month_day_last& year_month_day_last::operator+=(const months& _Months) noexcept { + *this = *this + _Months; + return *this; + } + template + constexpr year_month_day_last& year_month_day_last::operator-=(const months& _Months) noexcept { + *this = *this - _Months; + return *this; + } + constexpr year_month_day_last& year_month_day_last::operator+=(const years& _Years) noexcept { + *this = *this + _Years; + return *this; + } + constexpr year_month_day_last& year_month_day_last::operator-=(const years& _Years) noexcept { + *this = *this - _Years; + return *this; + } + + constexpr year_month_day::year_month_day(const year_month_day_last& _Ymdl) noexcept + : _Year{_Ymdl.year()}, _Month{_Ymdl.month()}, _Day{_Ymdl.day()} {} + + class year_month_weekday { + public: + year_month_weekday() = default; + constexpr year_month_weekday(const year& _Year_, const month& _Month_, const weekday_indexed& _Wdi) noexcept + : _Year{_Year_}, _Month{_Month_}, _Weekday_index{_Wdi} {} + constexpr year_month_weekday(const sys_days& _Sys_days) noexcept + : year_month_weekday{_Ymwd_from_days(_Sys_days.time_since_epoch())} {} + constexpr explicit year_month_weekday(const local_days& _Local_days) noexcept + : year_month_weekday{_Ymwd_from_days(_Local_days.time_since_epoch())} {} + + template + constexpr year_month_weekday& operator+=(const months& _Months) noexcept; + template + constexpr year_month_weekday& operator-=(const months& _Months) noexcept; + constexpr year_month_weekday& operator+=(const years& _Years) noexcept; + constexpr year_month_weekday& operator-=(const years& _Years) noexcept; + + _NODISCARD constexpr year year() const noexcept { + return _Year; + } + _NODISCARD constexpr month month() const noexcept { + return _Month; + } + _NODISCARD constexpr weekday weekday() const noexcept { + return _Weekday_index.weekday(); + } + _NODISCARD constexpr unsigned int index() const noexcept { + return _Weekday_index.index(); + } + _NODISCARD constexpr weekday_indexed weekday_indexed() const noexcept { + return _Weekday_index; + } + + _NODISCARD constexpr operator sys_days() const noexcept { + const sys_days _First = year_month_day{_Year, _Month, day{1}}; + const days _Diff = weekday() - _CHRONO weekday{_First}; + const days _Days = _Diff + days{(static_cast(index()) - 1) * 7}; + return _First + _Days; + } + _NODISCARD constexpr explicit operator local_days() const noexcept { + return local_days{static_cast(*this).time_since_epoch()}; + } + _NODISCARD constexpr bool ok() const noexcept { + if (!_Year.ok() || !_Month.ok() || !_Weekday_index.ok()) { + return false; + } + + if (_Weekday_index.index() <= 4) { + return true; + } + + // As index() == 5 is not always valid + // Determine the date of the first weekday and check if + days{28} is <= last day of the month + const sys_days _First_of_month = year_month_day{_Year, _Month, day{1}}; + const days _First_weekday = weekday() - _CHRONO weekday{_First_of_month} + days{1}; + const days _Last = _First_weekday + days{28}; + return static_cast(_Last.count()) <= static_cast(_Last_day(_Year, _Month)); + } + + private: + _CHRONO year _Year; + _CHRONO month _Month; + _CHRONO weekday_indexed _Weekday_index; + + _NODISCARD static constexpr year_month_weekday _Ymwd_from_days(days _Dp) noexcept { + const _CHRONO year_month_day _Ymd = sys_days{_Dp}; + const _CHRONO weekday _Wd = sys_days{_Dp}; + const auto _Idx = ((static_cast(_Ymd.day()) - 1) / 7) + 1; + return {_Ymd.year(), _Ymd.month(), _Wd[_Idx]}; + } + }; + + _NODISCARD constexpr bool operator==(const year_month_weekday& _Left, const year_month_weekday& _Right) noexcept { + return _Left.year() == _Right.year() && _Left.month() == _Right.month() + && _Left.weekday_indexed() == _Right.weekday_indexed(); + } + + template + _NODISCARD constexpr year_month_weekday operator+(const year_month_weekday& _Left, const months& _Right) noexcept { + const auto _Ym = year_month{_Left.year(), _Left.month()} + _Right; + return {_Ym.year(), _Ym.month(), _Left.weekday_indexed()}; + } + template + _NODISCARD constexpr year_month_weekday operator+(const months& _Left, const year_month_weekday& _Right) noexcept { + return _Right + _Left; + } + + template + _NODISCARD constexpr year_month_weekday operator-(const year_month_weekday& _Left, const months& _Right) noexcept { + return _Left + -_Right; + } + + _NODISCARD constexpr year_month_weekday operator+(const year_month_weekday& _Left, const years& _Right) noexcept { + return year_month_weekday{_Left.year() + _Right, _Left.month(), _Left.weekday_indexed()}; + } + _NODISCARD constexpr year_month_weekday operator+(const years& _Left, const year_month_weekday& _Right) noexcept { + return _Right + _Left; + } + + _NODISCARD constexpr year_month_weekday operator-(const year_month_weekday& _Left, const years& _Right) noexcept { + return _Left + -_Right; + } + + template + constexpr year_month_weekday& year_month_weekday::operator+=(const months& _Months) noexcept { + *this = *this + _Months; + return *this; + } + template + constexpr year_month_weekday& year_month_weekday::operator-=(const months& _Months) noexcept { + *this = *this - _Months; + return *this; + } + constexpr year_month_weekday& year_month_weekday::operator+=(const years& _Years) noexcept { + *this = *this + _Years; + return *this; + } + constexpr year_month_weekday& year_month_weekday::operator-=(const years& _Years) noexcept { + *this = *this - _Years; + return *this; + } + + class year_month_weekday_last { + public: + constexpr year_month_weekday_last(const year& _Year_, const month& _Month_, const weekday_last& _Wdl) noexcept + : _Year{_Year_}, _Month{_Month_}, _Weekday_last{_Wdl} {} + + template + constexpr year_month_weekday_last& operator+=(const months& _Months) noexcept; + template + constexpr year_month_weekday_last& operator-=(const months& _Months) noexcept; + constexpr year_month_weekday_last& operator+=(const years& _Years) noexcept; + constexpr year_month_weekday_last& operator-=(const years& _Years) noexcept; + + _NODISCARD constexpr year year() const noexcept { + return _Year; + } + _NODISCARD constexpr month month() const noexcept { + return _Month; + } + _NODISCARD constexpr weekday weekday() const noexcept { + return _Weekday_last.weekday(); + } + + _NODISCARD constexpr weekday_last weekday_last() const noexcept { + return _Weekday_last; + } + + _NODISCARD constexpr operator sys_days() const noexcept { + const sys_days _Last = year_month_day_last{_Year, month_day_last{_Month}}; + const auto _Diff = _CHRONO weekday{_Last} - weekday(); + return _Last - _Diff; + } + _NODISCARD constexpr explicit operator local_days() const noexcept { + return local_days{static_cast(*this).time_since_epoch()}; + } + _NODISCARD constexpr bool ok() const noexcept { + return _Year.ok() && _Month.ok() && _Weekday_last.ok(); + } + + private: + _CHRONO year _Year; + _CHRONO month _Month; + _CHRONO weekday_last _Weekday_last; + }; + + _NODISCARD constexpr bool operator==( + const year_month_weekday_last& _Left, const year_month_weekday_last& _Right) noexcept { + return _Left.year() == _Right.year() && _Left.month() == _Right.month() + && _Left.weekday_last() == _Right.weekday_last(); + } + + template + _NODISCARD constexpr year_month_weekday_last operator+( + const year_month_weekday_last& _Left, const months& _Right) noexcept { + const auto _Ym = year_month{_Left.year(), _Left.month()} + _Right; + return {_Ym.year(), _Ym.month(), _Left.weekday_last()}; + } + template + _NODISCARD constexpr year_month_weekday_last operator+( + const months& _Left, const year_month_weekday_last& _Right) noexcept { + return _Right + _Left; + } + + template + _NODISCARD constexpr year_month_weekday_last operator-( + const year_month_weekday_last& _Left, const months& _Right) noexcept { + return _Left + -_Right; + } + + _NODISCARD constexpr year_month_weekday_last operator+( + const year_month_weekday_last& _Left, const years& _Right) noexcept { + return {_Left.year() + _Right, _Left.month(), _Left.weekday_last()}; + } + _NODISCARD constexpr year_month_weekday_last operator+( + const years& _Left, const year_month_weekday_last& _Right) noexcept { + return _Right + _Left; + } + + _NODISCARD constexpr year_month_weekday_last operator-( + const year_month_weekday_last& _Left, const years& _Right) noexcept { + return _Left + -_Right; + } + + template + constexpr year_month_weekday_last& year_month_weekday_last::operator+=(const months& _Months) noexcept { + *this = *this + _Months; + return *this; + } + template + constexpr year_month_weekday_last& year_month_weekday_last::operator-=(const months& _Months) noexcept { + *this = *this - _Months; + return *this; + } + constexpr year_month_weekday_last& year_month_weekday_last::operator+=(const years& _Years) noexcept { + *this = *this + _Years; + return *this; + } + constexpr year_month_weekday_last& year_month_weekday_last::operator-=(const years& _Years) noexcept { + *this = *this - _Years; + return *this; + } + + // Civil calendar conventional syntax operators + _NODISCARD constexpr year_month operator/(const year& _Year, const month& _Month) noexcept { + return {_Year, _Month}; + } + _NODISCARD constexpr year_month operator/(const year& _Year, int _Month) noexcept { + return _Year / month{static_cast(_Month)}; + } + _NODISCARD constexpr month_day operator/(const month& _Month, const day& _Day) noexcept { + return {_Month, _Day}; + } + _NODISCARD constexpr month_day operator/(const month& _Month, int _Day) noexcept { + return _Month / day{static_cast(_Day)}; + } + _NODISCARD constexpr month_day operator/(int _Month, const day& _Day) noexcept { + return month{static_cast(_Month)} / _Day; + } + _NODISCARD constexpr month_day operator/(const day& _Day, const month& _Month) noexcept { + return _Month / _Day; + } + _NODISCARD constexpr month_day operator/(const day& _Day, int _Month) noexcept { + return month{static_cast(_Month)} / _Day; + } + _NODISCARD constexpr month_day_last operator/(const month& _Month, last_spec) noexcept { + return month_day_last{_Month}; + } + _NODISCARD constexpr month_day_last operator/(int _Month, last_spec) noexcept { + return month{static_cast(_Month)} / last; + } + _NODISCARD constexpr month_day_last operator/(last_spec, const month& _Month) noexcept { + return _Month / last; + } + _NODISCARD constexpr month_day_last operator/(last_spec, int _Month) noexcept { + return month{static_cast(_Month)} / last; + } + _NODISCARD constexpr month_weekday operator/(const month& _Month, const weekday_indexed& _Wdi) noexcept { + return {_Month, _Wdi}; + } + _NODISCARD constexpr month_weekday operator/(int _Month, const weekday_indexed& _Wdi) noexcept { + return month{static_cast(_Month)} / _Wdi; + } + _NODISCARD constexpr month_weekday operator/(const weekday_indexed& _Wdi, const month& _Month) noexcept { + return _Month / _Wdi; + } + _NODISCARD constexpr month_weekday operator/(const weekday_indexed& _Wdi, int _Month) noexcept { + return month{static_cast(_Month)} / _Wdi; + } + _NODISCARD constexpr month_weekday_last operator/(const month& _Month, const weekday_last& _Wdl) noexcept { + return {_Month, _Wdl}; + } + _NODISCARD constexpr month_weekday_last operator/(int _Month, const weekday_last& _Wdl) noexcept { + return month{static_cast(_Month)} / _Wdl; + } + _NODISCARD constexpr month_weekday_last operator/(const weekday_last& _Wdl, const month& _Month) noexcept { + return _Month / _Wdl; + } + _NODISCARD constexpr month_weekday_last operator/(const weekday_last& _Wdl, int _Month) noexcept { + return month{static_cast(_Month)} / _Wdl; + } + _NODISCARD constexpr year_month_day operator/(const year_month& _Ym, const day& _Day) noexcept { + return {_Ym.year(), _Ym.month(), _Day}; + } + _NODISCARD constexpr year_month_day operator/(const year_month& _Ym, int _Day) noexcept { + return _Ym / day{static_cast(_Day)}; + } + _NODISCARD constexpr year_month_day operator/(const year& _Year, const month_day& _Md) noexcept { + return _Year / _Md.month() / _Md.day(); + } + _NODISCARD constexpr year_month_day operator/(int _Year, const month_day& _Md) noexcept { + return year{_Year} / _Md.month() / _Md.day(); + } + _NODISCARD constexpr year_month_day operator/(const month_day& _Md, const year& _Year) noexcept { + return _Year / _Md.month() / _Md.day(); + } + _NODISCARD constexpr year_month_day operator/(const month_day& _Md, int _Year) noexcept { + return year{_Year} / _Md.month() / _Md.day(); + } + _NODISCARD constexpr year_month_day_last operator/(const year_month& _Ym, last_spec) noexcept { + return {_Ym.year(), month_day_last{_Ym.month()}}; + } + _NODISCARD constexpr year_month_day_last operator/(const year& _Year, const month_day_last& _Mdl) noexcept { + return {_Year, _Mdl}; + } + _NODISCARD constexpr year_month_day_last operator/(int _Year, const month_day_last& _Mdl) noexcept { + return year{_Year} / _Mdl; + } + _NODISCARD constexpr year_month_day_last operator/(const month_day_last& _Mdl, const year& _Year) noexcept { + return _Year / _Mdl; + } + _NODISCARD constexpr year_month_day_last operator/(const month_day_last& _Mdl, int _Year) noexcept { + return year{_Year} / _Mdl; + } + _NODISCARD constexpr year_month_weekday operator/(const year_month& _Ym, const weekday_indexed& _Wdi) noexcept { + return year_month_weekday{_Ym.year(), _Ym.month(), _Wdi}; + } + _NODISCARD constexpr year_month_weekday operator/(const year& _Year, const month_weekday& _Mwd) noexcept { + return year_month_weekday{_Year, _Mwd.month(), _Mwd.weekday_indexed()}; + } + _NODISCARD constexpr year_month_weekday operator/(int _Year, const month_weekday& _Mwd) noexcept { + return year{_Year} / _Mwd; + } + _NODISCARD constexpr year_month_weekday operator/(const month_weekday& _Mwd, const year& _Year) noexcept { + return _Year / _Mwd; + } + _NODISCARD constexpr year_month_weekday operator/(const month_weekday& _Mwd, int _Year) noexcept { + return year{_Year} / _Mwd; + } + _NODISCARD constexpr year_month_weekday_last operator/(const year_month& _Ym, const weekday_last& _Wdl) noexcept { + return {_Ym.year(), _Ym.month(), _Wdl}; + } + _NODISCARD constexpr year_month_weekday_last operator/( + const year& _Year, const month_weekday_last& _Mwdl) noexcept { + return {_Year, _Mwdl.month(), _Mwdl.weekday_last()}; + } + _NODISCARD constexpr year_month_weekday_last operator/(int _Year, const month_weekday_last& _Mwdl) noexcept { + return year{_Year} / _Mwdl; + } + _NODISCARD constexpr year_month_weekday_last operator/( + const month_weekday_last& _Mwdl, const year& _Year) noexcept { + return _Year / _Mwdl; + } + _NODISCARD constexpr year_month_weekday_last operator/(const month_weekday_last& _Mwdl, int _Year) noexcept { + return year{_Year} / _Mwdl; + } + + // Calendrical constants + inline constexpr weekday Sunday{0}; + inline constexpr weekday Monday{1}; + inline constexpr weekday Tuesday{2}; + inline constexpr weekday Wednesday{3}; + inline constexpr weekday Thursday{4}; + inline constexpr weekday Friday{5}; + inline constexpr weekday Saturday{6}; + + inline constexpr month January{1}; + inline constexpr month February{2}; + inline constexpr month March{3}; + inline constexpr month April{4}; + inline constexpr month May{5}; + inline constexpr month June{6}; + inline constexpr month July{7}; + inline constexpr month August{8}; + inline constexpr month September{9}; + inline constexpr month October{10}; + inline constexpr month November{11}; + inline constexpr month December{12}; + + _NODISCARD constexpr intmax_t _Pow10(const unsigned int _Exp) { + intmax_t _Result = 1; + for (unsigned int _Ix = 0; _Ix < _Exp; ++_Ix) { + _Result *= 10; + } + return _Result; + } + + template + requires _Is_duration_v<_Duration> class hh_mm_ss { + public: + static constexpr unsigned int fractional_width = [] { + auto _Num = _Duration::period::num; + constexpr auto _Den = _Duration::period::den; + // Returns the number of fractional digits of _Num / _Den in the range [0, 18]. + // If it can't be represented, 6 is returned. + // Example: _Fractional_width(1, 8) would return 3 for 0.125. + _STL_ASSERT(_Num > 0 && _Den > 0, "Numerator and denominator can't be less than 1."); + unsigned int _Result = 0; + for (; _Num % _Den != 0 && _Result < 19; _Num = _Num % _Den * 10, ++_Result) { + } + return _Result == 19 ? 6 : _Result; + }(); + using precision = + duration, ratio<1, _Pow10(fractional_width)>>; + + constexpr hh_mm_ss() noexcept : hh_mm_ss{_Duration::zero()} {} + // clang-format off + constexpr explicit hh_mm_ss(_Duration _Dur) + : _Is_neg{_Dur < _Duration::zero()}, + _Hours{_CHRONO duration_cast<_CHRONO hours>(_CHRONO abs(_Dur))}, + _Mins{_CHRONO duration_cast<_CHRONO minutes>(_CHRONO abs(_Dur) - hours())}, + _Secs{_CHRONO duration_cast<_CHRONO seconds>(_CHRONO abs(_Dur) - hours() - minutes())} { + // clang-format on + if constexpr (treat_as_floating_point_v) { + _Sub_secs = _CHRONO abs(_Dur) - hours() - minutes() - seconds(); + } else { + _Sub_secs = _CHRONO duration_cast(_CHRONO abs(_Dur) - hours() - minutes() - seconds()); + } + } + + _NODISCARD constexpr bool is_negative() const noexcept { + return _Is_neg; + } + _NODISCARD constexpr hours hours() const noexcept { + return _Hours; + } + _NODISCARD constexpr minutes minutes() const noexcept { + return _Mins; + } + _NODISCARD constexpr seconds seconds() const noexcept { + return _Secs; + } + _NODISCARD constexpr precision subseconds() const noexcept { + return _Sub_secs; + } + + _NODISCARD constexpr explicit operator precision() const noexcept { + return to_duration(); + } + _NODISCARD constexpr precision to_duration() const noexcept { + const auto _Dur = _Hours + _Mins + _Secs + _Sub_secs; + return _Is_neg ? -_Dur : _Dur; + } + + private: + bool _Is_neg; + _CHRONO hours _Hours; + _CHRONO minutes _Mins; + _CHRONO seconds _Secs; + precision _Sub_secs; + }; + + _NODISCARD constexpr bool is_am(const hours& _Hours) noexcept { + return _Hours >= hours{0} && _Hours <= hours{11}; + } + _NODISCARD constexpr bool is_pm(const hours& _Hours) noexcept { + return _Hours >= hours{12} && _Hours <= hours{23}; + } + + _NODISCARD constexpr hours make12(const hours& _Hours) noexcept { + const auto _H_count{_Hours.count()}; + auto _Ret{_H_count == 0 ? 12 : _H_count}; + if (_Ret > 12) { + _Ret -= 12; + } + + return hours{_Ret}; + } + _NODISCARD constexpr hours make24(const hours& _Hours, bool _Is_pm) noexcept { + const auto _H_count{_Hours.count()}; + auto _Ret{_H_count == 12 ? 0 : _H_count}; + if (_Is_pm) { + _Ret += 12; + } + + return hours{_Ret}; + } #endif // _HAS_CXX20 } // namespace chrono // HELPERS template -_NODISCARD bool _To_xtime_10_day_clamped(_CSTD xtime& _Xt, const chrono::duration<_Rep, _Period>& _Rel_time) noexcept( +_NODISCARD bool _To_xtime_10_day_clamped(_CSTD xtime& _Xt, const _CHRONO duration<_Rep, _Period>& _Rel_time) noexcept( is_arithmetic_v<_Rep>) { // Convert duration to xtime, maximum 10 days from now, returns whether clamping occurred. // If clamped, timeouts will be transformed into spurious non-timeout wakes, due to ABI restrictions where // the other side of the DLL boundary overflows int32_t milliseconds. // Every function calling this one is TRANSITION, ABI - constexpr chrono::nanoseconds _Ten_days{chrono::hours{24} * 10}; - constexpr chrono::duration _Ten_days_d{_Ten_days}; - chrono::nanoseconds _Tx0 = chrono::system_clock::now().time_since_epoch(); + constexpr _CHRONO nanoseconds _Ten_days{_CHRONO hours{24} * 10}; + constexpr _CHRONO duration _Ten_days_d{_Ten_days}; + _CHRONO nanoseconds _Tx0 = _CHRONO system_clock::now().time_since_epoch(); const bool _Clamped = _Ten_days_d < _Rel_time; if (_Clamped) { _Tx0 += _Ten_days; } else { - _Tx0 += chrono::duration_cast(_Rel_time); + _Tx0 += _CHRONO duration_cast<_CHRONO nanoseconds>(_Rel_time); } - const auto _Whole_seconds = chrono::duration_cast(_Tx0); + const auto _Whole_seconds = _CHRONO duration_cast<_CHRONO seconds>(_Tx0); _Xt.sec = _Whole_seconds.count(); _Tx0 -= _Whole_seconds; _Xt.nsec = static_cast(_Tx0.count()); @@ -730,58 +2092,66 @@ _NODISCARD bool _To_xtime_10_day_clamped(_CSTD xtime& _Xt, const chrono::duratio // duration LITERALS inline namespace literals { inline namespace chrono_literals { - _NODISCARD constexpr chrono::hours operator"" h(unsigned long long _Val) noexcept /* strengthened */ { - return chrono::hours(_Val); + _NODISCARD constexpr _CHRONO hours operator"" h(unsigned long long _Val) noexcept /* strengthened */ { + return _CHRONO hours(_Val); } - _NODISCARD constexpr chrono::duration> operator"" h(long double _Val) noexcept + _NODISCARD constexpr _CHRONO duration> operator"" h(long double _Val) noexcept /* strengthened */ { - return chrono::duration>(_Val); + return _CHRONO duration>(_Val); } - _NODISCARD constexpr chrono::minutes(operator"" min)(unsigned long long _Val) noexcept /* strengthened */ { - return chrono::minutes(_Val); + _NODISCARD constexpr _CHRONO minutes(operator"" min)(unsigned long long _Val) noexcept /* strengthened */ { + return _CHRONO minutes(_Val); } - _NODISCARD constexpr chrono::duration>(operator"" min)(long double _Val) noexcept + _NODISCARD constexpr _CHRONO duration>(operator"" min)(long double _Val) noexcept /* strengthened */ { - return chrono::duration>(_Val); + return _CHRONO duration>(_Val); } - _NODISCARD constexpr chrono::seconds operator"" s(unsigned long long _Val) noexcept /* strengthened */ { - return chrono::seconds(_Val); + _NODISCARD constexpr _CHRONO seconds operator"" s(unsigned long long _Val) noexcept /* strengthened */ { + return _CHRONO seconds(_Val); } - _NODISCARD constexpr chrono::duration operator"" s(long double _Val) noexcept /* strengthened */ { - return chrono::duration(_Val); + _NODISCARD constexpr _CHRONO duration operator"" s(long double _Val) noexcept /* strengthened */ { + return _CHRONO duration(_Val); } - _NODISCARD constexpr chrono::milliseconds operator"" ms(unsigned long long _Val) noexcept /* strengthened */ { - return chrono::milliseconds(_Val); + _NODISCARD constexpr _CHRONO milliseconds operator"" ms(unsigned long long _Val) noexcept /* strengthened */ { + return _CHRONO milliseconds(_Val); } - _NODISCARD constexpr chrono::duration operator"" ms(long double _Val) noexcept + _NODISCARD constexpr _CHRONO duration operator"" ms(long double _Val) noexcept /* strengthened */ { - return chrono::duration(_Val); + return _CHRONO duration(_Val); } - _NODISCARD constexpr chrono::microseconds operator"" us(unsigned long long _Val) noexcept /* strengthened */ { - return chrono::microseconds(_Val); + _NODISCARD constexpr _CHRONO microseconds operator"" us(unsigned long long _Val) noexcept /* strengthened */ { + return _CHRONO microseconds(_Val); } - _NODISCARD constexpr chrono::duration operator"" us(long double _Val) noexcept + _NODISCARD constexpr _CHRONO duration operator"" us(long double _Val) noexcept /* strengthened */ { - return chrono::duration(_Val); + return _CHRONO duration(_Val); } - _NODISCARD constexpr chrono::nanoseconds operator"" ns(unsigned long long _Val) noexcept /* strengthened */ { - return chrono::nanoseconds(_Val); + _NODISCARD constexpr _CHRONO nanoseconds operator"" ns(unsigned long long _Val) noexcept /* strengthened */ { + return _CHRONO nanoseconds(_Val); } - _NODISCARD constexpr chrono::duration operator"" ns(long double _Val) noexcept + _NODISCARD constexpr _CHRONO duration operator"" ns(long double _Val) noexcept /* strengthened */ { - return chrono::duration(_Val); + return _CHRONO duration(_Val); } +#if _HAS_CXX20 + _NODISCARD constexpr _CHRONO day operator"" d(unsigned long long _Day) noexcept { + return _CHRONO day{static_cast(_Day)}; + } + _NODISCARD constexpr _CHRONO year operator"" y(unsigned long long _Year) noexcept { + return _CHRONO year{static_cast(_Year)}; + } +#endif // _HAS_CXX20 } // namespace chrono_literals } // namespace literals diff --git a/stl/inc/execution b/stl/inc/execution index b1d73575657..7953f238a2a 100644 --- a/stl/inc/execution +++ b/stl/inc/execution @@ -2665,24 +2665,23 @@ bool _Process_sort_work_item(const _RanIt _Basis, _Pr _Pred, _Sort_work_item<_Ra // the return value is false // _Wi's range is completely sorted // _Right_fork_wi is unmodified - using _Diff = _Iter_diff_t<_RanIt>; - constexpr auto _Diffsort_max = static_cast<_Diff>(_ISORT_MAX); - const auto _Size = _Wi._Size; - const auto _First = _Basis + _Wi._Offset; - const auto _Last = _First + _Size; - const auto _Ideal = _Wi._Ideal; - if (_Size <= _Diffsort_max) { + const auto _Size = _Wi._Size; + const auto _First = _Basis + _Wi._Offset; + const auto _Last = _First + _Size; + const auto _Ideal = _Wi._Ideal; + if (_Size <= _Isort_max<_RanIt>) { _Insertion_sort_unchecked(_First, _Last, _Pred); _Work_complete += _Size; return false; } if (0 < _Ideal) { // divide and conquer by partitioning (quicksort) - const auto _Mid = _Partition_by_median_guess_unchecked(_First, _Last, _Pred); - const auto _New_ideal = static_cast<_Diff>(_Ideal / 2 + _Ideal / 4); // allow 1.5 log2(N) divisions - _Wi._Size = _Mid.first - _First; - _Wi._Ideal = _New_ideal; - _Right_fork_wi = {_Mid.second - _Basis, _Last - _Mid.second, _New_ideal}; + const auto _Mid = _Partition_by_median_guess_unchecked(_First, _Last, _Pred); + const auto _New_ideal = + static_cast<_Iter_diff_t<_RanIt>>(_Ideal / 2 + _Ideal / 4); // allow 1.5 log2(N) divisions + _Wi._Size = _Mid.first - _First; + _Wi._Ideal = _New_ideal; + _Right_fork_wi = {_Mid.second - _Basis, _Last - _Mid.second, _New_ideal}; _Work_complete += _Mid.second - _Mid.first; return true; } diff --git a/stl/inc/filesystem b/stl/inc/filesystem index 0f9bec6e02c..c0444a29bd9 100644 --- a/stl/inc/filesystem +++ b/stl/inc/filesystem @@ -2469,6 +2469,14 @@ namespace filesystem { return _Path >= _Rhs._Path; } + // [fs.dir.entry.io], inserter + template + friend _STD basic_ostream<_Elem, _Traits>& operator<<( // TRANSITION, VSO-570323 + _STD basic_ostream<_Elem, _Traits>& _Ostr, const directory_entry& _Entry) { // TRANSITION, VSO-570323 + // insert a directory_entry into a stream + return _Ostr << _Entry.path(); + } + private: void _Refresh(const __std_fs_find_data& _Data) noexcept { _Cached_data._Attributes = _Data._Attributes; diff --git a/stl/inc/hash_map b/stl/inc/hash_map index ffb0da9f74f..d2fc7b3f49d 100644 --- a/stl/inc/hash_map +++ b/stl/inc/hash_map @@ -84,20 +84,21 @@ namespace stdext { }; template - static const _Kty& _Kfn(const pair<_Ty1, _Ty2>& _Val) noexcept { // extract key from element value + _NODISCARD static const _Kty& _Kfn(const pair<_Ty1, _Ty2>& _Val) noexcept { // extract key from element value return _Val.first; } template - static const _Ty2& _Nonkfn(const pair<_Ty1, _Ty2>& _Val) noexcept { // extract non-key from element value + _NODISCARD static const _Ty2& _Nonkfn(const pair<_Ty1, _Ty2>& _Val) noexcept { + // extract non-key from element value return _Val.second; } - float& _Get_max_bucket_size() noexcept { + _NODISCARD float& _Get_max_bucket_size() noexcept { return _Max_buckets; } - const float& _Get_max_bucket_size() const noexcept { + _NODISCARD const float& _Get_max_bucket_size() const noexcept { return _Max_buckets; } @@ -224,7 +225,7 @@ namespace stdext { return this->_Try_emplace(_Keyval).first->_Myval.second; } - mapped_type& at(const key_type& _Keyval) { + _NODISCARD mapped_type& at(const key_type& _Keyval) { const auto _Target = this->_Find_last(_Keyval, this->_Traitsobj(_Keyval)); if (_Target._Duplicate) { return _Target._Duplicate->_Myval.second; @@ -233,7 +234,7 @@ namespace stdext { _Xout_of_range("invalid hash_map key"); } - const mapped_type& at(const key_type& _Keyval) const { + _NODISCARD const mapped_type& at(const key_type& _Keyval) const { const auto _Target = this->_Find_last(_Keyval, this->_Traitsobj(_Keyval)); if (_Target._Duplicate) { return _Target._Duplicate->_Myval.second; @@ -245,27 +246,27 @@ namespace stdext { using reverse_iterator = _STD reverse_iterator; using const_reverse_iterator = _STD reverse_iterator; - reverse_iterator rbegin() noexcept { + _NODISCARD reverse_iterator rbegin() noexcept { return reverse_iterator(this->end()); } - const_reverse_iterator rbegin() const noexcept { + _NODISCARD const_reverse_iterator rbegin() const noexcept { return const_reverse_iterator(this->end()); } - reverse_iterator rend() noexcept { + _NODISCARD reverse_iterator rend() noexcept { return reverse_iterator(this->begin()); } - const_reverse_iterator rend() const noexcept { + _NODISCARD const_reverse_iterator rend() const noexcept { return const_reverse_iterator(this->begin()); } - const_reverse_iterator crbegin() const noexcept { + _NODISCARD const_reverse_iterator crbegin() const noexcept { return rbegin(); } - const_reverse_iterator crend() const noexcept { + _NODISCARD const_reverse_iterator crend() const noexcept { return rend(); } @@ -406,27 +407,27 @@ namespace stdext { using reverse_iterator = _STD reverse_iterator; using const_reverse_iterator = _STD reverse_iterator; - reverse_iterator rbegin() noexcept { + _NODISCARD reverse_iterator rbegin() noexcept { return reverse_iterator(this->end()); } - const_reverse_iterator rbegin() const noexcept { + _NODISCARD const_reverse_iterator rbegin() const noexcept { return const_reverse_iterator(this->end()); } - reverse_iterator rend() noexcept { + _NODISCARD reverse_iterator rend() noexcept { return reverse_iterator(this->begin()); } - const_reverse_iterator rend() const noexcept { + _NODISCARD const_reverse_iterator rend() const noexcept { return const_reverse_iterator(this->begin()); } - const_reverse_iterator crbegin() const noexcept { + _NODISCARD const_reverse_iterator crbegin() const noexcept { return rbegin(); } - const_reverse_iterator crend() const noexcept { + _NODISCARD const_reverse_iterator crend() const noexcept { return rend(); } diff --git a/stl/inc/hash_set b/stl/inc/hash_set index 79f04e8a922..7a3a4214318 100644 --- a/stl/inc/hash_set +++ b/stl/inc/hash_set @@ -62,20 +62,20 @@ namespace stdext { using value_compare = key_compare; - static const _Kty& _Kfn(const value_type& _Val) noexcept { + _NODISCARD static const _Kty& _Kfn(const value_type& _Val) noexcept { return _Val; } - static int _Nonkfn(const value_type&) noexcept { + _NODISCARD static int _Nonkfn(const value_type&) noexcept { // extract "non-key" from element value (for container equality) return 0; } - float& _Get_max_bucket_size() noexcept { + _NODISCARD float& _Get_max_bucket_size() noexcept { return _Max_buckets; } - const float& _Get_max_bucket_size() const noexcept { + _NODISCARD const float& _Get_max_bucket_size() const noexcept { return _Max_buckets; } @@ -181,27 +181,27 @@ namespace stdext { using reverse_iterator = _STD reverse_iterator; using const_reverse_iterator = _STD reverse_iterator; - reverse_iterator rbegin() noexcept { + _NODISCARD reverse_iterator rbegin() noexcept { return reverse_iterator(this->end()); } - const_reverse_iterator rbegin() const noexcept { + _NODISCARD const_reverse_iterator rbegin() const noexcept { return const_reverse_iterator(this->end()); } - reverse_iterator rend() noexcept { + _NODISCARD reverse_iterator rend() noexcept { return reverse_iterator(this->begin()); } - const_reverse_iterator rend() const noexcept { + _NODISCARD const_reverse_iterator rend() const noexcept { return const_reverse_iterator(this->begin()); } - const_reverse_iterator crbegin() const noexcept { + _NODISCARD const_reverse_iterator crbegin() const noexcept { return rbegin(); } - const_reverse_iterator crend() const noexcept { + _NODISCARD const_reverse_iterator crend() const noexcept { return rend(); } @@ -325,27 +325,27 @@ namespace stdext { using reverse_iterator = _STD reverse_iterator; using const_reverse_iterator = _STD reverse_iterator; - reverse_iterator rbegin() noexcept { + _NODISCARD reverse_iterator rbegin() noexcept { return reverse_iterator(this->end()); } - const_reverse_iterator rbegin() const noexcept { + _NODISCARD const_reverse_iterator rbegin() const noexcept { return const_reverse_iterator(this->end()); } - reverse_iterator rend() noexcept { + _NODISCARD reverse_iterator rend() noexcept { return reverse_iterator(this->begin()); } - const_reverse_iterator rend() const noexcept { + _NODISCARD const_reverse_iterator rend() const noexcept { return const_reverse_iterator(this->begin()); } - const_reverse_iterator crbegin() const noexcept { + _NODISCARD const_reverse_iterator crbegin() const noexcept { return rbegin(); } - const_reverse_iterator crend() const noexcept { + _NODISCARD const_reverse_iterator crend() const noexcept { return rend(); } diff --git a/stl/inc/memory b/stl/inc/memory index beac884f890..279effbcc6b 100644 --- a/stl/inc/memory +++ b/stl/inc/memory @@ -28,35 +28,6 @@ _STL_DISABLE_CLANG_WARNINGS _STD_BEGIN #ifdef __cpp_lib_concepts namespace ranges { - // clang-format off - // CONCEPT _No_throw_input_iterator - template - concept _No_throw_input_iterator = input_iterator<_It> - && is_lvalue_reference_v> - && same_as>, iter_value_t<_It>>; - - // CONCEPT _No_throw_sentinel_for - template - concept _No_throw_sentinel_for = sentinel_for<_Se, _It>; - - // CONCEPT _No_throw_forward_iterator - template - concept _No_throw_forward_iterator = _No_throw_input_iterator<_It> - && forward_iterator<_It> - && _No_throw_sentinel_for<_It, _It>; - - // CONCEPT _No_throw_input_range - template - concept _No_throw_input_range = range<_Rng> - && _No_throw_input_iterator> - && _No_throw_sentinel_for, iterator_t<_Rng>>; - - // CONCEPT _No_throw_forward_range - template - concept _No_throw_forward_range = _No_throw_input_range<_Rng> - && _No_throw_forward_iterator>; - // clang-format on - // ALIAS TEMPLATE uninitialized_copy_result template using uninitialized_copy_result = in_out_result<_In, _Out>; @@ -214,10 +185,6 @@ _NoThrowFwdIt uninitialized_move(const _InIt _First, const _InIt _Last, _NoThrow #ifdef __cpp_lib_concepts namespace ranges { - // ALIAS TEMPLATE uninitialized_move_result - template - using uninitialized_move_result = in_out_result<_In, _Out>; - // VARIABLE ranges::uninitialized_move class _Uninitialized_move_fn : private _Not_quite_object { public: @@ -231,9 +198,9 @@ namespace ranges { // clang-format on _Adl_verify_range(_First1, _Last1); _Adl_verify_range(_First2, _Last2); - auto _UResult = - _Uninitialized_move_unchecked(_Get_unwrapped(_STD move(_First1)), _Get_unwrapped(_STD move(_Last1)), - _Get_unwrapped(_STD move(_First2)), _Get_unwrapped(_STD move(_Last2))); + auto _UResult = _RANGES _Uninitialized_move_unchecked(_Get_unwrapped(_STD move(_First1)), + _Get_unwrapped(_STD move(_Last1)), _Get_unwrapped(_STD move(_First2)), + _Get_unwrapped(_STD move(_Last2))); _Seek_wrapped(_First1, _STD move(_UResult.in)); _Seek_wrapped(_First2, _STD move(_UResult.out)); @@ -247,35 +214,12 @@ namespace ranges { _Rng1&& _Range1, _Rng2&& _Range2) const { // clang-format on auto _First1 = _RANGES begin(_Range1); - auto _UResult = _Uninitialized_move_unchecked( + auto _UResult = _RANGES _Uninitialized_move_unchecked( _Get_unwrapped(_STD move(_First1)), _Uend(_Range1), _Ubegin(_Range2), _Uend(_Range2)); _Seek_wrapped(_First1, _STD move(_UResult.in)); return {_STD move(_First1), _Rewrap_iterator(_Range2, _STD move(_UResult.out))}; } - - private: - template - _NODISCARD static uninitialized_move_result<_It, _Out> _Uninitialized_move_unchecked( - _It _IFirst, const _Se _ILast, _Out _OFirst, const _OSe _OLast) { - _STL_INTERNAL_STATIC_ASSERT(input_iterator<_It>); - _STL_INTERNAL_STATIC_ASSERT(sentinel_for<_Se, _It>); - _STL_INTERNAL_STATIC_ASSERT(_No_throw_forward_iterator<_Out>); - _STL_INTERNAL_STATIC_ASSERT(_No_throw_sentinel_for<_OSe, _Out>); - _STL_INTERNAL_STATIC_ASSERT(constructible_from, iter_rvalue_reference_t<_It>>); - - if constexpr (is_same_v<_Se, _It> && _Ptr_move_cat<_It, _Out>::_Really_trivial) { - return _Copy_memcpy_common(_IFirst, _ILast, _OFirst, _OLast); - } else { - _Uninitialized_backout _Backout{_STD move(_OFirst)}; - - for (; _IFirst != _ILast && _Backout._Last != _OLast; ++_IFirst) { - _Backout._Emplace_back(_RANGES iter_move(_IFirst)); - } - - return {_STD move(_IFirst), _Backout._Release()}; - } - } }; inline constexpr _Uninitialized_move_fn uninitialized_move{_Not_quite_object::_Construct_tag{}}; diff --git a/stl/inc/type_traits b/stl/inc/type_traits index c1a030758bb..2d50aa726cf 100644 --- a/stl/inc/type_traits +++ b/stl/inc/type_traits @@ -1804,6 +1804,67 @@ inline constexpr bool is_nothrow_invocable_r_v = _Select_invoke_traits<_Callable, _Args...>::template _Is_nothrow_invocable_r<_Rx>::value; #endif // _HAS_CXX17 +#if _HAS_CXX20 +#ifndef __EDG__ // TRANSITION, VSO-1268984 +#ifndef __clang__ // TRANSITION, LLVM-48860 +// STRUCT TEMPLATE is_layout_compatible +template +#ifdef _IS_LAYOUT_COMPATIBLE_SUPPORTED +struct is_layout_compatible : bool_constant<__is_layout_compatible(_Ty1, _Ty2)> { +#else // ^^^ _IS_LAYOUT_COMPATIBLE_SUPPORTED / !_IS_LAYOUT_COMPATIBLE_SUPPORTED vvv +struct is_layout_compatible : bool_constant<__builtin_is_layout_compatible(_Ty1, _Ty2)> { +#endif // _IS_LAYOUT_COMPATIBLE_SUPPORTED +}; + +template +#ifdef _IS_LAYOUT_COMPATIBLE_SUPPORTED +inline constexpr bool is_layout_compatible_v = __is_layout_compatible(_Ty1, _Ty2); +#else // ^^^ _IS_LAYOUT_COMPATIBLE_SUPPORTED / !_IS_LAYOUT_COMPATIBLE_SUPPORTED vvv +inline constexpr bool is_layout_compatible_v = __builtin_is_layout_compatible(_Ty1, _Ty2); +#endif // _IS_LAYOUT_COMPATIBLE_SUPPORTED + +// STRUCT TEMPLATE is_pointer_interconvertible_base_of +template +struct is_pointer_interconvertible_base_of +#ifdef _IS_LAYOUT_COMPATIBLE_SUPPORTED + : bool_constant<__is_pointer_interconvertible_base_of(_Base, _Derived)> { +}; +#else // ^^^ _IS_LAYOUT_COMPATIBLE_SUPPORTED / !_IS_LAYOUT_COMPATIBLE_SUPPORTED vvv + : bool_constant<__builtin_is_pointer_interconvertible_base_of(_Base, _Derived)> { +}; +#endif // _IS_LAYOUT_COMPATIBLE_SUPPORTED + +template +#ifdef _IS_LAYOUT_COMPATIBLE_SUPPORTED +inline constexpr bool is_pointer_interconvertible_base_of_v = __is_pointer_interconvertible_base_of(_Base, _Derived); +#else // ^^^ _IS_LAYOUT_COMPATIBLE_SUPPORTED / !_IS_LAYOUT_COMPATIBLE_SUPPORTED vvv +inline constexpr bool is_pointer_interconvertible_base_of_v = __builtin_is_pointer_interconvertible_base_of( + _Base, _Derived); +#endif // _IS_LAYOUT_COMPATIBLE_SUPPORTED + +// FUNCTION TEMPLATE is_pointer_interconvertible_with_class +template +_NODISCARD constexpr bool is_pointer_interconvertible_with_class(_MemberTy _ClassTy::*_Pm) noexcept { +#ifdef _IS_LAYOUT_COMPATIBLE_SUPPORTED + return __is_pointer_interconvertible_with_class(_ClassTy, _Pm); +#else // ^^^ _IS_LAYOUT_COMPATIBLE_SUPPORTED / !_IS_LAYOUT_COMPATIBLE_SUPPORTED vvv + return __builtin_is_pointer_interconvertible_with_class(_ClassTy, _Pm); +#endif // _IS_LAYOUT_COMPATIBLE_SUPPORTED +} + +// FUNCTION TEMPLATE is_corresponding_member +template +_NODISCARD constexpr bool is_corresponding_member(_MemberTy1 _ClassTy1::*_Pm1, _MemberTy2 _ClassTy2::*_Pm2) noexcept { +#ifdef _IS_LAYOUT_COMPATIBLE_SUPPORTED + return __is_corresponding_member(_ClassTy1, _ClassTy2, _Pm1, _Pm2); +#else // ^^^ _IS_LAYOUT_COMPATIBLE_SUPPORTED / !_IS_LAYOUT_COMPATIBLE_SUPPORTED vvv + return __builtin_is_corresponding_member(_ClassTy1, _ClassTy2, _Pm1, _Pm2); +#endif // _IS_LAYOUT_COMPATIBLE_SUPPORTED +} +#endif // __clang__ +#endif // __EDG__ +#endif // _HAS_CXX20 + // ALIAS TEMPLATE _Weak_types template struct _Function_args {}; // determine whether _Ty is a function diff --git a/stl/inc/xatomic.h b/stl/inc/xatomic.h index af41c5af67a..c5f97d76db9 100644 --- a/stl/inc/xatomic.h +++ b/stl/inc/xatomic.h @@ -28,7 +28,14 @@ _STL_DISABLE_CLANG_WARNINGS #define _INTRIN_ACQUIRE(x) x #define _INTRIN_RELEASE(x) x #define _INTRIN_ACQ_REL(x) x +#ifdef _M_CEE_PURE #define _YIELD_PROCESSOR() +#else // ^^^ _M_CEE_PURE / !_M_CEE_PURE vvv +#if 1 // TRANSITION, VS 2019 16.10 +extern "C" void _mm_pause(void); +#endif // TRANSITION, VS 2019 16.10 +#define _YIELD_PROCESSOR() _mm_pause() +#endif // ^^^ !_M_CEE_PURE ^^^ #elif defined(_M_ARM) || defined(_M_ARM64) || defined(_M_ARM64EC) #define _INTRIN_RELAXED(x) _CONCAT(x, _nf) diff --git a/stl/inc/xmemory b/stl/inc/xmemory index 38209d5c9cd..6c54d796390 100644 --- a/stl/inc/xmemory +++ b/stl/inc/xmemory @@ -788,16 +788,20 @@ public: using value_type = _Ty; +#if _HAS_DEPRECATED_ALLOCATOR_MEMBERS _CXX17_DEPRECATE_OLD_ALLOCATOR_MEMBERS typedef _Ty* pointer; _CXX17_DEPRECATE_OLD_ALLOCATOR_MEMBERS typedef const _Ty* const_pointer; _CXX17_DEPRECATE_OLD_ALLOCATOR_MEMBERS typedef _Ty& reference; _CXX17_DEPRECATE_OLD_ALLOCATOR_MEMBERS typedef const _Ty& const_reference; +#endif // _HAS_DEPRECATED_ALLOCATOR_MEMBERS using size_type = size_t; using difference_type = ptrdiff_t; - using propagate_on_container_move_assignment = true_type; + using propagate_on_container_move_assignment = true_type; + +#if _HAS_DEPRECATED_ALLOCATOR_MEMBERS using is_always_equal _CXX17_DEPRECATE_OLD_ALLOCATOR_MEMBERS = true_type; template @@ -812,6 +816,7 @@ public: _CXX17_DEPRECATE_OLD_ALLOCATOR_MEMBERS _NODISCARD const _Ty* address(const _Ty& _Val) const noexcept { return _STD addressof(_Val); } +#endif // _HAS_DEPRECATED_ALLOCATOR_MEMBERS constexpr allocator() noexcept {} @@ -830,6 +835,7 @@ public: return static_cast<_Ty*>(_Allocate<_New_alignof<_Ty>>(_Get_size_of_n(_Count))); } +#if _HAS_DEPRECATED_ALLOCATOR_MEMBERS _CXX17_DEPRECATE_OLD_ALLOCATOR_MEMBERS _NODISCARD __declspec(allocator) _Ty* allocate( _CRT_GUARDOVERFLOW const size_t _Count, const void*) { return allocate(_Count); @@ -848,6 +854,7 @@ public: _CXX17_DEPRECATE_OLD_ALLOCATOR_MEMBERS _NODISCARD size_t max_size() const noexcept { return static_cast(-1) / sizeof(_Ty); } +#endif // _HAS_DEPRECATED_ALLOCATOR_MEMBERS }; // CLASS allocator @@ -855,19 +862,24 @@ template <> class allocator { public: using value_type = void; +#if _HAS_DEPRECATED_ALLOCATOR_MEMBERS _CXX17_DEPRECATE_OLD_ALLOCATOR_MEMBERS typedef void* pointer; _CXX17_DEPRECATE_OLD_ALLOCATOR_MEMBERS typedef const void* const_pointer; +#endif // _HAS_DEPRECATED_ALLOCATOR_MEMBERS using size_type = size_t; using difference_type = ptrdiff_t; - using propagate_on_container_move_assignment = true_type; + using propagate_on_container_move_assignment = true_type; + +#if _HAS_DEPRECATED_ALLOCATOR_MEMBERS using is_always_equal _CXX17_DEPRECATE_OLD_ALLOCATOR_MEMBERS = true_type; template struct _CXX17_DEPRECATE_OLD_ALLOCATOR_MEMBERS rebind { using other = allocator<_Other>; }; +#endif // _HAS_DEPRECATED_ALLOCATOR_MEMBERS }; template @@ -1439,6 +1451,64 @@ _NoThrowFwdIt _Uninitialized_move_unchecked(_InIt _First, const _InIt _Last, _No } } +#ifdef __cpp_lib_concepts +namespace ranges { + // clang-format off + // CONCEPT _No_throw_input_iterator + template + concept _No_throw_input_iterator = input_iterator<_It> + && is_lvalue_reference_v> + && same_as>, iter_value_t<_It>>; + + // CONCEPT _No_throw_sentinel_for + template + concept _No_throw_sentinel_for = sentinel_for<_Se, _It>; + + // CONCEPT _No_throw_forward_iterator + template + concept _No_throw_forward_iterator = _No_throw_input_iterator<_It> + && forward_iterator<_It> + && _No_throw_sentinel_for<_It, _It>; + + // CONCEPT _No_throw_input_range + template + concept _No_throw_input_range = range<_Rng> + && _No_throw_input_iterator> + && _No_throw_sentinel_for, iterator_t<_Rng>>; + + // CONCEPT _No_throw_forward_range + template + concept _No_throw_forward_range = _No_throw_input_range<_Rng> + && _No_throw_forward_iterator>; + // clang-format on + + // ALIAS TEMPLATE uninitialized_move_result + template + using uninitialized_move_result = in_out_result<_In, _Out>; + + // FUNCTION TEMPLATE _Uninitialized_move_unchecked + // clang-format off + template _Se, _No_throw_forward_iterator _Out, + _No_throw_sentinel_for<_Out> _OSe> + requires constructible_from, iter_rvalue_reference_t<_It>> + uninitialized_move_result<_It, _Out> _Uninitialized_move_unchecked( + _It _IFirst, const _Se _ILast, _Out _OFirst, const _OSe _OLast) { + // clang-format on + if constexpr (is_same_v<_Se, _It> && _Ptr_move_cat<_It, _Out>::_Really_trivial) { + return _Copy_memcpy_common(_IFirst, _ILast, _OFirst, _OLast); + } else { + _Uninitialized_backout _Backout{_STD move(_OFirst)}; + + for (; _IFirst != _ILast && _Backout._Last != _OLast; ++_IFirst) { + _Backout._Emplace_back(_RANGES iter_move(_IFirst)); + } + + return {_STD move(_IFirst), _Backout._Release()}; + } + } +} // namespace ranges +#endif // __cpp_lib_concepts + // STRUCT TEMPLATE _Uninitialized_backout_al template class _NODISCARD _Uninitialized_backout_al { @@ -1702,10 +1772,13 @@ struct _In_place_key_extract_map<_Key, pair<_First, _Second>> { }; // STRUCT TEMPLATE _Wrap +#pragma warning(push) +#pragma warning(disable : 4624) // '%s': destructor was implicitly defined as deleted template struct _Wrap { _Ty _Value; // workaround for "T^ is not allowed in a union" }; +#pragma warning(pop) // STRUCT TEMPLATE _Alloc_temporary template diff --git a/stl/inc/yvals_core.h b/stl/inc/yvals_core.h index e37d8daf036..ce9b36d67aa 100644 --- a/stl/inc/yvals_core.h +++ b/stl/inc/yvals_core.h @@ -138,6 +138,8 @@ // P0318R1 unwrap_reference, unwrap_ref_decay // P0325R4 to_array() // P0339R6 polymorphic_allocator<> +// P0355R7 Calendars And Time Zones +// (partially implemented) // P0356R5 bind_front() // P0357R3 Supporting Incomplete Types In reference_wrapper // P0408R7 Efficient Access To basic_stringbuf's Buffer @@ -146,6 +148,7 @@ // P0457R2 starts_with()/ends_with() For basic_string/basic_string_view // P0458R2 contains() For Ordered And Unordered Associative Containers // P0463R1 endian +// P0466R5 Layout-Compatibility And Pointer-Interconvertibility Traits // P0476R2 bit_cast // P0482R6 Library Support For char8_t // (mbrtoc8 and c8rtomb not yet implemented) @@ -1024,6 +1027,10 @@ #define _HAS_DEPRECATED_ADAPTOR_TYPEDEFS (_HAS_FEATURES_REMOVED_IN_CXX20) #endif // _HAS_DEPRECATED_ADAPTOR_TYPEDEFS +#ifndef _HAS_DEPRECATED_ALLOCATOR_MEMBERS +#define _HAS_DEPRECATED_ALLOCATOR_MEMBERS (_HAS_FEATURES_REMOVED_IN_CXX20) +#endif // _HAS_DEPRECATED_ALLOCATOR_MEMBERS + #ifndef _HAS_DEPRECATED_IS_LITERAL_TYPE #define _HAS_DEPRECATED_IS_LITERAL_TYPE (_HAS_FEATURES_REMOVED_IN_CXX20) #endif // _HAS_DEPRECATED_IS_LITERAL_TYPE @@ -1208,19 +1215,33 @@ #define __cpp_lib_integer_comparison_functions 202002L #define __cpp_lib_interpolate 201902L #define __cpp_lib_is_constant_evaluated 201811L -#define __cpp_lib_is_nothrow_convertible 201806L -#define __cpp_lib_jthread 201911L -#define __cpp_lib_latch 201907L -#define __cpp_lib_list_remove_return_type 201806L -#define __cpp_lib_math_constants 201907L -#define __cpp_lib_polymorphic_allocator 201902L -#define __cpp_lib_remove_cvref 201711L -#define __cpp_lib_semaphore 201907L -#define __cpp_lib_shift 201806L -#define __cpp_lib_smart_ptr_for_overwrite 202002L -#define __cpp_lib_span 202002L -#define __cpp_lib_ssize 201902L -#define __cpp_lib_starts_ends_with 201711L + +#ifndef __EDG__ // TRANSITION, VSO-1268984 +#ifndef __clang__ // TRANSITION, LLVM-48860 +#define __cpp_lib_is_layout_compatible 201907L +#endif // __clang__ +#endif // __EDG__ + +#define __cpp_lib_is_nothrow_convertible 201806L + +#ifndef __EDG__ // TRANSITION, VSO-1268984 +#ifndef __clang__ // TRANSITION, LLVM-48860 +#define __cpp_lib_is_pointer_interconvertible 201907L +#endif // __clang__ +#endif // __EDG__ + +#define __cpp_lib_jthread 201911L +#define __cpp_lib_latch 201907L +#define __cpp_lib_list_remove_return_type 201806L +#define __cpp_lib_math_constants 201907L +#define __cpp_lib_polymorphic_allocator 201902L +#define __cpp_lib_remove_cvref 201711L +#define __cpp_lib_semaphore 201907L +#define __cpp_lib_shift 201806L +#define __cpp_lib_smart_ptr_for_overwrite 202002L +#define __cpp_lib_span 202002L +#define __cpp_lib_ssize 201902L +#define __cpp_lib_starts_ends_with 201711L #ifdef __cpp_lib_concepts // TRANSITION, GH-395 #define __cpp_lib_three_way_comparison 201711L @@ -1278,6 +1299,7 @@ compiler option, or define _ALLOW_RTCc_IN_STL to acknowledge that you have recei #define _STD_BEGIN namespace std { #define _STD_END } #define _STD ::std:: +#define _CHRONO ::std::chrono:: #define _RANGES ::std::ranges:: // We use the stdext (standard extension) namespace to contain extensions that are not part of the current standard diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index fab5573e6b1..76a64ab60d2 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -12,6 +12,8 @@ set(LLVM_PROJECT_SOURCE_DIR "${STL_SOURCE_DIR}/llvm-project" CACHE PATH set(LIBCXX_SOURCE_DIR "${LLVM_PROJECT_SOURCE_DIR}/libcxx" CACHE PATH "Location of the libcxx source tree") +option(TESTS_BUILD_ONLY "Only run the build steps of tests" OFF) + add_subdirectory(libcxx) add_subdirectory(std) add_subdirectory(tr1) diff --git a/tests/libcxx/expected_results.txt b/tests/libcxx/expected_results.txt index 8961a1cc341..ed1d3397670 100644 --- a/tests/libcxx/expected_results.txt +++ b/tests/libcxx/expected_results.txt @@ -57,21 +57,12 @@ std/language.support/support.limits/support.limits.general/locale.version.pass.c std/language.support/support.limits/support.limits.general/ostream.version.pass.cpp FAIL std/language.support/support.limits/support.limits.general/string_view.version.pass.cpp FAIL -# libc++ doesn't yet implement P1956R1, so it expects the old names `ispow2`, `ceil2`, `floor2`, and `log2p1` -std/numerics/bit/bit.pow.two/ceil2.pass.cpp FAIL -std/numerics/bit/bit.pow.two/floor2.pass.cpp FAIL -std/numerics/bit/bit.pow.two/ispow2.pass.cpp FAIL -std/numerics/bit/bit.pow.two/log2p1.pass.cpp FAIL - # test emits warning C4310: cast truncates constant value std/numerics/bit/bitops.rot/rotl.pass.cpp:0 FAIL # libc++ doesn't yet implement P1754R1 or P1964R2, so it expects an old value for `__cpp_lib_concepts` std/language.support/support.limits/support.limits.general/concepts.version.pass.cpp FAIL -# libc++ doesn't yet implement P1001R2, so it expects an old value for `__cpp_lib_execution` -std/language.support/support.limits/support.limits.general/execution.version.pass.cpp FAIL - # *** INTERACTIONS WITH CONTEST / C1XX THAT UPSTREAM LIKELY WON'T FIX *** # Tracked by VSO-593630 " Enable libcxx filesystem tests" @@ -197,6 +188,8 @@ std/language.support/support.limits/support.limits.general/type_traits.version.p std/language.support/support.limits/support.limits.general/version.version.pass.cpp FAIL # Contest does not understand .sh tests, which must be run specially +std/input.output/iostream.objects/narrow.stream.objects/cin.sh.cpp SKIPPED +std/input.output/iostream.objects/wide.stream.objects/wcin.sh.cpp SKIPPED std/namespace/addressable_functions.sh.cpp SKIPPED std/thread/thread.condition/thread.condition.condvarany/wait_terminates.sh.cpp SKIPPED @@ -280,211 +273,31 @@ std/utilities/memory/default.allocator/allocator_void.deprecated_in_cxx17.verify std/utilities/memory/default.allocator/allocator.members/allocate.constexpr.size.verify.cpp SKIPPED std/utilities/memory/default.allocator/allocator.members/allocate.verify.cpp SKIPPED -# GH-1382: Our machinery doesn't understand compile-only `.compile.pass.cpp` tests -std/strings/string.view/string.view.io/stream_insert_decl_present.compile.pass.cpp SKIPPED - # *** MISSING STL FEATURES *** # C++20 P0355R7 " Calendars And Time Zones" -std/utilities/time/days.pass.cpp FAIL -std/utilities/time/months.pass.cpp FAIL -std/utilities/time/weeks.pass.cpp FAIL -std/utilities/time/years.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.day/types.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.day/time.cal.day.members/ctor.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.day/time.cal.day.members/decrement.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.day/time.cal.day.members/increment.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.day/time.cal.day.members/ok.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.day/time.cal.day.members/plus_minus_equal.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.day/time.cal.day.nonmembers/comparisons.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.day/time.cal.day.nonmembers/literals.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.day/time.cal.day.nonmembers/minus.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.day/time.cal.day.nonmembers/plus.pass.cpp FAIL std/utilities/time/time.cal/time.cal.day/time.cal.day.nonmembers/streaming.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.last/types.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.md/types.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.md/time.cal.md.members/ctor.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.md/time.cal.md.members/day.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.md/time.cal.md.members/month.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.md/time.cal.md.members/ok.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.md/time.cal.md.nonmembers/comparisons.pass.cpp FAIL std/utilities/time/time.cal/time.cal.md/time.cal.md.nonmembers/streaming.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.mdlast/comparisons.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.mdlast/ctor.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.mdlast/month.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.mdlast/ok.pass.cpp FAIL std/utilities/time/time.cal/time.cal.mdlast/streaming.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.mdlast/types.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.month/types.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.month/time.cal.month.members/ctor.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.month/time.cal.month.members/decrement.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.month/time.cal.month.members/increment.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.month/time.cal.month.members/ok.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.month/time.cal.month.members/plus_minus_equal.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.month/time.cal.month.nonmembers/comparisons.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.month/time.cal.month.nonmembers/literals.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.month/time.cal.month.nonmembers/minus.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.month/time.cal.month.nonmembers/plus.pass.cpp FAIL std/utilities/time/time.cal/time.cal.month/time.cal.month.nonmembers/streaming.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.mwd/types.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.mwd/time.cal.mwd.members/ctor.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.mwd/time.cal.mwd.members/month.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.mwd/time.cal.mwd.members/ok.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.mwd/time.cal.mwd.members/weekday_indexed.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.mwd/time.cal.mwd.nonmembers/comparisons.pass.cpp FAIL std/utilities/time/time.cal/time.cal.mwd/time.cal.mwd.nonmembers/streaming.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.mwdlast/types.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.mwdlast/time.cal.mwdlast.members/ctor.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.mwdlast/time.cal.mwdlast.members/month.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.mwdlast/time.cal.mwdlast.members/ok.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.mwdlast/time.cal.mwdlast.members/weekday_last.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.mwdlast/time.cal.mwdlast.nonmembers/comparisons.pass.cpp FAIL std/utilities/time/time.cal/time.cal.mwdlast/time.cal.mwdlast.nonmembers/streaming.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.operators/month_day.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.operators/month_day_last.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.operators/month_weekday.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.operators/month_weekday_last.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.operators/year_month.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.operators/year_month_day.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.operators/year_month_day_last.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.operators/year_month_weekday.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.operators/year_month_weekday_last.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.wdidx/types.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.wdidx/time.cal.wdidx.members/ctor.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.wdidx/time.cal.wdidx.members/index.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.wdidx/time.cal.wdidx.members/ok.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.wdidx/time.cal.wdidx.members/weekday.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.wdidx/time.cal.wdidx.nonmembers/comparisons.pass.cpp FAIL std/utilities/time/time.cal/time.cal.wdidx/time.cal.wdidx.nonmembers/streaming.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.wdlast/types.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.wdlast/time.cal.wdlast.members/ctor.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.wdlast/time.cal.wdlast.members/ok.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.wdlast/time.cal.wdlast.members/weekday.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.wdlast/time.cal.wdlast.nonmembers/comparisons.pass.cpp FAIL std/utilities/time/time.cal/time.cal.wdlast/time.cal.wdlast.nonmembers/streaming.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.weekday/types.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.weekday/time.cal.weekday.members/c_encoding.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.weekday/time.cal.weekday.members/ctor.local_days.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.weekday/time.cal.weekday.members/ctor.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.weekday/time.cal.weekday.members/ctor.sys_days.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.weekday/time.cal.weekday.members/decrement.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.weekday/time.cal.weekday.members/increment.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.weekday/time.cal.weekday.members/iso_encoding.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.weekday/time.cal.weekday.members/ok.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.weekday/time.cal.weekday.members/operator[].pass.cpp FAIL -std/utilities/time/time.cal/time.cal.weekday/time.cal.weekday.members/plus_minus_equal.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.weekday/time.cal.weekday.nonmembers/comparisons.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.weekday/time.cal.weekday.nonmembers/literals.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.weekday/time.cal.weekday.nonmembers/minus.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.weekday/time.cal.weekday.nonmembers/plus.pass.cpp FAIL std/utilities/time/time.cal/time.cal.weekday/time.cal.weekday.nonmembers/streaming.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.year/types.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.year/time.cal.year.members/ctor.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.year/time.cal.year.members/decrement.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.year/time.cal.year.members/increment.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.year/time.cal.year.members/is_leap.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.year/time.cal.year.members/ok.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.year/time.cal.year.members/plus_minus.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.year/time.cal.year.members/plus_minus_equal.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.year/time.cal.year.nonmembers/comparisons.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.year/time.cal.year.nonmembers/literals.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.year/time.cal.year.nonmembers/minus.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.year/time.cal.year.nonmembers/plus.pass.cpp FAIL std/utilities/time/time.cal/time.cal.year/time.cal.year.nonmembers/streaming.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.ym/types.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.ym/time.cal.ym.members/ctor.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.ym/time.cal.ym.members/month.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.ym/time.cal.ym.members/ok.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.ym/time.cal.ym.members/plus_minus_equal_month.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.ym/time.cal.ym.members/plus_minus_equal_year.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.ym/time.cal.ym.members/year.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.ym/time.cal.ym.nonmembers/comparisons.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.ym/time.cal.ym.nonmembers/minus.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.ym/time.cal.ym.nonmembers/plus.pass.cpp FAIL std/utilities/time/time.cal/time.cal.ym/time.cal.ym.nonmembers/streaming.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.ymd/types.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.ymd/time.cal.ymd.members/ctor.local_days.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.ymd/time.cal.ymd.members/ctor.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.ymd/time.cal.ymd.members/ctor.sys_days.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.ymd/time.cal.ymd.members/ctor.year_month_day_last.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.ymd/time.cal.ymd.members/day.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.ymd/time.cal.ymd.members/month.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.ymd/time.cal.ymd.members/ok.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.ymd/time.cal.ymd.members/op.local_days.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.ymd/time.cal.ymd.members/op.sys_days.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.ymd/time.cal.ymd.members/plus_minus_equal_month.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.ymd/time.cal.ymd.members/plus_minus_equal_year.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.ymd/time.cal.ymd.members/year.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.ymd/time.cal.ymd.nonmembers/comparisons.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.ymd/time.cal.ymd.nonmembers/minus.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.ymd/time.cal.ymd.nonmembers/plus.pass.cpp FAIL std/utilities/time/time.cal/time.cal.ymd/time.cal.ymd.nonmembers/streaming.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.ymdlast/time.cal.ymdlast.members/ctor.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.ymdlast/time.cal.ymdlast.members/day.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.ymdlast/time.cal.ymdlast.members/month.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.ymdlast/time.cal.ymdlast.members/month_day_last.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.ymdlast/time.cal.ymdlast.members/ok.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.ymdlast/time.cal.ymdlast.members/op_local_days.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.ymdlast/time.cal.ymdlast.members/op_sys_days.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.ymdlast/time.cal.ymdlast.members/plus_minus_equal_month.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.ymdlast/time.cal.ymdlast.members/plus_minus_equal_year.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.ymdlast/time.cal.ymdlast.members/year.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.ymdlast/time.cal.ymdlast.nonmembers/comparisons.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.ymdlast/time.cal.ymdlast.nonmembers/minus.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.ymdlast/time.cal.ymdlast.nonmembers/plus.pass.cpp FAIL std/utilities/time/time.cal/time.cal.ymdlast/time.cal.ymdlast.nonmembers/streaming.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.ymwd/types.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.ymwd/time.cal.ymwd.members/ctor.local_days.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.ymwd/time.cal.ymwd.members/ctor.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.ymwd/time.cal.ymwd.members/ctor.sys_days.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.ymwd/time.cal.ymwd.members/index.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.ymwd/time.cal.ymwd.members/month.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.ymwd/time.cal.ymwd.members/ok.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.ymwd/time.cal.ymwd.members/op.local_days.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.ymwd/time.cal.ymwd.members/op.sys_days.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.ymwd/time.cal.ymwd.members/plus_minus_equal_month.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.ymwd/time.cal.ymwd.members/plus_minus_equal_year.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.ymwd/time.cal.ymwd.members/weekday.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.ymwd/time.cal.ymwd.members/weekday_indexed.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.ymwd/time.cal.ymwd.members/year.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.ymwd/time.cal.ymwd.nonmembers/comparisons.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.ymwd/time.cal.ymwd.nonmembers/minus.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.ymwd/time.cal.ymwd.nonmembers/plus.pass.cpp FAIL std/utilities/time/time.cal/time.cal.ymwd/time.cal.ymwd.nonmembers/streaming.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.ymwdlast/types.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.ymwdlast/time.cal.ymwdlast.members/ctor.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.ymwdlast/time.cal.ymwdlast.members/month.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.ymwdlast/time.cal.ymwdlast.members/ok.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.ymwdlast/time.cal.ymwdlast.members/op_local_days.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.ymwdlast/time.cal.ymwdlast.members/op_sys_days.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.ymwdlast/time.cal.ymwdlast.members/plus_minus_equal_month.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.ymwdlast/time.cal.ymwdlast.members/plus_minus_equal_year.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.ymwdlast/time.cal.ymwdlast.members/weekday.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.ymwdlast/time.cal.ymwdlast.members/year.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.ymwdlast/time.cal.ymwdlast.nonmembers/comparisons.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.ymwdlast/time.cal.ymwdlast.nonmembers/minus.pass.cpp FAIL -std/utilities/time/time.cal/time.cal.ymwdlast/time.cal.ymwdlast.nonmembers/plus.pass.cpp FAIL std/utilities/time/time.cal/time.cal.ymwdlast/time.cal.ymwdlast.nonmembers/streaming.pass.cpp FAIL std/utilities/time/time.clock/time.clock.file/consistency.pass.cpp FAIL std/utilities/time/time.clock/time.clock.file/file_time.pass.cpp FAIL std/utilities/time/time.clock/time.clock.file/now.pass.cpp FAIL std/utilities/time/time.clock/time.clock.file/rep_signed.pass.cpp FAIL -std/utilities/time/time.clock/time.clock.system/local_time.types.pass.cpp FAIL -std/utilities/time/time.clock/time.clock.system/sys.time.types.pass.cpp FAIL -std/utilities/time/time.duration/time.duration.literals/literals1.pass.cpp FAIL -std/utilities/time/time.hms/time.12/is_am.pass.cpp FAIL -std/utilities/time/time.hms/time.12/is_pm.pass.cpp FAIL -std/utilities/time/time.hms/time.12/make12.pass.cpp FAIL -std/utilities/time/time.hms/time.12/make24.pass.cpp FAIL -std/utilities/time/time.hms/time.hms.members/hours.pass.cpp FAIL -std/utilities/time/time.hms/time.hms.members/is_negative.pass.cpp FAIL -std/utilities/time/time.hms/time.hms.members/minutes.pass.cpp FAIL -std/utilities/time/time.hms/time.hms.members/precision.pass.cpp FAIL -std/utilities/time/time.hms/time.hms.members/precision_type.pass.cpp FAIL -std/utilities/time/time.hms/time.hms.members/seconds.pass.cpp FAIL -std/utilities/time/time.hms/time.hms.members/subseconds.pass.cpp FAIL -std/utilities/time/time.hms/time.hms.members/to_duration.pass.cpp FAIL -std/utilities/time/time.hms/time.hms.members/width.pass.cpp FAIL + +# C++20 P0466R5 "Layout-Compatibility And Pointer-Interconvertibility Traits" +std/language.support/support.limits/support.limits.general/type_traits.version.pass.cpp:1 FAIL # C++20 P0608R3 "Improving variant's Converting Constructor/Assignment" std/utilities/variant/variant.variant/variant.assign/conv.pass.cpp FAIL @@ -492,6 +305,10 @@ std/utilities/variant/variant.variant/variant.assign/T.pass.cpp FAIL std/utilities/variant/variant.variant/variant.ctor/conv.pass.cpp FAIL std/utilities/variant/variant.variant/variant.ctor/T.pass.cpp FAIL +# C++20 P0645R10 " Text Formatting" +std/language.support/support.limits/support.limits.general/format.version.pass.cpp FAIL +std/utilities/format/format.error/format.error.pass.cpp FAIL + # C++20 P0784R7 "More constexpr containers" 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 @@ -512,12 +329,32 @@ std/language.support/support.limits/support.limits.general/functional.version.pa std/language.support/support.limits/support.limits.general/iterator.version.pass.cpp FAIL std/language.support/support.limits/support.limits.general/memory.version.pass.cpp FAIL +# C++20 P1004R2 "constexpr std::vector" +std/language.support/support.limits/support.limits.general/vector.version.pass.cpp FAIL + +# C++20 P1614R2 "Adding Spaceship <=> To The Library" +std/language.support/support.limits/support.limits.general/compare.version.pass.cpp FAIL + +# C++23 P1048R1 "is_scoped_enum" +std/utilities/meta/meta.unary/meta.unary.prop/is_scoped_enum.pass.cpp FAIL + +# C++23 P1679R3 "contains() For basic_string/basic_string_view" +std/strings/basic.string/string.contains/contains.char.pass.cpp FAIL +std/strings/basic.string/string.contains/contains.ptr.pass.cpp FAIL +std/strings/basic.string/string.contains/contains.string_view.pass.cpp FAIL +std/strings/string.view/string.view.template/contains.char.pass.cpp FAIL +std/strings/string.view/string.view.template/contains.ptr.pass.cpp FAIL +std/strings/string.view/string.view.template/contains.string_view.pass.cpp FAIL + # *** MISSING COMPILER FEATURES *** # Nothing here! :-) # *** MISSING LWG ISSUE RESOLUTIONS *** +# LWG-2503 "multiline option should be added to syntax_option_type" +std/re/re.const/re.matchflag/match_multiline.pass.cpp FAIL + # LWG-2532 "Satisfying a promise at thread exit" (Open) # WCFB02 implements the proposed resolution for this issue std/thread/futures/futures.promise/set_exception_at_thread_exit.pass.cpp FAIL @@ -541,6 +378,10 @@ std/utilities/utility/pairs/pairs.pair/assign_pair.pass.cpp:0 FAIL std/utilities/utility/pairs/pairs.pair/assign_rv_pair.pass.cpp:0 FAIL std/utilities/utility/pairs/pairs.pair/assign_rv_pair_U_V.pass.cpp:0 FAIL +# VSO-1271673 "static analyzer doesn't know about short-circuiting" +std/algorithms/alg.sorting/alg.sort/partial.sort/partial_sort.pass.cpp:0 FAIL +std/algorithms/alg.sorting/alg.sort/partial.sort/partial_sort_comp.pass.cpp:0 FAIL + # *** CLANG COMPILER BUGS *** # LLVM-33230 "Clang on Windows should define __STDCPP_THREADS__ to be 1" @@ -581,7 +422,6 @@ std/containers/sequences/array/array.data/data.pass.cpp FAIL std/containers/sequences/array/iterators.pass.cpp FAIL # GH-1006 : debug checks for predicates are observable -std/algorithms/alg.sorting/alg.heap.operations/make.heap/make_heap_comp.pass.cpp FAIL std/algorithms/alg.sorting/alg.merge/inplace_merge_comp.pass.cpp FAIL std/algorithms/alg.sorting/alg.min.max/minmax_init_list_comp.pass.cpp FAIL @@ -646,6 +486,15 @@ std/utilities/meta/meta.trans/meta.trans.other/aligned_storage.pass.cpp FAIL std/depr/depr.c.headers/math_h.pass.cpp FAIL std/numerics/c.math/cmath.pass.cpp FAIL +# GH-1596: : unqualified calls to _Adl_verify_range incorrectly cause instantiation +std/algorithms/robust_against_adl.pass.cpp FAIL + +# GH-1595: : bit_ceil(T(-1)) should not be a constant expression +std/numerics/bit/bit.pow.two/bit_ceil.fail.cpp:0 FAIL + +# GH-1530: : Poisson approximation for binomial_distribution is not accurate +std/numerics/rand/rand.dis/rand.dist.bern/rand.dist.bern.bin/eval.PR44847.pass.cpp FAIL + # *** CRT BUGS *** # We're permanently missing aligned_alloc(). @@ -662,15 +511,6 @@ std/language.support/support.limits/c.limits/cfloat.pass.cpp:0 FAIL # *** LIKELY BOGUS TESTS *** -# "error: _LIBCPP_VERSION not defined" -std/thread/thread.barrier/version.pass.cpp FAIL -std/thread/thread.latch/version.pass.cpp FAIL -std/thread/thread.semaphore/version.pass.cpp FAIL - -# "error C3861: 'assert': identifier not found" -std/thread/thread.semaphore/timed.pass.cpp FAIL -std/thread/thread.semaphore/try_acquire.pass.cpp FAIL - # pass lambda without noexcept to barrier std/thread/thread.barrier/completion.pass.cpp FAIL std/thread/thread.barrier/max.pass.cpp FAIL @@ -684,15 +524,6 @@ std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.asgn/move.pass.cpp # Test bug after LWG-3257 "Missing feature testing macro update from P0858" was accepted. std/language.support/support.limits/support.limits.general/string.version.pass.cpp FAIL -# libc++ expects an old value for `__cpp_lib_array_constexpr` (`201603L`). We've implemented P0858R0, P1023R0, and P1032R1, increasing the value to `201811L`. -std/language.support/support.limits/support.limits.general/array.version.pass.cpp FAIL - -# libc++ expects the old macro `__cpp_lib_constexpr_misc`. After P1902R1, it should expect `__cpp_lib_constexpr_tuple` to have the value `201811L`. -std/language.support/support.limits/support.limits.general/tuple.version.pass.cpp FAIL - -# libc++ expects the old macro `__cpp_lib_constexpr_misc`. After P1902R1, it should expect `__cpp_lib_constexpr_utility` to have the value `201811L`. -std/language.support/support.limits/support.limits.general/utility.version.pass.cpp FAIL - # Not yet analyzed, likely bogus tests. Appears to be timing assumptions. std/thread/futures/futures.async/async.pass.cpp SKIPPED std/thread/futures/futures.shared_future/get.pass.cpp SKIPPED @@ -809,6 +640,39 @@ std/numerics/rand/rand.dis/rand.dist.samp/rand.dist.samp.plinear/eval.pass.cpp F # They shouldn't behave differently. Both of them should probably return NaN. std/numerics/c.math/c.math.lerp/c.math.lerp.pass.cpp FAIL +# --month{14} should be 1, not 13 as the test expects +std/utilities/time/time.cal/time.cal.month/time.cal.month.members/decrement.pass.cpp FAIL + +# test is broken due to month_weekday not being default constructible +std/utilities/time/time.cal/time.cal.mwd/time.cal.mwd.members/month.pass.cpp FAIL + +# conversion from '__int64' to 'long', possible loss of data +std/utilities/time/time.hms/time.hms.members/seconds.pass.cpp:0 FAIL +std/utilities/time/time.hms/time.hms.members/subseconds.pass.cpp:0 FAIL + +# Code: `for (int i = 1000; i < 20; ++i)` +# warning C6294: Ill-defined for-loop: initial condition does not satisfy test. Loop body not executed. +std/utilities/time/time.cal/time.cal.month/time.cal.month.nonmembers/comparisons.pass.cpp:0 FAIL +std/utilities/time/time.cal/time.cal.ym/time.cal.ym.nonmembers/comparisons.pass.cpp:0 FAIL +std/utilities/time/time.cal/time.cal.ymd/time.cal.ymd.nonmembers/comparisons.pass.cpp:0 FAIL +std/utilities/time/time.cal/time.cal.ymdlast/time.cal.ymdlast.nonmembers/comparisons.pass.cpp:0 FAIL +std/utilities/time/time.cal/time.cal.ymwd/time.cal.ymwd.nonmembers/comparisons.pass.cpp:0 FAIL +std/utilities/time/time.cal/time.cal.ymwdlast/time.cal.ymwdlast.nonmembers/comparisons.pass.cpp:0 FAIL + +# Tests are manually declaring printf, which appears to be unused. +# warning C28301: No annotations for first declaration of 'printf'. +std/utilities/time/time.cal/time.cal.weekday/time.cal.weekday.nonmembers/minus.pass.cpp:0 FAIL +std/utilities/time/time.cal/time.cal.year/time.cal.year.nonmembers/minus.pass.cpp:0 FAIL + +# Bogus test passes a class type as the second argument to std::advance +std/iterators/iterator.primitives/iterator.operations/robust_against_adl.pass.cpp FAIL + +# Non-Standard test should be moved from libcxx/test/std to libcxx/test/libcxx +std/utilities/memory/util.smartptr/util.smartptr.shared/libcxx.control_block_layout.pass.cpp FAIL + +# Non-Standard assumption that std::filesystem::file_time_type::duration::period is std::nano +std/input.output/filesystems/fs.filesystem.synopsis/file_time_type_resolution.compile.pass.cpp FAIL + # *** LIKELY STL BUGS *** # Not yet analyzed, likely STL bugs. Assertions and other runtime failures. @@ -1007,6 +871,31 @@ std/containers/sequences/deque/deque.modifiers/insert_iter_iter.pass.cpp SKIPPED # Not yet analyzed. Failing after https://reviews.llvm.org/D75622. std/re/re.const/re.matchflag/match_prev_avail.pass.cpp FAIL +# Not yet analyzed. Many diagnostics. +std/input.output/filesystems/class.path/path.member/path.charconv.pass.cpp FAIL + +# Not yet analyzed. Probably ADL shenanigans. +std/thread/thread.threads/thread.thread.class/thread.thread.constr/robust_against_adl.pass.cpp FAIL +std/utilities/function.objects/func.wrap/func.wrap.func/robust_against_adl.pass.cpp FAIL +std/utilities/function.objects/refwrap/refwrap.invoke/robust_against_adl.pass.cpp FAIL +std/utilities/variant/variant.visit/robust_against_adl.pass.cpp FAIL + +# Not yet analyzed. Probably MSVC bug. +std/utilities/function.objects/func.invoke/invoke_constexpr.pass.cpp:0 FAIL + +# Not yet analyzed. Probably name mangling bug. +std/utilities/function.objects/func.wrap/func.wrap.func/noncopyable_return_type.pass.cpp FAIL + +# Not yet analyzed. Failing for "[a[.ch.]z]". +std/re/re.alg/re.alg.match/awk.locale.pass.cpp FAIL +std/re/re.alg/re.alg.match/basic.locale.pass.cpp FAIL +std/re/re.alg/re.alg.match/ecma.locale.pass.cpp FAIL +std/re/re.alg/re.alg.match/extended.locale.pass.cpp FAIL +std/re/re.alg/re.alg.search/awk.locale.pass.cpp FAIL +std/re/re.alg/re.alg.search/basic.locale.pass.cpp FAIL +std/re/re.alg/re.alg.search/ecma.locale.pass.cpp FAIL +std/re/re.alg/re.alg.search/extended.locale.pass.cpp FAIL + # *** XFAILs WHICH PASS *** # Not yet implemented in libcxx and marked as XFAIL diff --git a/tests/libcxx/lit.site.cfg.in b/tests/libcxx/lit.site.cfg.in index fb530312e8a..0557736b467 100644 --- a/tests/libcxx/lit.site.cfg.in +++ b/tests/libcxx/lit.site.cfg.in @@ -30,6 +30,7 @@ lit_config.test_subdirs[config.name] = ['@LIBCXX_SOURCE_DIR@/test/std'] lit_config.cxx_runtime = '@CMAKE_RUNTIME_OUTPUT_DIRECTORY@' lit_config.target_arch = '@VCLIBS_TARGET_ARCHITECTURE@' +lit_config.build_only = '@TESTS_BUILD_ONLY@'.lower() in ['1', 'true', 'on'] # Add parameters and features to the config stl.test.config.configure( diff --git a/tests/libcxx/skipped_tests.txt b/tests/libcxx/skipped_tests.txt index 61b46acc242..d50700aaccf 100644 --- a/tests/libcxx/skipped_tests.txt +++ b/tests/libcxx/skipped_tests.txt @@ -57,21 +57,12 @@ language.support\support.limits\support.limits.general\locale.version.pass.cpp language.support\support.limits\support.limits.general\ostream.version.pass.cpp language.support\support.limits\support.limits.general\string_view.version.pass.cpp -# libc++ doesn't yet implement P1956R1, so it expects the old names `ispow2`, `ceil2`, `floor2`, and `log2p1` -numerics\bit\bit.pow.two\ceil2.pass.cpp -numerics\bit\bit.pow.two\floor2.pass.cpp -numerics\bit\bit.pow.two\ispow2.pass.cpp -numerics\bit\bit.pow.two\log2p1.pass.cpp - # test emits warning C4310: cast truncates constant value numerics\bit\bitops.rot\rotl.pass.cpp # libc++ doesn't yet implement P1754R1 or P1964R2, so it expects an old value for `__cpp_lib_concepts` language.support\support.limits\support.limits.general\concepts.version.pass.cpp -# libc++ doesn't yet implement P1001R2, so it expects an old value for `__cpp_lib_execution` -language.support\support.limits\support.limits.general\execution.version.pass.cpp - # *** INTERACTIONS WITH CONTEST / C1XX THAT UPSTREAM LIKELY WON'T FIX *** # Tracked by VSO-593630 " Enable libcxx filesystem tests" @@ -197,6 +188,8 @@ language.support\support.limits\support.limits.general\type_traits.version.pass. language.support\support.limits\support.limits.general\version.version.pass.cpp # Contest does not understand .sh tests, which must be run specially +input.output\iostream.objects\narrow.stream.objects\cin.sh.cpp +input.output\iostream.objects\wide.stream.objects\wcin.sh.cpp namespace\addressable_functions.sh.cpp thread\thread.condition\thread.condition.condvarany\wait_terminates.sh.cpp @@ -280,211 +273,31 @@ utilities\memory\default.allocator\allocator_void.deprecated_in_cxx17.verify.cpp utilities\memory\default.allocator\allocator.members\allocate.constexpr.size.verify.cpp utilities\memory\default.allocator\allocator.members\allocate.verify.cpp -# GH-1382: Our machinery doesn't understand compile-only `.compile.pass.cpp` tests -strings\string.view\string.view.io\stream_insert_decl_present.compile.pass.cpp - # *** MISSING STL FEATURES *** # C++20 P0355R7 " Calendars And Time Zones" -utilities\time\days.pass.cpp -utilities\time\months.pass.cpp -utilities\time\weeks.pass.cpp -utilities\time\years.pass.cpp -utilities\time\time.cal\time.cal.day\types.pass.cpp -utilities\time\time.cal\time.cal.day\time.cal.day.members\ctor.pass.cpp -utilities\time\time.cal\time.cal.day\time.cal.day.members\decrement.pass.cpp -utilities\time\time.cal\time.cal.day\time.cal.day.members\increment.pass.cpp -utilities\time\time.cal\time.cal.day\time.cal.day.members\ok.pass.cpp -utilities\time\time.cal\time.cal.day\time.cal.day.members\plus_minus_equal.pass.cpp -utilities\time\time.cal\time.cal.day\time.cal.day.nonmembers\comparisons.pass.cpp -utilities\time\time.cal\time.cal.day\time.cal.day.nonmembers\literals.pass.cpp -utilities\time\time.cal\time.cal.day\time.cal.day.nonmembers\minus.pass.cpp -utilities\time\time.cal\time.cal.day\time.cal.day.nonmembers\plus.pass.cpp utilities\time\time.cal\time.cal.day\time.cal.day.nonmembers\streaming.pass.cpp -utilities\time\time.cal\time.cal.last\types.pass.cpp -utilities\time\time.cal\time.cal.md\types.pass.cpp -utilities\time\time.cal\time.cal.md\time.cal.md.members\ctor.pass.cpp -utilities\time\time.cal\time.cal.md\time.cal.md.members\day.pass.cpp -utilities\time\time.cal\time.cal.md\time.cal.md.members\month.pass.cpp -utilities\time\time.cal\time.cal.md\time.cal.md.members\ok.pass.cpp -utilities\time\time.cal\time.cal.md\time.cal.md.nonmembers\comparisons.pass.cpp utilities\time\time.cal\time.cal.md\time.cal.md.nonmembers\streaming.pass.cpp -utilities\time\time.cal\time.cal.mdlast\comparisons.pass.cpp -utilities\time\time.cal\time.cal.mdlast\ctor.pass.cpp -utilities\time\time.cal\time.cal.mdlast\month.pass.cpp -utilities\time\time.cal\time.cal.mdlast\ok.pass.cpp utilities\time\time.cal\time.cal.mdlast\streaming.pass.cpp -utilities\time\time.cal\time.cal.mdlast\types.pass.cpp -utilities\time\time.cal\time.cal.month\types.pass.cpp -utilities\time\time.cal\time.cal.month\time.cal.month.members\ctor.pass.cpp -utilities\time\time.cal\time.cal.month\time.cal.month.members\decrement.pass.cpp -utilities\time\time.cal\time.cal.month\time.cal.month.members\increment.pass.cpp -utilities\time\time.cal\time.cal.month\time.cal.month.members\ok.pass.cpp -utilities\time\time.cal\time.cal.month\time.cal.month.members\plus_minus_equal.pass.cpp -utilities\time\time.cal\time.cal.month\time.cal.month.nonmembers\comparisons.pass.cpp -utilities\time\time.cal\time.cal.month\time.cal.month.nonmembers\literals.pass.cpp -utilities\time\time.cal\time.cal.month\time.cal.month.nonmembers\minus.pass.cpp -utilities\time\time.cal\time.cal.month\time.cal.month.nonmembers\plus.pass.cpp utilities\time\time.cal\time.cal.month\time.cal.month.nonmembers\streaming.pass.cpp -utilities\time\time.cal\time.cal.mwd\types.pass.cpp -utilities\time\time.cal\time.cal.mwd\time.cal.mwd.members\ctor.pass.cpp -utilities\time\time.cal\time.cal.mwd\time.cal.mwd.members\month.pass.cpp -utilities\time\time.cal\time.cal.mwd\time.cal.mwd.members\ok.pass.cpp -utilities\time\time.cal\time.cal.mwd\time.cal.mwd.members\weekday_indexed.pass.cpp -utilities\time\time.cal\time.cal.mwd\time.cal.mwd.nonmembers\comparisons.pass.cpp utilities\time\time.cal\time.cal.mwd\time.cal.mwd.nonmembers\streaming.pass.cpp -utilities\time\time.cal\time.cal.mwdlast\types.pass.cpp -utilities\time\time.cal\time.cal.mwdlast\time.cal.mwdlast.members\ctor.pass.cpp -utilities\time\time.cal\time.cal.mwdlast\time.cal.mwdlast.members\month.pass.cpp -utilities\time\time.cal\time.cal.mwdlast\time.cal.mwdlast.members\ok.pass.cpp -utilities\time\time.cal\time.cal.mwdlast\time.cal.mwdlast.members\weekday_last.pass.cpp -utilities\time\time.cal\time.cal.mwdlast\time.cal.mwdlast.nonmembers\comparisons.pass.cpp utilities\time\time.cal\time.cal.mwdlast\time.cal.mwdlast.nonmembers\streaming.pass.cpp -utilities\time\time.cal\time.cal.operators\month_day.pass.cpp -utilities\time\time.cal\time.cal.operators\month_day_last.pass.cpp -utilities\time\time.cal\time.cal.operators\month_weekday.pass.cpp -utilities\time\time.cal\time.cal.operators\month_weekday_last.pass.cpp -utilities\time\time.cal\time.cal.operators\year_month.pass.cpp -utilities\time\time.cal\time.cal.operators\year_month_day.pass.cpp -utilities\time\time.cal\time.cal.operators\year_month_day_last.pass.cpp -utilities\time\time.cal\time.cal.operators\year_month_weekday.pass.cpp -utilities\time\time.cal\time.cal.operators\year_month_weekday_last.pass.cpp -utilities\time\time.cal\time.cal.wdidx\types.pass.cpp -utilities\time\time.cal\time.cal.wdidx\time.cal.wdidx.members\ctor.pass.cpp -utilities\time\time.cal\time.cal.wdidx\time.cal.wdidx.members\index.pass.cpp -utilities\time\time.cal\time.cal.wdidx\time.cal.wdidx.members\ok.pass.cpp -utilities\time\time.cal\time.cal.wdidx\time.cal.wdidx.members\weekday.pass.cpp -utilities\time\time.cal\time.cal.wdidx\time.cal.wdidx.nonmembers\comparisons.pass.cpp utilities\time\time.cal\time.cal.wdidx\time.cal.wdidx.nonmembers\streaming.pass.cpp -utilities\time\time.cal\time.cal.wdlast\types.pass.cpp -utilities\time\time.cal\time.cal.wdlast\time.cal.wdlast.members\ctor.pass.cpp -utilities\time\time.cal\time.cal.wdlast\time.cal.wdlast.members\ok.pass.cpp -utilities\time\time.cal\time.cal.wdlast\time.cal.wdlast.members\weekday.pass.cpp -utilities\time\time.cal\time.cal.wdlast\time.cal.wdlast.nonmembers\comparisons.pass.cpp utilities\time\time.cal\time.cal.wdlast\time.cal.wdlast.nonmembers\streaming.pass.cpp -utilities\time\time.cal\time.cal.weekday\types.pass.cpp -utilities\time\time.cal\time.cal.weekday\time.cal.weekday.members\c_encoding.pass.cpp -utilities\time\time.cal\time.cal.weekday\time.cal.weekday.members\ctor.local_days.pass.cpp -utilities\time\time.cal\time.cal.weekday\time.cal.weekday.members\ctor.pass.cpp -utilities\time\time.cal\time.cal.weekday\time.cal.weekday.members\ctor.sys_days.pass.cpp -utilities\time\time.cal\time.cal.weekday\time.cal.weekday.members\decrement.pass.cpp -utilities\time\time.cal\time.cal.weekday\time.cal.weekday.members\increment.pass.cpp -utilities\time\time.cal\time.cal.weekday\time.cal.weekday.members\iso_encoding.pass.cpp -utilities\time\time.cal\time.cal.weekday\time.cal.weekday.members\ok.pass.cpp -utilities\time\time.cal\time.cal.weekday\time.cal.weekday.members\operator[].pass.cpp -utilities\time\time.cal\time.cal.weekday\time.cal.weekday.members\plus_minus_equal.pass.cpp -utilities\time\time.cal\time.cal.weekday\time.cal.weekday.nonmembers\comparisons.pass.cpp -utilities\time\time.cal\time.cal.weekday\time.cal.weekday.nonmembers\literals.pass.cpp -utilities\time\time.cal\time.cal.weekday\time.cal.weekday.nonmembers\minus.pass.cpp -utilities\time\time.cal\time.cal.weekday\time.cal.weekday.nonmembers\plus.pass.cpp utilities\time\time.cal\time.cal.weekday\time.cal.weekday.nonmembers\streaming.pass.cpp -utilities\time\time.cal\time.cal.year\types.pass.cpp -utilities\time\time.cal\time.cal.year\time.cal.year.members\ctor.pass.cpp -utilities\time\time.cal\time.cal.year\time.cal.year.members\decrement.pass.cpp -utilities\time\time.cal\time.cal.year\time.cal.year.members\increment.pass.cpp -utilities\time\time.cal\time.cal.year\time.cal.year.members\is_leap.pass.cpp -utilities\time\time.cal\time.cal.year\time.cal.year.members\ok.pass.cpp -utilities\time\time.cal\time.cal.year\time.cal.year.members\plus_minus.pass.cpp -utilities\time\time.cal\time.cal.year\time.cal.year.members\plus_minus_equal.pass.cpp -utilities\time\time.cal\time.cal.year\time.cal.year.nonmembers\comparisons.pass.cpp -utilities\time\time.cal\time.cal.year\time.cal.year.nonmembers\literals.pass.cpp -utilities\time\time.cal\time.cal.year\time.cal.year.nonmembers\minus.pass.cpp -utilities\time\time.cal\time.cal.year\time.cal.year.nonmembers\plus.pass.cpp utilities\time\time.cal\time.cal.year\time.cal.year.nonmembers\streaming.pass.cpp -utilities\time\time.cal\time.cal.ym\types.pass.cpp -utilities\time\time.cal\time.cal.ym\time.cal.ym.members\ctor.pass.cpp -utilities\time\time.cal\time.cal.ym\time.cal.ym.members\month.pass.cpp -utilities\time\time.cal\time.cal.ym\time.cal.ym.members\ok.pass.cpp -utilities\time\time.cal\time.cal.ym\time.cal.ym.members\plus_minus_equal_month.pass.cpp -utilities\time\time.cal\time.cal.ym\time.cal.ym.members\plus_minus_equal_year.pass.cpp -utilities\time\time.cal\time.cal.ym\time.cal.ym.members\year.pass.cpp -utilities\time\time.cal\time.cal.ym\time.cal.ym.nonmembers\comparisons.pass.cpp -utilities\time\time.cal\time.cal.ym\time.cal.ym.nonmembers\minus.pass.cpp -utilities\time\time.cal\time.cal.ym\time.cal.ym.nonmembers\plus.pass.cpp utilities\time\time.cal\time.cal.ym\time.cal.ym.nonmembers\streaming.pass.cpp -utilities\time\time.cal\time.cal.ymd\types.pass.cpp -utilities\time\time.cal\time.cal.ymd\time.cal.ymd.members\ctor.local_days.pass.cpp -utilities\time\time.cal\time.cal.ymd\time.cal.ymd.members\ctor.pass.cpp -utilities\time\time.cal\time.cal.ymd\time.cal.ymd.members\ctor.sys_days.pass.cpp -utilities\time\time.cal\time.cal.ymd\time.cal.ymd.members\ctor.year_month_day_last.pass.cpp -utilities\time\time.cal\time.cal.ymd\time.cal.ymd.members\day.pass.cpp -utilities\time\time.cal\time.cal.ymd\time.cal.ymd.members\month.pass.cpp -utilities\time\time.cal\time.cal.ymd\time.cal.ymd.members\ok.pass.cpp -utilities\time\time.cal\time.cal.ymd\time.cal.ymd.members\op.local_days.pass.cpp -utilities\time\time.cal\time.cal.ymd\time.cal.ymd.members\op.sys_days.pass.cpp -utilities\time\time.cal\time.cal.ymd\time.cal.ymd.members\plus_minus_equal_month.pass.cpp -utilities\time\time.cal\time.cal.ymd\time.cal.ymd.members\plus_minus_equal_year.pass.cpp -utilities\time\time.cal\time.cal.ymd\time.cal.ymd.members\year.pass.cpp -utilities\time\time.cal\time.cal.ymd\time.cal.ymd.nonmembers\comparisons.pass.cpp -utilities\time\time.cal\time.cal.ymd\time.cal.ymd.nonmembers\minus.pass.cpp -utilities\time\time.cal\time.cal.ymd\time.cal.ymd.nonmembers\plus.pass.cpp utilities\time\time.cal\time.cal.ymd\time.cal.ymd.nonmembers\streaming.pass.cpp -utilities\time\time.cal\time.cal.ymdlast\time.cal.ymdlast.members\ctor.pass.cpp -utilities\time\time.cal\time.cal.ymdlast\time.cal.ymdlast.members\day.pass.cpp -utilities\time\time.cal\time.cal.ymdlast\time.cal.ymdlast.members\month.pass.cpp -utilities\time\time.cal\time.cal.ymdlast\time.cal.ymdlast.members\month_day_last.pass.cpp -utilities\time\time.cal\time.cal.ymdlast\time.cal.ymdlast.members\ok.pass.cpp -utilities\time\time.cal\time.cal.ymdlast\time.cal.ymdlast.members\op_local_days.pass.cpp -utilities\time\time.cal\time.cal.ymdlast\time.cal.ymdlast.members\op_sys_days.pass.cpp -utilities\time\time.cal\time.cal.ymdlast\time.cal.ymdlast.members\plus_minus_equal_month.pass.cpp -utilities\time\time.cal\time.cal.ymdlast\time.cal.ymdlast.members\plus_minus_equal_year.pass.cpp -utilities\time\time.cal\time.cal.ymdlast\time.cal.ymdlast.members\year.pass.cpp -utilities\time\time.cal\time.cal.ymdlast\time.cal.ymdlast.nonmembers\comparisons.pass.cpp -utilities\time\time.cal\time.cal.ymdlast\time.cal.ymdlast.nonmembers\minus.pass.cpp -utilities\time\time.cal\time.cal.ymdlast\time.cal.ymdlast.nonmembers\plus.pass.cpp utilities\time\time.cal\time.cal.ymdlast\time.cal.ymdlast.nonmembers\streaming.pass.cpp -utilities\time\time.cal\time.cal.ymwd\types.pass.cpp -utilities\time\time.cal\time.cal.ymwd\time.cal.ymwd.members\ctor.local_days.pass.cpp -utilities\time\time.cal\time.cal.ymwd\time.cal.ymwd.members\ctor.pass.cpp -utilities\time\time.cal\time.cal.ymwd\time.cal.ymwd.members\ctor.sys_days.pass.cpp -utilities\time\time.cal\time.cal.ymwd\time.cal.ymwd.members\index.pass.cpp -utilities\time\time.cal\time.cal.ymwd\time.cal.ymwd.members\month.pass.cpp -utilities\time\time.cal\time.cal.ymwd\time.cal.ymwd.members\ok.pass.cpp -utilities\time\time.cal\time.cal.ymwd\time.cal.ymwd.members\op.local_days.pass.cpp -utilities\time\time.cal\time.cal.ymwd\time.cal.ymwd.members\op.sys_days.pass.cpp -utilities\time\time.cal\time.cal.ymwd\time.cal.ymwd.members\plus_minus_equal_month.pass.cpp -utilities\time\time.cal\time.cal.ymwd\time.cal.ymwd.members\plus_minus_equal_year.pass.cpp -utilities\time\time.cal\time.cal.ymwd\time.cal.ymwd.members\weekday.pass.cpp -utilities\time\time.cal\time.cal.ymwd\time.cal.ymwd.members\weekday_indexed.pass.cpp -utilities\time\time.cal\time.cal.ymwd\time.cal.ymwd.members\year.pass.cpp -utilities\time\time.cal\time.cal.ymwd\time.cal.ymwd.nonmembers\comparisons.pass.cpp -utilities\time\time.cal\time.cal.ymwd\time.cal.ymwd.nonmembers\minus.pass.cpp -utilities\time\time.cal\time.cal.ymwd\time.cal.ymwd.nonmembers\plus.pass.cpp utilities\time\time.cal\time.cal.ymwd\time.cal.ymwd.nonmembers\streaming.pass.cpp -utilities\time\time.cal\time.cal.ymwdlast\types.pass.cpp -utilities\time\time.cal\time.cal.ymwdlast\time.cal.ymwdlast.members\ctor.pass.cpp -utilities\time\time.cal\time.cal.ymwdlast\time.cal.ymwdlast.members\month.pass.cpp -utilities\time\time.cal\time.cal.ymwdlast\time.cal.ymwdlast.members\ok.pass.cpp -utilities\time\time.cal\time.cal.ymwdlast\time.cal.ymwdlast.members\op_local_days.pass.cpp -utilities\time\time.cal\time.cal.ymwdlast\time.cal.ymwdlast.members\op_sys_days.pass.cpp -utilities\time\time.cal\time.cal.ymwdlast\time.cal.ymwdlast.members\plus_minus_equal_month.pass.cpp -utilities\time\time.cal\time.cal.ymwdlast\time.cal.ymwdlast.members\plus_minus_equal_year.pass.cpp -utilities\time\time.cal\time.cal.ymwdlast\time.cal.ymwdlast.members\weekday.pass.cpp -utilities\time\time.cal\time.cal.ymwdlast\time.cal.ymwdlast.members\year.pass.cpp -utilities\time\time.cal\time.cal.ymwdlast\time.cal.ymwdlast.nonmembers\comparisons.pass.cpp -utilities\time\time.cal\time.cal.ymwdlast\time.cal.ymwdlast.nonmembers\minus.pass.cpp -utilities\time\time.cal\time.cal.ymwdlast\time.cal.ymwdlast.nonmembers\plus.pass.cpp utilities\time\time.cal\time.cal.ymwdlast\time.cal.ymwdlast.nonmembers\streaming.pass.cpp utilities\time\time.clock\time.clock.file\consistency.pass.cpp utilities\time\time.clock\time.clock.file\file_time.pass.cpp utilities\time\time.clock\time.clock.file\now.pass.cpp utilities\time\time.clock\time.clock.file\rep_signed.pass.cpp -utilities\time\time.clock\time.clock.system\local_time.types.pass.cpp -utilities\time\time.clock\time.clock.system\sys.time.types.pass.cpp -utilities\time\time.duration\time.duration.literals\literals1.pass.cpp -utilities\time\time.hms\time.12\is_am.pass.cpp -utilities\time\time.hms\time.12\is_pm.pass.cpp -utilities\time\time.hms\time.12\make12.pass.cpp -utilities\time\time.hms\time.12\make24.pass.cpp -utilities\time\time.hms\time.hms.members\hours.pass.cpp -utilities\time\time.hms\time.hms.members\is_negative.pass.cpp -utilities\time\time.hms\time.hms.members\minutes.pass.cpp -utilities\time\time.hms\time.hms.members\precision.pass.cpp -utilities\time\time.hms\time.hms.members\precision_type.pass.cpp -utilities\time\time.hms\time.hms.members\seconds.pass.cpp -utilities\time\time.hms\time.hms.members\subseconds.pass.cpp -utilities\time\time.hms\time.hms.members\to_duration.pass.cpp -utilities\time\time.hms\time.hms.members\width.pass.cpp + +# C++20 P0466R5 "Layout-Compatibility And Pointer-Interconvertibility Traits" +language.support\support.limits\support.limits.general\type_traits.version.pass.cpp # C++20 P0608R3 "Improving variant's Converting Constructor/Assignment" utilities\variant\variant.variant\variant.assign\conv.pass.cpp @@ -492,6 +305,10 @@ utilities\variant\variant.variant\variant.assign\T.pass.cpp utilities\variant\variant.variant\variant.ctor\conv.pass.cpp utilities\variant\variant.variant\variant.ctor\T.pass.cpp +# C++20 P0645R10 " Text Formatting" +language.support\support.limits\support.limits.general\format.version.pass.cpp +utilities\format\format.error\format.error.pass.cpp + # C++20 P0784R7 "More constexpr containers" utilities\memory\allocator.traits\allocator.traits.members\allocate.pass.cpp utilities\memory\allocator.traits\allocator.traits.members\allocate_hint.pass.cpp @@ -512,12 +329,32 @@ language.support\support.limits\support.limits.general\functional.version.pass.c language.support\support.limits\support.limits.general\iterator.version.pass.cpp language.support\support.limits\support.limits.general\memory.version.pass.cpp +# C++20 P1004R2 "constexpr std::vector" +language.support\support.limits\support.limits.general\vector.version.pass.cpp + +# C++20 P1614R2 "Adding Spaceship <=> To The Library" +language.support\support.limits\support.limits.general\compare.version.pass.cpp + +# C++23 P1048R1 "is_scoped_enum" +utilities\meta\meta.unary\meta.unary.prop\is_scoped_enum.pass.cpp + +# C++23 P1679R3 "contains() For basic_string/basic_string_view" +strings\basic.string\string.contains\contains.char.pass.cpp +strings\basic.string\string.contains\contains.ptr.pass.cpp +strings\basic.string\string.contains\contains.string_view.pass.cpp +strings\string.view\string.view.template\contains.char.pass.cpp +strings\string.view\string.view.template\contains.ptr.pass.cpp +strings\string.view\string.view.template\contains.string_view.pass.cpp + # *** MISSING COMPILER FEATURES *** # Nothing here! :-) # *** MISSING LWG ISSUE RESOLUTIONS *** +# LWG-2503 "multiline option should be added to syntax_option_type" +re\re.const\re.matchflag\match_multiline.pass.cpp + # LWG-2532 "Satisfying a promise at thread exit" (Open) # WCFB02 implements the proposed resolution for this issue thread\futures\futures.promise\set_exception_at_thread_exit.pass.cpp @@ -541,6 +378,10 @@ utilities\utility\pairs\pairs.pair\assign_pair.pass.cpp utilities\utility\pairs\pairs.pair\assign_rv_pair.pass.cpp utilities\utility\pairs\pairs.pair\assign_rv_pair_U_V.pass.cpp +# VSO-1271673 "static analyzer doesn't know about short-circuiting" +algorithms\alg.sorting\alg.sort\partial.sort\partial_sort.pass.cpp +algorithms\alg.sorting\alg.sort\partial.sort\partial_sort_comp.pass.cpp + # *** CLANG COMPILER BUGS *** # LLVM-33230 "Clang on Windows should define __STDCPP_THREADS__ to be 1" @@ -581,7 +422,6 @@ containers\sequences\array\array.data\data.pass.cpp containers\sequences\array\iterators.pass.cpp # GH-1006 : debug checks for predicates are observable -algorithms\alg.sorting\alg.heap.operations\make.heap\make_heap_comp.pass.cpp algorithms\alg.sorting\alg.merge\inplace_merge_comp.pass.cpp algorithms\alg.sorting\alg.min.max\minmax_init_list_comp.pass.cpp @@ -646,6 +486,15 @@ utilities\meta\meta.trans\meta.trans.other\aligned_storage.pass.cpp depr\depr.c.headers\math_h.pass.cpp numerics\c.math\cmath.pass.cpp +# GH-1596: : unqualified calls to _Adl_verify_range incorrectly cause instantiation +algorithms\robust_against_adl.pass.cpp + +# GH-1595: : bit_ceil(T(-1)) should not be a constant expression +numerics\bit\bit.pow.two\bit_ceil.fail.cpp + +# GH-1530: : Poisson approximation for binomial_distribution is not accurate +numerics\rand\rand.dis\rand.dist.bern\rand.dist.bern.bin\eval.PR44847.pass.cpp + # *** CRT BUGS *** # We're permanently missing aligned_alloc(). @@ -662,15 +511,6 @@ language.support\support.limits\c.limits\cfloat.pass.cpp # *** LIKELY BOGUS TESTS *** -# "error: _LIBCPP_VERSION not defined" -thread\thread.barrier\version.pass.cpp -thread\thread.latch\version.pass.cpp -thread\thread.semaphore\version.pass.cpp - -# "error C3861: 'assert': identifier not found" -thread\thread.semaphore\timed.pass.cpp -thread\thread.semaphore\try_acquire.pass.cpp - # pass lambda without noexcept to barrier thread\thread.barrier\completion.pass.cpp thread\thread.barrier\max.pass.cpp @@ -684,15 +524,6 @@ utilities\smartptr\unique.ptr\unique.ptr.class\unique.ptr.asgn\move.pass.cpp # Test bug after LWG-3257 "Missing feature testing macro update from P0858" was accepted. language.support\support.limits\support.limits.general\string.version.pass.cpp -# libc++ expects an old value for `__cpp_lib_array_constexpr` (`201603L`). We've implemented P0858R0, P1023R0, and P1032R1, increasing the value to `201811L`. -language.support\support.limits\support.limits.general\array.version.pass.cpp - -# libc++ expects the old macro `__cpp_lib_constexpr_misc`. After P1902R1, it should expect `__cpp_lib_constexpr_tuple` to have the value `201811L`. -language.support\support.limits\support.limits.general\tuple.version.pass.cpp - -# libc++ expects the old macro `__cpp_lib_constexpr_misc`. After P1902R1, it should expect `__cpp_lib_constexpr_utility` to have the value `201811L`. -language.support\support.limits\support.limits.general\utility.version.pass.cpp - # Not yet analyzed, likely bogus tests. Appears to be timing assumptions. thread\futures\futures.async\async.pass.cpp thread\futures\futures.shared_future\get.pass.cpp @@ -809,6 +640,39 @@ numerics\rand\rand.dis\rand.dist.samp\rand.dist.samp.plinear\eval.pass.cpp # They shouldn't behave differently. Both of them should probably return NaN. numerics\c.math\c.math.lerp\c.math.lerp.pass.cpp +# --month{14} should be 1, not 13 as the test expects +utilities\time\time.cal\time.cal.month\time.cal.month.members\decrement.pass.cpp + +# test is broken due to month_weekday not being default constructible +utilities\time\time.cal\time.cal.mwd\time.cal.mwd.members\month.pass.cpp + +# conversion from '__int64' to 'long', possible loss of data +utilities\time\time.hms\time.hms.members\seconds.pass.cpp +utilities\time\time.hms\time.hms.members\subseconds.pass.cpp + +# Code: `for (int i = 1000; i < 20; ++i)` +# warning C6294: Ill-defined for-loop: initial condition does not satisfy test. Loop body not executed. +utilities\time\time.cal\time.cal.month\time.cal.month.nonmembers\comparisons.pass.cpp +utilities\time\time.cal\time.cal.ym\time.cal.ym.nonmembers\comparisons.pass.cpp +utilities\time\time.cal\time.cal.ymd\time.cal.ymd.nonmembers\comparisons.pass.cpp +utilities\time\time.cal\time.cal.ymdlast\time.cal.ymdlast.nonmembers\comparisons.pass.cpp +utilities\time\time.cal\time.cal.ymwd\time.cal.ymwd.nonmembers\comparisons.pass.cpp +utilities\time\time.cal\time.cal.ymwdlast\time.cal.ymwdlast.nonmembers\comparisons.pass.cpp + +# Tests are manually declaring printf, which appears to be unused. +# warning C28301: No annotations for first declaration of 'printf'. +utilities\time\time.cal\time.cal.weekday\time.cal.weekday.nonmembers\minus.pass.cpp +utilities\time\time.cal\time.cal.year\time.cal.year.nonmembers\minus.pass.cpp + +# Bogus test passes a class type as the second argument to std::advance +iterators\iterator.primitives\iterator.operations\robust_against_adl.pass.cpp + +# Non-Standard test should be moved from libcxx/test/std to libcxx/test/libcxx +utilities\memory\util.smartptr\util.smartptr.shared\libcxx.control_block_layout.pass.cpp + +# Non-Standard assumption that std::filesystem::file_time_type::duration::period is std::nano +input.output\filesystems\fs.filesystem.synopsis\file_time_type_resolution.compile.pass.cpp + # *** LIKELY STL BUGS *** # Not yet analyzed, likely STL bugs. Assertions and other runtime failures. @@ -1006,3 +870,35 @@ containers\sequences\deque\deque.modifiers\insert_iter_iter.pass.cpp # Not yet analyzed. Failing after https://reviews.llvm.org/D75622. re\re.const\re.matchflag\match_prev_avail.pass.cpp + +# Not yet analyzed. Many diagnostics. +input.output\filesystems\class.path\path.member\path.charconv.pass.cpp + +# Not yet analyzed. Probably ADL shenanigans. +thread\thread.threads\thread.thread.class\thread.thread.constr\robust_against_adl.pass.cpp +utilities\function.objects\func.wrap\func.wrap.func\robust_against_adl.pass.cpp +utilities\function.objects\refwrap\refwrap.invoke\robust_against_adl.pass.cpp +utilities\variant\variant.visit\robust_against_adl.pass.cpp + +# Not yet analyzed. Probably MSVC bug. +utilities\function.objects\func.invoke\invoke_constexpr.pass.cpp + +# Not yet analyzed. Probably name mangling bug. +utilities\function.objects\func.wrap\func.wrap.func\noncopyable_return_type.pass.cpp + +# Not yet analyzed. Failing for "[a[.ch.]z]". +re\re.alg\re.alg.match\awk.locale.pass.cpp +re\re.alg\re.alg.match\basic.locale.pass.cpp +re\re.alg\re.alg.match\ecma.locale.pass.cpp +re\re.alg\re.alg.match\extended.locale.pass.cpp +re\re.alg\re.alg.search\awk.locale.pass.cpp +re\re.alg\re.alg.search\basic.locale.pass.cpp +re\re.alg\re.alg.search\ecma.locale.pass.cpp +re\re.alg\re.alg.search\extended.locale.pass.cpp + + +# *** SKIPPED FOR MSVC-INTERNAL CONTEST ONLY *** +# Our machinery doesn't understand compile-only `.compile.pass.cpp` tests. +# (Implemented for GitHub, see GH-1382.) +concepts\concept.constructible\constructible_from.compile.pass.cpp +strings\string.view\string.view.io\stream_insert_decl_present.compile.pass.cpp diff --git a/tests/std/include/test_atomic_wait.hpp b/tests/std/include/test_atomic_wait.hpp index a3d9b4471c2..cd061882d2d 100644 --- a/tests/std/include/test_atomic_wait.hpp +++ b/tests/std/include/test_atomic_wait.hpp @@ -43,7 +43,7 @@ void test_atomic_wait_func_impl(UnderlyingType& old_value, const UnderlyingType // timing assumption that the main thread evaluates the `wait(old_value)` before this timeout expires std::this_thread::sleep_for(waiting_duration); add_seq('6'); -#endif // CAN_FAIL_ON_TIMING_ASSUMPTION +#endif }); a.wait(old_value); @@ -187,6 +187,8 @@ struct big_char_like { friend bool operator==(big_char_like, big_char_like) = delete; }; +#pragma warning(push) +#pragma warning(disable : 4324) // structure was padded due to alignment specifier template struct with_padding_bits { alignas(size) char value; @@ -197,6 +199,7 @@ struct with_padding_bits { friend bool operator==(with_padding_bits, with_padding_bits) = delete; }; +#pragma warning(pop) inline void test_atomic_wait() { // wait for all the threads to be waiting; if this value is too small the test might be ineffective but should not @@ -249,7 +252,9 @@ inline void test_atomic_wait() { test_pad_bits>(waiting_duration); test_pad_bits>(waiting_duration); test_pad_bits>(waiting_duration); +#ifndef _M_ARM test_pad_bits>(waiting_duration); test_pad_bits>(waiting_duration); +#endif // ^^^ !ARM ^^^ #endif // __clang__, TRANSITION, LLVM-46685 } diff --git a/tests/std/lit.site.cfg.in b/tests/std/lit.site.cfg.in index 6455f31677a..653f76d16a3 100644 --- a/tests/std/lit.site.cfg.in +++ b/tests/std/lit.site.cfg.in @@ -30,6 +30,7 @@ lit_config.test_subdirs[config.name] = ['@CMAKE_CURRENT_SOURCE_DIR@/tests'] lit_config.cxx_headers = '@STL_TESTED_HEADERS_DIR@' lit_config.cxx_runtime = '@CMAKE_RUNTIME_OUTPUT_DIRECTORY@' lit_config.target_arch = '@VCLIBS_TARGET_ARCHITECTURE@' +lit_config.build_only = '@TESTS_BUILD_ONLY@'.lower() in ['1', 'true', 'on'] # Add parameters and features to the config stl.test.config.configure( diff --git a/tests/std/test.lst b/tests/std/test.lst index e1d4e28a8c8..4147920dacb 100644 --- a/tests/std/test.lst +++ b/tests/std/test.lst @@ -226,7 +226,12 @@ tests\P0220R1_searchers tests\P0220R1_string_view tests\P0325R4_to_array tests\P0339R6_polymorphic_allocator +tests\P0355R7_calendars_and_time_zones_clocks +tests\P0355R7_calendars_and_time_zones_dates +tests\P0355R7_calendars_and_time_zones_dates_literals +tests\P0355R7_calendars_and_time_zones_hms tests\P0355R7_calendars_and_time_zones_io +tests\P0355R7_calendars_and_time_zones_time_point_and_durations tests\P0356R5_bind_front tests\P0357R3_supporting_incomplete_types_in_reference_wrapper tests\P0408R7_efficient_access_to_stringbuf_buffer @@ -234,6 +239,7 @@ tests\P0414R2_shared_ptr_for_arrays tests\P0415R1_constexpr_complex tests\P0426R1_constexpr_char_traits tests\P0433R2_deduction_guides +tests\P0466R5_layout_compatibility_and_pointer_interconvertibility_traits tests\P0476R2_bit_cast tests\P0487R1_fixing_operator_shl_basic_istream_char_pointer tests\P0513R0_poisoning_the_hash @@ -287,6 +293,7 @@ tests\P0896R4_ranges_alg_generate tests\P0896R4_ranges_alg_generate_n tests\P0896R4_ranges_alg_heap tests\P0896R4_ranges_alg_includes +tests\P0896R4_ranges_alg_inplace_merge tests\P0896R4_ranges_alg_is_permutation tests\P0896R4_ranges_alg_is_sorted tests\P0896R4_ranges_alg_lexicographical_compare @@ -324,6 +331,8 @@ tests\P0896R4_ranges_alg_set_symmetric_difference tests\P0896R4_ranges_alg_set_union tests\P0896R4_ranges_alg_shuffle tests\P0896R4_ranges_alg_sort +tests\P0896R4_ranges_alg_stable_partition +tests\P0896R4_ranges_alg_stable_sort tests\P0896R4_ranges_alg_swap_ranges tests\P0896R4_ranges_alg_transform_binary tests\P0896R4_ranges_alg_transform_unary diff --git a/tests/std/tests/Dev11_0920385_list_sort_allocator/test.cpp b/tests/std/tests/Dev11_0920385_list_sort_allocator/test.cpp index aa38f7b4c6a..d1c74c1e5ad 100644 --- a/tests/std/tests/Dev11_0920385_list_sort_allocator/test.cpp +++ b/tests/std/tests/Dev11_0920385_list_sort_allocator/test.cpp @@ -3,6 +3,7 @@ // Test DevDiv-920385 ": list::sort shouldn't default-construct allocators". +#define _HAS_DEPRECATED_ALLOCATOR_MEMBERS 1 #define _SILENCE_CXX17_OLD_ALLOCATOR_MEMBERS_DEPRECATION_WARNING #include diff --git a/tests/std/tests/GH_000690_overaligned_function/test.cpp b/tests/std/tests/GH_000690_overaligned_function/test.cpp index effd03765af..0e5623f2054 100644 --- a/tests/std/tests/GH_000690_overaligned_function/test.cpp +++ b/tests/std/tests/GH_000690_overaligned_function/test.cpp @@ -1,6 +1,8 @@ // Copyright (c) Microsoft Corporation. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// UNSUPPORTED: arm + #include #include #include diff --git a/tests/std/tests/P0218R1_filesystem/test.cpp b/tests/std/tests/P0218R1_filesystem/test.cpp index 7273aff888f..610e1003b8b 100644 --- a/tests/std/tests/P0218R1_filesystem/test.cpp +++ b/tests/std/tests/P0218R1_filesystem/test.cpp @@ -1224,6 +1224,12 @@ void test_directory_entry() { EXPECT(good(ec)); remove(dirPath, ec); EXPECT(good(ec)); + + // LWG-3171 "LWG-2989 breaks directory_entry stream insertion" + const directory_entry iostreamEntry{path{R"(one\two\three)"}}; + ostringstream oss; + oss << iostreamEntry; + EXPECT(oss.str() == R"("one\\two\\three")"); } template @@ -3838,8 +3844,13 @@ basic_ostream& operator<<(basic_ostream& str, const return str << status.type() << L' ' << status.permissions(); } +struct directory_entry_wrapper { + directory_entry value; +}; + template -basic_ostream& operator<<(basic_ostream& str, const directory_entry& de) { +basic_ostream& operator<<(basic_ostream& str, const directory_entry_wrapper& de_wrapper) { + const directory_entry& de = de_wrapper.value; return str << L"\n symlink_status: " << de.symlink_status() << L"\n status: " << de.status() << L"\n size: " << de.file_size() << L"\n last_write_time: " << de.last_write_time().time_since_epoch().count() << L"\n hard_link_count: " << de.hard_link_count(); @@ -3872,7 +3883,7 @@ void run_interactive_tests(int argc, wchar_t* argv[]) { } else if (starts_with(arg, L"-stat:"sv)) { wcerr << quoted(arg) << L" => " << status(the_rest) << "\n"; } else if (starts_with(arg, L"-de:"sv)) { - wcerr << quoted(arg) << L" => " << directory_entry(the_rest) << "\n"; + wcerr << quoted(arg) << L" => " << directory_entry_wrapper{directory_entry(the_rest)} << "\n"; } else if (starts_with(arg, L"-mkdir:"sv)) { wcerr << L"create_directory => " << create_directory(the_rest) << "\n"; } else if (starts_with(arg, L"-mkdirs:"sv)) { diff --git a/tests/std/tests/P0355R7_calendars_and_time_zones_clocks/env.lst b/tests/std/tests/P0355R7_calendars_and_time_zones_clocks/env.lst new file mode 100644 index 00000000000..642f530ffad --- /dev/null +++ b/tests/std/tests/P0355R7_calendars_and_time_zones_clocks/env.lst @@ -0,0 +1,4 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\usual_latest_matrix.lst diff --git a/tests/std/tests/P0355R7_calendars_and_time_zones_clocks/test.compile.pass.cpp b/tests/std/tests/P0355R7_calendars_and_time_zones_clocks/test.compile.pass.cpp new file mode 100644 index 00000000000..26ac91006b0 --- /dev/null +++ b/tests/std/tests/P0355R7_calendars_and_time_zones_clocks/test.compile.pass.cpp @@ -0,0 +1,86 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include + +using namespace std::chrono; + +struct not_a_clock { + bool rep(); + static char period; + int duration(); + static float time_point; + using is_steady = long; + static int now; +}; + +struct real_fake_clock { + using rep = bool; + using period = char; + using duration = float; + using time_point = int; + static long is_steady; + static short now(); +}; + +struct no_rep { + using period = char; + using duration = float; + using time_point = int; + static long is_steady; + static short now(); +}; + +struct no_period { + using rep = bool; + using duration = float; + using time_point = int; + static long is_steady; + static short now(); +}; + +struct no_duration { + using rep = bool; + using period = char; + using time_point = int; + static long is_steady; + static short now(); +}; + +struct no_time_point { + using rep = bool; + using period = char; + using duration = float; + static long is_steady; + static short now(); +}; + +struct no_steady { + using rep = bool; + using period = char; + using duration = float; + using time_point = int; + static short now(); +}; + +struct no_now { + using rep = bool; + using period = char; + using duration = float; + using time_point = int; + static long is_steady; +}; + +static_assert(is_clock::value, "steady_clock is not a clock"); +static_assert(is_clock_v, "steady_clock is not a clock"); +static_assert(is_clock_v, "real_fake_clock is not a clock"); +static_assert(!is_clock_v, "not_a_clock is a clock"); + +static_assert(!is_clock_v, "no_rep is a clock"); +static_assert(!is_clock_v, "no_period is a clock"); +static_assert(!is_clock_v, "no_duration is a clock"); +static_assert(!is_clock_v, "no_time_point is a clock"); +static_assert(!is_clock_v, "no_steady is a clock"); +static_assert(!is_clock_v, "no_now is a clock"); + +int main() {} // COMPILE-ONLY diff --git a/tests/std/tests/P0355R7_calendars_and_time_zones_dates/env.lst b/tests/std/tests/P0355R7_calendars_and_time_zones_dates/env.lst new file mode 100644 index 00000000000..642f530ffad --- /dev/null +++ b/tests/std/tests/P0355R7_calendars_and_time_zones_dates/env.lst @@ -0,0 +1,4 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\usual_latest_matrix.lst diff --git a/tests/std/tests/P0355R7_calendars_and_time_zones_dates/test.cpp b/tests/std/tests/P0355R7_calendars_and_time_zones_dates/test.cpp new file mode 100644 index 00000000000..90d6d7ad946 --- /dev/null +++ b/tests/std/tests/P0355R7_calendars_and_time_zones_dates/test.cpp @@ -0,0 +1,988 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include + +using namespace std; +using namespace std::chrono; + +constexpr int y_min = -32767; +constexpr int y_max = 32767; + +// For testing LWG-3260 "year_month* arithmetic rejects durations convertible to years" +using Decades = duration, years::period>>; + +constexpr void day_test() { + day d{0u}; + + static_assert(noexcept(day{})); + static_assert(noexcept(day{0u})); + + static_assert(noexcept(++d)); + static_assert(noexcept(d++)); + static_assert(noexcept(--d)); + static_assert(noexcept(d--)); + static_assert(noexcept(d += days{})); + static_assert(noexcept(d -= days{})); + + static_assert(noexcept(static_cast(d))); + static_assert(noexcept(d.ok())); + + static_assert(noexcept(d == d)); + static_assert(noexcept(d <=> d)); + + static_assert(noexcept(d + days{})); + static_assert(noexcept(days{} + d)); + + static_assert(noexcept(d - days{})); + static_assert(noexcept(d - d)); + + static_assert(noexcept(0d)); + + assert(static_cast(d) == 0u); + assert(d == 0d); + assert(++d == 1d); + assert(d++ == 1d); + assert(d == 2d); + + assert(--d == 1d); + assert(d-- == 1d); + assert(d == 0d); + + d += days{2}; + assert(d == 2d); + d -= days{2}; + assert(d == 0d); + + assert(d < 2d); + assert(2d > d); + + for (unsigned int i = 0; i <= 255; ++i) { + if (i > 0 && i <= 31) { + assert(day{i}.ok()); + } else { + assert(!day{i}.ok()); + } + } + + assert(5d + days{5} == 10d); + assert(days{5} + 5d == 10d); + assert(10d - days{5} == 5d); + assert(10d - 2d == days{8}); +} + +constexpr void month_test() { + month m{1u}; + + static_assert(noexcept(month{})); + static_assert(noexcept(month{0u})); + + static_assert(noexcept(++m)); + static_assert(noexcept(m++)); + static_assert(noexcept(--m)); + static_assert(noexcept(m--)); + static_assert(noexcept(m += months{})); + static_assert(noexcept(m -= months{})); + + static_assert(noexcept(static_cast(m))); + static_assert(noexcept(m.ok())); + + static_assert(noexcept(m == m)); + static_assert(noexcept(m <=> m)); + + static_assert(noexcept(m + months{})); + static_assert(noexcept(months{0} + m)); + + static_assert(noexcept(m - months{})); + static_assert(noexcept(m - m)); + + assert(static_cast(m) == 1u); + assert(m == January); + assert(++m == February); + assert(m++ == February); + assert(m == March); + + assert(--m == February); + assert(m-- == February); + assert(m == January); + + m += months{2}; + assert(m == March); + m -= months{2}; + assert(m == January); + + for (unsigned int i = 0; i <= 255; ++i) { + if (i >= 1 && i <= 12) { + assert(month{i}.ok()); + } else { + assert(!month{i}.ok()); + } + } + + assert(February > m); + assert(m < February); + + assert(February + months{11} == January); + assert(months{11} + February == January); + assert(month{0} + months{1} == January); + assert(month{13} + months{1} == February); + assert(month{23} + months{1} == December); + assert(February - months{2} == December); + assert(January - February == months{11}); +} + +constexpr void year_test() { + year y{1}; + + static_assert(noexcept(year{})); + static_assert(noexcept(year{0})); + + static_assert(noexcept(++y)); + static_assert(noexcept(y++)); + static_assert(noexcept(--y)); + static_assert(noexcept(y--)); + static_assert(noexcept(y += years{})); + static_assert(noexcept(y -= years{})); + static_assert(noexcept(+y)); + static_assert(noexcept(-y)); + + static_assert(noexcept(y.is_leap())); + static_assert(noexcept(static_cast(y))); + static_assert(noexcept(y.ok())); + static_assert(noexcept(year::min())); + static_assert(noexcept(year::max())); + + static_assert(noexcept(y == y)); + static_assert(noexcept(y <=> y)); + + static_assert(noexcept(y + years{})); + static_assert(noexcept(years{} + y)); + + static_assert(noexcept(y - years{})); + static_assert(noexcept(y - y)); + + static_assert(noexcept(0y)); + + assert(static_cast(y) == 1); + assert(y == 1y); + assert(++y == 2y); + assert(y++ == 2y); + assert(y == 3y); + + assert(--y == 2y); + assert(y-- == 2y); + assert(y == 1y); + + y += years{2}; + assert(y == 3y); + y -= years{2}; + assert(y == 1y); + + year extreme{-30'000}; + extreme += years{60'000}; + assert(extreme == 30'000y); + extreme -= years{60'000}; + assert(extreme == -30'000y); + + assert(+y == 1y); + assert(-y == year{-1}); + auto y2 = -y; + assert(-y2 == y); + assert(+y2 == -y); + + assert(year::min() == year{y_min}); + assert(year::max() == year{y_max}); + + assert(!year{y_min - 1}.ok()); + assert(!year{y_max + 1}.ok()); + + for (int i = y_min; i <= y_max; ++i) { + assert(year{i}.ok()); + if (i % 4 == 0 && (i % 100 != 0 || i % 400 == 0)) { + assert(year{i}.is_leap()); + } else { + assert(!year{i}.is_leap()); + } + } + + assert(y < 2y); + assert(2y > y); + + assert(y + years{4} == 5y); + assert(years{4} + y == 5y); + + assert(y - years{4} == -3y); + assert(year{10} - year{5} == years{5}); + assert(year{-5} - year{-10} == years{5}); +} + +constexpr void weekday_test() { + weekday wd{0u}; + + static_assert(noexcept(weekday{})); + static_assert(noexcept(weekday{0u})); + static_assert(noexcept(weekday{sys_days{}})); + static_assert(noexcept(weekday{local_days{}})); + + static_assert(noexcept(++wd)); + static_assert(noexcept(wd++)); + static_assert(noexcept(--wd)); + static_assert(noexcept(wd--)); + static_assert(noexcept(wd += days{})); + static_assert(noexcept(wd -= days{})); + + static_assert(noexcept(wd.c_encoding())); + static_assert(noexcept(wd.iso_encoding())); + static_assert(noexcept(wd.ok())); + static_assert(noexcept(wd[0u])); + static_assert(noexcept(wd[last])); + + static_assert(noexcept(wd == wd)); + + static_assert(noexcept(wd + days{})); + static_assert(noexcept(days{} + wd)); + + static_assert(noexcept(wd - days{})); + static_assert(noexcept(wd - wd)); + + assert(weekday{7} == Sunday); + assert(weekday{sys_days{}} == Thursday); + assert(weekday{local_days{}} == sys_days{local_days{}.time_since_epoch()}); + + assert(wd == Sunday); + assert(++wd == Monday); + assert(wd++ == Monday); + assert(wd == Tuesday); + + assert(--wd == Monday); + assert(wd-- == Monday); + assert(wd == Sunday); + + wd += days{2}; + assert(wd == Tuesday); + wd -= days{3}; + assert(wd == Saturday); + + assert(Sunday.c_encoding() == 0u); + assert(Sunday.iso_encoding() == 7u); + + for (unsigned int i = 0; i <= 255; ++i) { + if (i <= 7) { + assert(weekday{i}.ok()); + } else { + assert(!weekday{i}.ok()); + } + } + assert(Monday + days{6} == Sunday); + assert(Monday + days{8} == Tuesday); + assert(Wednesday + days{14} == Wednesday); + assert(Sunday - Monday == days{6}); + assert(Sunday - Tuesday == days{5}); + assert(Wednesday - Thursday == days{6}); +} + +constexpr void weekday_indexed_test() { + const weekday_indexed wdi1{Monday, 2}; + + static_assert(noexcept(weekday_indexed{})); + static_assert(noexcept(weekday_indexed{weekday{}, 0u})); + + static_assert(noexcept(wdi1.weekday())); + static_assert(noexcept(wdi1.index())); + static_assert(noexcept(wdi1.ok())); + + static_assert(noexcept(wdi1 == wdi1)); + + assert(wdi1.weekday() == Monday); + assert(wdi1.index() == 2); + + weekday_indexed wdi2 = Monday[2]; + assert(wdi2.weekday() == Monday); + assert(wdi2.index() == 2); + + assert(wdi1 == wdi2); + + assert((!weekday_indexed{Sunday, 0}.ok())); + for (unsigned int i = 1; i <= 5; ++i) { + assert((weekday_indexed{Sunday, i}.ok())); + assert((weekday_indexed{Monday, i}.ok())); + assert((weekday_indexed{Tuesday, i}.ok())); + assert((weekday_indexed{Wednesday, i}.ok())); + assert((weekday_indexed{Thursday, i}.ok())); + assert((weekday_indexed{Friday, i}.ok())); + assert((weekday_indexed{Saturday, i}.ok())); + } + assert((!weekday_indexed{Sunday, 6}.ok())); + assert((!weekday_indexed{Sunday, 7}.ok())); +} + +constexpr void weekday_last_test() { + const weekday_last wdl{Monday}; + + static_assert(noexcept(weekday_last{weekday{}})); + + static_assert(noexcept(wdl.weekday())); + static_assert(noexcept(wdl.ok())); + + static_assert(noexcept(wdl == wdl)); + + assert(wdl.ok()); + assert(Monday[last].ok()); + assert(Monday[last].weekday() == Monday); + assert(wdl.weekday() == Monday); + assert(wdl == weekday_last{Monday}); +} + +constexpr void month_day_test() { + const month_day md{January, 1d}; + + static_assert(noexcept(month_day{})); + static_assert(noexcept(month_day{month{}, day{}})); + + static_assert(noexcept(md.month())); + static_assert(noexcept(md.day())); + static_assert(noexcept(md.ok())); + + static_assert(noexcept(md == md)); + static_assert(noexcept(md <=> md)); + + assert(md.month() == January); + assert(md.day() == 1d); + + assert((md < month_day{January, 2d})); + assert((month_day{January, 2d} > md)); + assert((md < month_day{December, 25d})); + assert((month_day{December, 25d} > md)); + assert((md == month_day{January, 1d})); + + if (is_constant_evaluated()) { + static_assert((January / 31).ok()); + static_assert((February / 29).ok()); + static_assert((April / 30).ok()); + static_assert(!(January / 32).ok()); + static_assert(!(February / 30).ok()); + static_assert(!(April / 31).ok()); + } else { + for (unsigned int i = 0; i <= 255; ++i) { + month m{i}; + for (unsigned int d = 0; d <= 255; ++d) { + if (d < 1 || d > 31 || i < 1 || i > 12) { + assert((!month_day{m, day{d}}.ok())); + } else if (d == 30 && m == February) { + assert((!month_day{m, day{d}}.ok())); + } else if (d == 31 && (m == February || m == April || m == June || m == September || m == November)) { + assert((!month_day{m, day{d}}.ok())); + } else { + assert((month_day{m, day{d}}.ok())); + } + } + } + } +} + +constexpr void month_day_last_test() { + const month_day_last mdl{January}; + + static_assert(noexcept(month_day_last{month{}})); + static_assert(noexcept(mdl.month())); + static_assert(noexcept(mdl.ok())); + + static_assert(noexcept(mdl == mdl)); + static_assert(noexcept(mdl <=> mdl)); + + assert((February / last).month() == February); + + assert(!(month{0} / last).ok()); + for (unsigned int i = 1; i <= 12; ++i) { + assert((month{i} / last).ok()); + } + assert(!(month{13} / last).ok()); + + assert(January / last == January / last); + assert(January / last < February / last); + assert(December / last > February / last); +} + +constexpr void month_weekday_test() { + const auto mwd1 = January / Monday[2]; + + static_assert(noexcept(month_weekday{month{}, weekday_indexed{Sunday, 0u}})); + + static_assert(noexcept(mwd1.month())); + static_assert(noexcept(mwd1.weekday_indexed())); + static_assert(noexcept(mwd1.ok())); + + static_assert(noexcept(mwd1 == mwd1)); + + assert(mwd1.month() == January); + assert(mwd1.weekday_indexed().weekday() == Monday); + assert(mwd1.weekday_indexed().index() == 2); + + assert(January / Monday[2] == January / Monday[2]); + + if (is_constant_evaluated()) { + static_assert((January / Monday[1]).ok()); + static_assert((January / Monday[5]).ok()); + static_assert(!(January / Monday[6]).ok()); + static_assert(!(January / Monday[0]).ok()); + static_assert(!(month{0} / Monday[1]).ok()); + } else { + for (auto m = 0u; m <= 255u; ++m) { + for (auto wd = 0u; wd <= 255u; ++wd) { + for (auto wdi = 0u; wdi <= 6u; ++wdi) { + const auto mwd = month{m} / weekday{wd}[wdi]; + if (m >= 1 && m <= 12 && wd <= 7 && wdi >= 1 && wdi <= 5) { + assert(mwd.ok()); + } else { + assert(!mwd.ok()); + } + } + } + } + } +} + +constexpr void month_weekday_last_test() { + const auto mwdl = January / Monday[last]; + + static_assert(noexcept(month_weekday_last{month{}, weekday_last{Sunday}})); + static_assert(noexcept(mwdl.month())); + static_assert(noexcept(mwdl.weekday_last())); + static_assert(noexcept(mwdl.ok())); + + static_assert(noexcept(mwdl == mwdl)); + + assert(mwdl.month() == January); + assert(mwdl.weekday_last().weekday() == Monday); + assert(mwdl == January / Monday[last]); +} + +constexpr void year_month_test() { + auto ym = 2020y / January; + + static_assert(noexcept(year_month{})); + static_assert(noexcept(year_month{year{}, month{}})); + + static_assert(noexcept(ym.year())); + static_assert(noexcept(ym.month())); + + static_assert(noexcept(ym += months{})); + static_assert(noexcept(ym -= months{})); + static_assert(noexcept(ym += years{})); + static_assert(noexcept(ym -= years{})); + + static_assert(noexcept(ym.ok())); + + static_assert(noexcept(ym == ym)); + static_assert(noexcept(ym <=> ym)); + + static_assert(noexcept(ym + months{})); + static_assert(noexcept(months{} + ym)); + static_assert(noexcept(ym - months{})); + + static_assert(noexcept(ym - ym)); + static_assert(noexcept(ym + years{})); + static_assert(noexcept(years{} + ym)); + static_assert(noexcept(ym - years{})); + + assert(ym.year() == 2020y); + assert(ym.month() == January); + + ym += months{2}; + assert(ym.year() == 2020y); + assert(ym.month() == March); + ym -= months{2}; + assert(ym.year() == 2020y); + assert(ym.month() == January); + + ym += years{2}; + assert(ym.year() == 2022y); + assert(ym.month() == January); + ym -= years{2}; + assert(ym.year() == 2020y); + assert(ym.month() == January); + + ym += Decades{2}; + assert(ym.year() == 2040y); + assert(ym.month() == January); + ym -= Decades{2}; + assert(ym.year() == 2020y); + assert(ym.month() == January); + + assert(2020y / April == 2020y / April); + assert(2019y / April < 2020y / April); + assert(2020y / March < 2020y / April); + assert(2020y / April > 2019y / April); + assert(2020y / April > 2020y / March); + + assert(ym + months{2} == 2020y / March); + assert(months{2} + ym == 2020y / March); + + assert(ym - months{2} == 2019y / November); + assert(ym - 2019y / January == months{12}); + + assert(ym + years{2} == 2022y / January); + assert(years{2} + ym == 2022y / January); + + assert(ym - years{2} == 2018y / January); + + assert(ym + Decades{2} == 2040y / January); + assert(Decades{2} + ym == 2040y / January); + + assert(ym - Decades{2} == 2000y / January); + + if (is_constant_evaluated()) { + static_assert((2020y / 1).ok()); + static_assert(!(2020y / 13).ok()); + static_assert(!(32768y / 1).ok()); + } else { + for (int y = y_min - 1; y <= y_max + 1; ++y) { + for (auto m = 0u; m <= 255u; ++m) { + const auto ym2 = year{y} / month{m}; + if (y == y_min - 1 || y == y_max + 1) { + assert(!ym2.ok()); + } else if (m >= 1 && m <= 12) { + assert(ym2.ok()); + } else { + assert(!ym2.ok()); + } + } + } + } +} + +constexpr void year_month_day_test() { + year_month_day ymd1{2020y / January / 1d}; + + static_assert(noexcept(year_month_day{})); + static_assert(noexcept(year_month_day{year{}, month{}, day{}})); + static_assert(noexcept(year_month_day{year_month_day_last{year{}, month_day_last{January}}})); + static_assert(noexcept(year_month_day{sys_days{}})); + static_assert(noexcept(year_month_day{local_days{}})); + + static_assert(noexcept(ymd1 += months{})); + static_assert(noexcept(ymd1 -= months{})); + static_assert(noexcept(ymd1 += years{})); + static_assert(noexcept(ymd1 -= years{})); + + static_assert(noexcept(ymd1.year())); + static_assert(noexcept(ymd1.month())); + static_assert(noexcept(ymd1.day())); + + static_assert(noexcept(static_cast(ymd1))); + static_assert(noexcept(static_cast(ymd1))); + static_assert(noexcept(ymd1.ok())); + + static_assert(noexcept(ymd1 == ymd1)); + static_assert(noexcept(ymd1 <=> ymd1)); + + static_assert(noexcept(ymd1 + months{})); + static_assert(noexcept(months{} + ymd1)); + static_assert(noexcept(ymd1 - months{})); + + static_assert(noexcept(ymd1 + years{})); + static_assert(noexcept(years{} + ymd1)); + static_assert(noexcept(ymd1 - years{})); + + assert(ymd1.year() == 2020y); + assert(ymd1.month() == January); + assert(ymd1.day() == 1d); + + year_month_day ymd2{2020y / January / last}; + assert(ymd2.year() == 2020y); + assert(ymd2.month() == January); + assert(ymd2.day() == 31d); + + year_month_day epoch{sys_days{}}; + assert(epoch == year_month_day{sys_days{epoch}}); + assert(epoch.year() == 1970y); + assert(epoch.month() == January); + assert(epoch.day() == 1d); + + local_days ldp; + sys_days sys{ldp.time_since_epoch()}; + year_month_day ymld{ldp}; + assert(ymld == year_month_day{sys}); + + ymd1 += months{2}; + assert(ymd1.year() == 2020y); + assert(ymd1.month() == March); + assert(ymd1.day() == 1d); + + ymd1 -= months{2}; + assert(ymd1.year() == 2020y); + assert(ymd1.month() == January); + assert(ymd1.day() == 1d); + + ymd1 += years{2}; + assert(ymd1.year() == 2022y); + assert(ymd1.month() == January); + assert(ymd1.day() == 1d); + + ymd1 -= years{2}; + assert(ymd1.year() == 2020y); + assert(ymd1.month() == January); + assert(ymd1.day() == 1d); + + ymd1 += Decades{2}; + assert(ymd1.year() == 2040y); + assert(ymd1.month() == January); + assert(ymd1.day() == 1d); + + ymd1 -= Decades{2}; + assert(ymd1.year() == 2020y); + assert(ymd1.month() == January); + assert(ymd1.day() == 1d); + + assert(2020y / April / 6d == sys_days{days{18'358}}); + assert(sys_days{2017y / January / 0} == 2016y / December / 31); + assert(sys_days{2017y / January / 31} == 2017y / January / 31); + assert(sys_days{2017y / January / 32} == 2017y / February / 1); + + assert(static_cast(ymld) == local_days{}); + + assert(2020y / January / 1d == 2020y / January / 1d); + assert(2019y / January / 1d < 2020y / January / 1d); + assert(2020y / January / 1d < 2020y / February / 1d); + assert(2020y / January / 1d < 2020y / January / 2d); + assert(2020y / January / 1d > 2019y / January / 1d); + assert(2020y / February / 1d > 2020y / January / 1d); + assert(2020y / January / 2d > 2020y / January / 1d); + + const auto ymd3 = 2019y / December / 31d + months{2}; + assert(ymd3 == 2020y / February / 31d); + assert(!ymd3.ok()); + assert(months{2} + 2019y / December / 31d == ymd3); + + + assert(2020y / January / 1d - months{2} == 2019y / November / 1d); + + assert(2020y / January / 1d + years{2} == 2022y / January / 1d); + assert(years{2} + 2020y / January / 1d == 2022y / January / 1d); + + assert(2020y / January / 1d - years{2} == 2018y / January / 1d); + + assert(2020y / January / 1d + Decades{2} == 2040y / January / 1d); + assert(Decades{2} + 2020y / January / 1d == 2040y / January / 1d); + + assert(2020y / January / 1d - Decades{2} == 2000y / January / 1d); + + if (is_constant_evaluated()) { + static_assert(!(-32768y / 1 / 1).ok()); + static_assert(!(32768y / 1 / 1).ok()); + static_assert((2020y / 1 / 1).ok()); + + static_assert(!(2020y / 0 / 1).ok()); + static_assert(!(2020y / 13 / 1).ok()); + static_assert((2020y / 5 / 1).ok()); + + static_assert(!(2020y / 2 / 30).ok()); + static_assert(!(2019y / 2 / 29).ok()); + static_assert(!(2020y / 1 / 0).ok()); + static_assert(!(2020y / 1 / 32).ok()); + static_assert((2020y / 2 / 29).ok()); + static_assert((2020y / 7 / 31).ok()); + } else { + for (int iy = -3000; iy <= 3000; ++iy) { // instead of [y_min, y_max], to limit the number of iterations + for (auto um = 0u; um <= 13u; ++um) { // instead of [0, 255], to limit the number of iterations + for (auto ud = 0u; ud <= 32u; ++ud) { + const year y{iy}; + const month m{um}; + const day d{ud}; + if (y.ok() && m.ok() && d >= 1d && d <= (y / m / last).day()) { + assert((y / m / d).ok()); + } else { + assert(!(y / m / d).ok()); + } + } + } + } + } +} + +constexpr void year_month_day_last_test() { + auto ymdl = 2020y / February / last; + + static_assert(noexcept(year_month_day_last{year{}, month_day_last{January}})); + + static_assert(noexcept(ymdl += months{})); + static_assert(noexcept(ymdl -= months{})); + static_assert(noexcept(ymdl += years{})); + static_assert(noexcept(ymdl -= years{})); + + static_assert(noexcept(ymdl.year())); + static_assert(noexcept(ymdl.month())); + static_assert(noexcept(ymdl.month_day_last())); + static_assert(noexcept(ymdl.day())); + + static_assert(noexcept(static_cast(ymdl))); + static_assert(noexcept(static_cast(ymdl))); + static_assert(noexcept(ymdl.ok())); + + static_assert(noexcept(ymdl == ymdl)); + static_assert(noexcept(ymdl <=> ymdl)); + + static_assert(noexcept(ymdl + months{})); + static_assert(noexcept(months{} + ymdl)); + static_assert(noexcept(ymdl - months{})); + + static_assert(noexcept(ymdl + years{})); + static_assert(noexcept(years{} + ymdl)); + static_assert(noexcept(ymdl - years{})); + + assert(ymdl == 2020y / February / last); + assert(ymdl == 2020y / February / 29d); + assert(ymdl.year() == 2020y); + assert(ymdl.month() == February); + assert(ymdl.month_day_last() == February / last); + assert(ymdl.day() == 29d); + + ymdl += months{2}; + assert(ymdl == 2020y / April / 30d); + + ymdl -= months{2}; + assert(ymdl == 2020y / February / 29d); + + ymdl += years{2}; + assert(ymdl == 2022y / February / 28d); + + ymdl -= years{2}; + assert(ymdl == 2020y / February / 29d); + + ymdl += Decades{2}; + assert(ymdl == 2040y / February / 29d); + + ymdl -= Decades{2}; + assert(ymdl == 2020y / February / 29d); + + assert(2020y / April / last == sys_days{days{18'382}}); + assert(static_cast(ymdl) == local_days{ymdl}); + + assert(ymdl < 2021y / February / last); + assert(ymdl < 2020y / March / last); + assert(2021y / February / last > ymdl); + assert(2020y / March / last > ymdl); + + assert(ymdl + months{2} == 2020y / April / last); + assert(months{2} + ymdl == 2020y / April / last); + + assert(ymdl - months{2} == 2019y / December / last); + + assert(ymdl + years{2} == 2022y / February / last); + assert(years{2} + ymdl == 2022y / February / last); + + assert(ymdl - years{2} == 2018y / February / last); + + assert(ymdl + Decades{2} == 2040y / February / last); + assert(Decades{2} + ymdl == 2040y / February / last); + + assert(ymdl - Decades{2} == 2000y / February / last); + + if (is_constant_evaluated()) { + static_assert((2020y / 1 / last).ok()); + static_assert(!(2020y / 13 / last).ok()); + } else { + for (int iy = y_min; iy <= y_max; ++iy) { + for (auto m = 0u; m <= 255u; ++m) { + const year y{iy}; + const auto mdl = month{m} / last; + if (y.ok() && mdl.ok()) { + assert((y / mdl).ok()); + } else { + assert(!(y / mdl).ok()); + } + } + } + } +} + +constexpr void year_month_weekday_test() { + auto ymwd = 2020y / April / Tuesday[2]; + + static_assert(noexcept(year_month_weekday{})); + static_assert(noexcept(year_month_weekday{year{}, month{}, weekday_indexed{}})); + static_assert(noexcept(year_month_weekday{sys_days{}})); + static_assert(noexcept(year_month_weekday{local_days{}})); + + static_assert(noexcept(ymwd += months{})); + static_assert(noexcept(ymwd -= months{})); + static_assert(noexcept(ymwd += years{})); + static_assert(noexcept(ymwd -= years{})); + + static_assert(noexcept(ymwd.year())); + static_assert(noexcept(ymwd.month())); + static_assert(noexcept(ymwd.weekday())); + static_assert(noexcept(ymwd.index())); + static_assert(noexcept(ymwd.weekday_indexed())); + + static_assert(noexcept(static_cast(ymwd))); + static_assert(noexcept(static_cast(ymwd))); + static_assert(noexcept(ymwd.ok())); + + static_assert(noexcept(ymwd == ymwd)); + + static_assert(noexcept(ymwd + months{})); + static_assert(noexcept(months{} + ymwd)); + static_assert(noexcept(ymwd - months{})); + + static_assert(noexcept(ymwd + years{})); + static_assert(noexcept(years{} + ymwd)); + static_assert(noexcept(ymwd - years{})); + + assert(ymwd == 2020y / April / Tuesday[2]); + assert(ymwd.year() == 2020y); + assert(ymwd.month() == April); + assert(ymwd.weekday() == Tuesday); + assert(ymwd.index() == 2u); + assert(ymwd.weekday_indexed() == Tuesday[2]); + + const year_month_weekday epoch{sys_days{}}; + assert(epoch == year_month_weekday{sys_days{epoch}}); + assert(epoch == 1970y / January / Thursday[1]); + + local_days ldp; + sys_days sys{ldp.time_since_epoch()}; + year_month_weekday ymlwd{ldp}; + assert(ymlwd == year_month_weekday{sys}); + + ymwd += months{2}; + assert(ymwd == 2020y / June / Tuesday[2]); + ymwd -= months{2}; + assert(ymwd == 2020y / April / Tuesday[2]); + + ymwd += years{2}; + assert(ymwd == 2022y / April / Tuesday[2]); + ymwd -= years{2}; + assert(ymwd == 2020y / April / Tuesday[2]); + + ymwd += Decades{2}; + assert(ymwd == 2040y / April / Tuesday[2]); + ymwd -= Decades{2}; + assert(ymwd == 2020y / April / Tuesday[2]); + + assert(static_cast(epoch) == sys_days{}); + const auto previous = 1970y / January / Thursday[0]; + assert(static_cast(previous) == (sys_days{} - days{7})); + assert(static_cast(ymwd) == local_days{ymwd}); + + + assert((2020y / April / Wednesday[5]).ok()); + assert(!(-32768y / April / Wednesday[1]).ok()); + assert(!(2020y / month{0} / Wednesday[1]).ok()); + assert(!(2020y / April / Tuesday[5]).ok()); + + assert(ymwd + months{2} == 2020y / June / Tuesday[2]); + assert(months{2} + ymwd == 2020y / June / Tuesday[2]); + + assert(ymwd - months{2} == 2020y / February / Tuesday[2]); + + assert(ymwd + years{2} == 2022y / April / Tuesday[2]); + assert(years{2} + ymwd == 2022y / April / Tuesday[2]); + + assert(ymwd - years{2} == 2018y / April / Tuesday[2]); + + assert(ymwd + Decades{2} == 2040y / April / Tuesday[2]); + assert(Decades{2} + ymwd == 2040y / April / Tuesday[2]); + + assert(ymwd - Decades{2} == 2000y / April / Tuesday[2]); +} + +constexpr void year_month_weekday_last_test() { + auto ymwdl = 2020y / January / Monday[last]; + + static_assert(noexcept(year_month_weekday_last{year{}, month{}, weekday_last{Sunday}})); + + static_assert(noexcept(ymwdl += months{})); + static_assert(noexcept(ymwdl -= months{})); + static_assert(noexcept(ymwdl += years{})); + static_assert(noexcept(ymwdl -= years{})); + + static_assert(noexcept(ymwdl.year())); + static_assert(noexcept(ymwdl.month())); + static_assert(noexcept(ymwdl.weekday())); + static_assert(noexcept(ymwdl.weekday_last())); + + static_assert(noexcept(static_cast(ymwdl))); + static_assert(noexcept(static_cast(ymwdl))); + static_assert(noexcept(ymwdl.ok())); + + static_assert(noexcept(ymwdl == ymwdl)); + + static_assert(noexcept(ymwdl + months{})); + static_assert(noexcept(months{} + ymwdl)); + static_assert(noexcept(ymwdl - months{})); + + static_assert(noexcept(ymwdl + years{})); + static_assert(noexcept(years{} + ymwdl)); + static_assert(noexcept(ymwdl - years{})); + + assert(ymwdl == 2020y / January / Monday[last]); + assert(ymwdl.year() == 2020y); + assert(ymwdl.month() == January); + assert(ymwdl.weekday() == Monday); + assert(ymwdl.weekday_last() == Monday[last]); + + ymwdl += months{2}; + assert(ymwdl == 2020y / March / Monday[last]); + ymwdl -= months{2}; + assert(ymwdl == 2020y / January / Monday[last]); + + ymwdl += years{2}; + assert(ymwdl == 2022y / January / Monday[last]); + ymwdl -= years{2}; + assert(ymwdl == 2020y / January / Monday[last]); + + ymwdl += Decades{2}; + assert(ymwdl == 2040y / January / Monday[last]); + ymwdl -= Decades{2}; + assert(ymwdl == 2020y / January / Monday[last]); + + assert(static_cast(ymwdl) == sys_days{days{18'288}}); + assert(static_cast(ymwdl) == local_days{ymwdl}); + + assert((2020y / April / Wednesday[last]).ok()); + assert(!(-32768y / April / Wednesday[last]).ok()); + assert(!(2020y / month{0} / Wednesday[last]).ok()); + assert(!(2020y / April / weekday{8}[last]).ok()); + + assert(ymwdl + months{2} == 2020y / March / Monday[last]); + assert(months{2} + ymwdl == 2020y / March / Monday[last]); + + assert(ymwdl - months{2} == 2019y / November / Monday[last]); + + assert(ymwdl + years{2} == 2022y / January / Monday[last]); + assert(years{2} + ymwdl == 2022y / January / Monday[last]); + + assert(ymwdl - years{2} == 2018y / January / Monday[last]); + + assert(ymwdl + Decades{2} == 2040y / January / Monday[last]); + assert(Decades{2} + ymwdl == 2040y / January / Monday[last]); + + assert(ymwdl - Decades{2} == 2000y / January / Monday[last]); +} + +constexpr bool test() { + day_test(); + month_test(); + year_test(); + weekday_test(); + weekday_indexed_test(); + weekday_last_test(); + month_day_test(); + month_day_last_test(); + month_weekday_test(); + month_weekday_last_test(); + year_month_test(); + year_month_day_test(); + year_month_day_last_test(); + year_month_weekday_test(); + year_month_weekday_last_test(); + return true; +} + +int main() { + test(); + static_assert(test()); +} diff --git a/tests/std/tests/P0355R7_calendars_and_time_zones_dates_literals/env.lst b/tests/std/tests/P0355R7_calendars_and_time_zones_dates_literals/env.lst new file mode 100644 index 00000000000..642f530ffad --- /dev/null +++ b/tests/std/tests/P0355R7_calendars_and_time_zones_dates_literals/env.lst @@ -0,0 +1,4 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\usual_latest_matrix.lst diff --git a/tests/std/tests/P0355R7_calendars_and_time_zones_dates_literals/test.compile.pass.cpp b/tests/std/tests/P0355R7_calendars_and_time_zones_dates_literals/test.compile.pass.cpp new file mode 100644 index 00000000000..f0512320f08 --- /dev/null +++ b/tests/std/tests/P0355R7_calendars_and_time_zones_dates_literals/test.compile.pass.cpp @@ -0,0 +1,186 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include + +using namespace std; +using namespace std::chrono; + +int main() {} // COMPILE-ONLY + +static_assert(noexcept(year{} / month{})); +static_assert(noexcept(year{} / 0)); +static_assert(noexcept(month{} / day{})); +static_assert(noexcept(month{} / 0)); +static_assert(noexcept(0 / day{})); +static_assert(noexcept(day{} / month{})); +static_assert(noexcept(day{} / 0)); +static_assert(noexcept(month{} / last)); +static_assert(noexcept(0 / last)); +static_assert(noexcept(last / month{})); +static_assert(noexcept(last / 0)); +static_assert(noexcept(month{} / Sunday[1])); +static_assert(noexcept(0 / Sunday[1])); +static_assert(noexcept(Sunday[1] / month{})); +static_assert(noexcept(Sunday[1] / 0)); +static_assert(noexcept(month{} / Sunday[last])); +static_assert(noexcept(0 / Sunday[last])); +static_assert(noexcept(Sunday[last] / month{})); +static_assert(noexcept(Sunday[last] / 0)); +static_assert(noexcept(year_month{} / day{})); +static_assert(noexcept(year_month{} / 0)); +static_assert(noexcept(year{} / month_day{})); +static_assert(noexcept(0 / month_day{})); +static_assert(noexcept(month_day{} / year{})); +static_assert(noexcept(month_day{} / 0)); +static_assert(noexcept(year_month{} / last)); +static_assert(noexcept(year{} / month_day_last{January})); +static_assert(noexcept(0 / month_day_last{January})); +static_assert(noexcept(month_day_last{January} / year{})); +static_assert(noexcept(month_day_last{January} / 0)); +static_assert(noexcept(year_month{} / Sunday[1])); +static_assert(noexcept(year{} / month_weekday{January, Sunday[1]})); +static_assert(noexcept(0 / month_weekday{January, Sunday[1]})); +static_assert(noexcept(month_weekday{January, Sunday[1]} / year{})); +static_assert(noexcept(month_weekday{January, Sunday[1]} / 0)); +static_assert(noexcept(year_month{} / Sunday[last])); +static_assert(noexcept(year{} / month_weekday_last{January, Sunday[last]})); +static_assert(noexcept(0 / month_weekday_last{January, Sunday[last]})); +static_assert(noexcept(month_weekday_last{January, Sunday[last]} / year{})); +static_assert(noexcept(month_weekday_last{January, Sunday[last]} / 0)); + +#define TRIVIAL_COPY_STANDARD_LAYOUT(TYPE) \ + static_assert(is_trivially_copyable_v, "chrono::" #TYPE " is not trivially copyable"); \ + static_assert(is_standard_layout_v, "chrono::" #TYPE " is not standard-layout"); + +TRIVIAL_COPY_STANDARD_LAYOUT(day) +TRIVIAL_COPY_STANDARD_LAYOUT(month) +TRIVIAL_COPY_STANDARD_LAYOUT(year) +TRIVIAL_COPY_STANDARD_LAYOUT(weekday) +TRIVIAL_COPY_STANDARD_LAYOUT(weekday_indexed) +TRIVIAL_COPY_STANDARD_LAYOUT(weekday_last) +TRIVIAL_COPY_STANDARD_LAYOUT(month_day) +TRIVIAL_COPY_STANDARD_LAYOUT(month_day_last) +TRIVIAL_COPY_STANDARD_LAYOUT(month_weekday) +TRIVIAL_COPY_STANDARD_LAYOUT(month_weekday_last) +TRIVIAL_COPY_STANDARD_LAYOUT(year_month) +TRIVIAL_COPY_STANDARD_LAYOUT(year_month_day) +TRIVIAL_COPY_STANDARD_LAYOUT(year_month_day_last) +TRIVIAL_COPY_STANDARD_LAYOUT(year_month_weekday) +TRIVIAL_COPY_STANDARD_LAYOUT(year_month_weekday_last) + +#define TYPE_ASSERT(TYPE, EXPR) \ + static_assert(is_same_v>, #EXPR " is not chrono::" #TYPE); + +TYPE_ASSERT(day, 0d) +TYPE_ASSERT(year, 0y) +TYPE_ASSERT(month, January) +TYPE_ASSERT(month, February) +TYPE_ASSERT(month, March) +TYPE_ASSERT(month, April) +TYPE_ASSERT(month, May) +TYPE_ASSERT(month, June) +TYPE_ASSERT(month, July) +TYPE_ASSERT(month, August) +TYPE_ASSERT(month, September) +TYPE_ASSERT(month, October) +TYPE_ASSERT(month, November) +TYPE_ASSERT(month, December) +TYPE_ASSERT(weekday, Sunday) +TYPE_ASSERT(weekday, Monday) +TYPE_ASSERT(weekday, Tuesday) +TYPE_ASSERT(weekday, Wednesday) +TYPE_ASSERT(weekday, Thursday) +TYPE_ASSERT(weekday, Friday) +TYPE_ASSERT(weekday, Saturday) +TYPE_ASSERT(last_spec, last) +TYPE_ASSERT(weekday_indexed, declval()[1]) +TYPE_ASSERT(weekday_last, declval()[last]) + +TYPE_ASSERT(year_month, 2020y / January) +TYPE_ASSERT(year_month, 2020y / 1) + +TYPE_ASSERT(month_day, January / 1d) +TYPE_ASSERT(month_day, January / 1) +TYPE_ASSERT(month_day, 1 / 1d) +TYPE_ASSERT(month_day, 1d / January) +TYPE_ASSERT(month_day, 1d / 1) + +TYPE_ASSERT(month_day_last, January / last) +TYPE_ASSERT(month_day_last, 1 / last) +TYPE_ASSERT(month_day_last, last / January) +TYPE_ASSERT(month_day_last, last / 1) + +TYPE_ASSERT(month_weekday, January / Monday[1]) +TYPE_ASSERT(month_weekday, 1 / Monday[1]) +TYPE_ASSERT(month_weekday, Monday[1] / January) +TYPE_ASSERT(month_weekday, Monday[1] / 1) + +TYPE_ASSERT(month_weekday_last, January / Monday[last]) +TYPE_ASSERT(month_weekday_last, 1 / Monday[last]) +TYPE_ASSERT(month_weekday_last, Monday[last] / January) +TYPE_ASSERT(month_weekday_last, Monday[last] / 1) + +TYPE_ASSERT(year_month_day, 2020y / January / 1d) +TYPE_ASSERT(year_month_day, 2020y / January / 1) +constexpr auto md = January / 1; +TYPE_ASSERT(year_month_day, 2020y / md) +TYPE_ASSERT(year_month_day, 2020 / md) +TYPE_ASSERT(year_month_day, January / 1 / 2020y) +TYPE_ASSERT(year_month_day, January / 1 / 2020) +TYPE_ASSERT(year_month_day, 1d / January / 2020y) +TYPE_ASSERT(year_month_day, 1d / January / 2020) +TYPE_ASSERT(year_month_day, 1d / 1 / 2020) +TYPE_ASSERT(year_month_day, 1d / 1 / 2020y) + +TYPE_ASSERT(year_month_day_last, 2020y / January / last) +constexpr auto mdl = January / last; +TYPE_ASSERT(year_month_day_last, 2020y / mdl) +TYPE_ASSERT(year_month_day_last, 2020 / mdl) +TYPE_ASSERT(year_month_day_last, last / January / 2020y) +TYPE_ASSERT(year_month_day_last, January / last / 2020) + +TYPE_ASSERT(year_month_weekday, 2020y / January / Monday[1]) +constexpr auto mwd = January / Monday[1]; +TYPE_ASSERT(year_month_weekday, 2020y / mwd) +TYPE_ASSERT(year_month_weekday, 2020 / mwd) +TYPE_ASSERT(year_month_weekday, January / Monday[1] / 2020y) +TYPE_ASSERT(year_month_weekday, January / Monday[1] / 2020) +TYPE_ASSERT(year_month_weekday, Monday[1] / January / 2020y) +TYPE_ASSERT(year_month_weekday, Monday[1] / January / 2020) + +TYPE_ASSERT(year_month_weekday_last, 2020y / January / Monday[last]) +constexpr auto mwdl = January / Monday[last]; +TYPE_ASSERT(year_month_weekday_last, 2020y / mwdl) +TYPE_ASSERT(year_month_weekday_last, 2020 / mwdl) +TYPE_ASSERT(year_month_weekday_last, January / Monday[last] / 2020y) +TYPE_ASSERT(year_month_weekday_last, January / Monday[last] / 2020) +TYPE_ASSERT(year_month_weekday_last, 1 / Monday[last] / 2020) +TYPE_ASSERT(year_month_weekday_last, 1 / Monday[last] / 2020y) +TYPE_ASSERT(year_month_weekday_last, Monday[last] / 1 / 2020y) +TYPE_ASSERT(year_month_weekday_last, Monday[last] / 1 / 2020) +TYPE_ASSERT(year_month_weekday_last, Monday[last] / January / 2020) +TYPE_ASSERT(year_month_weekday_last, Monday[last] / January / 2020y) + +#define VALUE_ASSERT(VALUE, EXPECTED) static_assert(VALUE == EXPECTED, "chrono::" #VALUE " is not " #EXPECTED); +VALUE_ASSERT(month{1}, January) +VALUE_ASSERT(month{2}, February) +VALUE_ASSERT(month{3}, March) +VALUE_ASSERT(month{4}, April) +VALUE_ASSERT(month{5}, May) +VALUE_ASSERT(month{6}, June) +VALUE_ASSERT(month{7}, July) +VALUE_ASSERT(month{8}, August) +VALUE_ASSERT(month{9}, September) +VALUE_ASSERT(month{10}, October) +VALUE_ASSERT(month{11}, November) +VALUE_ASSERT(month{12}, December) + +VALUE_ASSERT(weekday{0}, Sunday) +VALUE_ASSERT(weekday{1}, Monday) +VALUE_ASSERT(weekday{2}, Tuesday) +VALUE_ASSERT(weekday{3}, Wednesday) +VALUE_ASSERT(weekday{4}, Thursday) +VALUE_ASSERT(weekday{5}, Friday) +VALUE_ASSERT(weekday{6}, Saturday) diff --git a/tests/std/tests/P0355R7_calendars_and_time_zones_hms/env.lst b/tests/std/tests/P0355R7_calendars_and_time_zones_hms/env.lst new file mode 100644 index 00000000000..642f530ffad --- /dev/null +++ b/tests/std/tests/P0355R7_calendars_and_time_zones_hms/env.lst @@ -0,0 +1,4 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\usual_latest_matrix.lst diff --git a/tests/std/tests/P0355R7_calendars_and_time_zones_hms/test.cpp b/tests/std/tests/P0355R7_calendars_and_time_zones_hms/test.cpp new file mode 100644 index 00000000000..05d0320e311 --- /dev/null +++ b/tests/std/tests/P0355R7_calendars_and_time_zones_hms/test.cpp @@ -0,0 +1,225 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include +#include + +using namespace std; +using namespace std::chrono; + +using hms_hours = hh_mm_ss; +using f_hours = duration>; +using f_hms_hours = hh_mm_ss; + +constexpr void am_pm() { + static_assert(noexcept(is_am(hours{}))); + static_assert(noexcept(is_pm(hours{}))); + + for (hours i = 0h; i < 12h; ++i) { + assert(is_am(i)); + assert(!is_pm(i)); + } + for (hours i = 12h; i < 24h; ++i) { + assert(!is_am(i)); + assert(is_pm(i)); + } +} + +constexpr void make12_24() { + static_assert(noexcept(make12(hours{}))); + static_assert(noexcept(make24(hours{}, true))); + + assert(make12(1h) == 1h); + assert(make12(13h) == 1h); + assert(make12(0h) == 12h); + assert(make12(12h) == 12h); + + assert(make24(12h, true) == 12h); + assert(make24(12h, false) == 0h); + assert(make24(5h, true) == 17h); + assert(make24(5h, false) == 5h); +} + +template +constexpr auto width() { + return hh_mm_ss::fractional_width; +} +template +constexpr auto width() { + return hh_mm_ss>>::fractional_width; +} + +constexpr void fractional_width() { + static_assert(width() == 0); + static_assert(width() == 0); + static_assert(width() == 0); + static_assert(width() == 0); + static_assert(width() == 3); + static_assert(width() == 6); + static_assert(width() == 9); + + static_assert(width() == 1); + static_assert(width() == 6); + static_assert(width() == 2); + static_assert(width() == 1); + static_assert(width() == 6); + static_assert(width() == 6); + static_assert(width() == 3); + static_assert(width() == 6); + static_assert(width() == 1); + static_assert(width() == 4); + static_assert(width() == 3); + static_assert(width() == 6); + // static_assert(width() == 6); overflows + + static_assert(width() == 1); + static_assert(width() == 6); + static_assert(width() == 2); + static_assert(width() == 1); + static_assert(width() == 6); + static_assert(width() == 6); + static_assert(width() == 3); + static_assert(width() == 6); + static_assert(width() == 1); + static_assert(width() == 4); + static_assert(width() == 3); + static_assert(width() == 6); + // static_assert(width() == 6); overflows +} + +constexpr void constructor() { + static_assert(noexcept(hms_hours{})); + static_assert(noexcept(f_hms_hours{})); + + assert(hms_hours{}.hours() == hms_hours{hours::zero()}.hours()); + assert(hms_hours{}.minutes() == hms_hours{hours::zero()}.minutes()); + assert(hms_hours{}.seconds() == hms_hours{hours::zero()}.seconds()); + assert(hms_hours{}.subseconds() == hms_hours{hours::zero()}.subseconds()); + + assert(f_hms_hours{}.hours() == f_hms_hours{hours::zero()}.hours()); + assert(f_hms_hours{}.minutes() == f_hms_hours{hours::zero()}.minutes()); + assert(f_hms_hours{}.seconds() == f_hms_hours{hours::zero()}.seconds()); + assert(f_hms_hours{}.subseconds() == f_hms_hours{hours::zero()}.subseconds()); +} + +constexpr void is_negative() { + static_assert(noexcept(hms_hours{}.is_negative())); + static_assert(noexcept(f_hms_hours{}.is_negative())); + + assert(hh_mm_ss(days{-1}).is_negative()); + assert(!hh_mm_ss(days{1}).is_negative()); + + assert(hh_mm_ss{-1h}.is_negative()); + assert(!hh_mm_ss{1h}.is_negative()); + + assert(hh_mm_ss{-1min}.is_negative()); + assert(!hh_mm_ss{1min}.is_negative()); + + assert(hh_mm_ss{-1s}.is_negative()); + assert(!hh_mm_ss{1s}.is_negative()); + + assert(hh_mm_ss{-1ms}.is_negative()); + assert(!hh_mm_ss{1ms}.is_negative()); + + assert(hh_mm_ss{-1us}.is_negative()); + assert(!hh_mm_ss{1us}.is_negative()); + + assert(hh_mm_ss{-1ns}.is_negative()); + assert(!hh_mm_ss{1ns}.is_negative()); + + assert(f_hms_hours{f_hours{-1.f}}.is_negative()); + assert(!f_hms_hours{f_hours{1.f}}.is_negative()); +} + +constexpr auto ones = 1h + 1min + 1s + 1ms; + +constexpr void hour() { + static_assert(noexcept(hms_hours{}.hours())); + static_assert(noexcept(f_hms_hours{}.hours())); + + assert(hh_mm_ss(days{1}).hours() == 24h); + assert(hh_mm_ss(ones).hours() == 1h); + assert(hh_mm_ss(-ones).hours() == 1h); + assert(hh_mm_ss(59min).hours() == 0h); + assert(f_hms_hours{f_hours{1.f}}.hours() == 1h); +} + +constexpr void mins() { + static_assert(noexcept(hms_hours{}.minutes())); + static_assert(noexcept(f_hms_hours{}.minutes())); + + assert(hh_mm_ss(ones).minutes() == 1min); + assert(hh_mm_ss(-ones).minutes() == 1min); + assert(hh_mm_ss(59s).minutes() == 0min); + assert(f_hms_hours{f_hours{0.0166667f}}.minutes() == 1min); +} + +constexpr void secs() { + static_assert(noexcept(hms_hours{}.seconds())); + static_assert(noexcept(f_hms_hours{}.seconds())); + + assert(hh_mm_ss(ones).seconds() == 1s); + assert(hh_mm_ss(-ones).seconds() == 1s); + assert(hh_mm_ss(999ms).seconds() == 0s); + assert(f_hms_hours{f_hours{0.000277778f}}.seconds() == 1s); +} + +constexpr void subsecs() { + static_assert(noexcept(hms_hours{}.subseconds())); + static_assert(noexcept(f_hms_hours{}.subseconds())); + + assert(hh_mm_ss(ones).subseconds() == 1ms); + assert(hh_mm_ss(-ones).subseconds() == 1ms); + assert(hh_mm_ss(999us).subseconds() == 999us); + assert(hh_mm_ss(duration_cast(999us)).subseconds() == 0ms); + using f_hms_milli = hh_mm_ss>; + assert(f_hms_milli{1ms}.subseconds() == 1ms); +} + +constexpr void to_duration() { + using precision = hms_hours::precision; + using f_precision = f_hms_hours::precision; + + static_assert(noexcept(hms_hours{}.to_duration())); + static_assert(noexcept(static_cast(hms_hours{}))); + static_assert(noexcept(f_hms_hours{}.to_duration())); + static_assert(noexcept(static_cast(f_hms_hours{}))); + + assert(hh_mm_ss(ones).to_duration() == ones); + assert(hh_mm_ss(-ones).to_duration() == -ones); + assert(f_hms_hours{f_hours{1.f}}.to_duration() == 1h); + assert(f_hms_hours{f_hours{-1.f}}.to_duration() == -1h); + + hh_mm_ss hms(50ms); + milliseconds milli_val = static_cast(hms); + static_assert(is_same_v); + assert(hms.to_duration() == milli_val); + + f_hms_hours fhms{f_hours{1}}; + auto fhours_val = static_cast(fhms); + static_assert(is_same_v); + static_assert(is_same_v, f_precision>); + assert(fhms.to_duration() == fhours_val); +} + +constexpr bool test() { + am_pm(); + make12_24(); + fractional_width(); + constructor(); + is_negative(); + hour(); + mins(); + secs(); + subsecs(); + to_duration(); + return true; +} + +int main() { + test(); + static_assert(test()); +} diff --git a/tests/std/tests/P0355R7_calendars_and_time_zones_time_point_and_durations/env.lst b/tests/std/tests/P0355R7_calendars_and_time_zones_time_point_and_durations/env.lst new file mode 100644 index 00000000000..642f530ffad --- /dev/null +++ b/tests/std/tests/P0355R7_calendars_and_time_zones_time_point_and_durations/env.lst @@ -0,0 +1,4 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\usual_latest_matrix.lst diff --git a/tests/std/tests/P0355R7_calendars_and_time_zones_time_point_and_durations/test.cpp b/tests/std/tests/P0355R7_calendars_and_time_zones_time_point_and_durations/test.cpp new file mode 100644 index 00000000000..66bec4ea7da --- /dev/null +++ b/tests/std/tests/P0355R7_calendars_and_time_zones_time_point_and_durations/test.cpp @@ -0,0 +1,64 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include + +using namespace std; +using namespace std::chrono; + +#define DURATION_TEST(TYPE, BITS, ...) \ + static_assert( \ + is_integral_v && is_signed_v, "chrono::" #TYPE "::rep is not a signed integral type."); \ + static_assert( \ + numeric_limits::digits >= BITS, "chrono::" #TYPE "::rep is not at least " #BITS " bits."); \ + static_assert(is_same_v, "chrono::" #TYPE "::period is not " #__VA_ARGS__ "."); + +DURATION_TEST(days, 25, ratio_multiply, hours::period>) +DURATION_TEST(weeks, 22, ratio_multiply, days::period>) +DURATION_TEST(months, 20, ratio_divide>) +DURATION_TEST(years, 17, ratio_multiply, days::period>) + +// clang-format off +static_assert(is_same_v>, + "sys_seconds is not time_point."); +static_assert(is_same_v>, + "sys_days is not time_point."); + +static_assert(is_same_v>, + "local_seconds is not time_point."); +static_assert(is_same_v>, + "local_days is not time_point."); +// clang-format on + +constexpr bool test() { + steady_clock::time_point tp1; + + static_assert(noexcept(++tp1)); // strengthened + static_assert(noexcept(tp1++)); // strengthened + static_assert(noexcept(--tp1)); // strengthened + static_assert(noexcept(tp1--)); // strengthened + + auto tp2 = tp1++; + assert(tp1.time_since_epoch().count() == 1); + assert(tp2.time_since_epoch().count() == 0); + tp2 = ++tp1; + assert(tp1.time_since_epoch().count() == 2); + assert(tp2.time_since_epoch().count() == 2); + + tp2 = tp1--; + assert(tp1.time_since_epoch().count() == 1); + assert(tp2.time_since_epoch().count() == 2); + tp2 = --tp1; + assert(tp1.time_since_epoch().count() == 0); + assert(tp2.time_since_epoch().count() == 0); + + return true; +} + +int main() { + test(); + static_assert(test()); +} diff --git a/tests/std/tests/P0466R5_layout_compatibility_and_pointer_interconvertibility_traits/env.lst b/tests/std/tests/P0466R5_layout_compatibility_and_pointer_interconvertibility_traits/env.lst new file mode 100644 index 00000000000..642f530ffad --- /dev/null +++ b/tests/std/tests/P0466R5_layout_compatibility_and_pointer_interconvertibility_traits/env.lst @@ -0,0 +1,4 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\usual_latest_matrix.lst diff --git a/tests/std/tests/P0466R5_layout_compatibility_and_pointer_interconvertibility_traits/test.cpp b/tests/std/tests/P0466R5_layout_compatibility_and_pointer_interconvertibility_traits/test.cpp new file mode 100644 index 00000000000..78309c6cc21 --- /dev/null +++ b/tests/std/tests/P0466R5_layout_compatibility_and_pointer_interconvertibility_traits/test.cpp @@ -0,0 +1,254 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +#include +#include + +using namespace std; + +#define ASSERT(...) assert((__VA_ARGS__)) + +struct S { // Must be declared at namespace scope due to static data member + static int s1; + int v1; + int v2; +}; + +constexpr bool test() { +#ifndef __EDG__ // TRANSITION, VSO-1268984 +#ifndef __clang__ // TRANSITION, LLVM-48860 + // is_layout_compatible tests + { + struct S0 { + int v1; + int v2; + }; + + struct S1 { + S0 s1; + int v3; + }; + + struct S2 { + S0 s1; + int v2; + }; + + struct S3 { + S0 s1; + int v2; + int v3; + }; + + struct S4 { + int v1; + + private: + int v2; + }; + + struct S5 { + int v1; + + private: + int v2; + }; + + enum E1 { e1, e2, e3, e4 }; + enum E2 : int { e5 }; + enum E3 : unsigned int { e6, e7, e8 }; + enum class E4 : unsigned int { no, yes }; + enum class E5 { zero, fortytwo = 42 }; + + ASSERT(is_layout_compatible_v); + ASSERT(is_layout_compatible_v); + ASSERT(is_layout_compatible_v); + ASSERT(is_layout_compatible_v); + ASSERT(is_layout_compatible_v); + ASSERT(is_layout_compatible_v); + ASSERT(is_layout_compatible_v); + ASSERT(is_layout_compatible_v); + ASSERT(is_layout_compatible_v); + ASSERT(is_layout_compatible_v); + ASSERT(is_layout_compatible_v); + ASSERT(is_layout_compatible_v); + ASSERT(is_layout_compatible_v); + +#if defined(__clang__) || defined(__EDG__) // TRANSITION, VSO-1269781 + ASSERT(is_layout_compatible_v); + ASSERT(is_layout_compatible_v); + ASSERT(is_layout_compatible_v); +#endif // TRANSITION, VSO-1269781 + + ASSERT(!is_layout_compatible_v); + ASSERT(!is_layout_compatible_v); + ASSERT(!is_layout_compatible_v); + ASSERT(!is_layout_compatible_v); + ASSERT(!is_layout_compatible_v); + ASSERT(!is_layout_compatible_v); + ASSERT(!is_layout_compatible_v); + ASSERT(!is_layout_compatible_v); + ASSERT(!is_layout_compatible_v); + ASSERT(!is_layout_compatible_v); + } + + // is_pointer_interconvertible_base_of tests + { + class A {}; + class B : public A {}; + class C : public A { + int : 0; + }; + class D : public C {}; +// Disable warning C4408: anonymous union did not declare any data members +#pragma warning(push) +#pragma warning(disable : 4408) + class E : public A { + union {}; + }; +#pragma warning(pop) + class F : private A {}; // Non-public inheritance + class NS : public B, public C {}; // Non-standard layout + class I; // Incomplete + + union U { + int i; + char c; + }; + + ASSERT(is_pointer_interconvertible_base_of_v); + ASSERT(is_pointer_interconvertible_base_of_v); + ASSERT(is_pointer_interconvertible_base_of_v); + ASSERT(is_pointer_interconvertible_base_of_v); + ASSERT(is_pointer_interconvertible_base_of_v); + ASSERT(is_pointer_interconvertible_base_of_v); + ASSERT(is_pointer_interconvertible_base_of_v); + ASSERT(is_pointer_interconvertible_base_of_v); + ASSERT(is_pointer_interconvertible_base_of_v); + ASSERT(is_pointer_interconvertible_base_of_v); + ASSERT(is_pointer_interconvertible_base_of_v); + ASSERT(is_pointer_interconvertible_base_of_v); + + ASSERT(!is_pointer_interconvertible_base_of_v); + ASSERT(!is_pointer_interconvertible_base_of_v); + ASSERT(!is_pointer_interconvertible_base_of_v); + ASSERT(!is_pointer_interconvertible_base_of_v); + ASSERT(!is_pointer_interconvertible_base_of_v); + ASSERT(!is_pointer_interconvertible_base_of_v); + ASSERT(!is_pointer_interconvertible_base_of_v); + ASSERT(!is_pointer_interconvertible_base_of_v); + ASSERT(!is_pointer_interconvertible_base_of_v); + } + + // is_corresponding_member tests + { + struct S1 { + int v1; + int v2; + }; + + struct S2 { + int w1; + int w2; + }; + + struct S3 { + int v1; + int v2; + int v3; + }; + + struct S4 { + char v1; + int v2; + int v3; + }; + + struct S5 { + int v1; + int v2; + void* v3; + }; + + struct S6 { + int v1; + int v2; + double v3; + }; + + struct S7 { + int f1() { + return 0; + } + }; + + struct NS : S1, S2 {}; // Non-standard layout + + ASSERT(is_corresponding_member(&S1::v1, &S::v1)); + ASSERT(is_corresponding_member(&S1::v2, &S::v2)); + ASSERT(is_corresponding_member(&S1::v1, &S1::v1)); + ASSERT(is_corresponding_member(&S1::v2, &S1::v2)); + ASSERT(is_corresponding_member(&S1::v1, &S2::w1)); + ASSERT(is_corresponding_member(&S1::v2, &S2::w2)); + ASSERT(is_corresponding_member(&S1::v1, &S3::v1)); + ASSERT(is_corresponding_member(&S1::v2, &S3::v2)); + ASSERT(is_corresponding_member(&S5::v1, &S6::v1)); + ASSERT(is_corresponding_member(&S5::v2, &S6::v2)); + + ASSERT(!is_corresponding_member(&S1::v1, &S1::v2)); + ASSERT(!is_corresponding_member(&S1::v2, &S1::v1)); + ASSERT(!is_corresponding_member(&S1::v2, &S2::w1)); + ASSERT(!is_corresponding_member(&S1::v1, &S4::v1)); + ASSERT(!is_corresponding_member(&S1::v2, &S4::v2)); + ASSERT(!is_corresponding_member(&S3::v1, &S4::v1)); + ASSERT(!is_corresponding_member(&S3::v2, &S4::v2)); + ASSERT(!is_corresponding_member(&S5::v1, &S6::v2)); + ASSERT(!is_corresponding_member(&S5::v2, &S6::v1)); + ASSERT(!is_corresponding_member(&S5::v3, &S6::v3)); + ASSERT(!is_corresponding_member(&NS::v1, &NS::w1)); + ASSERT(!is_corresponding_member(&S7::f1, &S7::f1)); + ASSERT(!is_corresponding_member(static_cast(nullptr), static_cast(nullptr))); + ASSERT(!is_corresponding_member(&S1::v1, static_cast(nullptr))); + } + + // is_pointer_interconvertible_with_class tests + { + struct A { + int a; + }; + + struct B { + int b; + }; + + struct C { + int f1() { + return 0; + } + }; + + struct NS : A, B {}; // Non-standard layout + + union U { + int v1; + char v2; + }; + + ASSERT(is_pointer_interconvertible_with_class(&A::a)); + ASSERT(is_pointer_interconvertible_with_class(&NS::b)); + ASSERT(is_pointer_interconvertible_with_class(&U::v1)); + ASSERT(is_pointer_interconvertible_with_class(&U::v2)); + + ASSERT(!is_pointer_interconvertible_with_class(&NS::a)); + ASSERT(!is_pointer_interconvertible_with_class(&NS::b)); + ASSERT(!is_pointer_interconvertible_with_class(&C::f1)); + ASSERT(!is_pointer_interconvertible_with_class(static_cast(nullptr))); + } +#endif // __clang__ +#endif // __EDG__ + return true; +} + +int main() { + static_assert(test()); + test(); +} diff --git a/tests/std/tests/P0896R4_ranges_alg_inplace_merge/env.lst b/tests/std/tests/P0896R4_ranges_alg_inplace_merge/env.lst new file mode 100644 index 00000000000..f3ccc8613c6 --- /dev/null +++ b/tests/std/tests/P0896R4_ranges_alg_inplace_merge/env.lst @@ -0,0 +1,4 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\concepts_matrix.lst diff --git a/tests/std/tests/P0896R4_ranges_alg_inplace_merge/test.cpp b/tests/std/tests/P0896R4_ranges_alg_inplace_merge/test.cpp new file mode 100644 index 00000000000..9cf822b5dcb --- /dev/null +++ b/tests/std/tests/P0896R4_ranges_alg_inplace_merge/test.cpp @@ -0,0 +1,60 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include +#include + +#include + +using namespace std; +using P = pair; +// Validate dangling story +STATIC_ASSERT(same_as{}, nullptr_to)), ranges::dangling>); +STATIC_ASSERT(same_as{}, nullptr_to)), int*>); + +struct instantiator { + static constexpr P expected[] = {P{0, 1}, P{0, 5}, P{4, 2}, P{4, 6}, P{6, 7}, P{7, 3}, P{8, 4}, P{9, 8}, P{10, 9}}; + + template + static void call() { + using ranges::equal, ranges::is_sorted, ranges::iterator_t, ranges::inplace_merge; + + { // Validate range overload + P input[] = {P{0, 1}, P{4, 2}, P{7, 3}, P{8, 4}, P{0, 5}, P{4, 6}, P{6, 7}, P{9, 8}, P{10, 9}}; + Range range{input}; + const auto mid = ranges::next(range.begin(), 4); + const same_as> auto result = inplace_merge(range, mid, ranges::less{}, get_first); + assert(result == range.end()); + assert(equal(input, expected)); + + // Validate empty range + const Range empty_range{}; + const same_as> auto empty_result = + inplace_merge(empty_range, empty_range.begin(), ranges::less{}, get_first); + assert(empty_result == empty_range.begin()); + } + + { // Validate iterator overload + P input[] = {P{0, 1}, P{4, 2}, P{7, 3}, P{8, 4}, P{0, 5}, P{4, 6}, P{6, 7}, P{9, 8}, P{10, 9}}; + Range range{input}; + const auto mid = ranges::next(range.begin(), 4); + const same_as> auto result = + inplace_merge(range.begin(), mid, range.end(), ranges::less{}, get_first); + assert(result == range.end()); + assert(equal(input, expected)); + + // Validate empty range + const Range empty_range{}; + const same_as> auto empty_result = + inplace_merge(empty_range.begin(), empty_range.begin(), empty_range.end(), ranges::less{}, get_first); + assert(empty_result == empty_range.end()); + } + } +}; + +int main() { + test_bidi(); +} diff --git a/tests/std/tests/P0896R4_ranges_alg_stable_partition/env.lst b/tests/std/tests/P0896R4_ranges_alg_stable_partition/env.lst new file mode 100644 index 00000000000..f3ccc8613c6 --- /dev/null +++ b/tests/std/tests/P0896R4_ranges_alg_stable_partition/env.lst @@ -0,0 +1,4 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\concepts_matrix.lst diff --git a/tests/std/tests/P0896R4_ranges_alg_stable_partition/test.cpp b/tests/std/tests/P0896R4_ranges_alg_stable_partition/test.cpp new file mode 100644 index 00000000000..cc9cd58ee15 --- /dev/null +++ b/tests/std/tests/P0896R4_ranges_alg_stable_partition/test.cpp @@ -0,0 +1,67 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include +#include + +#include + +using namespace std; +using P = pair; + +constexpr auto is_even = [](int i) { return i % 2 == 0; }; + +// Validate dangling story +STATIC_ASSERT(same_as{}, is_even)), ranges::dangling>); +STATIC_ASSERT(same_as{}, is_even)), ranges::subrange>); + +struct instantiator { + template + static void call() { + using ranges::is_partitioned, ranges::is_sorted, ranges::iterator_t, ranges::stable_partition, ranges::subrange; + + { // Validate range overload + P input[] = {P{0, 1}, P{1, 2}, P{0, 3}, P{1, 4}, P{0, 5}, P{1, 6}, P{0, 7}, P{1, 8}}; + Range range{input}; + const auto mid = ranges::next(range.begin(), 4); + const same_as>> auto result = stable_partition(range, is_even, get_first); + assert(result.begin() == mid); + assert(result.end() == range.end()); + assert(is_partitioned(range, is_even, get_first)); + assert(is_sorted(range)); + + // Validate empty range + const Range empty_range{}; + const same_as>> auto empty_result = + stable_partition(empty_range, is_even, get_first); + assert(empty_result.begin() == empty_range.end()); + assert(empty_result.end() == empty_range.end()); + } + + { // Validate iterator overload + P input[] = {P{0, 1}, P{1, 2}, P{0, 3}, P{1, 4}, P{0, 5}, P{1, 6}, P{0, 7}, P{1, 8}}; + Range range{input}; + const auto mid = ranges::next(range.begin(), 4); + const same_as>> auto result = + stable_partition(range.begin(), range.end(), is_even, get_first); + assert(result.begin() == mid); + assert(result.end() == range.end()); + assert(is_partitioned(range, is_even, get_first)); + assert(is_sorted(range)); + + // Validate empty range + const Range empty_range{}; + const same_as>> auto empty_result = + stable_partition(empty_range.begin(), empty_range.end(), is_even, get_first); + assert(empty_result.begin() == empty_range.end()); + assert(empty_result.end() == empty_range.end()); + } + } +}; + +int main() { + test_bidi(); +} diff --git a/tests/std/tests/P0896R4_ranges_alg_stable_sort/env.lst b/tests/std/tests/P0896R4_ranges_alg_stable_sort/env.lst new file mode 100644 index 00000000000..f3ccc8613c6 --- /dev/null +++ b/tests/std/tests/P0896R4_ranges_alg_stable_sort/env.lst @@ -0,0 +1,4 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\concepts_matrix.lst diff --git a/tests/std/tests/P0896R4_ranges_alg_stable_sort/test.cpp b/tests/std/tests/P0896R4_ranges_alg_stable_sort/test.cpp new file mode 100644 index 00000000000..f20095aa55b --- /dev/null +++ b/tests/std/tests/P0896R4_ranges_alg_stable_sort/test.cpp @@ -0,0 +1,55 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include +#include +#include + +#include + +using namespace std; +using P = pair; + +// Validate dangling story +STATIC_ASSERT(same_as{})), ranges::dangling>); +STATIC_ASSERT(same_as{})), int*>); + +struct instantiator { + static constexpr array input = {P{1, 0}, P{-1260655766, 1}, P{-1298559576, 2}, P{1, 3}, P{-2095681771, 4}, + P{-441494788, 5}, P{-47163201, 6}, P{1, 7}, P{1429106719, 8}, P{1, 9}}; + + template + static void call() { + using ranges::stable_sort, ranges::is_sorted, ranges::iterator_t, ranges::less; + + { // Validate range overload + auto buff = input; + const R range{buff}; + const same_as> auto result = stable_sort(range, less{}, get_first); + assert(result == range.end()); + assert(is_sorted(range)); // Check for stability by not using a projection + } + + { // Validate iterator overload + auto buff = input; + const R range{buff}; + const same_as> auto result = stable_sort(range.begin(), range.end(), less{}, get_first); + assert(result == range.end()); + assert(is_sorted(range.begin(), range.end())); // Check for stability by not using a projection + } + + { // Validate empty range + const R range{}; + const same_as> auto result = stable_sort(range, less{}, get_first); + assert(result == range.end()); + assert(is_sorted(range, less{})); + } + } +}; + +int main() { + test_random(); +} diff --git a/tests/std/tests/P0898R3_concepts/test.cpp b/tests/std/tests/P0898R3_concepts/test.cpp index 6a3ece735e0..4ae135c53ad 100644 --- a/tests/std/tests/P0898R3_concepts/test.cpp +++ b/tests/std/tests/P0898R3_concepts/test.cpp @@ -2876,10 +2876,13 @@ namespace test_invocable_concepts { #define MCALLCONV __thiscall #include "invocable_cc.hpp" +#if !defined(_M_ARM) && !defined(_M_ARM64) #define NAME test_vector_vector #define CALLCONV __vectorcall #define MCALLCONV __vectorcall #include "invocable_cc.hpp" +#endif // ^^^ !ARM && !ARM64 ^^^ + } // namespace test_invocable_concepts namespace test_predicate { diff --git a/tests/std/tests/P1502R1_standard_library_header_units/custombuild.pl b/tests/std/tests/P1502R1_standard_library_header_units/custombuild.pl index b0b03595c17..214e5463338 100644 --- a/tests/std/tests/P1502R1_standard_library_header_units/custombuild.pl +++ b/tests/std/tests/P1502R1_standard_library_header_units/custombuild.pl @@ -99,8 +99,7 @@ () $header_unit_options .= " $_.obj"; } - # TRANSITION, remove /DMSVC_INTERNAL_TESTING after all compiler bugs are fixed - Run::ExecuteCL("/DMSVC_INTERNAL_TESTING $export_header_options"); - Run::ExecuteCL("/DMSVC_INTERNAL_TESTING test.cpp /Fe$cwd.exe $header_unit_options"); + Run::ExecuteCL("$export_header_options"); + Run::ExecuteCL("test.cpp /Fe$cwd.exe $header_unit_options"); } 1 diff --git a/tests/std/tests/P1502R1_standard_library_header_units/test.cpp b/tests/std/tests/P1502R1_standard_library_header_units/test.cpp index d660f96e77b..1fa579ad294 100644 --- a/tests/std/tests/P1502R1_standard_library_header_units/test.cpp +++ b/tests/std/tests/P1502R1_standard_library_header_units/test.cpp @@ -324,9 +324,13 @@ int main() { puts("Testing ."); promise p{}; future f{p.get_future()}; +#if 0 // TRANSITION, VSO-1271718 (Standard Library Header Units ICE with C++20 chrono) assert(f.wait_for(chrono::seconds{0}) == future_status::timeout); +#endif // ^^^ no workaround ^^^ p.set_value(1729); +#if 0 // TRANSITION, VSO-1271718 (Standard Library Header Units ICE with C++20 chrono) assert(f.wait_for(chrono::seconds{0}) == future_status::ready); +#endif // ^^^ no workaround ^^^ assert(f.get() == 1729); } @@ -756,7 +760,9 @@ int main() { } l.count_down(); // tell main() that we're done while (!token.stop_requested()) { +#if 0 // TRANSITION, VSO-1271718 (Standard Library Header Units ICE with C++20 chrono) this_thread::sleep_for(10ms); // not a timing assumption; avoids spinning furiously +#endif // ^^^ no workaround ^^^ } vec.push_back(-1000); // indicate that token.stop_requested() returned true }}; diff --git a/tests/std/tests/VSO_0000000_instantiate_iterators_misc/test.compile.pass.cpp b/tests/std/tests/VSO_0000000_instantiate_iterators_misc/test.compile.pass.cpp index c00a3dd8e21..3ad5fb18bf2 100644 --- a/tests/std/tests/VSO_0000000_instantiate_iterators_misc/test.compile.pass.cpp +++ b/tests/std/tests/VSO_0000000_instantiate_iterators_misc/test.compile.pass.cpp @@ -2,6 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception #define _HAS_DEPRECATED_ADAPTOR_TYPEDEFS 1 +#define _HAS_DEPRECATED_ALLOCATOR_MEMBERS 1 #define _HAS_DEPRECATED_NEGATORS 1 #define _HAS_DEPRECATED_RAW_STORAGE_ITERATOR 1 #define _HAS_DEPRECATED_TEMPORARY_BUFFER 1 diff --git a/tests/std/tests/VSO_0157762_feature_test_macros/test.compile.pass.cpp b/tests/std/tests/VSO_0157762_feature_test_macros/test.compile.pass.cpp index 9a6cd10c972..db066537944 100644 --- a/tests/std/tests/VSO_0157762_feature_test_macros/test.compile.pass.cpp +++ b/tests/std/tests/VSO_0157762_feature_test_macros/test.compile.pass.cpp @@ -850,6 +850,24 @@ STATIC_ASSERT(__cpp_lib_is_invocable == 201703L); #endif #endif +#if _HAS_CXX20 +#ifndef __EDG__ // TRANSITION, VSO-1268984 +#ifndef __clang__ // TRANSITION, LLVM-48860 +#ifndef __cpp_lib_is_layout_compatible +#error __cpp_lib_is_layout_compatible is not defined +#elif __cpp_lib_is_layout_compatible != 201907L +#error __cpp_lib_is_layout_compatible is not 201907L +#else +STATIC_ASSERT(__cpp_lib_is_layout_compatible == 201907L); +#endif +#else +#ifdef __cpp_lib_is_layout_compatible +#error __cpp_lib_is_layout_compatible is defined +#endif +#endif +#endif +#endif + #if _HAS_CXX20 #ifndef __cpp_lib_is_nothrow_convertible #error __cpp_lib_is_nothrow_convertible is not defined @@ -872,6 +890,24 @@ STATIC_ASSERT(__cpp_lib_is_nothrow_convertible == 201806L); STATIC_ASSERT(__cpp_lib_is_null_pointer == 201309L); #endif +#if _HAS_CXX20 +#ifndef __EDG__ // TRANSITION, VSO-1268984 +#ifndef __clang__ // TRANSITION, LLVM-48860 +#ifndef __cpp_lib_is_pointer_interconvertible +#error __cpp_lib_is_pointer_interconvertible is not defined +#elif __cpp_lib_is_pointer_interconvertible != 201907L +#error __cpp_lib_is_pointer_interconvertible is not 201907L +#else +STATIC_ASSERT(__cpp_lib_is_pointer_interconvertible == 201907L); +#endif +#else +#ifdef __cpp_lib_is_pointer_interconvertible +#error __cpp_lib_is_pointer_interconvertible is defined +#endif +#endif +#endif +#endif + #if _HAS_CXX17 #ifndef __cpp_lib_is_swappable #error __cpp_lib_is_swappable is not defined diff --git a/tests/tr1/lit.site.cfg.in b/tests/tr1/lit.site.cfg.in index 8e6afee6d49..a0d226bca8c 100644 --- a/tests/tr1/lit.site.cfg.in +++ b/tests/tr1/lit.site.cfg.in @@ -29,6 +29,7 @@ lit_config.test_subdirs[config.name] = ['@CMAKE_CURRENT_SOURCE_DIR@/tests'] lit_config.cxx_runtime = '@CMAKE_RUNTIME_OUTPUT_DIRECTORY@' lit_config.target_arch = '@VCLIBS_TARGET_ARCHITECTURE@' +lit_config.build_only = '@TESTS_BUILD_ONLY@'.lower() in ['1', 'true', 'on'] # Add parameters and features to the config stl.test.config.configure( diff --git a/tests/tr1/tests/memory/test.cpp b/tests/tr1/tests/memory/test.cpp index 897339b784e..5daa40cb0ce 100644 --- a/tests/tr1/tests/memory/test.cpp +++ b/tests/tr1/tests/memory/test.cpp @@ -5,6 +5,7 @@ #define TEST_NAME "" #define _HAS_AUTO_PTR_ETC 1 +#define _HAS_DEPRECATED_ALLOCATOR_MEMBERS 1 #define _HAS_DEPRECATED_RAW_STORAGE_ITERATOR 1 #define _HAS_DEPRECATED_TEMPORARY_BUFFER 1 #define _SILENCE_CXX17_OLD_ALLOCATOR_MEMBERS_DEPRECATION_WARNING diff --git a/tests/utils/stl/test/config.py b/tests/utils/stl/test/config.py index 335855c3934..5cff67b5133 100644 --- a/tests/utils/stl/test/config.py +++ b/tests/utils/stl/test/config.py @@ -9,24 +9,25 @@ import os def configure(parameters, features, config, lit_config): - # Apply parameters to the configuration first, since parameters are things - # that we request explicitly and which might influence what features are - # implicitly made available next. + # Apply the actions supplied by parameters to the configuration first, since + # parameters are things that we request explicitly and which might influence + # what features are implicitly made available next. for param in parameters: - feature = param.getFeature(config, lit_config.params) - if feature: - feature.enableIn(config) - lit_config.note( - "Enabling Lit feature '{}' as a result of parameter '{}'".format(feature.getName(config), param.name)) + actions = param.getActions(config, lit_config.params) + for action in actions: + action.applyTo(config) + #lit_config.note("Applied '{}' as a result of parameter '{}'".format( + # action.pretty(config, lit_config.params), + # param.pretty(config, lit_config.params))) # Then, apply the automatically-detected features. - printFeatures = [] for feature in features: - if feature.isSupported(config): - feature.enableIn(config) - printFeatures.append(feature.getName(config)) - printFeatures = ["'{}'".format(f) for f in sorted(printFeatures)] - lit_config.note("Enabling implicitly detected Lit features {}".format(', '.join(printFeatures))) + actions = feature.getActions(config) + for action in actions: + action.applyTo(config) + #lit_config.note("Applied '{}' as a result of implicitly detected feature '{}'".format( + # action.pretty(config, lit_config.params), + # feature.pretty(config))) # Normalize and validate all subdirectories to be tested lit_config.test_subdirs[config.name] = [os.path.normpath(subdir) for subdir in lit_config.test_subdirs[config.name]] diff --git a/tests/utils/stl/test/format.py b/tests/utils/stl/test/format.py index 85fa6ff80bd..c9d40635dd2 100644 --- a/tests/utils/stl/test/format.py +++ b/tests/utils/stl/test/format.py @@ -152,11 +152,11 @@ class SharedState: shared.env['TEMPDIR'] = execDir return [ - ('Build setup', self.getBuildSetupSteps(test, litConfig, shared)), - ('Build', self.getBuildSteps(test, litConfig, shared)), - ('Intellisense response file', self.getIsenseRspFileSteps(test, litConfig, shared)), - ('Test setup', self.getTestSetupSteps(test, litConfig, shared)), - ('Test', self.getTestSteps(test, litConfig, shared))] + ('Build setup', self.getBuildSetupSteps(test, litConfig, shared), True), + ('Build', self.getBuildSteps(test, litConfig, shared), True), + ('Intellisense response file', self.getIsenseRspFileSteps(test, litConfig, shared), False), + ('Test setup', self.getTestSetupSteps(test, litConfig, shared), False), + ('Test', self.getTestSteps(test, litConfig, shared), False)] def getBuildSetupSteps(self, test, litConfig, shared): shutil.rmtree(shared.execDir, ignore_errors=True) @@ -210,17 +210,17 @@ def execute(self, test, litConfig): if result: return result - if test.expectedResult and test.expectedResult.isFailure: - failVar = lit.Test.XFAIL - passVar = lit.Test.XPASS - else: - failVar = lit.Test.FAIL - passVar = lit.Test.PASS + # This test is expected to fail at some point, but we're not sure if + # it should fail during the build phase or the test phase. + someFail = test.expectedResult and test.expectedResult.isFailure stages = self.getStages(test, litConfig) report = '' - for stageName, steps in stages: + for stageName, steps, isBuildStep in stages: + if not isBuildStep and litConfig.build_only: + continue + report += stageName + ' steps:\n' for step in steps: cmd, out, err, rc = self.runStep(step, litConfig) @@ -232,9 +232,11 @@ def execute(self, test, litConfig): report += stl.util.makeReport(cmd, out, err, rc) if (step.shouldFail and rc == 0) or (not step.shouldFail and rc != 0): - return (failVar, report) + if someFail: + test.xfails = ['*'] + return (lit.Test.FAIL, report) - return (passVar, '') + return (lit.Test.PASS, '') except Exception as e: litConfig.error(repr(e)) diff --git a/tests/utils/stl/test/params.py b/tests/utils/stl/test/params.py index e57ddaf0cde..c83d14b7a2d 100644 --- a/tests/utils/stl/test/params.py +++ b/tests/utils/stl/test/params.py @@ -12,7 +12,7 @@ def getDefaultParameters(config, litConfig): DEFAULT_PARAMETERS = [ Parameter(name='long_tests', choices=[True, False], type=bool, default=True, help="Whether to run tests that take a long time. This can be useful when running on a slow device.", - feature=lambda enabled: Feature(name='long_tests') if enabled else None), + actions=lambda enabled: [AddFeature(name='long_tests')] if enabled else []), ] return DEFAULT_PARAMETERS diff --git a/tests/utils/stl/test/tests.py b/tests/utils/stl/test/tests.py index 3fda56ede3d..75dd5dbfb4c 100644 --- a/tests/utils/stl/test/tests.py +++ b/tests/utils/stl/test/tests.py @@ -7,13 +7,13 @@ # #===----------------------------------------------------------------------===## -from enum import Flag, auto +from enum import auto, Flag from itertools import chain import copy import os import shutil -from lit.Test import SKIPPED, Result, Test, UNRESOLVED, UNSUPPORTED +from lit.Test import Result, SKIPPED, Test, UNRESOLVED, UNSUPPORTED from libcxx.test.dsl import Feature import lit @@ -79,6 +79,15 @@ def configureTest(self, litConfig): self.compileFlags.extend(['/dE--write-isense-rsp', '/dE' + self.isenseRspPath]) self._configureTestType() + + forceFail = self.expectedResult and self.expectedResult.isFailure + buildFail = forceFail and TestType.COMPILE|TestType.LINK in self.testType + + if (litConfig.build_only and buildFail): + self.xfails = ['*'] + elif (not litConfig.build_only and forceFail): + self.xfails = ['*'] + return None def _parseTest(self): @@ -163,8 +172,6 @@ def _configureExpectedResult(self, litConfig): if self.expectedResult is not None: if self.expectedResult == SKIPPED: return Result(SKIPPED, 'This test was explicitly marked as skipped') - elif self.expectedResult.isFailure: - self.xfails = ['*'] elif self.config.unsupported: return Result(UNSUPPORTED, 'This test was marked as unsupported by a lit.cfg') @@ -202,6 +209,10 @@ def _handleEnvlst(self, litConfig): self.compileFlags.append('-m64') elif (targetArch == 'x86'.casefold()): self.compileFlags.append('-m32') + elif (targetArch == 'arm'.casefold()): + return Result(UNSUPPORTED, 'clang targeting arm is not supported') + elif (targetArch == 'arm64'.casefold()): + self.compileFlags.append('--target=arm64-pc-windows-msvc') if ('nvcc'.casefold() in os.path.basename(cxx).casefold()): # nvcc only supports targeting x64 @@ -210,17 +221,22 @@ def _handleEnvlst(self, litConfig): self.cxx = os.path.normpath(cxx) return None + def _addCustomFeature(self, name): + actions = Feature(name).getActions(self.config) + for action in actions: + action.applyTo(self.config) + def _parseFlags(self): foundStd = False for flag in chain(self.flags, self.compileFlags, self.linkFlags): if flag[1:5] == 'std:': foundStd = True if flag[5:] == 'c++latest': - Feature('c++2a').enableIn(self.config) + self._addCustomFeature('c++2a') elif flag[5:] == 'c++17': - Feature('c++17').enableIn(self.config) + self._addCustomFeature('c++17') elif flag[5:] == 'c++14': - Feature('c++14').enableIn(self.config) + self._addCustomFeature('c++14') elif flag[1:] == 'clr:pure': self.requires.append('clr_pure') # TRANSITION, GH-798 elif flag[1:] == 'clr': @@ -235,7 +251,10 @@ def _parseFlags(self): self.requires.append('arch_vfpv4') # available for arm, see features.py if not foundStd: - Feature('c++14').enableIn(self.config) + self._addCustomFeature('c++14') + + self._addCustomFeature('non-lockfree-atomics') # we always support non-lockfree-atomics + self._addCustomFeature('is-lockfree-runtime-function') # Ditto class LibcxxTest(STLTest):