diff --git a/.github/workflows/update-status-chart.yml b/.github/workflows/update-status-chart.yml
new file mode 100644
index 00000000000..c231c3529cb
--- /dev/null
+++ b/.github/workflows/update-status-chart.yml
@@ -0,0 +1,31 @@
+# Copyright (c) Microsoft Corporation.
+# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+name: Update Status Chart
+on:
+ schedule:
+ - cron: "0 7 * * *"
+ workflow_dispatch:
+jobs:
+ build:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout gh-pages
+ uses: actions/checkout@v2
+ with:
+ ref: gh-pages
+ - name: Setup Node.js
+ uses: actions/setup-node@v2
+ with:
+ node-version: ">=15.12.0"
+ - name: Run gather_stats.js
+ run: |
+ npm ci
+ SECRET_GITHUB_PERSONAL_ACCESS_TOKEN="${{ github.token }}" node gather_stats.js
+ - name: Commit Changes
+ run: |
+ git config user.name "github-actions[bot]"
+ git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
+ git add daily_table.js monthly_table.js
+ git diff-index --quiet HEAD || git commit -m "Automated update."
+ git push origin gh-pages
diff --git a/README.md b/README.md
index f81f691f560..1555cc8ce9c 100644
--- a/README.md
+++ b/README.md
@@ -57,7 +57,7 @@ issue. The [bug tag][] and [enhancement tag][] are being populated.
# Goals
-We're implementing the latest C++ Working Draft, currently [N4878][], which will eventually become the next C++
+We're implementing the latest C++ Working Draft, currently [N4885][], 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
@@ -172,14 +172,14 @@ acquire this dependency.
To build the x86 target:
-1. Open an "x86 Native Tools Command Prompt for VS 2019".
+1. Open an "x86 Native Tools Command Prompt for VS 2019 Preview".
2. Change directories to the previously cloned `STL` directory.
3. `cmake -G Ninja -S . -B out\build\x86`
4. `ninja -C out\build\x86`
To build the x64 target:
-1. Open an "x64 Native Tools Command Prompt for VS 2019".
+1. Open an "x64 Native Tools Command Prompt for VS 2019 Preview".
2. Change directories to the previously cloned `STL` directory.
3. `cmake -G Ninja -S . -B out\build\x64`
4. `ninja -C out\build\x64`
@@ -205,7 +205,7 @@ your .exe would "win" over the versions in System32.
The compiler looks for include directories according to the `INCLUDE` environment variable, and the linker looks for
import library directories according to the `LIB` environment variable, and the Windows loader will (eventually) look
for DLL dependencies according to directories in the `PATH` environment variable. From an
-"x64 Native Tools Command Prompt for VS 2019":
+"x64 Native Tools Command Prompt for VS 2019 Preview":
```
C:\Users\username\Desktop>set INCLUDE=C:\Dev\STL\out\build\x64\out\inc;%INCLUDE%
@@ -362,6 +362,57 @@ The `SKIPPED` result code indicates that a given test was explicitly skipped by
* taking a very long time to run
* failing or passing for the incorrect reason
+### Debugging Individual Tests
+
+While `stl-lit` is super awesome in finding out that *something* is wrong or not even compiling, it is not really
+helpful in debugging *what* is going wrong. However, debugging individual tests is rather simple given some additional
+steps. Let's assume we want to debug a new feature with tests located in `tests\std\tests\GH_XXXX_meow`.
+
+As always, build the STL from your branch and run the tests:
+```
+C:\STL\out\build\x64> ninja
+C:\STL\out\build\x64> python tests\utils\stl-lit\stl-lit.py -v C:\STL\tests\std\tests\GH_XXXX_meow
+```
+
+Let's assume one of the tests fails an assert and we want to debug that configuration. `stl-lit` will conveniently print
+the build command, which is far too long to provide here in full. The important part is to add the following options to
+provide debug symbols: `/Zi /Fdbark.pdb`.
+
+You can replace `bark` with any descriptive name you like. Add these before the `"-link"` option in the command line
+and recompile. Example:
+```
+C:\STL\out\build\x64>cl "C:\STL\tests\std\tests\GH_XXXX_meow\test.cpp" [... more arguments ...]
+"-FeC:\STL\out\build\x64\tests\std\tests\GH_XXXX_meow\Output\02\GH_XXXX_meow.exe" /Zi /Fdbark.pdb "-link"
+[... more arguments ...]
+```
+
+You can now start debugging the test via:
+```
+devenv "C:\STL\out\build\x64\tests\std\tests\GH_XXXX_meow\Output\02\GH_XXXX_meow.exe"
+ "C:\STL\tests\std\tests\GH_XXXX_meow\test.cpp"
+```
+
+However, this might not work right away, as Visual Studio may complain about a missing `msvcp140_oss.dll`. The reason
+is that the STL builds those and other DLLs itself and we should under no circumstances overwrite the installed ones.
+If you are testing one of the configurations with dynamic linkage (`/MD` or `/MDd`) the easiest solution is to add the
+build folder to your path:
+```
+set PATH=C:\STL\out\build\x64\out\bin\amd64;%PATH%
+```
+
+# Editing And Testing The Debugger Visualizer
+
+### Modify The Visualizer
+
+To modify how components are visualized in the debugger edit the file `stl\debugger\STL.natvis`. For more information on
+how to modify this file check the [natvis documentation][].
+
+### Test Your Changes
+
+You can add the natvis file to any Visual Studio C++ project if you right click your project > Add > Existing Item and
+select the STL.natvis file. After doing this you should be able to see your changes in a Visual Studio debugging
+session.
+
# Block Diagram
The STL is built atop other compiler support libraries that ship with Windows and Visual Studio, like the UCRT,
@@ -405,7 +456,7 @@ 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/
-[N4878]: https://wg21.link/n4878
+[N4885]: https://wg21.link/n4885
[NOTICE.txt]: NOTICE.txt
[Ninja]: https://ninja-build.org
[Pipelines]: https://dev.azure.com/vclibs/STL/_build/latest?definitionId=4&branchName=main
@@ -423,3 +474,4 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
[opencode@microsoft.com]: mailto:opencode@microsoft.com
[redistributables]: https://support.microsoft.com/en-us/help/2977003/the-latest-supported-visual-c-downloads
[vcpkg]: https://github.com/microsoft/vcpkg
+[natvis documentation]: https://docs.microsoft.com/en-us/visualstudio/debugger/create-custom-views-of-native-objects
diff --git a/azure-devops/create-vmss.ps1 b/azure-devops/create-vmss.ps1
index 64fa971fdc8..a927b1cc164 100644
--- a/azure-devops/create-vmss.ps1
+++ b/azure-devops/create-vmss.ps1
@@ -25,7 +25,9 @@ $Prefix = 'StlBuild-' + (Get-Date -Format 'yyyy-MM-dd')
$VMSize = 'Standard_D32ds_v4'
$ProtoVMName = 'PROTOTYPE'
$LiveVMPrefix = 'BUILD'
-$WindowsServerSku = '2019-Datacenter'
+$ImagePublisher = 'MicrosoftWindowsDesktop'
+$ImageOffer = 'Windows-10'
+$ImageSku = '20h2-ent-g2'
$ProgressActivity = 'Creating Scale Set'
$TotalProgress = 12
@@ -268,9 +270,9 @@ $VM = Set-AzVMOperatingSystem `
$VM = Add-AzVMNetworkInterface -VM $VM -Id $Nic.Id
$VM = Set-AzVMSourceImage `
-VM $VM `
- -PublisherName 'MicrosoftWindowsServer' `
- -Offer 'WindowsServer' `
- -Skus $WindowsServerSku `
+ -PublisherName $ImagePublisher `
+ -Offer $ImageOffer `
+ -Skus $ImageSku `
-Version latest
$VM = Set-AzVMBootDiagnostic -VM $VM -Disable
@@ -340,7 +342,7 @@ Set-AzVM `
$VM = Get-AzVM -ResourceGroupName $ResourceGroupName -Name $ProtoVMName
$PrototypeOSDiskName = $VM.StorageProfile.OsDisk.Name
-$ImageConfig = New-AzImageConfig -Location $Location -SourceVirtualMachineId $VM.ID
+$ImageConfig = New-AzImageConfig -Location $Location -SourceVirtualMachineId $VM.ID -HyperVGeneration 'V2'
$Image = New-AzImage -Image $ImageConfig -ImageName $ProtoVMName -ResourceGroupName $ResourceGroupName
####################################################################################################
diff --git a/azure-pipelines.yml b/azure-pipelines.yml
index 8e8832a925f..9c0fa71b56e 100644
--- a/azure-pipelines.yml
+++ b/azure-pipelines.yml
@@ -8,7 +8,7 @@ variables:
buildOutputLocation: 'D:\build'
vcpkgLocation: '$(Build.SourcesDirectory)/vcpkg'
-pool: 'StlBuild-2021-03-02'
+pool: 'StlBuild-2021-03-09-win10'
stages:
- stage: Code_Format
diff --git a/stl/CMakeLists.txt b/stl/CMakeLists.txt
index 33a9104b08d..751c6ad78aa 100644
--- a/stl/CMakeLists.txt
+++ b/stl/CMakeLists.txt
@@ -4,6 +4,7 @@
set(HEADERS
${CMAKE_CURRENT_LIST_DIR}/inc/__msvc_all_public_headers.hpp
${CMAKE_CURRENT_LIST_DIR}/inc/__msvc_system_error_abi.hpp
+ ${CMAKE_CURRENT_LIST_DIR}/inc/__msvc_tzdb.hpp
${CMAKE_CURRENT_LIST_DIR}/inc/algorithm
${CMAKE_CURRENT_LIST_DIR}/inc/any
${CMAKE_CURRENT_LIST_DIR}/inc/array
@@ -400,6 +401,7 @@ set(SOURCES_SATELLITE_ATOMIC_WAIT
${CMAKE_CURRENT_LIST_DIR}/src/atomic_wait.cpp
${CMAKE_CURRENT_LIST_DIR}/src/parallel_algorithms.cpp
${CMAKE_CURRENT_LIST_DIR}/src/syncstream.cpp
+ ${CMAKE_CURRENT_LIST_DIR}/src/tzdb.cpp
)
set(SOURCES_SATELLITE_CODECVT_IDS
@@ -499,7 +501,7 @@ function(add_stl_dlls D_SUFFIX THIS_CONFIG_DEFINITIONS THIS_CONFIG_COMPILE_OPTIO
file(WRITE "${_ATOMIC_WAIT_DEF_NAME}" "${_ATOMIC_WAIT_DEF_CONTENTS}")
add_library(msvcp${D_SUFFIX}_atomic_wait SHARED "${_ATOMIC_WAIT_DEF_NAME}")
- target_link_libraries(msvcp${D_SUFFIX}_atomic_wait PRIVATE msvcp${D_SUFFIX}_atomic_wait_objects msvcp${D_SUFFIX}_satellite_objects msvcp${D_SUFFIX}_implib_objects "msvcp${D_SUFFIX}" "${TOOLSET_LIB}/vcruntime${D_SUFFIX}.lib" "${TOOLSET_LIB}/msvcrt${D_SUFFIX}.lib" "ucrt${D_SUFFIX}.lib")
+ target_link_libraries(msvcp${D_SUFFIX}_atomic_wait PRIVATE msvcp${D_SUFFIX}_atomic_wait_objects msvcp${D_SUFFIX}_satellite_objects msvcp${D_SUFFIX}_implib_objects "msvcp${D_SUFFIX}" "${TOOLSET_LIB}/vcruntime${D_SUFFIX}.lib" "${TOOLSET_LIB}/msvcrt${D_SUFFIX}.lib" "ucrt${D_SUFFIX}.lib" "advapi32.lib")
set_target_properties(msvcp${D_SUFFIX}_atomic_wait PROPERTIES ARCHIVE_OUTPUT_NAME "msvcp140_atomic_wait${D_SUFFIX}${VCLIBS_SUFFIX}")
set_target_properties(msvcp${D_SUFFIX}_atomic_wait PROPERTIES ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}")
set_target_properties(msvcp${D_SUFFIX}_atomic_wait PROPERTIES OUTPUT_NAME "${_ATOMIC_WAIT_OUTPUT_NAME}")
diff --git a/stl/debugger/STL.natvis b/stl/debugger/STL.natvis
new file mode 100644
index 00000000000..aed5ae4210d
--- /dev/null
+++ b/stl/debugger/STL.natvis
@@ -0,0 +1,1634 @@
+
+
+
+
+
+
+ {*($T1 *)this}
+
+ *($T1 *)this
+
+
+
+
+
+ {_Myval1}
+
+ _Myval1
+
+
+
+
+
+
+ null
+
+
+
+
+
+ {{ size={_Last - _First} }}
+
+
+ _Last - _First
+ _First
+
+
+
+
+
+
+ {first}, {second}
+ ({first}, {second})
+
+ - first
+ - second
+
+
+
+
+
+
+ ({*this,view(noparens)})
+
+
+
+
+ {_Myfirst._Val}
+ ({*this,view(noparens)})
+
+ - _Myfirst._Val
+
+
+
+
+ {_Myfirst._Val}, {((_Mybase *) this)->_Myfirst._Val}
+ ({*this,view(noparens)})
+
+ - _Myfirst._Val
+ - ((_Mybase *) this)->_Myfirst._Val
+
+
+
+
+ {_Myfirst._Val}, {((_Mybase *) this)->_Myfirst._Val}, {((_Mybase::_Mybase *) this)->_Myfirst._Val}
+ ({*this,view(noparens)})
+
+ - _Myfirst._Val
+ - ((_Mybase *) this)->_Myfirst._Val
+ - ((_Mybase::_Mybase *) this)->_Myfirst._Val
+
+
+
+
+ {_Myfirst._Val}, {((_Mybase *) this)->_Myfirst._Val}, {((_Mybase::_Mybase *) this)->_Myfirst._Val}, {((_Mybase::_Mybase::_Mybase *) this)->_Myfirst._Val}
+ ({*this,view(noparens)})
+
+ - _Myfirst._Val
+ - ((_Mybase *) this)->_Myfirst._Val
+ - ((_Mybase::_Mybase *) this)->_Myfirst._Val
+ - ((_Mybase::_Mybase::_Mybase *) this)->_Myfirst._Val
+
+
+
+
+ {_Myfirst._Val}, {((_Mybase *) this)->_Myfirst._Val}, {((_Mybase::_Mybase *) this)->_Myfirst._Val}, {((_Mybase::_Mybase::_Mybase *) this)->_Myfirst._Val}, {((_Mybase::_Mybase::_Mybase::_Mybase *) this)->_Myfirst._Val}
+ ({*this,view(noparens)})
+
+ - _Myfirst._Val
+ - ((_Mybase *) this)->_Myfirst._Val
+ - ((_Mybase::_Mybase *) this)->_Myfirst._Val
+ - ((_Mybase::_Mybase::_Mybase *) this)->_Myfirst._Val
+ - ((_Mybase::_Mybase::_Mybase::_Mybase *) this)->_Myfirst._Val
+
+
+
+
+ {_Myfirst._Val}, {((_Mybase *) this)->_Myfirst._Val}, {((_Mybase::_Mybase *) this)->_Myfirst._Val}, {((_Mybase::_Mybase::_Mybase *) this)->_Myfirst._Val}, {((_Mybase::_Mybase::_Mybase::_Mybase *) this)->_Myfirst._Val}, {*((_Mybase::_Mybase::_Mybase::_Mybase::_Mybase *) this),view(noparens)}
+ ({*this,view(noparens)})
+
+ - _Myfirst._Val
+ - ((_Mybase *) this)->_Myfirst._Val
+ - ((_Mybase::_Mybase *) this)->_Myfirst._Val
+ - ((_Mybase::_Mybase::_Mybase *) this)->_Myfirst._Val
+ - ((_Mybase::_Mybase::_Mybase::_Mybase *) this)->_Myfirst._Val
+ Next five elements:
+ *((_Mybase::_Mybase::_Mybase::_Mybase::_Mybase *) this)
+
+
+
+
+
+ nullopt
+
+
+
+
+
+ nullopt
+ {value()}
+
+ - value()
+
+
+
+
+
+ {_Elem}
+
+
+
+
+ [valueless_by_exception]
+ {{ index=0, value={_Head} }}
+ {{ index=1, value={_Tail._Head} }}
+ {{ index=2, value={_Tail._Tail._Head} }}
+ {{ index=3, value={_Tail._Tail._Tail._Head} }}
+ {{ index=4, value={_Tail._Tail._Tail._Tail._Head} }}
+ {{ index=5, value={_Tail._Tail._Tail._Tail._Tail._Head} }}
+ {{ index=6, value={_Tail._Tail._Tail._Tail._Tail._Tail._Head} }}
+ {{ index=7, value={_Tail._Tail._Tail._Tail._Tail._Tail._Tail._Head} }}
+ {{ index=8, value={_Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Head} }}
+ {{ index=9, value={_Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Head} }}
+ {{ index=10, value={_Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Head} }}
+ {{ index=11, value={_Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Head} }}
+ {{ index=12, value={_Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Head} }}
+ {{ index=13, value={_Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Head} }}
+ {{ index=14, value={_Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Head} }}
+ {{ index=15, value={_Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Head} }}
+ {{ index=16, value={_Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Head} }}
+ {{ index=17, value={_Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Head} }}
+ {{ index=18, value={_Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Head} }}
+ {{ index=19, value={_Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Head} }}
+ {{ index=20, value={_Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Head} }}
+ {{ index=21, value={_Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Head} }}
+ {{ index=22, value={_Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Head} }}
+ {{ index=23, value={_Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Head} }}
+ {{ index=24, value={_Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Head} }}
+ {{ index=25, value={_Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Head} }}
+ {{ index=26, value={_Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Head} }}
+ {{ index=27, value={_Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Head} }}
+ {{ index=28, value={_Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Head} }}
+ {{ index=29, value={_Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Head} }}
+ {{ index=30, value={_Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Head} }}
+ {{ index=31, value={_Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Head} }}
+
+ - index()
+ - _Head
+ - _Tail._Head
+ - _Tail._Tail._Head
+ - _Tail._Tail._Tail._Head
+ - _Tail._Tail._Tail._Tail._Head
+ - _Tail._Tail._Tail._Tail._Tail._Head
+ - _Tail._Tail._Tail._Tail._Tail._Tail._Head
+ - _Tail._Tail._Tail._Tail._Tail._Tail._Tail._Head
+ - _Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Head
+ - _Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Head
+ - _Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Head
+ - _Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Head
+ - _Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Head
+ - _Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Head
+ - _Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Head
+ - _Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Head
+ - _Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Head
+ - _Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Head
+ - _Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Head
+ - _Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Head
+ - _Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Head
+ - _Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Head
+ - _Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Head
+ - _Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Head
+ - _Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Head
+ - _Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Head
+ - _Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Head
+ - _Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Head
+ - _Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Head
+ - _Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Head
+ - _Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Head
+ - _Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Head
+
+
+
+
+ monostate
+
+
+
+
+
+
+
+
+
+
+ [empty]
+ [not empty (Small)]
+ [not empty (Large)]
+
+
+ {has_value()}
+
+
+ {type()}
+
+
+ (Small/Trivial Object)
+
+
+ (Small Object)
+
+
+ (Dynamic Allocation)
+
+
+
+
+
+
+ {{ size={$T1} }}
+
+
+ $T1
+ (_Array[$i / _Bitsperword] >> ($i % _Bitsperword)) & 1,d
+
+
+
+
+
+ {(_Pbitset->_Array[_Mypos / _Pbitset->_Bitsperword] >> (_Mypos % _Pbitset->_Bitsperword)) & 1,d}
+
+ - _Pbitset
+ - _Mypos
+
+
+
+
+
+ allocator
+
+
+
+
+
+ default_delete
+
+
+
+
+
+ _Myptr
+ empty
+ unique_ptr {*_Myptr}
+
+ - _Myptr
+
+
+
+
+
+ _Mypair._Myval2
+ empty
+ unique_ptr {*_Mypair._Myval2}
+
+ - _Mypair._Myval2
+ - _Mypair
+
+
+
+
+
+ default
+
+ - _Ptr
+
+
+
+
+
+ custom deleter
+
+ - _Ptr
+ - _Dtor
+
+
+
+
+
+ custom deleter
+
+ - _Mypair._Myval2
+ - _Mypair
+
+
+
+
+
+ custom deleter, custom allocator
+
+ - _Ptr
+ - _Dtor
+ - _Myal
+
+
+
+
+
+ custom deleter, custom allocator
+
+ - _Mypair._Myval2._Myval2
+ - _Mypair
+ - _Mypair._Myval2
+
+
+
+
+ make_shared
+
+ - ($T1 *) &_Storage
+
+
+
+
+
+ allocate_shared
+
+ - ($T1 *) &_Storage
+ - _Myal
+
+
+
+
+
+ allocate_shared
+
+ - ($T1 *) &_Mypair._Myval2
+ - _Mypair
+
+
+
+
+
+ custom deleter
+
+ - _Mypair._Myval2
+ - _Mypair
+
+
+
+
+
+ custom deleter, custom allocator
+
+ - _Mypair._Myval2._Myval2
+ - _Mypair
+ - _Mypair._Myval2
+
+
+
+
+ _Ptr
+ empty
+ nullptr
+ {*_Ptr}
+ shared_ptr {*this,view(ptr)} [{_Rep->_Uses} strong ref] [{*_Rep}]
+ shared_ptr {*this,view(ptr)} [{_Rep->_Uses} strong ref, {_Rep->_Weaks - 1} weak ref] [{*_Rep}]
+ shared_ptr {*this,view(ptr)} [{_Rep->_Uses} strong ref, {_Rep->_Weaks - 1} weak refs] [{*_Rep}]
+ shared_ptr {*this,view(ptr)} [{_Rep->_Uses} strong refs] [{*_Rep}]
+ shared_ptr {*this,view(ptr)} [{_Rep->_Uses} strong refs, {_Rep->_Weaks - 1} weak ref] [{*_Rep}]
+ shared_ptr {*this,view(ptr)} [{_Rep->_Uses} strong refs, {_Rep->_Weaks - 1} weak refs] [{*_Rep}]
+
+ - _Ptr
+ - *_Rep
+
+
+
+
+ empty
+ nullptr
+ {*_Ptr}
+ expired [{_Rep->_Weaks} weak ref] [{*_Rep}]
+ expired [{_Rep->_Weaks} weak refs] [{*_Rep}]
+ weak_ptr {*this,view(ptr)} [{_Rep->_Uses} strong ref, {_Rep->_Weaks - 1} weak ref] [{*_Rep}]
+ weak_ptr {*this,view(ptr)} [{_Rep->_Uses} strong ref, {_Rep->_Weaks - 1} weak refs] [{*_Rep}]
+ weak_ptr {*this,view(ptr)} [{_Rep->_Uses} strong refs, {_Rep->_Weaks - 1} weak ref] [{*_Rep}]
+ weak_ptr {*this,view(ptr)} [{_Rep->_Uses} strong refs, {_Rep->_Weaks - 1} weak refs] [{*_Rep}]
+
+ - _Ptr
+ - *_Rep
+
+
+
+
+
+
+ {*_Ptr}
+
+ - _Ptr
+
+
+
+
+
+ {_Object}
+
+
+
+
+
+ {_Callee}
+
+ _Callee
+
+
+
+
+
+ {*_Ptr}
+
+ - _Ptr
+
+
+
+
+ plus<>
+ minus<>
+ multiplies<>
+ divides<>
+ modulus<>
+ negate<>
+ equal_to<>
+ not_equal_to<>
+ greater<>
+ less<>
+ greater_equal<>
+ less_equal<>
+ logical_and<>
+ logical_or<>
+ logical_not<>
+ bit_and<>
+ bit_or<>
+ bit_xor<>
+ bit_not<>
+
+
+
+ plus
+
+
+
+
+ minus
+
+
+
+
+ multiplies
+
+
+
+
+ divides
+
+
+
+
+ modulus
+
+
+
+
+ negate
+
+
+
+
+ equal_to
+
+
+
+
+ not_equal_to
+
+
+
+
+ greater
+
+
+
+
+ less
+
+
+
+
+ greater_equal
+
+
+
+
+ less_equal
+
+
+
+
+ logical_and
+
+
+
+
+ logical_or
+
+
+
+
+ logical_not
+
+
+
+
+ bit_and
+
+
+
+
+ bit_or
+
+
+
+
+ bit_xor
+
+
+
+
+ bit_not
+
+
+
+
+
+ not1({_Functor})
+
+ - _Functor
+
+
+
+
+ not2({_Functor})
+
+ - _Functor
+
+
+
+
+
+ _{$T1,d}
+
+
+
+
+
+ bind({_Myfun}, {_Mybargs,view(noparens)})
+
+ - _Myfun
+ - _Mybargs
+
+
+
+
+
+ bind({_Mypair}, {_Mypair._Myval2,view(noparens)})
+
+ - _Mypair
+ - _Mypair._Myval2
+
+
+
+
+
+
+ mem_fn({_Callee._Object})
+
+
+
+
+
+ mem_fn({_Pm})
+
+
+
+
+
+
+ {_Callee._Object}
+
+ - _Callee._Object
+ - _Myal
+
+
+
+
+
+ {_Mypair._Myval2}
+
+ - _Mypair._Myval2
+ - _Mypair
+
+
+
+
+ {_Callee}
+
+ - _Callee
+
+
+
+
+
+ empty
+ {*_Impl}
+
+ *_Impl
+
+
+
+
+
+ empty
+ {*_Mystorage._Ptrs[_EEN_IMPL]}
+
+ *_Mystorage._Ptrs[_EEN_IMPL]
+
+
+
+
+
+ hash
+
+
+
+
+
+ {_MyRep} nanoseconds
+
+
+
+
+ {_MyRep} microseconds
+
+
+
+
+ {_MyRep} milliseconds
+
+
+
+
+ {_MyRep} seconds
+
+
+
+
+ {_MyRep} minutes
+
+
+
+
+ {_MyRep} hours
+
+
+
+
+
+
+ {_Bx._Buf,na}
+ {_Bx._Ptr,na}
+ _Bx._Buf,na
+ _Bx._Ptr,na
+
+ - _Mysize
+ - _Myres
+
+ _Mysize
+ _Bx._Buf
+ _Bx._Ptr
+
+
+
+
+
+
+
+ {_Bx._Buf,su}
+ {_Bx._Ptr,su}
+ _Bx._Buf,su
+ _Bx._Ptr,su
+
+ - _Mysize
+ - _Myres
+
+ _Mysize
+ _Bx._Buf
+ _Bx._Ptr
+
+
+
+
+
+
+
+
+
+
+
+
+ {_Mypair._Myval2._Bx._Buf,na}
+ {_Mypair._Myval2._Bx._Ptr,na}
+ _Mypair._Myval2._Bx._Buf,na
+ _Mypair._Myval2._Bx._Ptr,na
+
+ - size()
+ - capacity()
+ - _Mypair
+
+ _Mypair._Myval2._Mysize
+ _Mypair._Myval2._Bx._Buf
+ _Mypair._Myval2._Bx._Ptr
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {_Mypair._Myval2._Bx._Buf,su}
+ {_Mypair._Myval2._Bx._Ptr,su}
+ _Mypair._Myval2._Bx._Buf,su
+ _Mypair._Myval2._Bx._Ptr,su
+
+ - size()
+ - capacity()
+ - _Mypair
+
+ _Mypair._Myval2._Mysize
+ _Mypair._Myval2._Bx._Buf
+ _Mypair._Myval2._Bx._Ptr
+
+
+
+
+
+
+
+
+
+
+
+ {_Mypair._Myval2._Bx._Buf,s32}
+ {_Mypair._Myval2._Bx._Ptr,s32}
+ _Mypair._Myval2._Bx._Buf,s32
+ _Mypair._Myval2._Bx._Ptr,s32
+
+ - size()
+ - capacity()
+ - _Mypair
+
+ _Mypair._Myval2._Mysize
+ _Mypair._Myval2._Bx._Buf
+ _Mypair._Myval2._Bx._Ptr
+
+
+
+
+
+
+ _Ptr,na
+
+ - _Ptr
+
+
+
+
+
+
+
+
+
+ _Ptr,su
+
+ - _Ptr
+
+
+
+
+
+ _Ptr,s32
+
+ - _Ptr
+
+
+
+
+
+
+ {_Mydata,[_Mysize]}
+ _Mydata,[_Mysize]
+
+ - size()
+
+ size()
+ data()
+
+
+
+
+
+
+ _Myptr
+
+ - _Myptr
+
+
+
+
+
+ _Mydata + _Myoff
+
+ - _Mydata + _Myoff
+ - _Myoff
+ - _Mydata,[_Mysize]
+
+
+
+
+
+ {{ size={$T2} }}
+
+
+ $T2
+ _Elems
+
+
+
+
+
+
+
+ _Ptr,na
+
+ - _Ptr
+
+
+
+
+
+
+ _Ptr + _Idx
+ {_Ptr[_Idx]}
+ end
+
+ - _Ptr + _Idx
+
+
+
+
+
+ {{ size={_Mysize} }}
+
+
+ _Mysize
+ _Map[(($i + _Myoff) / _EEN_DS) % _Mapsize][($i + _Myoff) % _EEN_DS]
+
+
+
+
+
+
+ {{ size={_Mypair._Myval2._Mysize} }}
+
+ - _Mypair
+
+ _Mypair._Myval2._Mysize
+ _Mypair._Myval2._Map[(($i + _Mypair._Myval2._Myoff) / _EEN_DS) % _Mypair._Myval2._Mapsize][($i + _Mypair._Myval2._Myoff) % _EEN_DS]
+
+
+
+
+
+
+ {((_Mydeque_t *)_Myproxy->_Mycont)->_Map[(_Myoff / _EEN_DS) % ((_Mydeque_t *)_Myproxy->_Mycont)->_Mapsize][_Myoff % _EEN_DS]}
+ end
+
+ - _Myoff - ((_Mydeque_t *)_Myproxy->_Mycont)->_Myoff
+ - &((_Mydeque_t *)_Myproxy->_Mycont)->_Map[(_Myoff / _EEN_DS) % ((_Mydeque_t *)_Myproxy->_Mycont)->_Mapsize][_Myoff % _EEN_DS]
+
+
+
+
+
+
+ empty
+ non-empty
+
+
+ _Myhead
+ _Next
+ _Myval
+
+
+
+
+
+
+ empty
+ non-empty
+
+ - _Mypair
+
+ _Mypair._Myval2._Myhead
+ _Next
+ _Myval
+
+
+
+
+
+
+ &_Ptr->_Myval,na
+ end
+ {**this}
+
+
+
+
+
+ {{ size={_Mysize} }}
+
+
+ _Mysize
+ _Myhead->_Next
+ _Next
+ _Myval
+
+
+
+
+
+
+ {{ size={_Mypair._Myval2._Mysize} }}
+
+ - _Mypair
+
+ _Mypair._Myval2._Mysize
+ _Mypair._Myval2._Myhead->_Next
+ _Next
+ _Myval
+
+
+
+
+
+
+ &_Ptr->_Myval,na
+
+
+
+
+
+ {{ size={_Mysize} }}
+
+ - (_Myvec._Myend - _Myvec._Myfirst) * _EEN_VBITS
+
+ _Mysize
+ (bool)((_Myvec._Myfirst[$i / _EEN_VBITS] >> ($i % _EEN_VBITS)) & 1)
+
+
+
+
+
+
+
+
+ {{ size={size()} }}
+
+ - capacity()
+ - _Myvec._Mypair
+
+ _Mysize
+ (bool)((_Myvec._Mypair._Myval2._Myfirst[$i / _EEN_VBITS] >> ($i % _EEN_VBITS)) & 1)
+
+
+
+
+
+
+
+ {(bool)((*_Myptr >> _Myoff) & 1)}
+
+ - _Myptr
+ - _Myoff
+
+
+
+
+
+
+ {{ size={_Mylast - _Myfirst} }}
+
+ - _Myend - _Myfirst
+
+ _Mylast - _Myfirst
+ _Myfirst
+
+
+
+
+
+
+
+
+ {{ size={size()} }}
+
+ - capacity()
+ - _Mypair
+
+ size()
+ _Mypair._Myval2._Myfirst
+
+
+
+
+
+
+ _Ptr,na
+
+ - _Ptr
+
+
+
+
+
+
+
+
+
+ {{ size={_Mysize} }}
+
+
+ _Mysize
+ _Myhead->_Parent
+ _Left
+ _Right
+ _Myval
+
+
+
+
+
+
+
+
+
+ {{ size={_Mypair._Myval2._Myval2._Mysize} }}
+
+ - _Mypair
+ - _Mypair._Myval2
+
+ _Mypair._Myval2._Myval2._Mysize
+ _Mypair._Myval2._Myval2._Myhead->_Parent
+ _Left
+ _Right
+ _Myval
+
+
+
+
+
+
+
+ {{ size={_Mypair._Myval2._Myval2._Mysize} }}
+
+ - _Mypair
+ - _Mypair._Myval2
+
+ _Mypair._Myval2._Myval2._Mysize
+ _Mypair._Myval2._Myval2._Myhead->_Parent
+ _Left
+ _Right
+ _Myval,view(MapHelper)
+
+
+
+
+
+ {second}
+
+
+
+
+ _Ptr->_Isnil ? nullptr : &_Ptr->_Myval
+ {_Ptr->_Myval}
+ end
+
+ - &_Ptr->_Myval
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {_List}
+
+ _List
+
+
+
+
+
+
+
+
+
+
+
+
+ {_List}
+
+ - _Maxidx
+ - ((float)_List._Mypair._Myval2._Mysize) / ((float)_Maxidx)
+ - _Traitsobj._Mypair._Myval2._Myval2
+ - _Traitsobj._Mypair
+ - _Traitsobj._Mypair._Myval2
+ - _List._Mypair
+ _List,view(simple)
+
+
+
+
+
+ {_List}
+
+ - _Maxidx
+ - ((float)_List._Mypair._Myval2._Mysize) / ((float)_Maxidx)
+ - _Traitsobj._Mypair._Myval2._Myval2
+ - _Traitsobj._Mypair
+ - _Traitsobj._Mypair._Myval2
+ - _List._Mypair
+ _List,view(MapHelper)
+
+
+
+
+
+ Test
+
+
+ _Mypair._Myval2._Mysize
+ _Mypair._Myval2._Myhead->_Next
+ _Next
+ _Myval
+
+
+
+
+
+
+
+ {c}
+
+ - c
+
+
+
+
+
+ {c}
+
+ - c
+ - comp
+
+
+
+
+
+
+
+ current._Ptr - 1,na
+ reverse_iterator {current._Ptr[-1]}
+
+ - current._Ptr - 1
+
+
+
+
+
+
+ current._Ptr + current._Idx - 1,na
+ reverse_iterator {current._Ptr[current._Idx - 1]}
+ reverse_iterator rend
+
+ - current._Ptr + current._Idx - 1
+
+
+
+
+
+ ¤t._Ptr->_Prev->_Myval,na
+ reverse_iterator {**this}
+
+
+
+
+ current._Ptr - 1,na
+ reverse_iterator {**this}
+
+ - current._Ptr - 1
+
+
+
+
+ reverse_iterator base() {current}
+
+ NOTE: *ri is equivalent to *prev(ri.base())
+ - current
+
+
+
+
+
+ current - 1
+ reverse_iterator {current[-1]}
+
+ - current - 1
+
+
+
+
+
+ back_insert_iterator into {container}
+
+ - container
+
+
+
+
+
+ front_insert_iterator into {container}
+
+ - container
+
+
+
+
+
+ insert_iterator into {container} at {iter}
+
+ - container
+ - iter
+
+
+
+
+
+ move_iterator {current}
+
+ - current
+
+
+
+
+
+ -i*{-_Val[1]}
+ {_Val[0]}-i*{-_Val[1]}
+ {_Val[0]}
+ i*{_Val[1]}
+ {_Val[0]}+i*{_Val[1]}
+
+ - _Val[0]
+ - _Val[1]
+
+
+
+
+
+ {{ size={_Mysize} }}
+
+
+ _Mysize
+ _Myptr
+
+
+
+
+
+
+
+
+ {data(),[size()]}
+
+
+
+
+ {_Stringbuffer}
+
+ - _Stringbuffer
+
+
+
+
+ {_Stringbuffer}
+
+ - _Stringbuffer
+
+
+
+
+ {_Stringbuffer}
+
+ - _Stringbuffer
+
+
+
+
+
+ empty
+ {_Visualization}
+ _Visualization
+
+
+
+
+
+ {first,[second - first]na}
+ false
+
+ - matched
+ - first
+ - second
+
+
+
+
+
+ {first._Ptr,[second._Ptr - first._Ptr]na}
+ false
+
+ - matched
+ - first
+ - second
+
+
+
+
+
+ not ready
+ {_Matches}
+
+ _Matches,view(simple)
+ - _Prefix
+ - _Suffix
+
+
+
+
+
+ &_MyVal
+ end
+ {_MyVal}
+
+ - _Begin
+ - _End
+ - _MyRe
+ - _Flags
+ - _MyVal
+
+
+
+
+
+ _Res
+ end
+ {*_Res}
+
+ - _Pos
+ - _Res
+ - _Suffix
+ - _Cur
+ - _Subs
+
+
+
+
+
+
+
+
+
+ {value()}
+
+ - value()
+
+
+
+
+
+
+
+
+
+ {value()}
+
+
+
+
+
+
+ unlocked
+ locked
+ unlocked
+ locked
+
+ - *(long *)((char *)(&_Mtx_storage) + 40)
+ - *(long *)((char *)(&_Mtx_storage) + 72)
+ - *(int *)((char *)(&_Mtx_storage) + 44)
+ - *(int *)((char *)(&_Mtx_storage) + 76)
+
+
+
+
+
+
+
+ - _Retrieved
+ - _Result
+ - _Exception
+
+
+
+
+
+
+ empty
+ pending
+ has_result
+
+ *_MyPromise._State._Assoc_state
+ - _MyPromise._Future_retrieved
+
+
+
+
+
+
+ empty
+ pending
+ has_result
+
+ *_Assoc_state
+
+
+
+
+
+
+ ptr_fun({_Pfun})
+
+
+
+
+
+
+
+ mem_fun({_Pmemfun})
+
+
+
+
+
+
+
+ mem_fun_ref({_Pmemfun})
+
+
+
+
+ bind1st({op}, {value})
+
+ - op
+ - value
+
+
+
+
+ bind2nd({op}, {value})
+
+ - op
+ - value
+
+
+
+
+ empty
+ auto_ptr {*_Myptr}
+
+ - _Myptr
+
+
+
+
+
+
+ {_Ptr->_Fn,na}, #initial suspend
+ {_Ptr->_Fn,na}, #final suspend
+ {_Ptr->_Fn,na}, suspend point #{(_Ptr->_Index)/2 - 1}
+ {_Ptr->_Fn,na}
+
+ - "initial suspend"
+ - "final suspend"
+ - (_Ptr->_Index)/2 - 1
+ this,view(ViewPromise)
+
+
+
+
+
+
+
+
+
+
+
+ - *reinterpret_cast<$T1 *>(reinterpret_cast<char*>(_Ptr) - _ALIGNED_SIZE)
+
+
+
+
+
+
+ - *reinterpret_cast<$T1 *>(reinterpret_cast<char*>(_Ptr) + 2*sizeof(void*))
+
+
+
+
+
+
+
+
+
+
+
+
+
+ empty
+ {primary_function(_Ptr),na} #final suspend
+ {primary_function(_Ptr),na} #initial suspend
+ {primary_function(_Ptr),na} #suspend point {suspend_point(_Ptr)}
+ {primary_function(_Ptr),na} #suspend point {suspend_point(_Ptr)}, line {suspend_point_line(_Ptr)}
+
+ this,view(ViewPromise)
+
+
+
+
+
+
+
+
+
diff --git a/stl/inc/__msvc_tzdb.hpp b/stl/inc/__msvc_tzdb.hpp
new file mode 100644
index 00000000000..d252f8a6d5d
--- /dev/null
+++ b/stl/inc/__msvc_tzdb.hpp
@@ -0,0 +1,154 @@
+// __msvc_tzdb.hpp internal header
+
+// Copyright (c) Microsoft Corporation.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+#pragma once
+#ifndef __MSVC_TZDB_HPP
+#define __MSVC_TZDB_HPP
+#include
+#if _STL_COMPILER_PREPROCESSOR
+#include
+#include
+#include
+#include
+
+#pragma pack(push, _CRT_PACKING)
+#pragma warning(push, _STL_WARNING_LEVEL)
+#pragma warning(disable : _STL_DISABLED_WARNINGS)
+_STL_DISABLE_CLANG_WARNINGS
+#pragma push_macro("new")
+#undef new
+
+using __std_tzdb_epoch_milli = double;
+
+struct __std_tzdb_leap_info {
+ uint16_t _Year;
+ uint16_t _Month;
+ uint16_t _Day;
+ uint16_t _Hour;
+ uint16_t _Negative;
+ uint16_t _Reserved;
+};
+
+enum class __std_tzdb_error {
+ _Success = 0,
+ _Win_error = 1,
+ _Icu_error = 2,
+};
+
+struct __std_tzdb_time_zones_info {
+ __std_tzdb_error _Err;
+ // timezone data version currently being used
+ const char* _Version;
+ size_t _Num_time_zones;
+ // ordered list of null-terminated time_zone/time_zone_link names
+ const char** _Names;
+ // contains corresponding entry for every name, if:
+ // (_Links[i] == nullptr) then _Names[i] is a time_zone
+ // (_Links[i] != nullptr) then _Names[i] is a time_zone_link to time_zone with name _Links[i]
+ const char** _Links;
+};
+
+struct __std_tzdb_current_zone_info {
+ __std_tzdb_error _Err;
+ const char* _Tz_name;
+};
+
+struct __std_tzdb_sys_info {
+ __std_tzdb_error _Err;
+ __std_tzdb_epoch_milli _Begin;
+ __std_tzdb_epoch_milli _End;
+ int32_t _Offset;
+ int32_t _Save;
+ const char* _Abbrev;
+};
+
+_EXTERN_C
+
+_NODISCARD __std_tzdb_time_zones_info* __stdcall __std_tzdb_get_time_zones() noexcept;
+void __stdcall __std_tzdb_delete_time_zones(__std_tzdb_time_zones_info* _Info) noexcept;
+
+_NODISCARD __std_tzdb_current_zone_info* __stdcall __std_tzdb_get_current_zone() noexcept;
+void __stdcall __std_tzdb_delete_current_zone(__std_tzdb_current_zone_info* _Info) noexcept;
+
+_NODISCARD __std_tzdb_sys_info* __stdcall __std_tzdb_get_sys_info(
+ const char* _Tz, size_t _Tz_len, __std_tzdb_epoch_milli _Local) noexcept;
+void __stdcall __std_tzdb_delete_sys_info(__std_tzdb_sys_info* _Info) noexcept;
+
+_NODISCARD __std_tzdb_leap_info* __stdcall __std_tzdb_get_leap_seconds(
+ size_t _Prev_ls_size, size_t* _Current_ls_size) noexcept;
+void __stdcall __std_tzdb_delete_leap_seconds(__std_tzdb_leap_info* _Info) noexcept;
+
+_NODISCARD void* __stdcall __std_calloc_crt(size_t _Count, size_t _Size) noexcept;
+void __stdcall __std_free_crt(void* _Ptr) noexcept;
+
+_END_EXTERN_C
+
+_STD_BEGIN
+
+template
+struct _Tzdb_deleter;
+
+template <>
+struct _Tzdb_deleter<__std_tzdb_time_zones_info> {
+ void operator()(__std_tzdb_time_zones_info* _Info) const noexcept {
+ __std_tzdb_delete_time_zones(_Info);
+ }
+};
+
+template <>
+struct _Tzdb_deleter<__std_tzdb_current_zone_info> {
+ void operator()(__std_tzdb_current_zone_info* _Info) const noexcept {
+ __std_tzdb_delete_current_zone(_Info);
+ }
+};
+
+template <>
+struct _Tzdb_deleter<__std_tzdb_sys_info> {
+ void operator()(__std_tzdb_sys_info* _Info) const noexcept {
+ __std_tzdb_delete_sys_info(_Info);
+ }
+};
+
+template <>
+struct _Tzdb_deleter<__std_tzdb_leap_info[]> {
+ void operator()(__std_tzdb_leap_info* _Info) const noexcept {
+ __std_tzdb_delete_leap_seconds(_Info);
+ }
+};
+
+template
+class _Crt_allocator {
+public:
+ using value_type = _Ty;
+ using propagate_on_container_move_assignment = true_type;
+ using is_always_equal = true_type;
+
+ constexpr _Crt_allocator() noexcept = default;
+
+ constexpr _Crt_allocator(const _Crt_allocator&) noexcept = default;
+ template
+ constexpr _Crt_allocator(const _Crt_allocator<_Other>&) noexcept {}
+
+ _NODISCARD __declspec(allocator) _Ty* allocate(_CRT_GUARDOVERFLOW const size_t _Count) {
+ const auto _Ptr = __std_calloc_crt(_Count, sizeof(_Ty));
+ if (!_Ptr) {
+ _Xbad_alloc();
+ }
+ return static_cast<_Ty*>(_Ptr);
+ }
+
+ void deallocate(_Ty* const _Ptr, size_t) noexcept {
+ __std_free_crt(_Ptr);
+ }
+};
+
+_STD_END
+
+#pragma pop_macro("new")
+_STL_RESTORE_CLANG_WARNINGS
+#pragma warning(pop)
+#pragma pack(pop)
+#endif // _STL_COMPILER_PREPROCESSOR
+#endif // __MSVC_TZDB_HPP
diff --git a/stl/inc/algorithm b/stl/inc/algorithm
index 8f13788c196..e128b93569c 100644
--- a/stl/inc/algorithm
+++ b/stl/inc/algorithm
@@ -114,23 +114,6 @@ namespace ranges {
}
};
- // STRUCT TEMPLATE in_in_result
- template
- struct in_in_result {
- /* [[no_unique_address]] */ _In1 in1;
- /* [[no_unique_address]] */ _In2 in2;
-
- template <_Convertible_from _IIn1, _Convertible_from _IIn2>
- constexpr operator in_in_result<_IIn1, _IIn2>() const& {
- return {in1, in2};
- }
-
- template <_Convertible_from<_In1> _IIn1, _Convertible_from<_In2> _IIn2>
- constexpr operator in_in_result<_IIn1, _IIn2>() && {
- return {_STD move(in1), _STD move(in2)};
- }
- };
-
// STRUCT TEMPLATE in_in_out_result
template
struct in_in_out_result {
@@ -416,21 +399,6 @@ namespace ranges {
inline constexpr _For_each_n_fn for_each_n{_Not_quite_object::_Construct_tag{}};
// VARIABLE ranges::find
- // clang-format off
- // concept-constrained for strict enforcement as it is used by several algorithms
- template _Se, class _Ty, class _Pj>
- requires indirect_binary_predicate, const _Ty*>
- _NODISCARD constexpr _It _Find_unchecked(_It _First, const _Se _Last, const _Ty& _Val, _Pj _Proj) {
- for (; _First != _Last; ++_First) {
- if (_STD invoke(_Proj, *_First) == _Val) {
- break;
- }
- }
-
- return _First;
- }
- // clang-format on
-
class _Find_fn : private _Not_quite_object {
public:
using _Not_quite_object::_Not_quite_object;
@@ -792,107 +760,19 @@ _NODISCARD pair<_FwdIt1, _FwdIt2> mismatch(
#ifdef __cpp_lib_concepts
namespace ranges {
- // ALIAS TEMPLATE mismatch_result
- template
- using mismatch_result = in_in_result<_In1, _In2>;
-
- // VARIABLE ranges::mismatch
- class _Mismatch_fn : private _Not_quite_object {
- private:
- template
- _NODISCARD static constexpr mismatch_result<_It1, _It2> _Mismatch_n(
- _It1 _First1, _It2 _First2, iter_difference_t<_It1> _Count, _Pr _Pred, _Pj1 _Proj1, _Pj2 _Proj2) {
- auto _UFirst1 = _Get_unwrapped(_STD move(_First1));
- auto _UFirst2 = _Get_unwrapped(_STD move(_First2));
-
- for (; _Count != 0; ++_UFirst1, (void) ++_UFirst2, --_Count) {
- if (!_STD invoke(_Pred, _STD invoke(_Proj1, *_UFirst1), _STD invoke(_Proj2, *_UFirst2))) {
- break;
- }
- }
-
- _Seek_wrapped(_First1, _STD move(_UFirst1));
- _Seek_wrapped(_First2, _STD move(_UFirst2));
- return {_STD move(_First1), _STD move(_First2)};
- }
-
- template
- _NODISCARD static constexpr mismatch_result<_It1, _It2> _Mismatch_4(
- _It1 _First1, _Se1 _Last1, _It2 _First2, _Se2 _Last2, _Pr _Pred, _Pj1 _Proj1, _Pj2 _Proj2) {
- auto _UFirst1 = _Get_unwrapped(_STD move(_First1));
- const auto _ULast1 = _Get_unwrapped(_STD move(_Last1));
- auto _UFirst2 = _Get_unwrapped(_STD move(_First2));
- const auto _ULast2 = _Get_unwrapped(_STD move(_Last2));
-
- for (; _UFirst1 != _ULast1 && _UFirst2 != _ULast2; ++_UFirst1, (void) ++_UFirst2) {
- if (!_STD invoke(_Pred, _STD invoke(_Proj1, *_UFirst1), _STD invoke(_Proj2, *_UFirst2))) {
- break;
- }
- }
-
- _Seek_wrapped(_First1, _STD move(_UFirst1));
- _Seek_wrapped(_First2, _STD move(_UFirst2));
- return {_STD move(_First1), _STD move(_First2)};
- }
-
- public:
- using _Not_quite_object::_Not_quite_object;
-
- // clang-format off
- template _Se1, input_iterator _It2, sentinel_for<_It2> _Se2,
- class _Pr = ranges::equal_to, class _Pj1 = identity, class _Pj2 = identity>
- requires indirectly_comparable<_It1, _It2, _Pr, _Pj1, _Pj2>
- _NODISCARD constexpr mismatch_result<_It1, _It2> operator()(_It1 _First1, _Se1 _Last1,
- _It2 _First2, _Se2 _Last2, _Pr _Pred = {}, _Pj1 _Proj1 = {}, _Pj2 _Proj2 = {}) const {
- _Adl_verify_range(_First1, _Last1);
- _Adl_verify_range(_First2, _Last2);
-
- if constexpr (sized_sentinel_for<_Se1, _It1> && sized_sentinel_for<_Se2, _It2>) {
- iter_difference_t<_It1> _Count1 = _Last1 - _First1;
- const iter_difference_t<_It2> _Count2 = _Last2 - _First2;
- if (_Count1 > _Count2) {
- _Count1 = static_cast(_Count2);
- }
-
- return _Mismatch_n(_STD move(_First1), _STD move(_First2), _Count1,
- _Pass_fn(_Pred), _Pass_fn(_Proj1), _Pass_fn(_Proj2));
- } else {
- return _Mismatch_4(_STD move(_First1), _STD move(_Last1), _STD move(_First2), _STD move(_Last2),
- _Pass_fn(_Pred), _Pass_fn(_Proj1), _Pass_fn(_Proj2));
- }
- }
-
- template
- requires indirectly_comparable, iterator_t<_Rng2>, _Pr, _Pj1, _Pj2>
- _NODISCARD constexpr mismatch_result, borrowed_iterator_t<_Rng2>> operator()(
- _Rng1&& _Range1, _Rng2&& _Range2, _Pr _Pred = {}, _Pj1 _Proj1 = {}, _Pj2 _Proj2 = {}) const {
- if constexpr (sized_range<_Rng1> && sized_range<_Rng2>) {
- range_difference_t<_Rng1> _Count1 = _RANGES distance(_Range1);
- const range_difference_t<_Rng2> _Count2 = _RANGES distance(_Range2);
- if (_Count1 > _Count2) {
- _Count1 = static_cast>(_Count2);
- }
-
- return _Mismatch_n(_RANGES begin(_Range1), _RANGES begin(_Range2), _Count1,
- _Pass_fn(_Pred), _Pass_fn(_Proj1), _Pass_fn(_Proj2));
- } else {
- return _Mismatch_4(_RANGES begin(_Range1), _RANGES end(_Range1),
- _RANGES begin(_Range2), _RANGES end(_Range2),
- _Pass_fn(_Pred), _Pass_fn(_Proj1), _Pass_fn(_Proj2));
- }
- }
- // clang-format on
- };
-
- inline constexpr _Mismatch_fn mismatch{_Not_quite_object::_Construct_tag{}};
-
// VARIABLE ranges::equal
class _Equal_fn : private _Not_quite_object {
private:
template
_NODISCARD static constexpr bool _Equal_count(
_It1 _First1, _It2 _First2, _Size _Count, _Pr _Pred, _Pj1 _Proj1, _Pj2 _Proj2) {
+ if constexpr (_Equal_memcmp_is_safe<_It1, _It2,
+ _Pr> && same_as<_Pj1, identity> && same_as<_Pj2, identity>) {
+ if (!_STD is_constant_evaluated()) {
+ return _Memcmp_count(_First1, _First2, static_cast(_Count)) == 0;
+ }
+ }
+
for (; _Count != 0; ++_First1, (void) ++_First2, --_Count) {
if (!_STD invoke(_Pred, _STD invoke(_Proj1, *_First1), _STD invoke(_Proj2, *_First2))) {
return false;
@@ -1508,7 +1388,15 @@ namespace ranges {
// clang-format off
template _Se, weakly_incrementable _Out>
requires indirectly_copyable<_It, _Out>
- _NODISCARD constexpr copy_result<_It, _Out> _Copy_unchecked(_It _First, const _Se _Last, _Out _Result) {
+ _NODISCARD constexpr copy_result<_It, _Out> _Copy_unchecked(_It _First, _Se _Last, _Out _Result) {
+ if constexpr (_Ptr_copy_cat<_It, _Out>::_Trivially_copyable && sized_sentinel_for<_Se, _It>) {
+ if (!_STD is_constant_evaluated()) {
+ auto _Final = _RANGES next(_First, _STD move(_Last));
+ _Result = _Copy_memmove(_STD move(_First), _Final, _STD move(_Result));
+ return {_STD move(_Final), _STD move(_Result)};
+ }
+ }
+
for (; _First != _Last; ++_First, (void) ++_Result) {
*_Result = *_First;
}
@@ -1560,6 +1448,15 @@ namespace ranges {
requires indirectly_copyable<_It, _Out>
constexpr copy_n_result<_It, _Out> operator()(_It _First, iter_difference_t<_It> _Count, _Out _Result) const {
auto _UFirst = _Get_unwrapped_n(_STD move(_First), _Count);
+ if constexpr (_Ptr_copy_cat::_Trivially_copyable) {
+ if (!_STD is_constant_evaluated()) {
+ auto _Final = _UFirst + _Count;
+ _Result = _Copy_memmove(_STD move(_UFirst), _Final, _STD move(_Result));
+ _Seek_wrapped(_First, _STD move(_Final));
+ return {_STD move(_First), _STD move(_Result)};
+ }
+ }
+
for (; _Count > 0; ++_UFirst, (void) ++_Result, --_Count) {
*_Result = *_UFirst;
}
@@ -1703,8 +1600,15 @@ namespace ranges {
// 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) {
+ constexpr move_result<_It, _Out> _Move_unchecked(_It _First, _Se _Last, _Out _Result) {
// clang-format on
+ if constexpr (_Ptr_move_cat<_It, _Out>::_Trivially_copyable) {
+ if (!_STD is_constant_evaluated()) {
+ auto _Final = _RANGES next(_First, _STD move(_Last));
+ _Result = _Copy_memmove(_STD move(_First), _Final, _STD move(_Result));
+ return {_STD move(_Final), _STD move(_Result)};
+ }
+ }
for (; _First != _Last; ++_First, (void) ++_Result) {
*_Result = _RANGES iter_move(_First);
@@ -2127,10 +2031,7 @@ _NODISCARD _CONSTEXPR20 bool _Equal_rev_pred_unchecked(_InIt1 _First1, _InIt2 _F
if (!_STD is_constant_evaluated())
#endif // __cpp_lib_is_constant_evaluated
{
- const auto _First1_ch = _To_pointer(_First1);
- const auto _First2_ch = _To_pointer(_First2);
- const auto _Count = static_cast(_To_pointer(_Last2) - _First2_ch);
- return _CSTD memcmp(_First1_ch, _First2_ch, _Count) == 0;
+ return _Memcmp_ranges(_First2, _Last2, _First1) == 0;
}
}
@@ -2222,7 +2123,7 @@ namespace ranges {
// clang-format off
template
concept _Equal_rev_pred_can_memcmp = is_same_v<_Pj1, identity> && is_same_v<_Pj2, identity>
- && is_same_v<_Se2, _It2> && _Equal_memcmp_is_safe<_It1, _It2, _Pr>;
+ && sized_sentinel_for<_Se2, _It2> && _Equal_memcmp_is_safe<_It1, _It2, _Pr>;
template _Se2, class _Pr, class _Pj1, class _Pj2>
requires indirectly_comparable<_It1, _It2, _Pr, _Pj1, _Pj2>
@@ -2233,12 +2134,14 @@ namespace ranges {
constexpr bool _Optimize = _Equal_rev_pred_can_memcmp<_It1, _It2, _Se2, _Pr, _Pj1, _Pj2>;
if constexpr (_Optimize) {
if (!_STD is_constant_evaluated()) {
- const auto _First1_ch = reinterpret_cast(_STD to_address(_First1));
- const auto _First2_ch = reinterpret_cast(_STD to_address(_First2));
- const auto _Count =
- static_cast(reinterpret_cast(_STD to_address(_Last2)) - _First2_ch);
- const bool _Eq = _CSTD memcmp(_First1_ch, _First2_ch, _Count) == 0;
- if (_Eq) {
+ bool _Ans;
+ if constexpr (same_as<_It2, _Se2>) {
+ _Ans = _Memcmp_ranges(_First2, _Last2, _First1) == 0;
+ } else {
+ _Ans = _Memcmp_count(_First1, _First2, static_cast(_Last2 - _First2)) == 0;
+ }
+
+ if (_Ans) {
_First1 += (_Last2 - _First2);
return {true, _STD move(_First1)};
} else {
@@ -3596,17 +3499,19 @@ namespace ranges {
auto _UFirst = _Get_unwrapped(_STD move(_First));
const auto _ULast = _Get_unwrapped(_STD move(_Last));
if (!_STD is_constant_evaluated()) {
- if constexpr (_Fill_memset_is_safe) {
- const auto _Distance = static_cast(_ULast - _UFirst);
- _Fill_memset(_UFirst, _Value, _Distance);
- _Seek_wrapped(_First, _UFirst + _Distance);
- return _First;
- } else if constexpr (_Fill_zero_memset_is_safe) {
- if (_Is_all_bits_zero(_Value)) {
+ if constexpr (sized_sentinel_for) {
+ if constexpr (_Fill_memset_is_safe) {
const auto _Distance = static_cast(_ULast - _UFirst);
- _Fill_zero_memset(_UFirst, _Distance);
+ _Fill_memset(_UFirst, _Value, _Distance);
_Seek_wrapped(_First, _UFirst + _Distance);
return _First;
+ } else if constexpr (_Fill_zero_memset_is_safe) {
+ if (_Is_all_bits_zero(_Value)) {
+ const auto _Distance = static_cast(_ULast - _UFirst);
+ _Fill_zero_memset(_UFirst, _Distance);
+ _Seek_wrapped(_First, _UFirst + _Distance);
+ return _First;
+ }
}
}
}
@@ -4482,10 +4387,11 @@ _CONSTEXPR20 _OutIt reverse_copy(_BidIt _First, _BidIt _Last, _OutIt _Dest) {
auto _UDest = _Get_unwrapped_n(_Dest, _Idl_distance<_BidIt>(_UFirst, _ULast));
#if _USE_STD_VECTOR_ALGORITHMS
- using _Elem = remove_pointer_t;
- using _DestElem = remove_pointer_t;
+ using _Elem = remove_reference_t<_Iter_ref_t>>;
+ using _DestElem = remove_reference_t<_Iter_ref_t>;
constexpr bool _Allow_vectorization = conjunction_v, _DestElem>,
- is_pointer, is_trivially_copyable<_Elem>, negation>>;
+ bool_constant<_Iterators_are_contiguous>, is_trivially_copyable<_Elem>,
+ negation>>;
constexpr size_t _Nx = sizeof(_Elem);
#pragma warning(suppress : 6326) // Potential comparison of a constant with another constant
@@ -4495,13 +4401,13 @@ _CONSTEXPR20 _OutIt reverse_copy(_BidIt _First, _BidIt _Last, _OutIt _Dest) {
#endif // __cpp_lib_is_constant_evaluated
{
if constexpr (_Nx == 1) {
- __std_reverse_copy_trivially_copyable_1(_UFirst, _ULast, _UDest);
+ __std_reverse_copy_trivially_copyable_1(_To_address(_UFirst), _To_address(_ULast), _To_address(_UDest));
} else if constexpr (_Nx == 2) {
- __std_reverse_copy_trivially_copyable_2(_UFirst, _ULast, _UDest);
+ __std_reverse_copy_trivially_copyable_2(_To_address(_UFirst), _To_address(_ULast), _To_address(_UDest));
} else if constexpr (_Nx == 4) {
- __std_reverse_copy_trivially_copyable_4(_UFirst, _ULast, _UDest);
+ __std_reverse_copy_trivially_copyable_4(_To_address(_UFirst), _To_address(_ULast), _To_address(_UDest));
} else {
- __std_reverse_copy_trivially_copyable_8(_UFirst, _ULast, _UDest);
+ __std_reverse_copy_trivially_copyable_8(_To_address(_UFirst), _To_address(_ULast), _To_address(_UDest));
}
_UDest += _ULast - _UFirst;
@@ -4898,20 +4804,18 @@ _SampleIt sample(_PopIt _First, _PopIt _Last, _SampleIt _Dest, _Diff _Count,
}
#ifdef __cpp_lib_concepts
-// STRUCT TEMPLATE _Require_constant
-template
-struct _Require_constant; // not defined; _Require_constant is a valid type if E is a constant expression
-
// CONCEPT uniform_random_bit_generator
// clang-format off
template
-concept uniform_random_bit_generator = invocable<_Ty&> && unsigned_integral> && requires {
- { (_Ty::min)() } -> same_as>;
- { (_Ty::max)() } -> same_as>;
- typename _Require_constant<(_Ty::min)()>;
- typename _Require_constant<(_Ty::max)()>;
- requires (_Ty::min)() < (_Ty::max)();
-};
+concept uniform_random_bit_generator = invocable<_Ty&>
+ && unsigned_integral>
+ && requires {
+ { (_Ty::min)() } -> same_as>;
+ { (_Ty::max)() } -> same_as>;
+ typename _Require_constant<(_Ty::min)()>;
+ typename _Require_constant<(_Ty::max)()>;
+ requires (_Ty::min)() < (_Ty::max)();
+ };
// clang-format on
namespace ranges {
@@ -10488,6 +10392,18 @@ namespace ranges {
_STL_INTERNAL_STATIC_ASSERT(sentinel_for<_Se2, _It2>);
_STL_INTERNAL_STATIC_ASSERT(indirect_strict_weak_order<_Pr, projected<_It1, _Pj1>, projected<_It2, _Pj2>>);
+ using _Memcmp_classification_pred =
+ typename decltype(_Lex_compare_memcmp_classify(_First1, _First2, _Pred))::_Pred;
+ if constexpr (!is_void_v<_Memcmp_classification_pred> && sized_sentinel_for<_Se1, _It1> //
+ && sized_sentinel_for<_Se2, _It2> && same_as<_Pj1, identity> && same_as<_Pj2, identity>) {
+ if (!_STD is_constant_evaluated()) {
+ const auto _Num1 = static_cast(_Last1 - _First1);
+ const auto _Num2 = static_cast(_Last2 - _First2);
+ const int _Ans = _Memcmp_count(_First1, _First2, (_STD min)(_Num1, _Num2));
+ return _Memcmp_classification_pred{}(_Ans, 0) || (_Ans == 0 && _Num1 < _Num2);
+ }
+ }
+
for (;; ++_First1, (void) ++_First2) {
if (_First2 == _Last2) {
return false;
diff --git a/stl/inc/chrono b/stl/inc/chrono
index 69d0f848fcf..2c52c87919c 100644
--- a/stl/inc/chrono
+++ b/stl/inc/chrono
@@ -16,10 +16,18 @@
#include
#if _HAS_CXX20
+#include <__msvc_tzdb.hpp>
+#include
+#include
+#include
#include
-#ifdef __cpp_lib_concepts
-#include
-#endif // defined(__cpp_lib_concepts)
+#include
+#include
+#include
+#include
+#include
+#include
+#include
#endif // _HAS_CXX20
#pragma pack(push, _CRT_PACKING)
@@ -58,20 +66,19 @@ namespace chrono {
};
#if _HAS_CXX20
+ template
+ inline constexpr bool _Is_clock_v = false;
+
template
- concept _Is_clock = requires {
- typename _Clock::rep;
- typename _Clock::period;
- typename _Clock::duration;
- typename _Clock::time_point;
- _Clock::is_steady;
- _Clock::now();
- };
+ inline constexpr bool
+ _Is_clock_v<_Clock, void_t> =
+ true; // TRANSITION, GH-602
template
- struct is_clock : bool_constant<_Is_clock<_Clock>> {};
+ struct is_clock : bool_constant<_Is_clock_v<_Clock>> {};
template
- inline constexpr bool is_clock_v = _Is_clock<_Clock>;
+ inline constexpr bool is_clock_v = _Is_clock_v<_Clock>;
#endif // _HAS_CXX20
// CLASS TEMPLATE duration
@@ -204,7 +211,8 @@ namespace chrono {
using rep = typename _Duration::rep;
using period = typename _Duration::period;
- static_assert(_Is_duration_v<_Duration>, "duration must be an instance of std::duration");
+ static_assert(_Is_duration_v<_Duration>,
+ "N4885 [time.point.general]/1 mandates Duration to be a specialization of chrono::duration.");
constexpr time_point() = default;
@@ -2120,8 +2128,11 @@ namespace chrono {
}
template
- requires _Is_duration_v<_Duration> class hh_mm_ss {
+ class hh_mm_ss {
public:
+ static_assert(_Is_duration_v<_Duration>,
+ "N4885 [time.hms.overview]/2 mandates Duration to be a specialization of chrono::duration.");
+
static constexpr unsigned int fractional_width = [] {
auto _Num = _Duration::period::num;
constexpr auto _Den = _Duration::period::den;
@@ -2209,6 +2220,2957 @@ namespace chrono {
return hours{_Ret};
}
+
+ // [time.zone.info]
+
+ // STRUCT sys_info
+ struct sys_info {
+ sys_seconds begin;
+ sys_seconds end;
+ seconds offset;
+ minutes save;
+ string abbrev;
+ };
+
+ // STRUCT local_info
+ struct local_info {
+ static constexpr int unique = 0;
+ static constexpr int nonexistent = 1;
+ static constexpr int ambiguous = 2;
+
+ int result;
+ sys_info first;
+ sys_info second;
+ };
+
+ // CLASS nonexistent_local_time
+ class nonexistent_local_time : public runtime_error {
+ public:
+ template
+ nonexistent_local_time(const local_time<_Duration>&, const local_info&)
+ : runtime_error("TRANSITION: work in progress") {}
+ };
+
+ // CLASS ambiguous_local_time
+ class ambiguous_local_time : public runtime_error {
+ public:
+ template
+ ambiguous_local_time(const local_time<_Duration>&, const local_info&)
+ : runtime_error("TRANSITION: work in progress") {}
+ };
+
+ // [time.zone.timezone]
+
+ // ENUM CLASS choose
+ enum class choose { earliest, latest };
+
+ // CLASS time_zone
+ class time_zone {
+ public:
+ explicit time_zone(string_view _Name_) : _Name(_Name_) {}
+
+ time_zone(time_zone&&) = default;
+ time_zone& operator=(time_zone&&) = default;
+
+ _NODISCARD string_view name() const noexcept {
+ return _Name;
+ }
+
+ template
+ _NODISCARD sys_info get_info(const sys_time<_Duration>& _Sys) const {
+ return _Get_info(_Sys.time_since_epoch());
+ }
+
+ template
+ _NODISCARD local_info get_info(const local_time<_Duration>& _Local) const {
+ local_info _Info{};
+ const auto _Time_since_ep = _Local.time_since_epoch();
+ _Info.first = _Get_info(_Time_since_ep);
+
+ const sys_seconds _Local_sys{_CHRONO duration_cast(_Time_since_ep)};
+ const auto _Curr_sys = _Local_sys - _Info.first.offset;
+ if (_Info.first.begin != _Min_seconds && _Curr_sys < _Info.first.begin + days{1}) {
+ // get previous transition information
+ _Info.second = get_info(_Info.first.begin - seconds{1});
+
+ const auto _Transition = _Info.first.begin;
+ const auto _Prev_sys = _Local_sys - _Info.second.offset;
+ if (_Curr_sys >= _Transition) {
+ if (_Prev_sys < _Transition) {
+ _Info.result = local_info::ambiguous;
+ _STD swap(_Info.first, _Info.second);
+ } else {
+ _Info.result = local_info::unique;
+ _Info.second = {};
+ }
+ } else {
+ if (_Prev_sys >= _Transition) {
+ _Info.result = local_info::nonexistent;
+ _STD swap(_Info.first, _Info.second);
+ } else {
+ _Info.result = local_info::unique;
+ _Info.first = _STD move(_Info.second);
+ _Info.second = {};
+ }
+ }
+ } else if (_Info.first.end != _Max_seconds && _Curr_sys > _Info.first.end - days{1}) {
+ // get next transition information
+ _Info.second = get_info(_Info.first.end + seconds{1});
+
+ const auto _Transition = _Info.first.end;
+ const auto _Next_sys = _Local_sys - _Info.second.offset;
+ if (_Curr_sys < _Transition) {
+ if (_Next_sys >= _Transition) {
+ _Info.result = local_info::ambiguous;
+ } else {
+ _Info.result = local_info::unique;
+ _Info.second = {};
+ }
+ } else {
+ if (_Next_sys < _Transition) {
+ _Info.result = local_info::nonexistent;
+ } else {
+ _Info.result = local_info::unique;
+ _Info.first = _STD move(_Info.second);
+ _Info.second = {};
+ }
+ }
+ } else {
+ // local time is contained inside of first transition boundaries by at least 1 day
+ _Info.result = local_info::unique;
+ _Info.second = {};
+ }
+
+ return _Info;
+ }
+
+ template
+ _NODISCARD sys_time> to_sys(const local_time<_Duration>& _Local) const {
+ const auto _Info = get_info(_Local);
+ if (_Info.result == local_info::nonexistent) {
+ _THROW(nonexistent_local_time(_Local, _Info));
+ } else if (_Info.result == local_info::ambiguous) {
+ _THROW(ambiguous_local_time(_Local, _Info));
+ }
+
+ return sys_time>{_Local.time_since_epoch() - _Info.first.offset};
+ }
+
+ template
+ _NODISCARD sys_time> to_sys(
+ const local_time<_Duration>& _Local, const choose _Choose) const {
+ const auto _Info = get_info(_Local);
+ if (_Info.result == local_info::nonexistent) {
+ return _Info.first.end;
+ }
+
+ const auto _Offset = (_Info.result == local_info::unique || _Choose == choose::earliest)
+ ? _Info.first.offset
+ : _Info.second.offset;
+ return sys_time>{_Local.time_since_epoch() - _Offset};
+ }
+
+ template
+ _NODISCARD local_time> to_local(const sys_time<_Duration>& _Sys) const {
+ const auto _Info = get_info(_Sys);
+ return local_time>{_Sys.time_since_epoch() + _Info.offset};
+ }
+
+ static constexpr sys_seconds _Min_seconds{sys_days{(year::min)() / January / 1}};
+ static constexpr sys_seconds _Max_seconds{sys_seconds{sys_days{(year::max)() / December / 32}} - seconds{1}};
+
+ private:
+ template
+ _NODISCARD sys_info _Get_info(const _Duration& _Dur) const {
+ using _Internal_duration = duration<__std_tzdb_epoch_milli, milli>;
+ const auto _Internal_dur = _CHRONO duration_cast<_Internal_duration>(_Dur);
+ const unique_ptr<__std_tzdb_sys_info, _Tzdb_deleter<__std_tzdb_sys_info>> _Info{
+ __std_tzdb_get_sys_info(_Name.c_str(), _Name.length(), _Internal_dur.count())};
+ if (_Info == nullptr) {
+ _Xbad_alloc();
+ } else if (_Info->_Err == __std_tzdb_error::_Win_error) {
+ _XGetLastError();
+ } else if (_Info->_Err == __std_tzdb_error::_Icu_error) {
+ _Xruntime_error("Internal error loading IANA database information");
+ }
+
+ constexpr auto _Min_internal =
+ _CHRONO duration_cast<_Internal_duration>(_Min_seconds.time_since_epoch()).count();
+ constexpr auto _Max_internal =
+ _CHRONO duration_cast<_Internal_duration>(_Max_seconds.time_since_epoch()).count();
+ const auto _Begin =
+ _Info->_Begin <= _Min_internal
+ ? _Min_seconds
+ : sys_seconds{_CHRONO duration_cast(_Internal_duration{_Info->_Begin})};
+ const auto _End =
+ _Info->_End >= _Max_internal
+ ? _Max_seconds
+ : sys_seconds{_CHRONO duration_cast(_Internal_duration{_Info->_End})};
+ return {.begin = _Begin,
+ .end = _End,
+ .offset = _CHRONO duration_cast(_Internal_duration{_Info->_Offset}),
+ .save = _CHRONO duration_cast(_Internal_duration{_Info->_Save}),
+ .abbrev = _Info->_Abbrev};
+ }
+
+ string _Name;
+ };
+
+ _NODISCARD inline bool operator==(const time_zone& _Left, const time_zone& _Right) noexcept {
+ return _Left.name() == _Right.name();
+ }
+
+#ifdef __cpp_lib_concepts
+ _NODISCARD inline strong_ordering operator<=>(const time_zone& _Left, const time_zone& _Right) noexcept {
+ return _Left.name() <=> _Right.name();
+ }
+#endif // __cpp_lib_concepts
+
+ // [time.zone.leap]
+
+ // CLASS leap_second
+ class leap_second {
+ public:
+ leap_second(const leap_second&) = default;
+ leap_second& operator=(const leap_second&) = default;
+
+ constexpr leap_second(
+ const sys_seconds& _Date_, const bool _Is_positive_, const seconds& _Prev_elapsed) noexcept
+ : _Date{_Date_}, _Is_positive{_Is_positive_} {
+ _Elapsed_offset = _Prev_elapsed + value();
+ }
+
+ _NODISCARD constexpr sys_seconds date() const noexcept {
+ return _Date;
+ }
+
+ _NODISCARD constexpr seconds value() const noexcept {
+ return _Is_positive ? seconds{1} : seconds{-1};
+ }
+
+ _NODISCARD constexpr bool _Positive() const noexcept {
+ return _Is_positive;
+ }
+
+ _NODISCARD constexpr seconds _Elapsed() const noexcept {
+ return _Elapsed_offset;
+ }
+
+ private:
+ sys_seconds _Date;
+ bool _Is_positive;
+ seconds _Elapsed_offset;
+ };
+
+ _NODISCARD constexpr bool operator==(const leap_second& _Left, const leap_second& _Right) noexcept {
+ return _Left.date() == _Right.date();
+ }
+ template
+ _NODISCARD constexpr bool operator==(const leap_second& _Left, const sys_time<_Duration>& _Right) noexcept {
+ return _Left.date() == _Right;
+ }
+
+ template
+ _NODISCARD constexpr bool operator<(const leap_second& _Left, const sys_time<_Duration>& _Right) noexcept {
+ return _Left.date() < _Right;
+ }
+ template
+ _NODISCARD constexpr bool operator<(const sys_time<_Duration>& _Left, const leap_second& _Right) noexcept {
+ return _Left < _Right.date();
+ }
+
+ template
+ _NODISCARD constexpr bool operator>(const leap_second& _Left, const sys_time<_Duration>& _Right) noexcept {
+ return _Right < _Left.date();
+ }
+ template
+ _NODISCARD constexpr bool operator>(const sys_time<_Duration>& _Left, const leap_second& _Right) noexcept {
+ return _Right.date() < _Left;
+ }
+
+ template
+ _NODISCARD constexpr bool operator<=(const leap_second& _Left, const sys_time<_Duration>& _Right) noexcept {
+ return !(_Right < _Left.date());
+ }
+ template
+ _NODISCARD constexpr bool operator<=(const sys_time<_Duration>& _Left, const leap_second& _Right) noexcept {
+ return !(_Right.date() < _Left);
+ }
+
+ template
+ _NODISCARD constexpr bool operator>=(const leap_second& _Left, const sys_time<_Duration>& _Right) noexcept {
+ return !(_Left.date() < _Right);
+ }
+ template
+ _NODISCARD constexpr bool operator>=(const sys_time<_Duration>& _Left, const leap_second& _Right) noexcept {
+ return !(_Left < _Right.date());
+ }
+
+#ifdef __cpp_lib_concepts
+ // clang-format off
+ template
+ requires three_way_comparable_with>
+ _NODISCARD constexpr auto operator<=>(
+ const leap_second& _Left, const sys_time<_Duration>& _Right) noexcept {
+ // clang-format on
+ return _Left.date() <=> _Right;
+ }
+ _NODISCARD constexpr strong_ordering operator<=>(const leap_second& _Left, const leap_second& _Right) noexcept {
+ return _Left.date() <=> _Right.date();
+ }
+#endif // __cpp_lib_concepts
+
+ // [time.zone.link]
+
+ // CLASS time_zone_link
+ class time_zone_link {
+ public:
+ explicit time_zone_link(string_view _Name_, string_view _Target_) : _Name(_Name_), _Target(_Target_) {}
+
+ time_zone_link(time_zone_link&&) = default;
+ time_zone_link& operator=(time_zone_link&&) = default;
+
+ _NODISCARD string_view name() const noexcept {
+ return _Name;
+ }
+
+ _NODISCARD string_view target() const noexcept {
+ return _Target;
+ }
+
+ private:
+ string _Name;
+ string _Target;
+ };
+
+ _NODISCARD inline bool operator==(const time_zone_link& _Left, const time_zone_link& _Right) noexcept {
+ return _Left.name() == _Right.name();
+ }
+
+#ifdef __cpp_lib_concepts
+ _NODISCARD inline strong_ordering operator<=>(const time_zone_link& _Left, const time_zone_link& _Right) noexcept {
+ return _Left.name() <=> _Right.name();
+ }
+#endif // __cpp_lib_concepts
+
+ // [time.zone.db]
+
+ _NODISCARD inline string _Tzdb_generate_current_zone() {
+ unique_ptr<__std_tzdb_current_zone_info, _Tzdb_deleter<__std_tzdb_current_zone_info>> _Info{
+ __std_tzdb_get_current_zone()};
+ if (_Info == nullptr) {
+ _Xbad_alloc();
+ } else if (_Info->_Err == __std_tzdb_error::_Win_error) {
+ _XGetLastError();
+ } else if (_Info->_Err == __std_tzdb_error::_Icu_error) {
+ _Xruntime_error("Internal error loading IANA database information");
+ }
+
+ return {_Info->_Tz_name};
+ }
+
+ template
+ _NODISCARD const _Ty* _Locate_zone_impl(const vector<_Ty>& _Vec, string_view _Name) {
+ const auto _Result = _STD find_if(_Vec.begin(), _Vec.end(), [&](auto& _Tz) { return _Tz.name() == _Name; });
+ return _Result == _Vec.end() ? nullptr : &*_Result;
+ }
+
+ // STRUCT tzdb
+ struct tzdb {
+ string version;
+ vector zones;
+ vector links;
+ vector leap_seconds;
+ bool _All_ls_positive;
+
+ _NODISCARD const time_zone* locate_zone(string_view _Tz_name) const {
+ auto _Tz = _Locate_zone_impl(zones, _Tz_name);
+ if (_Tz != nullptr) {
+ return _Tz;
+ }
+
+ const auto _Link = _Locate_zone_impl(links, _Tz_name);
+ if (_Link != nullptr) {
+ _Tz = _Locate_zone_impl(zones, _Link->target());
+ if (_Tz != nullptr) {
+ return _Tz;
+ }
+ }
+
+ _Xruntime_error("unable to locate time_zone with given name");
+ }
+
+ _NODISCARD const time_zone* current_zone() const {
+ return locate_zone(_Tzdb_generate_current_zone());
+ }
+ };
+
+ _NODISCARD inline tuple _Tzdb_generate_time_zones() {
+ unique_ptr<__std_tzdb_time_zones_info, _Tzdb_deleter<__std_tzdb_time_zones_info>> _Info{
+ __std_tzdb_get_time_zones()};
+ if (_Info == nullptr) {
+ _Xbad_alloc();
+ } else if (_Info->_Err == __std_tzdb_error::_Win_error) {
+ _XGetLastError();
+ } else if (_Info->_Err == __std_tzdb_error::_Icu_error) {
+ _Xruntime_error("Internal error loading IANA database information");
+ }
+
+ decltype(tzdb::zones) _Time_zones;
+ decltype(tzdb::links) _Time_zone_links;
+ for (size_t _Idx = 0; _Idx < _Info->_Num_time_zones; ++_Idx) {
+ const string_view _Name{_Info->_Names[_Idx]};
+ if (_Info->_Links[_Idx] == nullptr) {
+ _Time_zones.emplace_back(_Name);
+ } else {
+ const string_view _Target{_Info->_Links[_Idx]};
+ _Time_zone_links.emplace_back(_Name, _Target);
+ }
+ }
+
+ return {_Info->_Version, _STD move(_Time_zones), _STD move(_Time_zone_links)};
+ }
+
+ _NODISCARD inline pair _Tzdb_generate_leap_seconds(const size_t _Current_size) {
+ // Returns empty vector if no new leap seconds are found.
+ static constexpr leap_second _Known_leap_seconds[]{
+ {sys_seconds{seconds{78796800}}, true, seconds{0}},
+ {sys_seconds{seconds{94694400}}, true, seconds{1}},
+ {sys_seconds{seconds{126230400}}, true, seconds{2}},
+ {sys_seconds{seconds{157766400}}, true, seconds{3}},
+ {sys_seconds{seconds{189302400}}, true, seconds{4}},
+ {sys_seconds{seconds{220924800}}, true, seconds{5}},
+ {sys_seconds{seconds{252460800}}, true, seconds{6}},
+ {sys_seconds{seconds{283996800}}, true, seconds{7}},
+ {sys_seconds{seconds{315532800}}, true, seconds{8}},
+ {sys_seconds{seconds{362793600}}, true, seconds{9}},
+ {sys_seconds{seconds{394329600}}, true, seconds{10}},
+ {sys_seconds{seconds{425865600}}, true, seconds{11}},
+ {sys_seconds{seconds{489024000}}, true, seconds{12}},
+ {sys_seconds{seconds{567993600}}, true, seconds{13}},
+ {sys_seconds{seconds{631152000}}, true, seconds{14}},
+ {sys_seconds{seconds{662688000}}, true, seconds{15}},
+ {sys_seconds{seconds{709948800}}, true, seconds{16}},
+ {sys_seconds{seconds{741484800}}, true, seconds{17}},
+ {sys_seconds{seconds{773020800}}, true, seconds{18}},
+ {sys_seconds{seconds{820454400}}, true, seconds{19}},
+ {sys_seconds{seconds{867715200}}, true, seconds{20}},
+ {sys_seconds{seconds{915148800}}, true, seconds{21}},
+ {sys_seconds{seconds{1136073600}}, true, seconds{22}},
+ {sys_seconds{seconds{1230768000}}, true, seconds{23}},
+ {sys_seconds{seconds{1341100800}}, true, seconds{24}},
+ {sys_seconds{seconds{1435708800}}, true, seconds{25}},
+ {sys_seconds{seconds{1483228800}}, true, seconds{26}},
+ };
+
+ // __std_tzdb_get_leap_seconds gets leap second (LS) data from the registry, but only if it contains more
+ // LSs than we already know about. The registry only contains LSs after 2018, so we need to tell it how many of
+ // *those* we already know about. The *total* number of LSs known at this point is a combination of what the
+ // caller knows (_Current_size, 0 on first call) and the _Known_leap_seconds entries.
+ constexpr size_t _Pre_2018_count = 27;
+ const size_t _Known_post_2018_ls_size =
+ (_STD max)(_Current_size, _STD size(_Known_leap_seconds)) - _Pre_2018_count;
+
+ size_t _Reg_post_2018_ls_size; // number of post-2018 LSs found in the registry
+ unique_ptr<__std_tzdb_leap_info[], _Tzdb_deleter<__std_tzdb_leap_info[]>> _Reg_ls_data{
+ __std_tzdb_get_leap_seconds(_Known_post_2018_ls_size, &_Reg_post_2018_ls_size)};
+
+ if (_Reg_post_2018_ls_size > _Known_post_2018_ls_size && !_Reg_ls_data) {
+ _Xbad_alloc(); // registry has new data, but failed to allocate storage
+ } else if (_Reg_post_2018_ls_size == 0 && _Reg_ls_data) {
+ _XGetLastError(); // allocated storage for registry data, but failed to read
+ }
+
+ const size_t _New_size = _Pre_2018_count + _Reg_post_2018_ls_size; // total size with registry data
+ decltype(tzdb::leap_seconds) _Leap_sec_info;
+ bool _All_ls_positive = true;
+
+ if (_New_size > _Current_size) {
+ _Leap_sec_info.reserve(_New_size);
+ _Leap_sec_info.assign(_STD cbegin(_Known_leap_seconds), _STD cend(_Known_leap_seconds));
+
+ for (size_t _Idx = 0; _Idx < _Reg_post_2018_ls_size; ++_Idx) {
+ // Leap seconds occur at _Ls._Hour:59:59. We store the next second after, so we need to add an entire
+ // hour.
+ const auto& _Ls = _Reg_ls_data[_Idx];
+ const auto _Date =
+ static_cast(year_month_day{year{_Ls._Year}, month{_Ls._Month}, day{_Ls._Day}})
+ + hours{_Ls._Hour + 1};
+ _Leap_sec_info.emplace_back(_Date, !_Ls._Negative, _Leap_sec_info.back()._Elapsed());
+ _All_ls_positive = _All_ls_positive && !_Ls._Negative;
+ }
+ }
+
+ return {_STD move(_Leap_sec_info), _All_ls_positive};
+ }
+
+ _NODISCARD inline string _Tzdb_update_version(const string_view _Version, const size_t _Num_leap_seconds) {
+ string _Icu_version{_Version.substr(0, _Version.find_last_of('.'))};
+ return _STD move(_Icu_version) + "." + _STD to_string(_Num_leap_seconds);
+ }
+
+ // CLASS tzdb_list
+ class tzdb_list {
+ private:
+ using _ListType = forward_list>;
+
+ public:
+ using const_iterator = _ListType::const_iterator;
+
+ tzdb_list(const tzdb_list&) = delete;
+ tzdb_list& operator=(const tzdb_list&) = delete;
+
+ tzdb_list() {
+ auto [_Icu_version, _Zones, _Links] = _Tzdb_generate_time_zones();
+ auto [_Leap_sec, _All_ls_positive] = _Tzdb_generate_leap_seconds(0);
+ auto _Version = _Icu_version + "." + _STD to_string(_Leap_sec.size());
+ _Tzdb_list.emplace_front(tzdb{
+ _STD move(_Version), _STD move(_Zones), _STD move(_Links), _STD move(_Leap_sec), _All_ls_positive});
+ }
+
+ _NODISCARD const tzdb& front() const noexcept {
+ _Shared_lock _Lk(_Tzdb_mutex);
+ return _Tzdb_list.front();
+ }
+
+ const_iterator erase_after(const_iterator _Where) noexcept /* strengthened */ {
+ _Unique_lock _Lk(_Tzdb_mutex);
+ return _Tzdb_list.erase_after(_Where);
+ }
+
+ _NODISCARD const_iterator begin() const noexcept {
+ _Shared_lock _Lk(_Tzdb_mutex);
+ return _Tzdb_list.begin();
+ }
+
+ _NODISCARD const_iterator end() const noexcept {
+ return _Tzdb_list.end(); // no lock necessary for forward_list::end()
+ }
+
+ _NODISCARD const_iterator cbegin() const noexcept {
+ _Shared_lock _Lk(_Tzdb_mutex);
+ return _Tzdb_list.cbegin();
+ }
+
+ _NODISCARD const_iterator cend() const noexcept {
+ return _Tzdb_list.cend(); // no lock necessary for forward_list::cend()
+ }
+
+ template
+ void _Emplace_front(_ArgsTy&&... _Args) {
+ _Unique_lock _Lk(_Tzdb_mutex);
+ _Tzdb_list.emplace_front(_STD forward<_ArgsTy>(_Args)...);
+ }
+
+ const tzdb& _Reload() {
+ _Unique_lock _Lk(_Tzdb_mutex);
+ auto [_Leap_sec, _All_ls_positive] = _Tzdb_generate_leap_seconds(_Tzdb_list.front().leap_seconds.size());
+ if (!_Leap_sec.empty()) {
+ const auto& _Tzdb = _Tzdb_list.front();
+ vector _Zones;
+ _STD transform(_Tzdb.zones.begin(), _Tzdb.zones.end(), _STD back_inserter(_Zones),
+ [](const auto& _Tz) { return time_zone{_Tz.name()}; });
+ vector _Links;
+ _STD transform(
+ _Tzdb.links.begin(), _Tzdb.links.end(), _STD back_inserter(_Links), [](const auto& _Link) {
+ return time_zone_link{_Link.name(), _Link.target()};
+ });
+ auto _Version = _Tzdb_update_version(_Tzdb.version, _Leap_sec.size());
+ _Tzdb_list.emplace_front(tzdb{
+ _STD move(_Version), _STD move(_Zones), _STD move(_Links), _STD move(_Leap_sec), _All_ls_positive});
+ }
+ return _Tzdb_list.front();
+ }
+
+ private:
+ _ListType _Tzdb_list;
+ mutable _Smtx_t _Tzdb_mutex = {};
+
+ struct _NODISCARD _Shared_lock {
+ explicit _Shared_lock(_Smtx_t& _Mtx_) : _Mtx{&_Mtx_} {
+ _Smtx_lock_shared(_Mtx);
+ }
+
+ _Shared_lock(const _Shared_lock&) = delete;
+ _Shared_lock& operator=(const _Shared_lock&) = delete;
+
+ ~_Shared_lock() {
+ _Smtx_unlock_shared(_Mtx);
+ }
+
+ _Smtx_t* _Mtx;
+ };
+
+ struct _NODISCARD _Unique_lock {
+ explicit _Unique_lock(_Smtx_t& _Mtx_) : _Mtx{&_Mtx_} {
+ _Smtx_lock_exclusive(_Mtx);
+ }
+
+ _Unique_lock(const _Unique_lock&) = delete;
+ _Unique_lock& operator=(const _Unique_lock&) = delete;
+
+ ~_Unique_lock() {
+ _Smtx_unlock_exclusive(_Mtx);
+ }
+
+ _Smtx_t* _Mtx;
+ };
+ };
+
+ inline atomic _Global_tzdb_list;
+
+ // FUNCTION get_tzdb_list
+ _NODISCARD inline tzdb_list& get_tzdb_list() {
+ auto* _Tzdb_ptr = _Global_tzdb_list.load();
+ if (_Tzdb_ptr != nullptr) {
+ return *_Tzdb_ptr;
+ }
+
+ auto _My_tzdb = static_cast(__std_calloc_crt(1, sizeof(tzdb_list)));
+ if (_My_tzdb == nullptr) {
+ _Xruntime_error("bad allocation"); // not bad_alloc, see N4878 [time.zone.db.access]/4
+ }
+
+ _TRY_BEGIN
+ _STD construct_at(_My_tzdb);
+ _CATCH(const runtime_error&)
+ __std_free_crt(_My_tzdb);
+ _RERAISE;
+ _CATCH(const exception& _Except)
+#if _HAS_EXCEPTIONS
+ __std_free_crt(_My_tzdb);
+ _Xruntime_error(_Except.what());
+#endif // _HAS_EXCEPTIONS
+ _CATCH_END
+
+ if (_Global_tzdb_list.compare_exchange_strong(_Tzdb_ptr, _My_tzdb)) {
+ _Tzdb_ptr = _My_tzdb;
+ } else {
+ _STD destroy_at(_My_tzdb);
+ __std_free_crt(_My_tzdb);
+ }
+
+ return *_Tzdb_ptr;
+ }
+
+ // FUNCTION get_tzdb
+ _NODISCARD inline const tzdb& get_tzdb() {
+ return _CHRONO get_tzdb_list().front();
+ }
+
+ // FUNCTION locate_zone
+ _NODISCARD inline const time_zone* locate_zone(string_view _Tz_name) {
+ return _CHRONO get_tzdb().locate_zone(_Tz_name);
+ }
+
+ // FUNCTION current_zone
+ _NODISCARD inline const time_zone* current_zone() {
+ return _CHRONO get_tzdb().current_zone();
+ }
+
+ // FUNCTION reload_tzdb
+ inline const tzdb& reload_tzdb() {
+ _TRY_BEGIN
+ return _CHRONO get_tzdb_list()._Reload();
+ _CATCH(const runtime_error&)
+ _RERAISE;
+ _CATCH(const exception& _Except)
+#if _HAS_EXCEPTIONS
+ _Xruntime_error(_Except.what());
+#endif // _HAS_EXCEPTIONS
+ _CATCH_END
+ }
+
+ // FUNCTION remote_version
+ _NODISCARD inline string remote_version() {
+ const auto& _Tzdb = _CHRONO get_tzdb();
+ const auto& _Version = _Tzdb.version;
+ const auto [_Leap_sec, _Ignored] = _Tzdb_generate_leap_seconds(_Tzdb.leap_seconds.size());
+ return _Leap_sec.empty() ? _Version : _Tzdb_update_version(_Version, _Leap_sec.size());
+ }
+
+ // [time.zone.zonedtraits]
+
+ // STRUCT TEMPLATE zoned_traits
+ template
+ struct zoned_traits {};
+
+ // STRUCT zoned_traits
+ template <>
+ struct zoned_traits {
+ _NODISCARD static const time_zone* default_zone() {
+ return _CHRONO get_tzdb().locate_zone("UTC");
+ }
+
+ _NODISCARD static const time_zone* locate_zone(string_view _Name) {
+ return _CHRONO get_tzdb().locate_zone(_Name);
+ }
+ };
+
+ // [time.zone.zonedtime]
+
+ // CLASS TEMPLATE zoned_time
+ template
+ class zoned_time {
+ private:
+ static_assert(_Is_duration_v<_Duration>,
+ "N4885 [time.zone.zonedtime.overview]/2 mandates Duration to be a specialization of chrono::duration.");
+
+ using _Traits = zoned_traits<_TimeZonePtr>;
+
+ public:
+ using duration = common_type_t<_Duration, seconds>;
+
+ template >
+ zoned_time() : _Zone{_Traits::default_zone()} {}
+ zoned_time(const zoned_time&) = default;
+ zoned_time& operator=(const zoned_time&) = default;
+
+ template >
+ zoned_time(const sys_time<_Duration>& _Sys) : _Zone{_Traits::default_zone()}, _Tp{_Sys} {}
+
+ explicit zoned_time(_TimeZonePtr _Tz) noexcept /* strengthened */ : _Zone{_STD move(_Tz)} {}
+
+ // clang-format off
+ template ::value,
+ int> = 0>
+ // clang-format on
+ explicit zoned_time(string_view _Name) : _Zone{_Traits::locate_zone(_Name)} {}
+
+ template , sys_time<_Duration>>, int> = 0>
+ zoned_time(const zoned_time<_Duration2, _TimeZonePtr>& _Zt) noexcept /* strengthened */
+ : _Zone{_Zt.get_time_zone()}, _Tp{_Zt.get_sys_time()} {}
+
+ zoned_time(_TimeZonePtr _Tz, const sys_time<_Duration>& _Sys) : _Zone{_STD move(_Tz)}, _Tp{_Sys} {}
+
+ // clang-format off
+ template &>::value,
+ int> = 0>
+ // clang-format on
+ zoned_time(string_view _Name, type_identity_t&> _Sys)
+ : zoned_time{_Traits::locate_zone(_Name), _Sys} {}
+
+ template ()->to_sys(local_time<_Duration>{})), sys_time>,
+ int> = 0>
+ zoned_time(_TimeZonePtr _Tz, const local_time<_Duration>& _Local)
+ : _Zone{_STD move(_Tz)}, _Tp{_Zone->to_sys(_Local)} {}
+
+ // clang-format off
+ template &>::value,
+ int> = 0>
+ // clang-format on
+ zoned_time(string_view _Name, type_identity_t>& _Local)
+ : zoned_time{_Traits::locate_zone(_Name), _Local} {}
+
+ template ()->to_sys(local_time<_Duration>{}, choose::earliest)),
+ sys_time>,
+ int> = 0>
+ zoned_time(_TimeZonePtr _Tz, const local_time<_Duration>& _Local, choose _Choose)
+ : _Zone{_STD move(_Tz)}, _Tp{_Zone->to_sys(_Local, _Choose)} {}
+
+ // clang-format off
+ template &, choose>::value,
+ int> = 0>
+ // clang-format on
+ zoned_time(string_view _Name, type_identity_t&> _Local, choose _Choose)
+ : zoned_time{_Traits::locate_zone(_Name), _Local, _Choose} {}
+
+ template , sys_time<_Duration>>, int> = 0>
+ zoned_time(_TimeZonePtr _Tz, const zoned_time<_Duration2, _TimeZonePtr2>& _Zt) noexcept /* strengthened */
+ : _Zone{_STD move(_Tz)}, _Tp{_Zt.get_sys_time()} {}
+
+ template , sys_time<_Duration>>, int> = 0>
+ zoned_time(
+ _TimeZonePtr _Tz, const zoned_time<_Duration2, _TimeZonePtr2>& _Zt, choose) noexcept /* strengthened */
+ : zoned_time{_Tz, _Zt} {}
+
+ // clang-format off
+ template &>::value,
+ int> = 0>
+ // clang-format on
+ zoned_time(string_view _Name, const zoned_time<_Duration2, _TimeZonePtr2>& _Zt)
+ : zoned_time{_Traits::locate_zone(_Name), _Zt} {}
+
+ // clang-format off
+ template &, choose>::value,
+ int> = 0>
+ // clang-format on
+ zoned_time(string_view _Name, const zoned_time<_Duration2, _TimeZonePtr2>& _Zt, choose _Choose)
+ : zoned_time{_Traits::locate_zone(_Name), _Zt, _Choose} {}
+
+ zoned_time& operator=(const sys_time<_Duration>& _Sys) noexcept /* strengthened */ {
+ _Tp = _Sys;
+ return *this;
+ }
+
+ zoned_time& operator=(const local_time<_Duration>& _Local) {
+ _Tp = _Zone->to_sys(_Local);
+ return *this;
+ }
+
+ operator sys_time() const noexcept /* strengthened */ {
+ return get_sys_time();
+ }
+
+ explicit operator local_time() const {
+ return get_local_time();
+ }
+
+ _NODISCARD _TimeZonePtr get_time_zone() const noexcept /* strengthened */ {
+ return _Zone;
+ }
+
+ _NODISCARD local_time get_local_time() const {
+ return _Zone->to_local(_Tp);
+ }
+
+ _NODISCARD sys_time get_sys_time() const noexcept /* strengthened */ {
+ return _Tp;
+ }
+
+ _NODISCARD sys_info get_info() const {
+ return _Zone->get_info(_Tp);
+ }
+
+ private:
+ _TimeZonePtr _Zone;
+ sys_time _Tp{};
+ };
+
+ zoned_time()->zoned_time;
+
+ template
+ zoned_time(sys_time<_Duration>) -> zoned_time>;
+
+ template
+ using _Time_zone_representation = conditional_t, const time_zone*,
+ remove_cvref_t<_TimeZonePtrOrName>>;
+
+ template
+ zoned_time(_TimeZonePtrOrName&&) -> zoned_time>;
+
+ template
+ zoned_time(_TimeZonePtrOrName&&, sys_time<_Duration>)
+ -> zoned_time, _Time_zone_representation<_TimeZonePtrOrName>>;
+
+ template
+ zoned_time(_TimeZonePtrOrName&&, local_time<_Duration>, choose = choose::earliest)
+ -> zoned_time, _Time_zone_representation<_TimeZonePtrOrName>>;
+
+ template
+ zoned_time(_TimeZonePtrOrName&&, zoned_time<_Duration, _TimeZonePtr2>, choose = choose::earliest)
+ -> zoned_time, _Time_zone_representation<_TimeZonePtrOrName>>;
+
+ using zoned_seconds = zoned_time;
+
+ template
+ _NODISCARD bool operator==(
+ const zoned_time<_Duration1, _TimeZonePtr>& _Left, const zoned_time<_Duration2, _TimeZonePtr>& _Right) {
+ return _Left.get_time_zone() == _Right.get_time_zone() && _Left.get_sys_time() == _Right.get_sys_time();
+ }
+
+ // [time.clock.utc]
+
+ class utc_clock;
+ template
+ using utc_time = time_point;
+ using utc_seconds = utc_time;
+
+ // STRUCT leap_second_info
+ struct leap_second_info {
+ bool is_leap_second;
+ seconds elapsed;
+ };
+
+ // FUNCTION TEMPLATE get_leap_second_info
+ template
+ _NODISCARD leap_second_info get_leap_second_info(const utc_time<_Duration>& _Time) {
+ const utc_seconds _Time_floor = _CHRONO floor(_Time);
+ const auto& _Tzdb = _CHRONO get_tzdb();
+ const auto& _Ls_vector = _Tzdb.leap_seconds;
+
+ // Find first leap second after _Time.
+ vector::const_iterator _It;
+ if (_Tzdb._All_ls_positive) {
+ // Where "target_ls" is the next leap second at or after _Time, _It either points to:
+ // (1) The 2nd leap second after _Time if _Time_floor is in the range [target_ls - _Elapsed() - 1,
+ // target_ls), or
+ // (2) The leap second just after _Time otherwise.
+ // Note that we can always use prev(_It) to determine whether _Time is *during* a leap second insertion,
+ // since that falls under case (2) above. However, when we fall under case (1), we need to execute an
+ // additional decrement to get the correct elapsed offset. For example, if leap seconds are inserted at
+ // seconds {100, 200, 300, 400}, we have:
+ //
+ // UTC sys *_It
+ // 99 99 100
+ // 100 X 200
+ // 101 100 200
+ // 102 101 200
+ // ...
+ // 199 198 200
+ // 200 199 300^
+ // 201 X 300
+ // 202 200 300
+ // ...
+ // 299 297 300
+ // 300 298 400^
+ // 301 299 400^
+ // 302 X 400
+ // 303 300 400
+ //
+ // ^_It points to 2nd leap second
+
+ _It = _STD upper_bound(_Ls_vector.begin(), _Ls_vector.end(), sys_seconds{_Time_floor.time_since_epoch()});
+ } else {
+ seconds _Prev_elapsed{0};
+ for (_It = _Ls_vector.begin(); _It != _Ls_vector.end(); ++_It) {
+ // UTC time when leap second insertion begins. In all cases, _It->date() + _It->_Elapsed() is the *end*
+ // of the insertion. For a negative leap that's also the beginning, but for a positive one, insertion
+ // begins 1 second earlier.
+ const utc_seconds _This_ls_begin{
+ _It->date().time_since_epoch() + (_It->_Positive() ? _Prev_elapsed : _It->_Elapsed())};
+ if (_This_ls_begin > _Time_floor) {
+ break;
+ }
+ _Prev_elapsed = _It->_Elapsed();
+ }
+ }
+
+ if (_It == _Ls_vector.begin()) {
+ return {false, seconds{0}};
+ } else {
+ // Convert to the last leap second before or equal to _Time.
+ const auto& _Last_leap = *--_It;
+ const utc_seconds _Utc_leap_second{_Last_leap.date().time_since_epoch() + _It->_Elapsed() - seconds{1}};
+#ifdef __cpp_lib_concepts
+ const auto _Leap_cmp = _Utc_leap_second <=> _Time_floor;
+#else // ^^^ __cpp_lib_concepts / TRANSITION, GH-395 workaround vvv
+ const auto _Leap_cmp = _Utc_leap_second > _Time_floor ? strong_ordering::greater
+ : _Utc_leap_second == _Time_floor ? strong_ordering::equal
+ : strong_ordering::less;
+#endif // ^^^ workaround
+ if (_Tzdb._All_ls_positive && _STD is_gt(_Leap_cmp)) { // Case (1)
+ --_It;
+ }
+ return {_Last_leap._Positive() && _STD is_eq(_Leap_cmp), _It->_Elapsed()};
+ }
+ }
+
+ // CLASS utc_clock
+ class utc_clock {
+ public:
+ using rep = system_clock::rep;
+ using period = system_clock::period;
+ using duration = _CHRONO duration;
+ using time_point = _CHRONO time_point;
+ static constexpr bool is_steady = system_clock::is_steady;
+
+ _NODISCARD static time_point now() {
+ return from_sys(system_clock::now());
+ }
+
+ template
+ _NODISCARD static sys_time> to_sys(const utc_time<_Duration>& _Utc_time) {
+ using _CommonType = common_type_t<_Duration, seconds>;
+ const auto _Lsi{_CHRONO get_leap_second_info(_Utc_time)};
+ _CommonType _Ticks;
+ if (_Lsi.is_leap_second) {
+ const auto _Leap_sec_minus_one = _CHRONO floor(_Utc_time.time_since_epoch()) - _Lsi.elapsed;
+ if constexpr (is_integral_v) {
+ constexpr auto _Delta{seconds{1} - _CommonType{1}};
+ _Ticks = _Leap_sec_minus_one + _Delta;
+ } else {
+ const auto _Leap_sec_begin = _CHRONO ceil<_CommonType>(_Leap_sec_minus_one + seconds{1});
+ _Ticks = _CommonType{_STD nextafter(_Leap_sec_begin.count(), typename _CommonType::rep{0})};
+ }
+ } else {
+ _Ticks = _Utc_time.time_since_epoch() - _Lsi.elapsed;
+ }
+ return sys_time<_CommonType>{_Ticks};
+ }
+
+ template
+ _NODISCARD static utc_time> from_sys(const sys_time<_Duration>& _Sys_time) {
+ const auto& _Tzdb = _CHRONO get_tzdb();
+ const auto& _Ls_vector = _Tzdb.leap_seconds;
+ auto _It = _STD upper_bound(_Ls_vector.begin(), _Ls_vector.end(), _CHRONO floor(_Sys_time));
+ const auto _Offset = _It == _Ls_vector.begin() ? seconds{0} : (--_It)->_Elapsed();
+ return utc_time>{_Sys_time.time_since_epoch() + _Offset};
+ }
+ };
+
+ // [time.clock.tai]
+
+ class tai_clock;
+
+ template
+ using tai_time = time_point;
+ using tai_seconds = tai_time;
+
+ // CLASS tai_clock
+ class tai_clock {
+ public:
+ using rep = system_clock::rep;
+ using period = system_clock::period;
+ using duration = _CHRONO duration;
+ using time_point = _CHRONO time_point;
+ static constexpr bool is_steady = system_clock::is_steady;
+
+ static constexpr seconds _Tai_epoch_adjust{378691210};
+
+ _NODISCARD static time_point now() {
+ return from_utc(utc_clock::now());
+ }
+
+ template
+ _NODISCARD static utc_time> to_utc(
+ const tai_time<_Duration>& _Time) noexcept {
+ return utc_time>{_Time.time_since_epoch()} - _Tai_epoch_adjust;
+ }
+
+ template
+ _NODISCARD static tai_time> from_utc(
+ const utc_time<_Duration>& _Time) noexcept {
+ return tai_time>{_Time.time_since_epoch()} + _Tai_epoch_adjust;
+ }
+ };
+
+ // [time.clock.gps]
+
+ class gps_clock;
+
+ template
+ using gps_time = time_point;
+ using gps_seconds = gps_time;
+
+ // CLASS gps_clock
+ class gps_clock {
+ public:
+ using rep = system_clock::rep;
+ using period = system_clock::period;
+ using duration = _CHRONO duration;
+ using time_point = _CHRONO time_point;
+ static constexpr bool is_steady = system_clock::is_steady;
+
+ static constexpr seconds _Gps_epoch_adjust{-315964809};
+
+ _NODISCARD static time_point now() {
+ return from_utc(utc_clock::now());
+ }
+
+ template
+ _NODISCARD static utc_time> to_utc(
+ const gps_time<_Duration>& _Time) noexcept {
+ return utc_time>{_Time.time_since_epoch()} - _Gps_epoch_adjust;
+ }
+
+ template
+ _NODISCARD static gps_time> from_utc(
+ const utc_time<_Duration>& _Time) noexcept {
+ return gps_time>{_Time.time_since_epoch()} + _Gps_epoch_adjust;
+ }
+ };
+#endif // ^^^ _HAS_CXX20
+} // namespace chrono
+
+// [time.clock.file]
+
+#if _HAS_CXX20
+namespace filesystem {
+ struct _File_time_clock;
+} // namespace filesystem
+
+namespace chrono {
+ // ALIAS file_clock
+ using file_clock = filesystem::_File_time_clock;
+
+ template
+ using file_time = time_point;
+} // namespace chrono
+#endif // ^^^ _HAS_CXX20
+
+#if _HAS_CXX17
+namespace filesystem {
+ inline constexpr long long __std_fs_file_time_epoch_adjustment = 0x19DB1DED53E8000LL; // TRANSITION, ABI
+
+ struct _File_time_clock { // Implementation of trivial-clock
+ using rep = long long;
+ using period = chrono::system_clock::period;
+ using duration = chrono::duration;
+ using time_point = chrono::time_point<_File_time_clock>;
+ static constexpr bool is_steady = false;
+
+ _NODISCARD static time_point now() noexcept { // get current time; undo epoch adjustment
+ return time_point(duration(_Xtime_get_ticks() + __std_fs_file_time_epoch_adjustment)); // TRANSITION, ABI
+ }
+
+#if _HAS_CXX20
+ // Assumes that FILETIME counts leap seconds only after the first 27 (i.e., after 1 January 2017), even though
+ // systems can opt out of this behavior.
+ static constexpr chrono::seconds _Skipped_filetime_leap_seconds{27};
+ static constexpr chrono::sys_days _Cutoff{
+ chrono::year_month_day{chrono::year{2017}, chrono::January, chrono::day{1}}};
+
+ template
+ _NODISCARD static chrono::utc_time> to_utc(
+ const chrono::file_time<_Duration>& _File_time) {
+ using namespace chrono;
+ using _CommonType = common_type_t<_Duration, seconds>;
+ const auto _Ticks = _File_time.time_since_epoch()
+ - _CHRONO duration_cast(duration{__std_fs_file_time_epoch_adjustment});
+
+ if (_Ticks < _Cutoff.time_since_epoch()) {
+ return utc_clock::from_sys(sys_time<_CommonType>{_Ticks});
+ } else {
+ return utc_time<_CommonType>{_Ticks + _Skipped_filetime_leap_seconds};
+ }
+ }
+
+ template
+ _NODISCARD static chrono::file_time> from_utc(
+ const chrono::utc_time<_Duration>& _Utc_time) {
+ using namespace chrono;
+ file_time> _File_time{
+ _CHRONO duration_cast(duration{__std_fs_file_time_epoch_adjustment})};
+
+ if (_Utc_time < utc_seconds{_Cutoff.time_since_epoch()} + _Skipped_filetime_leap_seconds) {
+ _File_time += utc_clock::to_sys(_Utc_time).time_since_epoch();
+ } else {
+ _File_time += _Utc_time.time_since_epoch() - _Skipped_filetime_leap_seconds;
+ }
+
+ return _File_time;
+ }
+#endif // ^^^ _HAS_CXX20
+ };
+} // namespace filesystem
+#endif // ^^^ _HAS_CXX17
+
+namespace chrono {
+#if _HAS_CXX20
+ // [time.clock.conv]
+
+ // STRUCT TEMPLATE clock_time_conversion
+ template
+ struct clock_time_conversion {};
+
+ // [time.clock.cast.id]
+
+ template
+ struct clock_time_conversion<_Clock, _Clock> {
+ template
+ _NODISCARD time_point<_Clock, _Duration> operator()(const time_point<_Clock, _Duration>& _Time) const
+ noexcept(is_arithmetic_v) /* strengthened */ {
+ return _Time;
+ }
+ };
+
+ template <>
+ struct clock_time_conversion {
+ template
+ _NODISCARD sys_time<_Duration> operator()(const sys_time<_Duration>& _Time) const
+ noexcept(is_arithmetic_v) /* strengthened */ {
+ return _Time;
+ }
+ };
+
+ template <>
+ struct clock_time_conversion {
+ template
+ _NODISCARD utc_time<_Duration> operator()(const utc_time<_Duration>& _Time) const
+ noexcept(is_arithmetic_v) /* strengthened */ {
+ return _Time;
+ }
+ };
+
+ // [time.clock.cast.sys.utc]
+
+ template <>
+ struct clock_time_conversion {
+ template
+ _NODISCARD utc_time> operator()(const sys_time<_Duration>& _Sys_time) const {
+ return utc_clock::from_sys(_Sys_time);
+ }
+ };
+
+ template <>
+ struct clock_time_conversion {
+ template
+ _NODISCARD sys_time> operator()(const utc_time<_Duration>& _Utc_time) const {
+ return utc_clock::to_sys(_Utc_time);
+ }
+ };
+
+ // [time.clock.cast.sys]
+
+ template
+ inline constexpr bool _Is_time_point_for_clock = false;
+
+ template
+ inline constexpr bool _Is_time_point_for_clock, _Clock> = true;
+
+ template
+ struct clock_time_conversion {
+ template &>()))>>
+ _NODISCARD auto operator()(const time_point<_SourceClock, _Duration>& _Time) const
+ noexcept(noexcept(_SourceClock::to_sys(_Time))) /* strengthened */ {
+ static_assert(_Is_time_point_for_clock,
+ "N4885 [time.clock.cast.sys]/2: Mandates: SourceClock::to_sys(t) returns a sys_time");
+ return _SourceClock::to_sys(_Time);
+ }
+ };
+
+ template
+ struct clock_time_conversion<_DestClock, system_clock> {
+ template &>()))>>
+ _NODISCARD auto operator()(const sys_time<_Duration>& _Time) const
+ noexcept(noexcept(_DestClock::from_sys(_Time))) /* strengthened */ {
+ static_assert(_Is_time_point_for_clock,
+ "N4885 [time.clock.cast.sys]/5: Mandates: DestClock::from_sys(t) returns a "
+ "time_point");
+ return _DestClock::from_sys(_Time);
+ }
+ };
+
+ // [time.clock.cast.utc]
+
+ template
+ struct clock_time_conversion {
+ template &>()))>>
+ _NODISCARD auto operator()(const time_point<_SourceClock, _Duration>& _Time) const
+ noexcept(noexcept(_SourceClock::to_utc(_Time))) /* strengthened */ {
+ static_assert(_Is_time_point_for_clock,
+ "N4885 [time.clock.cast.utc]/2: Mandates: SourceClock::to_utc(t) returns a utc_time");
+ return _SourceClock::to_utc(_Time);
+ }
+ };
+
+ template
+ struct clock_time_conversion<_DestClock, utc_clock> {
+ template &>()))>>
+ _NODISCARD auto operator()(const utc_time<_Duration>& _Time) const
+ noexcept(noexcept(_DestClock::from_utc(_Time))) /* strengthened */ {
+ static_assert(_Is_time_point_for_clock