diff --git a/.clang-format b/.clang-format index 1eab9190596..a7c98218459 100644 --- a/.clang-format +++ b/.clang-format @@ -1,7 +1,17 @@ # Copyright (c) Microsoft Corporation. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -# https://releases.llvm.org/11.0.0/tools/clang/docs/ClangFormatStyleOptions.html +# https://releases.llvm.org/20.1.0/tools/clang/docs/ClangFormatStyleOptions.html + +# To update this .clang-format file for a new clang-format version: +# 1. Update the documentation link above. +# 2. Copy the output of `clang-format -dump-config --style=LLVM` into a temporary file. +# a. Comment out all of its lines. +# 3. Compare that temporary file to this .clang-format file. +# 4. Adjust this .clang-format file to record new and updated options. +# a. Read the new documentation to understand such changes. +# 5. The goal is for the comparison from the temporary file to this .clang-format file to be pure additions (green). +# a. That is, comments here are recording the defaults, while added lines are our customized settings. --- # Language: Cpp @@ -10,47 +20,113 @@ BasedOnStyle: LLVM AccessModifierOffset: -4 # AlignAfterOpenBracket: Align AlignAfterOpenBracket: DontAlign -# AlignConsecutiveMacros: false -AlignConsecutiveMacros: true -# AlignConsecutiveAssignments: false -AlignConsecutiveAssignments: true -# AlignConsecutiveBitFields: false -# AlignConsecutiveDeclarations: false +# AlignArrayOfStructures: None +# AlignConsecutiveAssignments: +# Enabled: false +# AcrossEmptyLines: false +# AcrossComments: false +# AlignCompound: false +# AlignFunctionDeclarations: false +# AlignFunctionPointers: false +# PadOperators: true +AlignConsecutiveAssignments: Consecutive +# AlignConsecutiveBitFields: +# Enabled: false +# AcrossEmptyLines: false +# AcrossComments: false +# AlignCompound: false +# AlignFunctionDeclarations: false +# AlignFunctionPointers: false +# PadOperators: false +# AlignConsecutiveDeclarations: +# Enabled: false +# AcrossEmptyLines: false +# AcrossComments: false +# AlignCompound: false +# AlignFunctionDeclarations: true +# AlignFunctionPointers: false +# PadOperators: false +# AlignConsecutiveMacros: +# Enabled: false +# AcrossEmptyLines: false +# AcrossComments: false +# AlignCompound: false +# AlignFunctionDeclarations: false +# AlignFunctionPointers: false +# PadOperators: false +AlignConsecutiveMacros: Consecutive +# AlignConsecutiveShortCaseStatements: +# Enabled: false +# AcrossEmptyLines: false +# AcrossComments: false +# AlignCaseArrows: false +# AlignCaseColons: false +# AlignConsecutiveTableGenBreakingDAGArgColons: +# Enabled: false +# AcrossEmptyLines: false +# AcrossComments: false +# AlignCompound: false +# AlignFunctionDeclarations: false +# AlignFunctionPointers: false +# PadOperators: false +# AlignConsecutiveTableGenCondOperatorColons: +# Enabled: false +# AcrossEmptyLines: false +# AcrossComments: false +# AlignCompound: false +# AlignFunctionDeclarations: false +# AlignFunctionPointers: false +# PadOperators: false +# AlignConsecutiveTableGenDefinitionColons: +# Enabled: false +# AcrossEmptyLines: false +# AcrossComments: false +# AlignCompound: false +# AlignFunctionDeclarations: false +# AlignFunctionPointers: false +# PadOperators: false # AlignEscapedNewlines: Right AlignEscapedNewlines: Left # AlignOperands: Align AlignOperands: AlignAfterOperator -# AlignTrailingComments: true -AlignTrailingComments: false +# AlignTrailingComments: +# Kind: Always +# OverEmptyLines: 0 +AlignTrailingComments: + Kind: Never # AllowAllArgumentsOnNextLine: true -# AllowAllConstructorInitializersOnNextLine: true # AllowAllParametersOfDeclarationOnNextLine: true -# AllowShortEnumsOnASingleLine: true +# AllowBreakBeforeNoexceptSpecifier: Never +AllowBreakBeforeNoexceptSpecifier: OnlyWithParen # AllowShortBlocksOnASingleLine: Never +# AllowShortCaseExpressionOnASingleLine: true # AllowShortCaseLabelsOnASingleLine: false +# AllowShortCompoundRequirementOnASingleLine: true +# AllowShortEnumsOnASingleLine: true # AllowShortFunctionsOnASingleLine: All AllowShortFunctionsOnASingleLine: Empty -# AllowShortLambdasOnASingleLine: All # AllowShortIfStatementsOnASingleLine: Never +# AllowShortLambdasOnASingleLine: All # AllowShortLoopsOnASingleLine: false +# AllowShortNamespacesOnASingleLine: false # AlwaysBreakAfterDefinitionReturnType: None -# AlwaysBreakAfterReturnType: None # AlwaysBreakBeforeMultilineStrings: false -# AlwaysBreakTemplateDeclarations: MultiLine -AlwaysBreakTemplateDeclarations: Yes +# AttributeMacros: +# - __capability # BinPackArguments: true -# BinPackParameters: true +# BinPackParameters: BinPack +# BitFieldColonSpacing: Both # BraceWrapping: # AfterCaseLabel: false # AfterClass: false # AfterControlStatement: Never # AfterEnum: false +# AfterExternBlock: false # AfterFunction: false # AfterNamespace: false # AfterObjCDeclaration: false # AfterStruct: false # AfterUnion: false -# AfterExternBlock: false # BeforeCatch: false # BeforeElse: false # BeforeLambdaBody: false @@ -59,80 +135,120 @@ AlwaysBreakTemplateDeclarations: Yes # SplitEmptyFunction: true # SplitEmptyRecord: true # SplitEmptyNamespace: true +# BreakAdjacentStringLiterals: true +# BreakAfterAttributes: Leave +BreakAfterAttributes: Never +# BreakAfterJavaFieldAnnotations: false +# BreakAfterReturnType: None +# BreakArrays: true # BreakBeforeBinaryOperators: None BreakBeforeBinaryOperators: NonAssignment +# BreakBeforeConceptDeclarations: Always # BreakBeforeBraces: Attach -# BreakBeforeInheritanceComma: false -# BreakInheritanceList: BeforeColon +# BreakBeforeInlineASMColon: OnlyMultiline # BreakBeforeTernaryOperators: true -# BreakConstructorInitializersBeforeComma: false +# BreakBinaryOperations: Never # BreakConstructorInitializers: BeforeColon -# BreakAfterJavaFieldAnnotations: false +# BreakFunctionDefinitionParameters: false +# BreakInheritanceList: BeforeColon # BreakStringLiterals: true +# BreakTemplateDeclarations: MultiLine +BreakTemplateDeclarations: Yes # ColumnLimit: 80 ColumnLimit: 120 # CommentPragmas: '^ IWYU pragma:' # CompactNamespaces: false -# ConstructorInitializerAllOnOneLineOrOnePerLine: false # ConstructorInitializerIndentWidth: 4 # ContinuationIndentWidth: 4 # Cpp11BracedListStyle: true -# DeriveLineEnding: true -DeriveLineEnding: false # DerivePointerAlignment: false # DisableFormat: false +# EmptyLineAfterAccessModifier: Never +# EmptyLineBeforeAccessModifier: LogicalBlock # ExperimentalAutoDetectBinPacking: false # FixNamespaceComments: true # ForEachMacros: # - foreach # - Q_FOREACH # - BOOST_FOREACH +# IfMacros: +# - KJ_IF_MAYBE # IncludeBlocks: Preserve IncludeBlocks: Regroup # IncludeCategories: # - Regex: '^"(llvm|llvm-c|clang|clang-c)/' # Priority: 2 # SortPriority: 0 +# CaseSensitive: false # - Regex: '^(<|"(gtest|gmock|isl|json)/)' # Priority: 3 # SortPriority: 0 +# CaseSensitive: false # - Regex: '.*' # Priority: 1 # SortPriority: 0 +# CaseSensitive: false IncludeCategories: - - Regex: '^$' - Priority: 1 - - Regex: '^<(Windows|userenv)\.h>$' - Priority: 3 - SortPriority: 3 - - Regex: '^$' - Priority: 3 - SortPriority: 4 - - Regex: '^<__.*\.hpp>$' - Priority: 2 + - Regex: '^<(yvals|yvals_core)\.h>$' + Priority: 10 + - Regex: '^<__msvc_.*\.hpp>$' + Priority: 20 + - Regex: '^$' # should be included before any header that includes + Priority: 30 + SortPriority: 30 + - Regex: '^<(DbgEng|DbgHelp|Shlwapi|Windows)\.h>$' + Priority: 30 + SortPriority: 31 + - Regex: '^$' + Priority: 30 + SortPriority: 32 - Regex: '\.hpp[>"]$' - Priority: 5 + Priority: 40 - Regex: '.*' - Priority: 2 + Priority: 20 # IncludeIsMainRegex: '(Test)?$' # IncludeIsMainSourceRegex: '' -# IndentCaseLabels: false +# IndentAccessModifiers: false # IndentCaseBlocks: false IndentCaseBlocks: true +# IndentCaseLabels: false +# IndentExportBlock: true +# IndentExternBlock: AfterExternBlock # IndentGotoLabels: true # IndentPPDirectives: None -# IndentExternBlock: AfterExternBlock +# IndentRequiresClause: true # IndentWidth: 2 IndentWidth: 4 # IndentWrappedFunctionNames: false IndentWrappedFunctionNames: true +# InsertBraces: false +InsertBraces: true +# InsertNewlineAtEOF: false +InsertNewlineAtEOF: true # InsertTrailingCommas: None +# IntegerLiteralSeparator: +# Binary: 0 +# BinaryMinDigits: 0 +# Decimal: 0 +# DecimalMinDigits: 0 +# Hex: 0 +# HexMinDigits: 0 # JavaScriptQuotes: Leave # JavaScriptWrapImports: true -# KeepEmptyLinesAtTheStartOfBlocks: true +# KeepEmptyLines: +# AtEndOfFile: false +# AtStartOfBlock: true +# AtStartOfFile: true +KeepEmptyLines: + AtStartOfFile: false +# KeepFormFeed: false +# LambdaBodyIndentation: Signature +# LineEnding: DeriveLF +LineEnding: CRLF # NOTE: MacroBlockBegin/MacroBlockEnd don't work with _CATCH_ALL. # MacroBlockBegin: '' # MacroBlockEnd: '' +# MainIncludeChar: Quote # MaxEmptyLinesToKeep: 1 MaxEmptyLinesToKeep: 2 # NamespaceIndentation: None @@ -142,60 +258,109 @@ NamespaceIndentation: All # ObjCBreakBeforeNestedBlockParam: true # ObjCSpaceAfterProperty: false # ObjCSpaceBeforeProtocolList: true +# PackConstructorInitializers: BinPack # PenaltyBreakAssignment: 2 # PenaltyBreakBeforeFirstCallParameter: 19 +# PenaltyBreakBeforeMemberAccess: 150 # PenaltyBreakComment: 300 # PenaltyBreakFirstLessLess: 120 +# PenaltyBreakOpenParenthesis: 0 +# PenaltyBreakScopeResolution: 500 # PenaltyBreakString: 1000 # PenaltyBreakTemplateDeclaration: 10 # PenaltyExcessCharacter: 1000000 +# PenaltyIndentedWhitespace: 0 # PenaltyReturnTypeOnItsOwnLine: 60 # PointerAlignment: Right PointerAlignment: Left -# ReflowComments: true -# SortIncludes: true -# SortUsingDeclarations: true +# PPIndentWidth: -1 +# QualifierAlignment: Leave +# ReferenceAlignment: Pointer +# ReflowComments: Always +# RemoveBracesLLVM: false +# RemoveEmptyLinesInUnwrappedLines: false +# RemoveParentheses: Leave +# RemoveSemicolon: false +RemoveSemicolon: true +# RequiresClausePosition: OwnLine +# RequiresExpressionIndentation: OuterScope +# SeparateDefinitionBlocks: Leave +# ShortNamespaceLines: 1 +# SkipMacroDefinitionBody: false +# SortIncludes: CaseSensitive +# SortJavaStaticImport: Before +# SortUsingDeclarations: LexicographicNumeric # SpaceAfterCStyleCast: false SpaceAfterCStyleCast: true # SpaceAfterLogicalNot: false # SpaceAfterTemplateKeyword: true +# SpaceAroundPointerQualifiers: Default # SpaceBeforeAssignmentOperators: true +# SpaceBeforeCaseColon: false # SpaceBeforeCpp11BracedList: false # SpaceBeforeCtorInitializerColon: true # SpaceBeforeInheritanceColon: true +# SpaceBeforeJsonColon: false # SpaceBeforeParens: ControlStatements +# SpaceBeforeParensOptions: +# AfterControlStatements: true +# AfterForeachMacros: true +# AfterFunctionDefinitionName: false +# AfterFunctionDeclarationName: false +# AfterIfMacros: true +# AfterOverloadedOperator: false +# AfterPlacementOperator: true +# AfterRequiresInClause: false +# AfterRequiresInExpression: false +# BeforeNonEmptyParentheses: false +SpaceBeforeParens: Custom +SpaceBeforeParensOptions: + AfterRequiresInClause: true # SpaceBeforeRangeBasedForLoopColon: true +# SpaceBeforeSquareBrackets: false # SpaceInEmptyBlock: false -# SpaceInEmptyParentheses: false # SpacesBeforeTrailingComments: 1 -# SpacesInAngles: false -# SpacesInConditionalStatement: false +# SpacesInAngles: Never # SpacesInContainerLiterals: true -# SpacesInCStyleCastParentheses: false -# SpacesInParentheses: false +# SpacesInLineCommentPrefix: +# Minimum: 1 +# Maximum: -1 +# SpacesInParens: Never +# SpacesInParensOptions: +# ExceptDoubleParentheses: false +# InCStyleCasts: false +# InConditionalStatements: false +# InEmptyParentheses: false +# Other: false # SpacesInSquareBrackets: false -# SpaceBeforeSquareBrackets: false # Standard: Latest +# StatementAttributeLikeMacros: +# - Q_EMIT # StatementMacros: # - Q_UNUSED # - QT_REQUIRE_VERSION # NOTE: _STD_BEGIN, _STD_END, etc. aren't macros for complete statements, but telling # clang-format that they are produces the behavior that we want (with no block indentation). StatementMacros: + - _EXTERN_CXX_WORKAROUND + - _END_EXTERN_CXX_WORKAROUND - _STD_BEGIN - _STD_END - _STDEXT_BEGIN - _STDEXT_END - - _EXTERN_C - - _END_EXTERN_C + - _FMT_P2286_BEGIN + - _FMT_P2286_END - _EXTERN_C_UNLESS_PURE - _END_EXTERN_C_UNLESS_PURE +# TableGenBreakInsideDAGArg: DontBreak # TabWidth: 8 -# UseCRLF: false -UseCRLF: true # UseTab: Never +# VerilogBreakBetweenInstancePorts: true # WhitespaceSensitiveMacros: -# - STRINGIZE -# - PP_STRINGIZE # - BOOST_PP_STRINGIZE +# - CF_SWIFT_NAME +# - NS_SWIFT_NAME +# - PP_STRINGIZE +# - STRINGIZE +# WrapNamespaceBodyWithEmptyLines: Leave ... diff --git a/.gitattributes b/.gitattributes index dc85e5fa21f..e52cc8c23e0 100644 --- a/.gitattributes +++ b/.gitattributes @@ -6,7 +6,12 @@ # Ensure GitHub detects our C++ code as C++ code. /stl/inc/** linguist-language=C++ +/stl/modules/** linguist-language=C++ /stl/src/** linguist-language=C++ +*.h linguist-language=C++ + +# Ensure GitHub detects lit.cfg and lit.local.cfg as Python instead of HAProxy. +*.cfg linguist-language=Python # Ensure GitHub detects our Perl legacy test harness code as Perl code instead of Raku. *.pl linguist-language=Perl diff --git a/.github/ISSUE_TEMPLATE/bug-report.md b/.github/ISSUE_TEMPLATE/bug-report.md index 13aae520361..97b57aaa2dd 100644 --- a/.github/ISSUE_TEMPLATE/bug-report.md +++ b/.github/ISSUE_TEMPLATE/bug-report.md @@ -1,19 +1,19 @@ --- name: Bug Report about: Report a bug in the STL -title: "
: Problem" +title: "`
`: Problem" labels: '' assignees: '' --- -**Describe the bug** +# Describe the bug A clear and concise description of what the bug is. Please check that you've read the guidelines for submitting STL bug reports in `README.md`. If you are having problems with any component that is not the STL, instructions to get to the right place are there. -**Command-line test case** +# Command-line test case ``` C:\Temp>type repro.cpp #include @@ -26,12 +26,18 @@ int main() { std::cout << "test failure\n"; } -C:\Temp>cl /EHsc /W4 /WX .\repro.cpp -Microsoft (R) C/C++ Optimizing Compiler Version 19.23.28019.1 for x64 +C:\Temp>cl /EHsc /W4 /WX /std:c++latest .\repro.cpp +Microsoft (R) C/C++ Optimizing Compiler Version 19.36.32522 for x64 Copyright (C) Microsoft Corporation. All rights reserved. +/std:c++latest is provided as a preview of language features from the latest C++ +working draft, and we're eager to hear about bugs and suggestions for improvements. +However, note that these features are provided as-is without support, and subject +to changes or removal as the working draft evolves. See +https://go.microsoft.com/fwlink/?linkid=2045807 for details. + repro.cpp -Microsoft (R) Incremental Linker Version 14.23.28019.1 +Microsoft (R) Incremental Linker Version 14.36.32522.0 Copyright (C) Microsoft Corporation. All rights reserved. /out:repro.exe @@ -41,25 +47,39 @@ C:\Temp>.\repro.exe test failure ``` -**Expected behavior** +# Expected behavior A clear and concise description of what you expected to happen. Alternatively, include `static_assert` or `assert` lines in your test case above whose failure clearly indicates the problem. -**STL version** -* Option 1: Visual Studio version - * Displayed in Help > About Microsoft Visual Studio - * Example: +# STL version +* Option 1: MSVC Compiler version + + Example: + ``` + C:\Temp>cl.exe + Microsoft (R) C/C++ Optimizing Compiler Version 19.50.35503 for x64 + Copyright (C) Microsoft Corporation. All rights reserved. + + usage: cl [ option... ] filename... [ /link linkoption... ] ``` - Microsoft Visual Studio Community 2019 Preview - Version 16.5.0 Preview 5.0 +* Option 2: `_MSVC_STL_UPDATE` value + + Example: ``` + C:\Temp>type meow.cpp + #include + int main() { + std::cout << _MSVC_STL_UPDATE << "\n"; + } -* Option 2: git commit hash - * Example: + C:\Temp>cl /EHsc /nologo /W4 meow.cpp && meow + meow.cpp + 202507 + ``` +* Option 3: git commit hash + + Example: ``` - https://github.com/microsoft/STL/commit/2195148 + https://github.com/microsoft/STL/commit/219514876ea86491de191ceaa88632616bbc0f19 ``` -**Additional context** +# Additional context Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/cxx23-feature.md b/.github/ISSUE_TEMPLATE/cxx23-feature.md index 399071c4475..2d9002a3134 100644 --- a/.github/ISSUE_TEMPLATE/cxx23-feature.md +++ b/.github/ISSUE_TEMPLATE/cxx23-feature.md @@ -21,9 +21,6 @@ and the publication of the papers. When the papers are available, the https://wg21.link redirector will start working. Feature-test macro: -`#define MACRO_NAME MACRO_VALUE` - -Note: We're still working on finishing C++20. Until we're done -with that (and the compiler implements distinct `/std:c++20` and -`/std:c++latest` options), we won't be able to review PRs for -C++23 features. +```cpp +#define MACRO_NAME MACRO_VALUE +``` diff --git a/.github/workflows/update-status-chart.yml b/.github/workflows/update-status-chart.yml new file mode 100644 index 00000000000..ac8a5896680 --- /dev/null +++ b/.github/workflows/update-status-chart.yml @@ -0,0 +1,39 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +name: Update Status Chart +on: + schedule: + - cron: "0 7 * * *" + workflow_dispatch: +permissions: + contents: write +jobs: + build: + if: ${{ github.repository == 'microsoft/STL' }} + runs-on: ubuntu-latest + steps: + - name: Checkout gh-pages + uses: actions/checkout@v6 + with: + ref: gh-pages + - name: Setup Node.js + uses: actions/setup-node@v6 + with: + node-version: ">=25.2.1" + - name: Install Packages + run: | + npm ci + - name: Compile And Run gather_stats.mts + run: | + SECRET_GITHUB_PERSONAL_ACCESS_TOKEN="${{ github.token }}" npm run gather + - name: Compile And Bundle status_chart.mts + run: | + npm run make + - 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 src/daily_table.mts src/monthly_table.mts built/status_chart.mjs + git diff-index --quiet HEAD || git commit -m "Automated update." + git push origin gh-pages diff --git a/.gitignore b/.gitignore index c55023a9a53..f9438ec8ca5 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,5 @@ __pycache__/ /build/ /out/ /tools/out/ +/CMakeLists.txt.user +*.log diff --git a/.gitmodules b/.gitmodules index 0e762eb7cdc..f1618b17f50 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,10 +1,12 @@ # Copyright (c) Microsoft Corporation. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -[submodule "vcpkg"] - path = vcpkg - url = https://github.com/microsoft/vcpkg.git - fetchRecurseSubmodules = false [submodule "llvm-project"] path = llvm-project url = https://github.com/llvm/llvm-project.git +[submodule "boost-math"] + path = boost-math + url = https://github.com/boostorg/math.git +[submodule "benchmarks/google-benchmark"] + path = benchmarks/google-benchmark + url = https://github.com/google/benchmark.git diff --git a/.mailmap b/.mailmap new file mode 100644 index 00000000000..dd26e091b9b --- /dev/null +++ b/.mailmap @@ -0,0 +1,11 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +# This file maps author and committer email addresses to canonical names and email +# addresses for display in the output of `git log` and `git blame`. +# Format: +# Canonical Name + + +Amy Wishnousky +Anju del Moral Gonzalez diff --git a/.vscode/settings.json b/.vscode/settings.json index 5312b7ed5b4..1b2295bc984 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -2,7 +2,10 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception { "C_Cpp.autoAddFileAssociations": false, - "editor.formatOnSave": true, + "editor.formatOnSave": false, + "[cpp]": { + "editor.formatOnSave": true + }, "files.associations": { ".clang-format": "yaml", "header-units.json": "jsonc", @@ -10,11 +13,26 @@ }, "files.eol": "\r\n", "files.exclude": { + "benchmarks/google-benchmark": true, + "boost-math": true, "llvm-project": true, - "stl/msbuild": true, - "vcpkg": true + "stl/msbuild": true }, "files.insertFinalNewline": true, "files.trimFinalNewlines": true, - "files.trimTrailingWhitespace": true + "files.trimTrailingWhitespace": true, + "git.ignoredRepositories": [ + "benchmarks/google-benchmark", + "boost-math", + "llvm-project" + ], + "python.analysis.extraPaths": [ + "./llvm-project/libcxx/utils", + "./llvm-project/llvm/utils/lit", + "./tests/utils" + ], + "search.exclude": { + "stl/src/xcharconv_ryu_tables.cpp": true, + "tests/std/tests/P0067R5_charconv/*test_cases*.hpp": true + } } diff --git a/CMakeLists.txt b/CMakeLists.txt index 8b166a3d5a2..afb6a97f978 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,98 +1,122 @@ # Copyright (c) Microsoft Corporation. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -if (NOT DEFINED CMAKE_TOOLCHAIN_FILE AND EXISTS "${CMAKE_CURRENT_LIST_DIR}/vcpkg/scripts/buildsystems/vcpkg.cmake") - set(CMAKE_TOOLCHAIN_FILE "${CMAKE_CURRENT_LIST_DIR}/vcpkg/scripts/buildsystems/vcpkg.cmake") -endif() +cmake_minimum_required(VERSION 4.2.1) -cmake_minimum_required(VERSION 3.19) set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY) project(msvc_standard_libraries LANGUAGES CXX) -find_package(Boost REQUIRED) - -set(VCLIBS_MIN_BOOST_VERSION 1.74.0) -if("${Boost_VERSION}" VERSION_LESS "${VCLIBS_MIN_BOOST_VERSION}") - message(FATAL_ERROR "Detected Boost version is too old (older than ${VCLIBS_MIN_BOOST_VERSION}).") +if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS "19.51.36014") + message(FATAL_ERROR "The STL must be built with MSVC Compiler 19.51.36014 or later.") endif() -option(BUILD_TESTING "Enable testing" ON) -set(VCLIBS_SUFFIX "_oss" CACHE STRING "suffix for built DLL names to avoid conflicts with distributed DLLs") +include(CheckCXXSourceCompiles) +check_cxx_source_compiles([=[ +#include +static_assert(WDK_NTDDI_VERSION >= NTDDI_WIN11_GE, "Inspecting WDK_NTDDI_VERSION, the Windows SDK version."); +int main() {} +]=] WINDOWS_SDK_VERSION_CHECK) + +if(NOT WINDOWS_SDK_VERSION_CHECK) + message(FATAL_ERROR "The STL must be built with the Windows 11 SDK (10.0.26100) or later. Make sure it's available by selecting it in the Individual Components tab of the VS Installer.") +endif() if(NOT DEFINED VCLIBS_TARGET_ARCHITECTURE) set(VCLIBS_TARGET_ARCHITECTURE "${CMAKE_CXX_COMPILER_ARCHITECTURE_ID}") endif() -set(CMAKE_CXX_FLAGS "") -set(CMAKE_CXX_FLAGS_DEBUG "") -set(CMAKE_CXX_FLAGS_RELEASE "") -set(CMAKE_CXX_STANDARD_LIBRARIES "kernel32.lib") -set(CMAKE_CXX_STANDARD_LIBRARIES_INIT "kernel32.lib") -set(CMAKE_MSVC_RUNTIME_LIBRARY "") +string(TOLOWER "${VCLIBS_TARGET_ARCHITECTURE}" VCLIBS_TARGET_ARCHITECTURE) -if("${VCLIBS_TARGET_ARCHITECTURE}" MATCHES "^[xX]86$") +if(VCLIBS_TARGET_ARCHITECTURE MATCHES "^(x86|x64)$") + enable_language(ASM_MASM) +endif() + +# add the tools subdirectory _before_ we change all the flags +add_subdirectory(tools EXCLUDE_FROM_ALL) + +# these allow the targets to show up in the top-level +# (as opposed to under the tools subdirectory) +if(TARGET run-format) + add_custom_target(format) + add_dependencies(format run-format) +endif() + +if(TARGET run-validate) + add_custom_target(validate) + add_dependencies(validate run-validate) +endif() + +option(CONFIGURE_TESTING "Enable testing" ON) +set(VCLIBS_SUFFIX "_oss" CACHE STRING "suffix for built DLL names to avoid conflicts with distributed DLLs") + +option(STL_USE_ANALYZE "Pass the /analyze flag to MSVC" OFF) +option(STL_ASAN_BUILD "Build the STL with ASan enabled" OFF) + +set(VCLIBS_EXPLICIT_MACHINE "") + +if(VCLIBS_TARGET_ARCHITECTURE STREQUAL "x86") set(VCLIBS_TARGET_ARCHITECTURE "x86") set(VCLIBS_I386_OR_AMD64 "i386") set(VCLIBS_X86_OR_X64 "x86") - # Note that we set _WIN32_WINNT to a high level to make declarations available, but still engage downlevel - # runtime dynamic linking by setting our own _STL_WIN32_WINNT back to Windows XP. - add_compile_definitions(_X86_ _VCRT_WIN32_WINNT=0x0501 _STL_WIN32_WINNT=0x0501 - _WIN32_WINNT=0x0602 NTDDI_VERSION=NTDDI_WIN8) - add_compile_options(/arch:IA32) -elseif(VCLIBS_TARGET_ARCHITECTURE MATCHES "^[xX]64$") +elseif(VCLIBS_TARGET_ARCHITECTURE STREQUAL "x64") set(VCLIBS_TARGET_ARCHITECTURE "x64") set(VCLIBS_I386_OR_AMD64 "amd64") set(VCLIBS_X86_OR_X64 "x64") - add_compile_definitions(_AMD64_ _VCRT_WIN32_WINNT=0x0501 _STL_WIN32_WINNT=0x0501 - _WIN32_WINNT=0x0602 NTDDI_VERSION=NTDDI_WIN8) -elseif(VCLIBS_TARGET_ARCHITECTURE MATCHES "^[aA][rR][mM][vV]7$") - set(VCLIBS_TARGET_ARCHITECTURE "arm") - set(VCLIBS_I386_OR_AMD64 "arm") - set(VCLIBS_X86_OR_X64 "arm") - add_compile_definitions(_ARM_ _VCRT_WIN32_WINNT=0x0602 _STL_WIN32_WINNT=0x0602 - _WIN32_WINNT=0x0602 NTDDI_VERSION=NTDDI_WIN8) - string(APPEND CMAKE_CXX_STANDARD_LIBRARIES " Synchronization.lib") -elseif(VCLIBS_TARGET_ARCHITECTURE MATCHES "^[aA][rR][mM]64$") +elseif(VCLIBS_TARGET_ARCHITECTURE STREQUAL "arm64") set(VCLIBS_TARGET_ARCHITECTURE "arm64") set(VCLIBS_I386_OR_AMD64 "arm64") set(VCLIBS_X86_OR_X64 "arm64") - add_compile_definitions(_ARM64_ _VCRT_WIN32_WINNT=0x0A00 _STL_WIN32_WINNT=0x0A00 - _WIN32_WINNT=0x0A00 NTDDI_VERSION=NTDDI_WIN10) - string(APPEND CMAKE_CXX_STANDARD_LIBRARIES " Synchronization.lib") +elseif(VCLIBS_TARGET_ARCHITECTURE STREQUAL "arm64ec") + set(VCLIBS_TARGET_ARCHITECTURE "arm64ec") + set(VCLIBS_I386_OR_AMD64 "arm64ec") + set(VCLIBS_X86_OR_X64 "arm64") # Yes, really: `%VCToolsInstallDir%lib\arm64ec` only contains the Link Options + add_compile_options($<$:/arm64EC>) + set(VCLIBS_EXPLICIT_MACHINE "/machine:arm64ec") else() message(FATAL_ERROR "Could not determine target architecture: VCLIBS_TARGET_ARCHITECTURE: ${VCLIBS_TARGET_ARCHITECTURE}") endif() -add_compile_definitions( - _ALLOW_ITERATOR_DEBUG_LEVEL_MISMATCH WIN32_LEAN_AND_MEAN STRICT _CRT_STDIO_ARBITRARY_WIDE_SPECIFIERS - _CRT_DECLARE_NONSTDC_NAMES=1 ) - -add_compile_options(/diagnostics:caret /W4 /WX /w14265 /w15038 /d1FastFail /guard:cf /Z7 /Gm- /Gy /Zp8 /std:c++latest /permissive- /Zc:threadSafeInit- /Zl) - -set(VCLIBS_DEBUG_OPTIONS "/Od") -set(VCLIBS_RELEASE_OPTIONS "/O2;/Os") # TRANSITION: Potentially remove /Os - -set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/out/lib/${VCLIBS_I386_OR_AMD64}") -set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/out/lib/${VCLIBS_I386_OR_AMD64}") -set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/out/bin/${VCLIBS_I386_OR_AMD64}") - -set(CMAKE_STATIC_LINKER_FLAGS "/WX") -set(CMAKE_STATIC_LINKER_FLAGS_DEBUG "") -set(CMAKE_STATIC_LINKER_FLAGS_RELEASE "") -set(CMAKE_SHARED_LINKER_FLAGS "/DEBUG:FULL /WX /RELEASE /SUBSYSTEM:Console /NODEFAULTLIB /INCREMENTAL:NO /MANIFEST:NO /DLL /profile /guard:cf /DEBUGTYPE:cv,fixup /LARGEADDRESSAWARE") -set(CMAKE_SHARED_LINKER_FLAGS_DEBUG "") -set(CMAKE_SHARED_LINKER_FLAGS_RELEASE "") - get_filename_component(TOOLSET_BINARIES_DIR "${CMAKE_CXX_COMPILER}" DIRECTORY) # Example: $\VC\Tools\MSVC\14.23.27931\bin\Hostx86\x86 get_filename_component(TOOLSET_ROOT_DIR "${TOOLSET_BINARIES_DIR}" DIRECTORY) # $\VC\Tools\MSVC\14.23.27931\bin\Hostx86 get_filename_component(TOOLSET_ROOT_DIR "${TOOLSET_ROOT_DIR}" DIRECTORY) # $\VC\Tools\MSVC\14.23.27931\bin get_filename_component(TOOLSET_ROOT_DIR "${TOOLSET_ROOT_DIR}" DIRECTORY) # $\VC\Tools\MSVC\14.23.27931 - set(TOOLSET_LIB "${TOOLSET_ROOT_DIR}/lib/${VCLIBS_X86_OR_X64}") +set(STL_ARCHIVE_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/out/lib/${VCLIBS_I386_OR_AMD64}") +set(STL_LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/out/lib/${VCLIBS_I386_OR_AMD64}") +set(STL_RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/out/bin/${VCLIBS_I386_OR_AMD64}") -add_subdirectory(stl) +# Note that we set _WIN32_WINNT to a high level to make declarations available. +add_compile_definitions( + _ALLOW_ITERATOR_DEBUG_LEVEL_MISMATCH WIN32_LEAN_AND_MEAN STRICT _CRT_STDIO_ARBITRARY_WIDE_SPECIFIERS + _WIN32_WINNT=0x0A00 NTDDI_VERSION=NTDDI_WIN11_GE) + +if(STL_USE_ANALYZE) + # TRANSITION, Windows SDK 10.0.26100 emits + # "warning C6553: The annotation for function 'LCMapStringEx' on _Param_(9) does not apply to a value type." + # Reported as OS-40109504 "Windows SDK: incorrect SAL annotations on functions the STL uses". + add_compile_options("$<$:/analyze:autolog-;/wd6553>") + + if(VCLIBS_TARGET_ARCHITECTURE STREQUAL "arm64ec") + # TRANSITION, Windows SDK 10.0.26100 emits + # "warning C28301: No annotations for first declaration of 'meow'" + # for various intrinsics when building for ARM64EC. + add_compile_options("$<$:/wd28301>") + endif() +endif() + +set(VCLIBS_DEBUG_OPTIONS "$<$:/Od>") + +# TRANSITION, GH-2108: Investigate building the STL with only /O2, not /Os. +set(VCLIBS_RELEASE_OPTIONS "$<$:/O2;/Os>") -if(BUILD_TESTING) - enable_testing() +if(CONFIGURE_TESTING) add_subdirectory(tests) endif() + +if(STL_ASAN_BUILD) + message(STATUS "Building with ASan enabled") + add_compile_options("$<$:-fsanitize=address;-fno-sanitize-address-vcasan-lib>") +endif() + +add_subdirectory(boost-math) +add_subdirectory(stl) diff --git a/CMakePresets.json b/CMakePresets.json new file mode 100644 index 00000000000..8559f56fa9b --- /dev/null +++ b/CMakePresets.json @@ -0,0 +1,117 @@ +{ + "version": 5, + "cmakeMinimumRequired": { + "major": 3, + "minor": 26, + "patch": 0 + }, + "configurePresets": [ + { + "name": "base", + "hidden": true, + "generator": "Ninja", + "binaryDir": "${sourceDir}/out/${presetName}", + "toolset": { + "strategy": "external", + "value": "version=preview" + } + }, + { + "name": "x64", + "inherits": "base", + "description": "x64 Ninja Config", + "architecture": { + "strategy": "external", + "value": "x64" + }, + "condition": { + "type": "inList", + "string": "$env{VSCMD_ARG_TGT_ARCH}", + "list": [ + "x64", + "" + ] + } + }, + { + "name": "x86", + "inherits": "base", + "description": "x86 Ninja Config", + "architecture": { + "strategy": "external", + "value": "x86" + }, + "condition": { + "type": "inList", + "string": "$env{VSCMD_ARG_TGT_ARCH}", + "list": [ + "x86", + "" + ] + } + }, + { + "name": "ARM64", + "inherits": "base", + "description": "ARM64 Ninja Config", + "architecture": { + "strategy": "external", + "value": "ARM64" + }, + "condition": { + "type": "inList", + "string": "$env{VSCMD_ARG_TGT_ARCH}", + "list": [ + "arm64", + "" + ] + }, + "cacheVariables": { + "TESTS_BUILD_ONLY": true + } + }, + { + "name": "ARM64EC", + "inherits": "base", + "description": "ARM64EC Ninja Config", + "architecture": { + "strategy": "external", + "value": "ARM64EC" + }, + "condition": { + "type": "inList", + "string": "$env{VSCMD_ARG_TGT_ARCH}", + "list": [ + "arm64", + "" + ] + }, + "cacheVariables": { + "TESTS_BUILD_ONLY": true, + "VCLIBS_TARGET_ARCHITECTURE": "ARM64EC" + } + } + ], + "buildPresets": [ + { + "name": "x64", + "configurePreset": "x64", + "description": "Build x64 STL" + }, + { + "name": "x86", + "configurePreset": "x86", + "description": "Build x86 STL" + }, + { + "name": "ARM64", + "configurePreset": "ARM64", + "description": "Build ARM64 STL" + }, + { + "name": "ARM64EC", + "configurePreset": "ARM64EC", + "description": "Build ARM64EC STL" + } + ] +} diff --git a/CMakeSettings.json b/CMakeSettings.json deleted file mode 100644 index f5c1dfff5c1..00000000000 --- a/CMakeSettings.json +++ /dev/null @@ -1,52 +0,0 @@ -{ - "configurations": [ - { - "name": "x86", - "buildCommandArgs": "-v", - "buildRoot": "${projectDir}\\out\\build\\${name}", - "cmakeCommandArgs": "", - "configurationType": "Debug", - "ctestCommandArgs": "", - "generator": "Ninja", - "inheritEnvironments": [ "msvc_x86" ], - "installRoot": "${projectDir}\\out\\install\\${name}", - "variables": [] - }, - { - "name": "x64", - "buildCommandArgs": "-v", - "buildRoot": "${projectDir}\\out\\build\\${name}", - "cmakeCommandArgs": "", - "configurationType": "Debug", - "ctestCommandArgs": "", - "generator": "Ninja", - "inheritEnvironments": [ "msvc_x64_x64" ], - "installRoot": "${projectDir}\\out\\install\\${name}", - "variables": [] - }, - { - "name": "ARM", - "buildCommandArgs": "-v", - "buildRoot": "${projectDir}\\out\\build\\${name}", - "cmakeCommandArgs": "", - "configurationType": "Debug", - "ctestCommandArgs": "", - "generator": "Ninja", - "inheritEnvironments": [ "msvc_arm" ], - "installRoot": "${projectDir}\\out\\install\\${name}", - "variables": [] - }, - { - "name": "ARM64", - "buildCommandArgs": "-v", - "buildRoot": "${projectDir}\\out\\build\\${name}", - "cmakeCommandArgs": "", - "configurationType": "Debug", - "ctestCommandArgs": "", - "generator": "Ninja", - "inheritEnvironments": [ "msvc_arm64" ], - "installRoot": "${projectDir}\\out\\install\\${name}", - "variables": [] - } - ] -} diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 00000000000..686e5e7a090 --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,10 @@ +# Microsoft Open Source Code of Conduct + +This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). + +Resources: + +- [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/) +- [Microsoft Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) +- Contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with questions or concerns +- Employees can reach out at [aka.ms/opensource/moderation-support](https://aka.ms/opensource/moderation-support) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index d9f04a5248b..2001d4026bb 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -8,8 +8,62 @@ When you submit a pull request, a CLA bot will automatically determine whether y a CLA and decorate the PR appropriately (e.g., status check, comment). Simply follow the instructions provided by the bot. You will only need to do this once across all repos using our CLA. +## Types of Contributions + +### Submitting a Pull Request + +The STL repo has many open issues that track work which needs to be completed. +If you're unsure of where to start, you may want to: + +* look for pinned issues, or +* check issues under the labels [`good first issue`][label:"good first issue"], + [`high priority`][label:"high priority"], or [`help wanted`][label:"help wanted"]. + +### Reviewing a Pull Request + +We love code reviews from contributors! Reviews from other contributors can often accelerate the reviewing process +by helping a PR reach a more finished state before maintainers review the changes. As a result, such a PR may require +fewer maintainer review iterations before reaching a "Ready to Merge" state. + +To gain insight into our Code Review process, you can check out: + +* pull requests which are [undergoing review][review:changes-requested], +* [Advice for Reviewing Pull Requests][wiki:advice-for-reviewing], and +* [Code Review Videos][wiki:videos]. + +## PR Checklist + +Before submitting a pull request, please ensure: + +1. Any non-standard identifiers in product code (including local variables, exposition-only members, etc.) + begin with an underscore and a capital letter, as per [\[lex.name\]/3.1][]. + +2. Your changes don't affect the ABI for any type or function that a user may use (including adding or removing + non-static data members, adding or removing virtual member functions, changing whether a type is an aggregate + or trivially copyable, etc.). + +3. Your changes are written from scratch using only acceptable sources: + * this repository, + * the C++ Working Draft (including any cited standards), + * other WG21 papers (excluding reference implementations outside of proposed standard wording), + * LWG issues, or + * a project listed in [NOTICE.txt][] (make sure to cite the project in the PR description!). + +If your changes are derived from any other project, you _must_ mention it in the pull request description, +so we can determine whether the license is compatible and whether any other steps need to be taken. + # Code of Conduct This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). -For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or -contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. + +See [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md) for more information. + +[label:"good first issue"]: + https://github.com/microsoft/STL/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22 +[label:"high priority"]: https://github.com/microsoft/STL/issues?q=is%3Aopen+is%3Aissue+label%3A%22high+priority%22 +[label:"help wanted"]: https://github.com/microsoft/STL/issues?q=is%3Aopen+is%3Aissue+label%3A%22help+wanted%22 +[review:changes-requested]: https://github.com/microsoft/STL/pulls?q=is%3Apr+is%3Aopen+review%3Achanges-requested +[wiki:advice-for-reviewing]: https://github.com/microsoft/STL/wiki/Advice-for-Reviewing-Pull-Requests +[NOTICE.txt]: https://github.com/microsoft/STL/blob/main/NOTICE.txt +[wiki:videos]: https://github.com/microsoft/STL/wiki/Code-Review-Videos +[\[lex.name\]/3.1]: https://eel.is/c++draft/lex.name#3.1 diff --git a/NOTICE.txt b/NOTICE.txt index 0e92d4512ee..8c846a8667a 100644 --- a/NOTICE.txt +++ b/NOTICE.txt @@ -137,3 +137,82 @@ In addition, certain files include the notices provided below. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// + +---------------------- + +// Copyright (c) 2012 - present, Victor Zverovich +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// --- Optional exception to the license --- +// +// As an exception, if, as a result of your compiling your source code, portions +// of this Software are embedded into a machine-executable object form of such +// source code, you may redistribute such embedded portions in such object form +// without including the above copyright and permission notices. + +---------------------- + +// UNICODE, INC. LICENSE AGREEMENT - DATA FILES AND SOFTWARE +// +// See Terms of Use +// for definitions of Unicode Inc.'s Data Files and Software. +// +// NOTICE TO USER: Carefully read the following legal agreement. +// BY DOWNLOADING, INSTALLING, COPYING OR OTHERWISE USING UNICODE INC.'S +// DATA FILES ("DATA FILES"), AND/OR SOFTWARE ("SOFTWARE"), +// YOU UNEQUIVOCALLY ACCEPT, AND AGREE TO BE BOUND BY, ALL OF THE +// TERMS AND CONDITIONS OF THIS AGREEMENT. +// IF YOU DO NOT AGREE, DO NOT DOWNLOAD, INSTALL, COPY, DISTRIBUTE OR USE +// THE DATA FILES OR SOFTWARE. +// +// COPYRIGHT AND PERMISSION NOTICE +// +// Copyright (c) 1991-2022 Unicode, Inc. All rights reserved. +// Distributed under the Terms of Use in https://www.unicode.org/copyright.html. +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of the Unicode data files and any associated documentation +// (the "Data Files") or Unicode software and any associated documentation +// (the "Software") to deal in the Data Files or Software +// without restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, and/or sell copies of +// the Data Files or Software, and to permit persons to whom the Data Files +// or Software are furnished to do so, provided that either +// (a) this copyright and permission notice appear with all copies +// of the Data Files or Software, or +// (b) this copyright and permission notice appear in associated +// Documentation. +// +// THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF +// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT OF THIRD PARTY RIGHTS. +// IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS +// NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL +// DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, +// DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER +// TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +// PERFORMANCE OF THE DATA FILES OR SOFTWARE. +// +// Except as contained in this notice, the name of a copyright holder +// shall not be used in advertising or otherwise to promote the sale, +// use or other dealings in these Data Files or Software without prior +// written authorization of the copyright holder. diff --git a/README.md b/README.md index 8cc98b808cf..83293a4c233 100644 --- a/README.md +++ b/README.md @@ -6,8 +6,8 @@ which ships as part of the MSVC toolset and the Visual Studio IDE. * Our [Changelog][] tracks which updates to this repository appear in each VS release. * 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=main)][Pipelines] +* [![CI Status Badge][STL-CI-badge]][STL-CI-link] (STL-CI build status) +* [![ASan CI Status Badge][STL-ASan-CI-badge]][STL-ASan-CI-link] (STL-ASan-CI build status) # What This Repo Is Useful For @@ -15,7 +15,8 @@ If you're a programmer who just wants to use the STL, you **don't** need this re and select the "Desktop development with C++" workload. If you want to participate in the STL's development, welcome! You can report issues, comment on pull requests, and learn -about what we're working on. You can also submit pull requests to fix bugs or add features (see below). +about what we're working on. You can also submit pull requests to fix bugs or add features: see [CONTRIBUTING.md][] for +more information. Finally, you can take our code and use it in other apps and libraries (according to the terms of our license, like everything else). @@ -38,7 +39,7 @@ soon as possible.) and fully ported libcxx to run under [lit][] using the various configurations/compilers we test internally. * Continuous Integration: **In progress.** We've set up Azure Pipelines to validate changes to the repository. -Currently, it builds the STL (native desktop for x86, x64, ARM, and ARM64). Also, it strictly verifies that all of our +Currently, it builds the STL for x64, x86, ARM64, and ARM64EC. Also, it strictly verifies that all of our files have been formatted with [clang-format][] and follow our other whitespace conventions. * Contribution Guidelines: **Coming soon.** Working on the STL's code involves following many rules. We have codebase @@ -57,20 +58,20 @@ 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 [N5032][], 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.) We're currently prioritizing C++20 features before starting any work on C++23. +expression specifications.) Our primary goals are conformance, performance, usability, and compatibility. * Conformance: The Working Paper is a moving target; as features and LWG issue resolutions are added, we need to -implement them. That can involve a lot of work, because the STL is required to behave in very specific ways and to +implement them. That can involve a lot of work because the STL is required to behave in very specific ways and to handle users doing very unusual things. -* Performance: The STL needs to be extremely fast at runtime; speed is one of C++'s core strengths, and most C++ +* Performance: The STL needs to be extremely fast at runtime; speed is one of C++'s core strengths and most C++ programs use the STL extensively. As a result, we spend more time on optimization than most general-purpose libraries. (However, we're wary of changes that improve some scenarios at the expense of others, or changes that make code significantly more complicated and fragile. That is, there's a "complexity budget" that must be spent carefully.) @@ -79,15 +80,15 @@ significantly more complicated and fragile. That is, there's a "complexity budge debugging checks. For example, we've extensively marked the STL with `[[nodiscard]]` attributes because this helps programmers avoid bugs. -* Compatibility: This includes binary compatibility and source compatibility. We're keeping VS 2019 binary-compatible -with VS 2017 and VS 2015, which restricts what we can change in VS 2019 updates. (We've found that significant changes +* Compatibility: This includes binary compatibility and source compatibility. We're keeping VS 2026 binary-compatible +with VS 2015-2022, which restricts what we can change in VS 2026 updates. (We've found that significant changes are possible even though other changes are impossible, which we'll be documenting in our Contribution Guidelines soon.) While there are a few exceptions to this rule (e.g. if a feature is added to the Working Paper, we implement it, and then the feature is significantly changed before the International Standard is finalized, we reserve the right to break binary compatibility because `/std:c++latest` offers an experimental preview of such features), binary compatibility generally overrides all other considerations, even conformance. Source compatibility refers to being able to successfully recompile user code without changes. We consider source compatibility to be important, but not -all-important; breaking source compatibility can be an acceptable cost, if done for the right reasons in the right way +all-important; breaking source compatibility can be an acceptable cost if done for the right reasons in the right way (e.g. in a controlled manner with escape hatches). # Non-Goals @@ -121,7 +122,7 @@ reproducing the bug. * You should be reasonably confident that you're looking at an actual implementation bug, instead of undefined behavior or surprising-yet-Standard behavior. Comparing against other implementations can help (but remember that implementations -can differ while conforming to the Standard); try Godbolt's [Compiler Explorer][] and [Wandbox][]. If you still aren't +can differ while conforming to the Standard); try [Compiler Explorer][]. If you still aren't sure, ask the nearest C++ expert. * You should prepare a self-contained command-line test case, ideally as small as possible. We need a source file, a @@ -135,168 +136,189 @@ time-consuming for us to reduce.) * A good title is helpful. We prefer "``: Short description of your issue". You don't usually need to mention `std::` or C++. For example, "``: `is_cute` should be true for `enum class FluffyKittens`". -It's okay if you report an apparent STL bug that turns out to be a compiler bug, or surprising-yet-Standard behavior. +It's okay if you report an apparent STL bug that turns out to be a compiler bug or surprising-yet-Standard behavior. Just try to follow these rules, so we can spend more time fixing bugs and implementing features. +# Visual Studio Installer Prerequisites + +* Install [VS 2026 Insiders][] and keep it up to date. + + **You must install Insiders for STL development.** *See Note 1 below.* + + Select the "Desktop development with C++" workload. + + Select the following components at a minimum: + - "MSVC Build Tools for x64/x86 (Preview)" + - "C++ CMake tools for Windows" + - "MSVC AddressSanitizer" + - "Windows 11 SDK (10.0.26100)" or later + - "C++ Clang tools for Windows (20.1.8 - x64/x86)" + - *Optional, see Note 2 below:* "MSVC Build Tools for ARM64/ARM64EC (Preview)" +* Install [Python][] 3.14.3 or later. + + Select "Add python.exe to PATH" if you want to follow the instructions below that invoke `python`. + Otherwise, you should be familiar with alternative methods. + +*Note 1:* The STL and the compiler ship together, and we frequently need the latest +compiler fixes and features, so the last production release of the compiler is too old. + +*Note 2:* The x64/x86 build tools are usually sufficient. +You'll need the ARM64/ARM64EC build tools if you're working with architecture-sensitive code. +For example, `` has conditionally compiled code for the `_M_ARM64` and `_M_ARM64EC` predefined macros. + # How To Build With The Visual Studio IDE -The STL uses boost-math headers to provide P0226R1 Mathematical Special Functions. We recommend using [vcpkg][] to -acquire this dependency. - -1. Install Visual Studio 2019 16.9 Preview 4 or later. - * We recommend selecting "C++ CMake tools for Windows" in the VS Installer. - This will ensure that you're using supported versions of CMake and Ninja. - * Otherwise, install [CMake][] 3.19 or later, and [Ninja][] 1.10.2 or later. -2. Open Visual Studio, and choose the "Clone or check out code" option. Enter the URL of this repository, - `https://github.com/microsoft/STL`. -3. Open a terminal in the IDE with `` Ctrl + ` `` (by default) or press on "View" in the top bar, and then "Terminal". -4. In the terminal, invoke `git submodule update --init --progress llvm-project vcpkg` -5. In the terminal, invoke `.\vcpkg\bootstrap-vcpkg.bat` -6. In the terminal, invoke `.\vcpkg\vcpkg.exe install boost-math:x86-windows boost-math:x64-windows` -7. Choose the architecture you wish to build in the IDE, and build as you would any other project. All necessary CMake - settings are set by `CMakeSettings.json`. - -# How To Build With A Native Tools Command Prompt - -1. Install Visual Studio 2019 16.9 Preview 4 or later. - * We recommend selecting "C++ CMake tools for Windows" in the VS Installer. - This will ensure that you're using supported versions of CMake and Ninja. - * Otherwise, install [CMake][] 3.19 or later, and [Ninja][] 1.10.2 or later. -2. Open a command prompt. -3. Change directories to a location where you'd like a clone of this STL repository. -4. `git clone https://github.com/microsoft/STL` -5. `cd STL` -6. `git submodule update --init --progress llvm-project vcpkg` -7. `.\vcpkg\bootstrap-vcpkg.bat` -8. `.\vcpkg\vcpkg.exe install boost-math:x86-windows boost-math:x64-windows` +1. Open Visual Studio and select "Clone a repository". +2. Enter `https://github.com/microsoft/STL.git` as the repository location. Choose a local path. Click "Clone". +3. File > Open > Folder... > Select the folder that you just cloned the repository into. +4. Use the IDE's dropdown menu to choose the architecture you want to build. We recommend x64 for general development. +5. Build > Build All. + +# How To Build With The Command Prompt + +1. Open a command prompt. +2. Change directories to a location where you'd like a clone of this STL repository. +3. `git clone https://github.com/microsoft/STL.git --recurse-submodules` +4. `pushd STL` + +The following instructions assume that you're starting in the previously cloned `STL` directory. +If you installed VS to a non-default location, change the `vcvarsall.bat` paths below accordingly. + +To build the x64 target (recommended): + +1. `pushd "%ProgramFiles%\Microsoft Visual Studio\18\Insiders\VC\Auxiliary\Build"` +1. `vcvarsall.bat x64 -vcvars_ver=preview` +1. `popd` +1. `cmake --preset x64` +1. `cmake --build --preset x64` To build the x86 target: -1. Open an "x86 Native Tools Command Prompt for VS 2019". -2. Change directories to the previously cloned `STL` directory. -3. `cmake -G Ninja -S . -B out\build\x86` -4. `ninja -C out\build\x86` +1. `pushd "%ProgramFiles%\Microsoft Visual Studio\18\Insiders\VC\Auxiliary\Build"` +1. `vcvarsall.bat x86 -vcvars_ver=preview` +1. `popd` +1. `cmake --preset x86` +1. `cmake --build --preset x86` -To build the x64 target: +To build the ARM64 target: -1. Open an "x64 Native Tools Command Prompt for VS 2019". -2. Change directories to the previously cloned `STL` directory. -3. `cmake -G Ninja -S . -B out\build\x64` -4. `ninja -C out\build\x64` +1. `pushd "%ProgramFiles%\Microsoft Visual Studio\18\Insiders\VC\Auxiliary\Build"` +1. `vcvarsall.bat x64_arm64 -vcvars_ver=preview` +1. `popd` +1. `cmake --preset ARM64` +1. `cmake --build --preset ARM64` + +To build the ARM64EC target: + +1. `pushd "%ProgramFiles%\Microsoft Visual Studio\18\Insiders\VC\Auxiliary\Build"` +1. `vcvarsall.bat x64_arm64 -vcvars_ver=preview` +1. `popd` +1. `cmake --preset ARM64EC` +1. `cmake --build --preset ARM64EC` # How To Consume Consumption of the built library is largely based on the build system you're using. There are at least 2 directories you need to hook up. Assuming you built the x64 target with the Visual Studio IDE, with the STL repository cloned to -`C:\Dev\STL`, build outputs will end up at `C:\Dev\STL\out\build\x64\out`. Ensure that the `inc` directory is searched +`C:\Dev\STL`, build outputs will end up at `C:\Dev\STL\out\x64\out`. Ensure that the `inc` directory is searched for headers, and that `lib\{architecture}` is searched for link libraries, before any defaults supplied by MSVC. The names of the import and static libraries are the same as those that ship with MSVC. As a result, the compiler `/MD`, `/MDd`, `/MT`, or `/MTd` switches will work without modification of your build scripts or command-line muscle memory. Should you choose to use the DLL flavors, the DLLs to deploy are built to `bin\{architecture}`. Note that the DLLs generated by the CMake build system here have a suffix, defaulting to `_oss`, which distinguishes them from the binaries -that ship with MSVC. That avoids any conflict with the DLLs installed by the [redistributables][] into System32, and +that ship with MSVC. That avoids any conflict with the DLLs installed by the [redistributables][] into System32 and ensures that other components wanting to be a "guest in your process", like print drivers and shell extensions, see the export surface of the STL they were built with. Otherwise, the "`msvcp140.dll`" you deployed in the same directory as your .exe would "win" over the versions in System32. -## Complete Example Using x64 DLL Flavor - 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": +for DLL dependencies according to directories in the `PATH` environment variable. +The build generates a batch script named `set_environment.bat` in the output directory. If you run this script, +it will insert the proper directories into the `INCLUDE`, `LIB`, and `PATH` environment +variables to ensure that the built headers and libraries are used. + +## Complete Example Using x64 DLL Flavor ``` -C:\Users\username\Desktop>set INCLUDE=C:\Dev\STL\out\build\x64\out\inc;%INCLUDE% +C:\Temp>pushd D:\GitHub\STL -C:\Users\username\Desktop>set LIB=C:\Dev\STL\out\build\x64\out\lib\amd64;%LIB% +D:\GitHub\STL>pushd "%ProgramFiles%\Microsoft Visual Studio\18\Insiders\VC\Auxiliary\Build" -C:\Users\username\Desktop>set PATH=C:\Dev\STL\out\build\x64\out\bin\amd64;%PATH% +C:\Program Files\Microsoft Visual Studio\18\Insiders\VC\Auxiliary\Build>vcvarsall.bat x64 -vcvars_ver=preview +********************************************************************** +** Visual Studio 2026 Developer Command Prompt v18.4.0-insiders +** Copyright (c) 2026 Microsoft Corporation +********************************************************************** +[vcvarsall.bat] Environment initialized for: 'x64' -C:\Users\username\Desktop>type example.cpp -#include +C:\Program Files\Microsoft Visual Studio\18\Insiders\VC\Auxiliary\Build>popd + +D:\GitHub\STL>cmake --preset x64 +[...] +-- Build files have been written to: D:/GitHub/STL/out/x64 + +D:\GitHub\STL>cmake --build --preset x64 +[762/762] Linking CXX static library out\lib\amd64\libcpmtd0.lib + +D:\GitHub\STL>out\x64\set_environment.bat + +D:\GitHub\STL>popd + +C:\Temp>type .\example.cpp +``` +```cpp +#include int main() { - std::cout << "Hello STL OSS world!\n"; + std::println("Hello STL OSS world!"); } - -C:\Users\username\Desktop>cl /nologo /EHsc /W4 /WX /MDd /std:c++latest .\example.cpp +``` +``` +C:\Temp>cl /EHsc /nologo /W4 /WX /MDd /std:c++latest .\example.cpp example.cpp -C:\Users\username\Desktop>.\example.exe +C:\Temp>.\example.exe Hello STL OSS world! -C:\Users\username\Desktop>dumpbin /IMPORTS .\example.exe | findstr msvcp +C:\Temp>dumpbin /DEPENDENTS .\example.exe | findstr msvcp msvcp140d_oss.dll ``` -# How To Run The Tests With A Native Tools Command Prompt - -1. Follow either [How To Build With A Native Tools Command Prompt][] or [How To Build With The Visual Studio IDE][]. -2. Acquire [Python][] 3.9.1 or newer and have it on the `PATH` (or run it directly using its absolute or relative path). -3. Have LLVM's `bin` directory on the `PATH` (so `clang-cl.exe` is available). - * We recommend selecting "C++ Clang tools for Windows" in the VS Installer. This will automatically add LLVM to the - `PATH` of the x86 and x64 Native Tools Command Prompts, and will ensure that you're using a supported version. - * Otherwise, use [LLVM's installer][] and choose to add LLVM to your `PATH` during installation. -4. Follow the instructions below. - -## Running All The Tests - -After configuring and building the project, running `ctest` from the build output directory will run all the tests. -CTest will only display the standard error output of tests that failed. In order to get more details from CTest's -`lit` invocations, run the tests with `ctest -V`. +# How To Run The Tests -## Running A Subset Of The Tests +Our tests are currently split across three test suites that are located at `tests\std`, `tests\tr1`, and +`llvm-project\libcxx\test\std`. The test runner `${PROJECT_BINARY_DIR}\tests\utils\stl-lit\stl-lit.py` accepts paths to +directories in the test suites and runs all tests located in the subtree rooted at those paths. This can mean executing +the entirety of a single test suite, running all tests under a category in `libcxx`, or running a single test in `std` +and `tr1`. -`${PROJECT_BINARY_DIR}\tests\utils\stl-lit\stl-lit.py` can be invoked on a subdirectory of a testsuite and will execute -all the tests under that subdirectory. This can mean executing the entirety of a single testsuite, running all tests -under a category in libcxx, or running a single test in `std` and `tr1`. +Some useful `stl-lit.py` options: +* `-v` (verbose) tells `stl-lit.py` to show us output from failed test cases. +* `-Dnotags=ASAN` disables the "extra ASan configs" that we typically run only in CI. This is useful to limit runtime + for full validation runs, but often omitted when running just a few test cases to enable the extra ASan coverage. ## Examples -These examples assume that your current directory is `C:\Dev\STL\out\build\x64`. - -* This command will run all of the testsuites with verbose output. - + `ctest -V` -* This command will also run all of the testsuites. - + `python tests\utils\stl-lit\stl-lit.py ..\..\..\llvm-project\libcxx\test ..\..\..\tests\std ..\..\..\tests\tr1` -* This command will run all of the std testsuite. - + `python tests\utils\stl-lit\stl-lit.py ..\..\..\tests\std` -* If you want to run a subset of a testsuite, you need to point it to the right place in the sources. The following -will run the single test found under VSO_0000000_any_calling_conventions. - + `python tests\utils\stl-lit\stl-lit.py ..\..\..\tests\std\tests\VSO_0000000_any_calling_conventions` -* You can invoke `stl-lit` with any arbitrary subdirectory of a testsuite. In libcxx this allows you to have finer +These examples assume that your current directory is `C:\Dev\STL\out\x64`. + +* This command will run all of the test suites: + + `python tests\utils\stl-lit\stl-lit.py -Dnotags=ASAN ..\..\llvm-project\libcxx\test ..\..\tests\std ..\..\tests\tr1` +* This command will run only the std test suite. + + `python tests\utils\stl-lit\stl-lit.py -Dnotags=ASAN ..\..\tests\std` +* If you want to run a subset of a test suite, you need to point it to the right place in the sources. The following +will run the single test found under `VSO_0000000_any_calling_conventions`. + + `python tests\utils\stl-lit\stl-lit.py -Dnotags=ASAN ..\..\tests\std\tests\VSO_0000000_any_calling_conventions` +* You can invoke `stl-lit` with any arbitrary subdirectory of a test suite. In libcxx this allows you to have finer control over what category of tests you would like to run. The following will run all the libcxx map tests. - + `python tests\utils\stl-lit\stl-lit.py ..\..\..\llvm-project\libcxx\test\std\containers\associative\map` + + `python tests\utils\stl-lit\stl-lit.py -Dnotags=ASAN ..\..\llvm-project\libcxx\test\std\containers\associative\map` +* You can also use the `--filter` option to include tests whose names match a regular expression. The following + command will run tests with "atomic_wait" in their names in both the std and libcxx test suites. + + `python tests\utils\stl-lit\stl-lit.py ..\..\llvm-project\libcxx\test ..\..\tests\std --filter=atomic_wait` +* There's also a `--filter-out` option to exclude tests matching a regular expression; + `--filter=iota --filter-out=view` would run tests with names matching "iota" but not "view". ## Interpreting The Results Of Tests -### CTest - -When running the tests via CTest, all of the testsuites are considered to be a single test. If any single test in a -testsuite fails, CTest will simply report that the `stl` test failed. - -Example: -``` -0% tests passed, 1 tests failed out of 1 - -Total Test time (real) = 2441.55 sec - -The following tests FAILED: - 1 - stl (Failed) -``` - -The primary utility of CTest in this case is to conveniently invoke `stl-lit.py` with the correct set of arguments. - -CTest will output everything that was sent to stderr for each of the failed testsuites, which can be used to identify -which individual test within the testsuite failed. It can sometimes be helpful to run CTest with the `-V` option in -order to see the stdout of the tests. - -### stl-lit - -When running the tests directly via the generated `stl-lit.py` script the result of each test will be printed. The -format of each result is `{Result Code}: {Testsuite Name} :: {Test Name}:{Configuration Number}`. +`stl-lit.py` prints the result of each test. The format of each result is +`{Result Code}: {Test Suite Name} :: {Test Name}:{Configuration Number}`. Example: ``` @@ -335,7 +357,7 @@ Testing Time: 3.96s Unsupported Tests : 5 ``` -In the above example we see that 23 tests succeeded and 5 were unsupported. +In the above example, we see that 23 tests succeeded and 5 were unsupported. ### Result Code Values @@ -346,21 +368,163 @@ The `PASS` and `FAIL` result codes are self-explanatory. We want our tests to `P The `XPASS` and `XFAIL` result codes are less obvious. `XPASS` is actually a failure result and indicates that we expected a test to fail but it passed. `XFAIL` is a successful result and indicates that we expected the test to fail -and it did. Typically an `XPASS` result means that the `expected_results.txt` file for the testsuite needs to be +and it did. Typically an `XPASS` result means that the `expected_results.txt` file for the test suite needs to be modified. If the `XPASS` result is a test legitimately passing, the usual course of action would be to remove a `FAIL` entry from the `expected_results.txt`. However, some tests from `libcxx` mark themselves as `XFAIL` (meaning they expect to fail) for features they have added tests for but have yet to implement in `libcxx`. If the STL implements those features first the tests will begin passing unexpectedly for us and return `XPASS` results. In order to resolve -this it is necessary to add a `PASS` entry to the `expected_results.txt` of the testsuite in question. +this it is necessary to add a `PASS` entry to the `expected_results.txt` of the test suite in question. -The `UNSUPPORTED` result code means that the requirements for a test are not met and so it will not be run. Currently -all tests which use the `/BE` or `/clr:pure` options are unsupported. +The `UNSUPPORTED` result code means that the requirements for a test are not met and so it will not be run. Currently, +all tests which use the `/clr` or `/clr:pure` options are unsupported. Also, the `/BE` option is unsupported for x86. The `SKIPPED` result code indicates that a given test was explicitly skipped by adding a `SKIPPED` entry to the `expected_results.txt`. A test may be skipped for a number of reasons, which include, but are not limited to: * being an incorrect test * taking a very long time to run -* failing or passing for the incorrect reason +* failing or passing for an 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:\Dev\STL\out\x64> ninja +C:\Dev\STL\out\x64> python tests\utils\stl-lit\stl-lit.py -v C:\Dev\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:\Dev\STL\out\x64>cl "C:\Dev\STL\tests\std\tests\GH_XXXX_meow\test.cpp" [... more arguments ...] +"-FeC:\Dev\STL\out\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:\Dev\STL\out\x64\tests\std\tests\GH_XXXX_meow\Output\02\GH_XXXX_meow.exe" + "C:\Dev\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:\Dev\STL\out\x64\out\bin\amd64;%PATH% +``` + +## Running Tests With Address Sanitizer (ASan) + +You don't need any extra steps to run with test code and the code in STL headers instrumented with [ASan][]. +The test matrices include both ASan and non-ASan configurations if you don't pass `-Dtags=ASAN` or `-Dnotags=ASAN` +to exclude one or the other. + +However, to instrument the separately-compiled code (the DLL, the satellites, the [Import Library][] - everything that's +in `stl\src`), you need to build the STL with ASan. Change the build steps to add `-DSTL_ASAN_BUILD=ON`: + +``` +cmake --preset x64 -DSTL_ASAN_BUILD=ON +cmake --build --preset x64 +``` + +ASan-instrumented STL binaries require that the executable be instrumented as well, so you'll have to skip the non-ASan +configurations by passing `-Dtags=ASAN` to `stl-lit.py`: + +(This example assumes that your current directory is `C:\Dev\STL\out\x64`.) + +``` +python tests\utils\stl-lit\stl-lit.py ..\..\tests\std\tests\VSO_0000000_vector_algorithms -Dtags=ASAN -v +``` + +# Benchmarking + +For performance-sensitive code (e.g. containers and algorithms) +you may wish to write and/or run benchmarks, and the STL team will likely +run any benchmarks we do have in our PR process. Additionally, +if you are writing a "performance improvement" PR, please add and run benchmarks +to show that the PR does, in fact, improve performance. + +The benchmarking code is located in `benchmarks`. Adding a new benchmark is as easy as adding a new file +to `benchmarks/src`, and then adding `add_benchmark( )` +to `benchmarks/CMakeLists.txt`. +You may also modify an existing benchmark file. We use Google's [Benchmark][gbenchmark] library, +so you may find [their documentation][gbenchmark:docs] helpful, and you can also read the existing code +for how _we_ use it. + +To run benchmarks, you'll need to first build the STL, then build the benchmarks: + +```cmd +cmake --preset x64 +cmake --build --preset x64 +cmake -B out\bench -S benchmarks -G Ninja -DSTL_BINARY_DIR=out\x64 +cmake --build out\bench +``` + +You can then run your benchmark with: + +```cmd +out\bench\benchmark- --benchmark_out= --benchmark_out_format=csv +``` + +And then you can copy this CSV file into Excel, or another spreadsheet program. For example: + +```cmd +out\bench\benchmark-std_copy --benchmark_out=benchmark-std_copy-results.csv --benchmark_out_format=csv +``` + +If you want to see all the other flags you can pass, run: + +```cmd +out\bench\benchmark- --help +``` + +## Other Useful Incantations + +To compile the benchmarks with additional compiler options, use the [`CXXFLAGS` environment variable][CXXFLAGS]. +Set it after configuring and building the STL, but before configuring and building the benchmarks. +For example, to examine how the `/arch:AVX2` option affects auto-vectorization and bit algorithm intrinsics: + +``` +set CXXFLAGS=/arch:AVX2 +cmake -B out\bench -S benchmarks -G Ninja -DSTL_BINARY_DIR=out\x64 +cmake --build out\bench +``` + +To compile the benchmarks with Clang, use `-DCMAKE_CXX_COMPILER=clang-cl`: + +``` +cmake -B out\bench -S benchmarks -G Ninja -DSTL_BINARY_DIR=out\x64 -DCMAKE_CXX_COMPILER=clang-cl +cmake --build out\bench +``` + +To run a benchmark on specific cores (e.g. P-cores vs. E-cores) and with higher priority +(to avoid interference), use the [`start` command][start-command]: + +``` +start /b /wait /high /affinity 0F out\bench\benchmark-std_copy +``` + +# 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 @@ -368,7 +532,40 @@ The STL is built atop other compiler support libraries that ship with Windows an VCRuntime, and VCStartup. The following diagram describes the dependencies between those components and their ship vehicles. -![MSVC Libraries Block Diagram](docs/msvc_libraries.plantuml.svg) +```mermaid +flowchart TB +%%{ init: {"flowchart": {"htmlLabels": true}} }%% + classDef default text-align:left + subgraph VisualStudioSubgraph[Visual Studio] + direction TB + STLNode("STL + This repo; provides C++ Standard Library headers, separately + compiled implementations of most of the iostreams functionality, + and a few runtime support components like std::exception_ptr.") + subgraph VCRuntimeSubgraph[VCRuntime] + direction TB + VCStartupNode("VCStartup + Provides compiler support mechanisms that + live in each binary; such as machinery to + call constructors and destructors for global + variables, the entry point, and the /GS cookie.
+ Merged into static and import libraries of VCRuntime.") + VCRuntimeNode("VCRuntime + Provides compiler support mechanisms that can be + shared between binaries; code that the compiler calls + on your behalf, such as the C++ exception handling + runtime, string.h intrinsics, math intrinsics, and + declarations for CPU-vendor-specific intrinsics.") + end + end + subgraph WindowsSDKSubgraph[Windows SDK] + UniversalCRTNode("Universal CRT + Windows component that provides C library support, such as printf, + C locales, and some POSIX-like shims for the Windows API, like _stat.") + end + STLNode ==> VCRuntimeSubgraph & UniversalCRTNode + VCStartupNode ==> VCRuntimeNode ==> UniversalCRTNode +``` # Contributing @@ -380,10 +577,13 @@ When you submit a pull request, a CLA bot will automatically determine whether y a CLA and decorate the PR appropriately (e.g., status check, comment). Simply follow the instructions provided by the bot. You will only need to do this once across all repos using our CLA. +See [CONTRIBUTING.md][] for more information. + # Code Of Conduct -This project has adopted the [Microsoft Open Source Code of Conduct][]. For more information see the -[Code of Conduct FAQ][] or contact [opencode@microsoft.com][] with any additional questions or comments. +This project has adopted the [Microsoft Open Source Code of Conduct][]. + +See [CODE_OF_CONDUCT.md][] for more information. # License @@ -393,33 +593,37 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception [Changelog]: https://github.com/microsoft/STL/wiki/Changelog [clang-format]: https://clang.llvm.org/docs/ClangFormat.html -[CMake]: https://cmake.org/download -[Code of Conduct FAQ]: https://opensource.microsoft.com/codeofconduct/faq/ +[CODE_OF_CONDUCT.md]: CODE_OF_CONDUCT.md [Compiler Explorer]: https://godbolt.org +[CONTRIBUTING.md]: CONTRIBUTING.md [Developer Community]: https://aka.ms/feedback/report?space=62 [Discord server]: https://discord.gg/XWanNww -[How To Build With A Native Tools Command Prompt]: #how-to-build-with-a-native-tools-command-prompt -[How To Build With The Visual Studio IDE]: #how-to-build-with-the-visual-studio-ide [LICENSE.txt]: LICENSE.txt -[LLVM's installer]: https://releases.llvm.org/download.html [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 +[N5032]: https://wg21.link/N5032 [NOTICE.txt]: NOTICE.txt -[Ninja]: https://ninja-build.org -[Pipelines]: https://dev.azure.com/vclibs/STL/_build/latest?definitionId=4&branchName=main +[STL-CI-badge]: https://dev.azure.com/vclibs/STL/_apis/build/status%2FSTL-CI?branchName=main "STL-CI" +[STL-CI-link]: https://dev.azure.com/vclibs/STL/_build/latest?definitionId=4&branchName=main +[STL-ASan-CI-badge]: https://dev.azure.com/vclibs/STL/_apis/build/status%2FSTL-ASan-CI?branchName=main "STL-ASan-CI" +[STL-ASan-CI-link]: https://dev.azure.com/vclibs/STL/_build/latest?definitionId=5&branchName=main [Python]: https://www.python.org/downloads/windows/ [Roadmap]: https://github.com/microsoft/STL/wiki/Roadmap [Status Chart]: https://microsoft.github.io/STL/ -[Wandbox]: https://wandbox.org [bug tag]: https://github.com/microsoft/STL/issues?q=is%3Aopen+is%3Aissue+label%3Abug [cxx20 tag]: https://github.com/microsoft/STL/issues?q=is%3Aopen+is%3Aissue+label%3Acxx20 [enhancement tag]: https://github.com/microsoft/STL/issues?q=is%3Aopen+is%3Aissue+label%3Aenhancement +[gbenchmark]: https://github.com/google/benchmark +[gbenchmark:docs]: https://github.com/google/benchmark/blob/main/docs/user_guide.md [hub]: https://support.microsoft.com/en-us/help/4021566/windows-10-send-feedback-to-microsoft-with-feedback-hub-app [libcxx]: https://libcxx.llvm.org [lit]: https://llvm.org/docs/CommandGuide/lit.html [lit result codes]: https://llvm.org/docs/CommandGuide/lit.html#test-status-results -[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 +[redistributables]: https://learn.microsoft.com/en-US/cpp/windows/latest-supported-vc-redist +[natvis documentation]: https://learn.microsoft.com/en-us/visualstudio/debugger/create-custom-views-of-native-objects +[ASan]: https://learn.microsoft.com/en-us/cpp/sanitizers/asan +[Import Library]: /docs/import_library.md +[VS 2026 Insiders]: https://visualstudio.microsoft.com/insiders/ +[CXXFLAGS]: https://cmake.org/cmake/help/latest/envvar/CXXFLAGS.html +[start-command]: https://learn.microsoft.com/en-us/windows-server/administration/windows-commands/start diff --git a/SECURITY.md b/SECURITY.md index 57fdc268902..b3c89efc852 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -1,46 +1,41 @@ - - -## Security - -Microsoft takes the security of our software products and services seriously, which includes all source code -repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/Microsoft), -[Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), -[Xamarin](https://github.com/xamarin), and [many more](https://opensource.microsoft.com/). - -If you believe you have found a security vulnerability in any Microsoft-owned repository that meets Microsoft's -[definition](https://docs.microsoft.com/en-us/previous-versions/tn-archive/cc751383(v=technet.10)) of a security -vulnerability, please report it to us as described below. - -## Reporting Security Issues - -**Please do not report security vulnerabilities through public GitHub issues.** Instead, please report them to the -Microsoft Security Response Center at [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your -message with our PGP key; please download it from the -[Microsoft Security Response Center PGP Key page](https://technet.microsoft.com/en-us/security/dn606155). - -You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we -received your original message. Additional information can be found at -[microsoft.com/msrc](https://www.microsoft.com/msrc). - -Please include the requested information listed below (as much as you can provide) to help us better understand the -nature and scope of the possible issue: - - * Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.) - * Full paths of source file(s) related to the manifestation of the issue - * The location of the affected source code (tag/branch/commit or direct URL) - * Any special configuration required to reproduce the issue - * Step-by-step instructions to reproduce the issue - * Proof-of-concept or exploit code (if possible) - * Impact of the issue, including how an attacker might exploit the issue - -This information will help us triage your report more quickly. - -## Preferred Languages - -We prefer all communications to be in English. - -## Policy - -Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://www.microsoft.com/en-us/msrc/cvd). - - + + +## Security + +Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/Microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet) and [Xamarin](https://github.com/xamarin). + +If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://aka.ms/security.md/definition), please report it to us as described below. + +## Reporting Security Issues + +**Please do not report security vulnerabilities through public GitHub issues.** + +Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://aka.ms/security.md/msrc/create-report). + +If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://aka.ms/security.md/msrc/pgp). + +You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://www.microsoft.com/msrc). + +Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue: + + * Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.) + * Full paths of source file(s) related to the manifestation of the issue + * The location of the affected source code (tag/branch/commit or direct URL) + * Any special configuration required to reproduce the issue + * Step-by-step instructions to reproduce the issue + * Proof-of-concept or exploit code (if possible) + * Impact of the issue, including how an attacker might exploit the issue + +This information will help us triage your report more quickly. + +If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://aka.ms/security.md/msrc/bounty) page for more details about our active programs. + +## Preferred Languages + +We prefer all communications to be in English. + +## Policy + +Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://aka.ms/security.md/cvd). + + diff --git a/azure-devops/asan-pipeline.yml b/azure-devops/asan-pipeline.yml new file mode 100644 index 00000000000..a035ffb76f8 --- /dev/null +++ b/azure-devops/asan-pipeline.yml @@ -0,0 +1,62 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +# Build STL targeting x64, x86, and arm64, then run extra ASan testing + +variables: + - template: config.yml + +trigger: none + +schedules: +- cron: '0 2 * * *' + displayName: ASan-Daily-CI + branches: + include: + - main + +stages: + - stage: Test_x64_ASan + displayName: 'Test x64 ASan' + dependsOn: [] + pool: + name: ${{ variables.poolName }} + demands: ${{ variables.poolDemands }} + jobs: + - template: build-and-test.yml + parameters: + hostArch: x64 + targetArch: x64 + targetPlatform: x64 + asanBuild: true + testTargets: STL-ASan-CI + + - stage: Test_x86_ASan + displayName: 'Test x86 ASan' + dependsOn: [] + pool: + name: ${{ variables.poolName }} + demands: ${{ variables.poolDemands }} + jobs: + - template: build-and-test.yml + parameters: + hostArch: x86 + targetArch: x86 + targetPlatform: x86 + asanBuild: true + testTargets: STL-ASan-CI + + - stage: Test_ARM64_ASan + displayName: 'Test ARM64 ASan' + dependsOn: [] + pool: + name: ${{ variables.arm64PoolName }} + demands: ${{ variables.poolDemands }} + jobs: + - template: build-and-test.yml + parameters: + hostArch: arm64 + targetArch: arm64 + targetPlatform: arm64 + asanBuild: true + testTargets: STL-ASan-CI diff --git a/azure-devops/build-and-test.yml b/azure-devops/build-and-test.yml new file mode 100644 index 00000000000..c37891ffe60 --- /dev/null +++ b/azure-devops/build-and-test.yml @@ -0,0 +1,90 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +parameters: +- name: hostArch + type: string +- name: targetArch + type: string +- name: targetPlatform + type: string +- name: analyzeBuild + type: boolean + default: false +- name: asanBuild + type: boolean + default: false +- name: buildBenchmarks + type: boolean + default: false +- name: testTargets + type: string + default: 'STL-CI' +- name: numShards + type: number + default: 10 +- name: configureTesting + type: boolean + default: true +- name: buildStl + type: boolean + default: true +- name: runTesting + type: boolean + default: true +- name: testsBuildOnly + type: boolean + default: false +jobs: +- job: '${{ parameters.targetPlatform }}' + strategy: + parallel: ${{ parameters.numShards }} + timeoutInMinutes: 30 + steps: + - template: checkout-self.yml + - template: checkout-submodule.yml + parameters: + enabled: ${{ parameters.configureTesting }} + path: 'llvm-project' + url: 'https://github.com/llvm/llvm-project.git' + - template: checkout-submodule.yml + parameters: + enabled: true + path: 'boost-math' + url: 'https://github.com/boostorg/math.git' + - template: checkout-submodule.yml + parameters: + enabled: ${{ parameters.buildBenchmarks }} + path: 'benchmarks/google-benchmark' + url: 'https://github.com/google/benchmark.git' + - template: cmake-configure-build.yml + parameters: + hostArch: ${{ parameters.hostArch }} + targetArch: ${{ parameters.targetArch }} + targetPlatform: ${{ parameters.targetPlatform }} + analyzeBuild: ${{ parameters.analyzeBuild }} + asanBuild: ${{ parameters.asanBuild }} + configureTesting: ${{ parameters.configureTesting }} + buildStl: ${{ parameters.buildStl }} + testsBuildOnly: ${{ parameters.testsBuildOnly }} + - template: build-benchmarks.yml + parameters: + hostArch: ${{ parameters.hostArch }} + targetArch: ${{ parameters.targetArch }} + targetPlatform: ${{ parameters.targetPlatform }} + buildBenchmarks: ${{ parameters.buildBenchmarks }} + compiler: cl + - template: build-benchmarks.yml + parameters: + hostArch: ${{ parameters.hostArch }} + targetArch: ${{ parameters.targetArch }} + targetPlatform: ${{ parameters.targetPlatform }} + buildBenchmarks: ${{ parameters.buildBenchmarks }} + compiler: clang-cl + - template: run-tests.yml + parameters: + hostArch: ${{ parameters.hostArch }} + targetArch: ${{ parameters.targetArch }} + targetPlatform: ${{ parameters.targetPlatform }} + testTargets: ${{ parameters.testTargets }} + runTesting: ${{ parameters.runTesting }} diff --git a/azure-devops/build-benchmarks.yml b/azure-devops/build-benchmarks.yml new file mode 100644 index 00000000000..59d9db7d15a --- /dev/null +++ b/azure-devops/build-benchmarks.yml @@ -0,0 +1,56 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +parameters: +- name: hostArch + type: string +- name: targetArch + type: string +- name: targetPlatform + type: string +- name: buildBenchmarks + type: boolean +- name: compiler + type: string + +steps: +- task: PowerShell@2 + displayName: 'Configure Benchmarks for ${{ parameters.compiler }}' + inputs: + pwsh: true + targetType: inline + script: | + $PSNativeCommandUseErrorActionPreference = $true + if (Test-Path -LiteralPath "$(benchmarkBuildOutputLocation)\${{ parameters.compiler }}") { + Remove-Item -LiteralPath "$(benchmarkBuildOutputLocation)\${{ parameters.compiler }}" -Recurse -Force + } + & "$(launchVsDevShell)" -HostArch ${{ parameters.hostArch }} -Arch ${{ parameters.targetArch }} + cmake -G Ninja ` + -DCMAKE_CXX_COMPILER=${{ parameters.compiler }} ` + -DCMAKE_BUILD_TYPE=Release ` + -DSTL_BINARY_DIR="$(buildOutputLocation)" ` + -DVCLIBS_TARGET_ARCHITECTURE=${{ parameters.targetPlatform }} ` + -S $(Build.SourcesDirectory)/benchmarks -B "$(benchmarkBuildOutputLocation)\${{ parameters.compiler }}" + timeoutInMinutes: 2 + env: { TMP: $(tmpDir), TEMP: $(tmpDir) } + # TRANSITION, we currently only build the benchmarks with Clang for x64 + condition: > + and(succeeded(), ${{ parameters.buildBenchmarks }}, + not(and(eq('${{ parameters.compiler }}', 'clang-cl'), + not(eq('${{ parameters.targetPlatform }}', 'x64'))))) +- task: PowerShell@2 + displayName: 'Build Benchmarks for ${{ parameters.compiler }}' + inputs: + pwsh: true + targetType: inline + script: | + $PSNativeCommandUseErrorActionPreference = $true + & "$(launchVsDevShell)" -HostArch ${{ parameters.hostArch }} -Arch ${{ parameters.targetArch }} + cmake --build "$(benchmarkBuildOutputLocation)\${{ parameters.compiler }}" + timeoutInMinutes: 2 + env: { TMP: $(tmpDir), TEMP: $(tmpDir) } + # TRANSITION, we currently only build the benchmarks with Clang for x64 + condition: > + and(succeeded(), ${{ parameters.buildBenchmarks }}, + not(and(eq('${{ parameters.compiler }}', 'clang-cl'), + not(eq('${{ parameters.targetPlatform }}', 'x64'))))) diff --git a/azure-devops/checkout-self.yml b/azure-devops/checkout-self.yml new file mode 100644 index 00000000000..9939678389f --- /dev/null +++ b/azure-devops/checkout-self.yml @@ -0,0 +1,29 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +steps: +- task: PowerShell@2 + displayName: 'Setup TMP Directory' + inputs: + pwsh: true + targetType: inline + script: | + $PSNativeCommandUseErrorActionPreference = $true + if (Test-Path -LiteralPath "$(tmpDir)") { + Remove-Item -LiteralPath "$(tmpDir)" -Recurse -Force + } + mkdir "$(tmpDir)" -Force | Out-Null +- checkout: self + clean: true + submodules: false + fetchDepth: 1 + fetchTags: false + retryCountOnTaskFailure: 4 +- task: PowerShell@2 + displayName: 'Clean After Checkout' + inputs: + pwsh: true + targetType: inline + script: | + $PSNativeCommandUseErrorActionPreference = $true + git clean --quiet -x -d -f -f diff --git a/azure-devops/checkout-sources.yml b/azure-devops/checkout-sources.yml deleted file mode 100644 index 916f72572fa..00000000000 --- a/azure-devops/checkout-sources.yml +++ /dev/null @@ -1,71 +0,0 @@ -# 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/checkout-submodule.yml b/azure-devops/checkout-submodule.yml new file mode 100644 index 00000000000..3e038a5f655 --- /dev/null +++ b/azure-devops/checkout-submodule.yml @@ -0,0 +1,34 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +parameters: +- name: enabled + type: boolean +- name: path + type: string +- name: url + type: string +steps: +- task: PowerShell@2 + displayName: 'Checkout ${{ parameters.path }} Submodule' + condition: and(succeeded(), ${{ parameters.enabled }}) + retryCountOnTaskFailure: 4 + inputs: + pwsh: true + targetType: inline + script: | + $PSNativeCommandUseErrorActionPreference = $true + $submodule = '${{ parameters.path }}' + $rawStatus = git submodule status --cached $submodule + $sha = $rawStatus -creplace '^[ \-+]([0-9a-f]+) .*$', '$1' + cd $submodule + git init + if ((git remote) -eq $null) { + git remote add submodule-upstream ${{ parameters.url }} + } + git fetch --filter=tree:0 --depth=1 submodule-upstream $sha + if ($submodule -ceq 'llvm-project') { + git sparse-checkout set --sparse-index libcxx/test libcxx/utils/libcxx llvm/utils/lit + } + git reset --quiet --hard FETCH_HEAD + git clean --quiet -x -d -f -f diff --git a/azure-devops/cmake-configure-build.yml b/azure-devops/cmake-configure-build.yml index 02e1cd93fa4..40aab7af428 100644 --- a/azure-devops/cmake-configure-build.yml +++ b/azure-devops/cmake-configure-build.yml @@ -6,47 +6,59 @@ parameters: 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: '' +- name: analyzeBuild + type: boolean +- name: asanBuild + type: boolean +- name: configureTesting + type: boolean +- name: buildStl + type: boolean +- name: testsBuildOnly + type: boolean +- name: litFlags + type: object + default: + - '--xunit-xml-output=$(buildOutputLocation)/test-results.xml' + - '--order=lexical' + - '--num-shards=$(System.TotalJobsInPhase)' + - '--run-shard=$(System.JobPositionInPhase)' + steps: - task: PowerShell@2 - displayName: 'Get Test Parallelism' - timeoutInMinutes: 1 + displayName: 'Configure STL' inputs: + pwsh: true 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' + $PSNativeCommandUseErrorActionPreference = $true + if (Test-Path -LiteralPath "$(buildOutputLocation)") { + Remove-Item -LiteralPath "$(buildOutputLocation)" -Recurse -Force + } + & "$(launchVsDevShell)" -HostArch ${{ parameters.hostArch }} -Arch ${{ parameters.targetArch }} + cmake -G Ninja ` + -DCMAKE_CXX_COMPILER=cl ` + -DCMAKE_BUILD_TYPE=Release ` + -DLIT_FLAGS="${{ join(';', parameters.litFlags) }}" ` + -DSTL_USE_ANALYZE=${{ parameters.analyzeBuild }} ` + -DSTL_ASAN_BUILD=${{ parameters.asanBuild }} ` + -DCONFIGURE_TESTING=${{ parameters.configureTesting }} ` + -DTESTS_BUILD_ONLY=${{ parameters.testsBuildOnly }} ` + -DVCLIBS_TARGET_ARCHITECTURE=${{ parameters.targetPlatform }} ` + -S $(Build.SourcesDirectory) -B "$(buildOutputLocation)" 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 +- task: PowerShell@2 + displayName: 'Build STL' + inputs: + pwsh: true + targetType: inline + script: | + $PSNativeCommandUseErrorActionPreference = $true + & "$(launchVsDevShell)" -HostArch ${{ parameters.hostArch }} -Arch ${{ parameters.targetArch }} + cmake --build "$(buildOutputLocation)" + timeoutInMinutes: 5 + condition: and(succeeded(), ${{ parameters.buildStl }}) env: { TMP: $(tmpDir), TEMP: $(tmpDir) } diff --git a/azure-devops/config.yml b/azure-devops/config.yml new file mode 100644 index 00000000000..a311bbe8b95 --- /dev/null +++ b/azure-devops/config.yml @@ -0,0 +1,36 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +# Common configuration used by both pipelines + +variables: +- name: poolName + value: 'Stl-2026-02-20T0952-x64-Pool' + readonly: true +- name: arm64PoolName + value: 'Stl-2026-02-20T0952-arm64-Pool' + readonly: true +- name: poolDemands + value: 'EnableSpotVM -equals false' + readonly: true +- name: launchVsDevShell + value: 'C:\Program Files\Microsoft Visual Studio\18\Insiders\Common7\Tools\Launch-VsDevShell.ps1' + readonly: true +- name: tmpDir + value: 'C:\stlTemp' + readonly: true +- name: buildOutputLocation + value: 'C:\stlBuild' + readonly: true +- name: benchmarkBuildOutputLocation + value: 'C:\stlBenchmark' + readonly: true +- name: validationBuildOutputLocation + value: 'C:\stlValidation' + readonly: true +- name: Codeql.SkipTaskAutoInjection + value: true + readonly: true +- name: skipComponentGovernanceDetection + value: true + readonly: true diff --git a/azure-devops/create-1es-hosted-pool.ps1 b/azure-devops/create-1es-hosted-pool.ps1 new file mode 100644 index 00000000000..69470e2f1ba --- /dev/null +++ b/azure-devops/create-1es-hosted-pool.ps1 @@ -0,0 +1,492 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +<# +.SYNOPSIS +Creates a 1ES Hosted Pool, set up for the STL's CI. + +.DESCRIPTION +See https://github.com/microsoft/STL/wiki/Checklist-for-Toolset-Updates for more information. + +.PARAMETER Arch +The architecture can be either x64 or arm64. +#> +[CmdletBinding(PositionalBinding=$false)] +Param( + [Parameter(Mandatory)][ValidateSet('x64', 'arm64')][String]$Arch +) + +$ErrorActionPreference = 'Stop' + +$CurrentDate = Get-Date +$Timestamp = $CurrentDate.ToString('yyyy-MM-ddTHHmm') + +if ($Arch -ieq 'x64') { + $Location = 'eastus2' + $VMSize = 'Standard_F32as_v6' + $PoolSize = 64 + $ImagePublisher = 'MicrosoftWindowsServer' + $ImageOffer = 'WindowsServer' + $ImageSku = '2025-datacenter-azure-edition' +} else { + # CPP_STL_GitHub has quota for 672 cores (21 VMs) in westcentralus, not currently used. + $AvailableLocations = @('eastus2', 'northeurope') # Locations where CPP_STL_GitHub has quota for 1024 cores (32 VMs). + $AvailableLocationIdx = 5 # Increment for each new pool, to cycle through the available locations. + $Location = $AvailableLocations[$AvailableLocationIdx % $AvailableLocations.Length] + $VMSize = 'Standard_D32ps_v6' + $PoolSize = 32 + $ImageId = '/SharedGalleries/WindowsServer.1P/Images/2025-datacenter-azure-edition-arm64/Versions/latest' +} + +$ProtoVMName = 'PROTOTYPE' + +$LogFile = "1es-hosted-pool-$Timestamp-$Arch.log" +$ProgressActivity = 'Preparing STL CI pool' +$TotalProgress = 38 +$CurrentProgress = 1 + +<# +.SYNOPSIS +Displays an updated progress bar. + +.DESCRIPTION +Display-ProgressBar increments $CurrentProgress and displays $Status in the progress bar. + +.PARAMETER Status +A message describing the current operation being performed. +#> +function Display-ProgressBar { + [CmdletBinding(PositionalBinding=$false)] + Param([Parameter(Mandatory)][string]$Status) + + Write-Progress ` + -Activity $ProgressActivity ` + -Status $Status ` + -PercentComplete (100 * $script:CurrentProgress++ / $TotalProgress) +} + +<# +.SYNOPSIS +Generates a random password. + +.DESCRIPTION +New-Password generates a password, randomly, of length $Length, containing +only alphanumeric characters, underscore, and dash. + +.PARAMETER Length +The length of the returned password. +#> +function New-Password { + [CmdletBinding(PositionalBinding=$false)] + Param([int]$Length = 32) + + # This 64-character alphabet generates 6 bits of entropy per character. + $alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-'.ToCharArray() + + [SecureString] $result = [SecureString]::new() + for ($idx = 0; $idx -lt $Length; $idx++) { + $result.AppendChar((Get-SecureRandom -InputObject $alphabet)) + } + + return $result +} + +#################################################################################################### +Display-ProgressBar -Status 'Silencing breaking change warnings' + +# https://aka.ms/azps-changewarnings +$Env:SuppressAzurePowerShellBreakingChangeWarnings = 'true' + +Update-AzConfig ` + -DisplayBreakingChangeWarning $false ` + -Scope 'Process' >> $LogFile + +#################################################################################################### +Display-ProgressBar -Status 'Getting the subscription context' + +if ((Get-AzContext).Subscription.Name -cne 'CPP_STL_GitHub') { + Write-Error 'Please sign in with `Connect-AzAccount -Subscription ''CPP_STL_GitHub''` before running this script.' +} + +#################################################################################################### +Display-ProgressBar -Status 'Creating resource group' + +$ResourceGroupName = "Stl-$Timestamp-$Arch" + +New-AzResourceGroup ` + -Name $ResourceGroupName ` + -Location $Location >> $LogFile + +#################################################################################################### +Display-ProgressBar -Status 'Creating credentials' + +$AdminPWSecure = New-Password +$Credential = New-Object System.Management.Automation.PSCredential ('AdminUser', $AdminPWSecure) + +#################################################################################################### +Display-ProgressBar -Status 'Creating public IP address' + +$PublicIpAddressName = "$ResourceGroupName-PublicIpAddress" +$PublicIpAddress = New-AzPublicIpAddress ` + -Name $PublicIpAddressName ` + -ResourceGroupName $ResourceGroupName ` + -Location $Location ` + -Sku 'Standard' ` + -AllocationMethod 'Static' + +#################################################################################################### +Display-ProgressBar -Status 'Creating NAT gateway' + +$NatGatewayName = "$ResourceGroupName-NatGateway" +$NatGateway = New-AzNatGateway ` + -Name $NatGatewayName ` + -ResourceGroupName $ResourceGroupName ` + -Location $Location ` + -IdleTimeoutInMinutes 10 ` + -Sku 'Standard' ` + -PublicIpAddress $PublicIpAddress + +#################################################################################################### +Display-ProgressBar -Status 'Creating network security group' + +$NetworkSecurityGroupName = "$ResourceGroupName-NetworkSecurity" +$NetworkSecurityGroup = New-AzNetworkSecurityGroup ` + -Name $NetworkSecurityGroupName ` + -ResourceGroupName $ResourceGroupName ` + -Location $Location + +#################################################################################################### +Display-ProgressBar -Status 'Creating virtual network subnet config' + +# TRANSITION, 2026-03-31: "After March 31, 2026, new virtual networks will default to using private subnets, +# meaning that an explicit outbound method must be enabled in order to reach public endpoints on the Internet +# and within Microsoft." +# https://learn.microsoft.com/en-us/azure/virtual-network/ip-services/default-outbound-access +# We're using `-DefaultOutboundAccess $false` to opt-in early. +$SubnetName = "$ResourceGroupName-Subnet" +$Subnet = New-AzVirtualNetworkSubnetConfig ` + -Name $SubnetName ` + -AddressPrefix '10.0.0.0/16' ` + -DefaultOutboundAccess $false ` + -NatGateway $NatGateway ` + -NetworkSecurityGroup $NetworkSecurityGroup + +#################################################################################################### +Display-ProgressBar -Status 'Creating virtual network' + +$VirtualNetworkName = "$ResourceGroupName-Network" +$VirtualNetwork = New-AzVirtualNetwork ` + -Name $VirtualNetworkName ` + -ResourceGroupName $ResourceGroupName ` + -Location $Location ` + -AddressPrefix '10.0.0.0/16' ` + -Subnet $Subnet + +#################################################################################################### +Display-ProgressBar -Status 'Creating network interface' + +$NicName = "$ResourceGroupName-NIC" +$Nic = New-AzNetworkInterface ` + -Name $NicName ` + -ResourceGroupName $ResourceGroupName ` + -Location $Location ` + -Subnet $VirtualNetwork.Subnets[0] + +#################################################################################################### +Display-ProgressBar -Status 'Creating prototype VM config' + +if ($Arch -ieq 'x64') { + $VM = New-AzVMConfig ` + -VMName $ProtoVMName ` + -VMSize $VMSize ` + -DiskControllerType 'NVMe' ` + -Priority 'Regular' +} else { + $VM = New-AzVMConfig ` + -VMName $ProtoVMName ` + -VMSize $VMSize ` + -DiskControllerType 'SCSI' ` + -Priority 'Regular' ` + -SecurityType 'TrustedLaunch' ` + -SharedGalleryImageId $ImageId +} + +#################################################################################################### +Display-ProgressBar -Status 'Setting prototype VM OS' + +$VM = Set-AzVMOperatingSystem ` + -VM $VM ` + -Windows ` + -ComputerName $ProtoVMName ` + -Credential $Credential ` + -ProvisionVMAgent + +#################################################################################################### +Display-ProgressBar -Status 'Adding prototype VM network interface' + +$VM = Add-AzVMNetworkInterface ` + -VM $VM ` + -Id $Nic.Id + +#################################################################################################### +Display-ProgressBar -Status 'Setting prototype VM source image' + +if ($Arch -ieq 'x64') { + $VM = Set-AzVMSourceImage ` + -VM $VM ` + -PublisherName $ImagePublisher ` + -Offer $ImageOffer ` + -Skus $ImageSku ` + -Version 'latest' +} else { + # We passed -SharedGalleryImageId to New-AzVMConfig above. +} + +#################################################################################################### +Display-ProgressBar -Status 'Setting prototype VM boot diagnostic' + +$VM = Set-AzVMBootDiagnostic ` + -VM $VM ` + -Disable + +#################################################################################################### +Display-ProgressBar -Status 'Creating prototype VM' + +New-AzVm ` + -ResourceGroupName $ResourceGroupName ` + -Location $Location ` + -VM $VM >> $LogFile + +#################################################################################################### +Display-ProgressBar -Status 'Getting prototype VM OS disk name' + +$VM = Get-AzVM ` + -ResourceGroupName $ResourceGroupName ` + -Name $ProtoVMName + +$PrototypeOSDiskName = $VM.StorageProfile.OsDisk.Name + +#################################################################################################### +Display-ProgressBar -Status 'Running provision-image.ps1 in VM' + +$ProvisionImageResult = Invoke-AzVMRunCommand ` + -ResourceId $VM.ID ` + -CommandId 'RunPowerShellScript' ` + -ScriptPath "$PSScriptRoot\provision-image.ps1" ` + -Parameter @{ 'Arch' = $Arch; } + +Write-Host $ProvisionImageResult.value.Message + +if ($ProvisionImageResult.value.Message -cnotmatch 'PROVISION_IMAGE_SUCCEEDED') { + Write-Host 'provision-image.ps1 failed, stopping VM...' + + Stop-AzVM ` + -Id $VM.ID ` + -Force >> $LogFile + + Write-Error "VM stopped. Remember to delete unusable resource group: $ResourceGroupName" +} + +#################################################################################################### +Display-ProgressBar -Status 'Restarting VM' + +Restart-AzVM ` + -Id $VM.ID >> $LogFile + +#################################################################################################### +Display-ProgressBar -Status 'Sleeping after restart' + +# The VM appears to be busy immediately after restarting. +# This workaround waits for a minute before attempting to run sysprep. +Start-Sleep -Seconds 60 + +#################################################################################################### +Display-ProgressBar -Status 'Running sysprep in VM' + +Invoke-AzVMRunCommand ` + -ResourceId $VM.ID ` + -CommandId 'RunPowerShellScript' ` + -ScriptString 'C:\Windows\system32\sysprep\sysprep.exe /oobe /generalize /mode:vm /shutdown' >> $LogFile + +#################################################################################################### +Display-ProgressBar -Status 'Waiting for VM to shut down' + +while ('PowerState/stopped' -notin (Get-AzVM -ResourceId $VM.ID -Status).Statuses.Code) { + Start-Sleep -Seconds 10 +} + +#################################################################################################### +Display-ProgressBar -Status 'Stopping VM' + +Stop-AzVM ` + -Id $VM.ID ` + -Force >> $LogFile + +#################################################################################################### +Display-ProgressBar -Status 'Generalizing VM' + +Set-AzVM ` + -Id $VM.ID ` + -Generalized >> $LogFile + +#################################################################################################### +Display-ProgressBar -Status 'Creating gallery' + +$GalleryName = "$ResourceGroupName-Gallery" -replace '-', '_' +$Gallery = New-AzGallery ` + -Location $Location ` + -ResourceGroupName $ResourceGroupName ` + -Name $GalleryName + +#################################################################################################### +Display-ProgressBar -Status 'Granting access to 1ES Resource Management' + +$ServicePrincipalObjectId = (Get-AzADServicePrincipal -DisplayName '1ES Resource Management' -First 1).Id + +New-AzRoleAssignment ` + -ObjectId $ServicePrincipalObjectId ` + -RoleDefinitionName 'Reader' ` + -Scope $Gallery.Id >> $LogFile + +#################################################################################################### +Display-ProgressBar -Status 'Creating image definition' + +$ImageDefinitionName = "$ResourceGroupName-ImageDefinition" +$FeatureTrustedLaunch = @{ Name = 'SecurityType'; Value = 'TrustedLaunch'; } +if ($Arch -ieq 'x64') { + $FeatureNVMe = @{ Name = 'DiskControllerTypes'; Value = 'SCSI, NVMe'; } +} else { + $FeatureNVMe = @{ Name = 'DiskControllerTypes'; Value = 'SCSI'; } +} +$ImageDefinitionFeatures = @($FeatureTrustedLaunch, $FeatureNVMe) +New-AzGalleryImageDefinition ` + -Location $Location ` + -ResourceGroupName $ResourceGroupName ` + -GalleryName $GalleryName ` + -Name $ImageDefinitionName ` + -OsState 'Generalized' ` + -OsType 'Windows' ` + -Publisher 'StlPublisher' ` + -Offer 'StlOffer' ` + -Sku 'StlSku' ` + -Architecture $Arch ` + -Feature $ImageDefinitionFeatures ` + -HyperVGeneration 'V2' >> $LogFile + +#################################################################################################### +Display-ProgressBar -Status 'Creating image version' + +$ImageVersionName = $CurrentDate.ToString('yyyyMMdd.HHmm.0') +$ImageVersion = New-AzGalleryImageVersion ` + -Location $Location ` + -ResourceGroupName $ResourceGroupName ` + -GalleryName $GalleryName ` + -GalleryImageDefinitionName $ImageDefinitionName ` + -Name $ImageVersionName ` + -SourceImageVMId $VM.ID + +#################################################################################################### +Display-ProgressBar -Status 'Registering CloudTest resource provider' + +Register-AzResourceProvider ` + -ProviderNamespace 'Microsoft.CloudTest' >> $LogFile + +#################################################################################################### +Display-ProgressBar -Status 'Creating 1ES image' + +$ImageName = "$ResourceGroupName-Image" +New-AzResource ` + -Location $Location ` + -ResourceGroupName $ResourceGroupName ` + -ResourceType 'Microsoft.CloudTest/Images' ` + -ResourceName $ImageName ` + -Properties @{ 'imageType' = 'SharedImageGallery'; 'resourceId' = $ImageVersion.Id; } ` + -Force >> $LogFile + +#################################################################################################### +Display-ProgressBar -Status 'Creating 1ES Hosted Pool' + +$PoolName = "$ResourceGroupName-Pool" + +$PoolProperties = @{ + 'organization' = 'https://dev.azure.com/vclibs' + 'projects' = @('STL') + 'sku' = @{ 'name' = $VMSize; 'tier' = 'StandardSSD'; 'enableSpot' = $false; } + 'images' = @(@{ 'imageName' = $ImageName; 'poolBufferPercentage' = '100'; }) + 'maxPoolSize' = $PoolSize + 'agentProfile' = @{ 'type' = 'Stateless'; } +} + +New-AzResource ` + -Location $Location ` + -ResourceGroupName $ResourceGroupName ` + -ResourceType 'Microsoft.CloudTest/hostedpools' ` + -ResourceName $PoolName ` + -Properties $PoolProperties ` + -Force >> $LogFile + +#################################################################################################### +Display-ProgressBar -Status 'Deleting unused VM' + +Remove-AzVM ` + -Id $VM.ID ` + -Force >> $LogFile + +#################################################################################################### +Display-ProgressBar -Status 'Deleting unused disk' + +Remove-AzDisk ` + -ResourceGroupName $ResourceGroupName ` + -DiskName $PrototypeOSDiskName ` + -Force >> $LogFile + +#################################################################################################### +Display-ProgressBar -Status 'Deleting unused network interface' + +Remove-AzNetworkInterface ` + -ResourceGroupName $ResourceGroupName ` + -Name $NicName ` + -Force >> $LogFile + +#################################################################################################### +Display-ProgressBar -Status 'Deleting unused virtual network' + +Remove-AzVirtualNetwork ` + -ResourceGroupName $ResourceGroupName ` + -Name $VirtualNetworkName ` + -Force >> $LogFile + +#################################################################################################### +Display-ProgressBar -Status 'Deleting unused network security group' + +Remove-AzNetworkSecurityGroup ` + -ResourceGroupName $ResourceGroupName ` + -Name $NetworkSecurityGroupName ` + -Force >> $LogFile + +#################################################################################################### +Display-ProgressBar -Status 'Deleting unused NAT gateway' + +Remove-AzNatGateway ` + -ResourceGroupName $ResourceGroupName ` + -Name $NatGatewayName ` + -Force >> $LogFile + +#################################################################################################### +Display-ProgressBar -Status 'Deleting unused public IP address' + +Remove-AzPublicIpAddress ` + -ResourceGroupName $ResourceGroupName ` + -Name $PublicIpAddressName ` + -Force >> $LogFile + +#################################################################################################### +Write-Progress -Activity $ProgressActivity -Completed + +Write-Host "Elapsed time: $(((Get-Date) - $CurrentDate).ToString('hh\:mm\:ss'))" + +if ((Get-AzResource -ResourceGroupName $ResourceGroupName -Name $PoolName) -ne $null) { + Write-Host "Created pool: $PoolName" +} else { + Write-Error "Failed to create pool: $PoolName" +} diff --git a/azure-devops/create-vmss.ps1 b/azure-devops/create-vmss.ps1 deleted file mode 100644 index 963fb7f874a..00000000000 --- a/azure-devops/create-vmss.ps1 +++ /dev/null @@ -1,405 +0,0 @@ -# Copyright (c) Microsoft Corporation. -# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - -<# -.SYNOPSIS -Creates a Windows virtual machine scale set, set up for the STL's CI. - -.DESCRIPTION -create-vmss.ps1 creates an Azure Windows VM scale set, set up for the STL's CI -system. See https://docs.microsoft.com/en-us/azure/virtual-machine-scale-sets/overview -for more information. - -This script assumes you have installed Azure tools into PowerShell by following the instructions -at https://docs.microsoft.com/en-us/powershell/azure/install-az-ps -or are running from Azure Cloud Shell. -#> - -$ErrorActionPreference = 'Stop' - -# https://aka.ms/azps-changewarnings -$Env:SuppressAzurePowerShellBreakingChangeWarnings = 'true' - -$Location = 'westus2' -$Prefix = 'StlBuild-' + (Get-Date -Format 'yyyy-MM-dd') -$VMSize = 'Standard_D32as_v4' -$ProtoVMName = 'PROTOTYPE' -$LiveVMPrefix = 'BUILD' -$WindowsServerSku = '2019-Datacenter' - -$ProgressActivity = 'Creating Scale Set' -$TotalProgress = 12 -$CurrentProgress = 1 - -<# -.SYNOPSIS -Returns whether there's a name collision in the resource group. - -.DESCRIPTION -Find-ResourceGroupNameCollision takes a list of resources, and checks if $Test -collides names with any of the resources. - -.PARAMETER Test -The name to test. - -.PARAMETER Resources -The list of resources. -#> -function Find-ResourceGroupNameCollision { - [CmdletBinding()] - Param([string]$Test, $Resources) - - foreach ($resource in $Resources) { - if ($resource.ResourceGroupName -eq $Test) { - return $true - } - } - - return $false -} - -<# -.SYNOPSIS -Attempts to find a name that does not collide with any resources in the resource group. - -.DESCRIPTION -Find-ResourceGroupName takes a set of resources from Get-AzResourceGroup, and finds the -first name in {$Prefix, $Prefix-1, $Prefix-2, ...} such that the name doesn't collide with -any of the resources in the resource group. - -.PARAMETER Prefix -The prefix of the final name; the returned name will be of the form "$Prefix(-[1-9][0-9]*)?" -#> -function Find-ResourceGroupName { - [CmdletBinding()] - Param([string] $Prefix) - - $resources = Get-AzResourceGroup - $result = $Prefix - $suffix = 0 - while (Find-ResourceGroupNameCollision -Test $result -Resources $resources) { - $suffix++ - $result = "$Prefix-$suffix" - } - - return $result -} - -<# -.SYNOPSIS -Generates a random password. - -.DESCRIPTION -New-Password generates a password, randomly, of length $Length, containing -only alphanumeric characters, underscore, and dash. - -.PARAMETER Length -The length of the returned password. -#> -function New-Password { - Param ([int] $Length = 32) - - # This 64-character alphabet generates 6 bits of entropy per character. - # The power-of-2 alphabet size allows us to select a character by masking a random Byte with bitwise-AND. - $alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-" - $mask = 63 - if ($alphabet.Length -ne 64) { - throw 'Bad alphabet length' - } - - [Byte[]]$randomData = [Byte[]]::new($Length) - $rng = $null - try { - $rng = [System.Security.Cryptography.RandomNumberGenerator]::Create() - $rng.GetBytes($randomData) - } - finally { - if ($null -ne $rng) { - $rng.Dispose() - } - } - - $result = '' - for ($idx = 0; $idx -lt $Length; $idx++) { - $result += $alphabet[$randomData[$idx] -band $mask] - } - - return $result -} - -<# -.SYNOPSIS -Waits for the shutdown of the specified resource. - -.DESCRIPTION -Wait-Shutdown takes a VM, and checks if there's a 'PowerState/stopped' -code; if there is, it returns. If there isn't, it waits 10 seconds and -tries again. - -.PARAMETER ResourceGroupName -The name of the resource group to look up the VM in. - -.PARAMETER Name -The name of the virtual machine to wait on. -#> -function Wait-Shutdown { - [CmdletBinding()] - Param([string]$ResourceGroupName, [string]$Name) - - Write-Host "Waiting for $Name to stop..." - while ($true) { - $Vm = Get-AzVM -ResourceGroupName $ResourceGroupName -Name $Name -Status - $highestStatus = $Vm.Statuses.Count - for ($idx = 0; $idx -lt $highestStatus; $idx++) { - if ($Vm.Statuses[$idx].Code -eq 'PowerState/stopped') { - return - } - } - - Write-Host "... not stopped yet, sleeping for 10 seconds" - Start-Sleep -Seconds 10 - } -} - - -#################################################################################################### -Write-Progress ` - -Activity $ProgressActivity ` - -Status 'Setting the subscription context' ` - -PercentComplete (100 / $TotalProgress * $CurrentProgress++) - -Set-AzContext -SubscriptionName CPP_STL_GitHub - -#################################################################################################### -Write-Progress ` - -Activity $ProgressActivity ` - -Status 'Creating resource group' ` - -PercentComplete (100 / $TotalProgress * $CurrentProgress++) - -$ResourceGroupName = Find-ResourceGroupName $Prefix -$AdminPW = New-Password -New-AzResourceGroup -Name $ResourceGroupName -Location $Location -$AdminPWSecure = ConvertTo-SecureString $AdminPW -AsPlainText -Force -$Credential = New-Object System.Management.Automation.PSCredential ("AdminUser", $AdminPWSecure) - -#################################################################################################### -Write-Progress ` - -Activity $ProgressActivity ` - -Status 'Creating virtual network' ` - -PercentComplete (100 / $TotalProgress * $CurrentProgress++) - -$allowHttp = New-AzNetworkSecurityRuleConfig ` - -Name AllowHTTP ` - -Description 'Allow HTTP(S)' ` - -Access Allow ` - -Protocol Tcp ` - -Direction Outbound ` - -Priority 1008 ` - -SourceAddressPrefix * ` - -SourcePortRange * ` - -DestinationAddressPrefix * ` - -DestinationPortRange @(80, 443) - -$allowDns = New-AzNetworkSecurityRuleConfig ` - -Name AllowDNS ` - -Description 'Allow DNS' ` - -Access Allow ` - -Protocol * ` - -Direction Outbound ` - -Priority 1009 ` - -SourceAddressPrefix * ` - -SourcePortRange * ` - -DestinationAddressPrefix * ` - -DestinationPortRange 53 - -$denyEverythingElse = New-AzNetworkSecurityRuleConfig ` - -Name DenyElse ` - -Description 'Deny everything else' ` - -Access Deny ` - -Protocol * ` - -Direction Outbound ` - -Priority 1010 ` - -SourceAddressPrefix * ` - -SourcePortRange * ` - -DestinationAddressPrefix * ` - -DestinationPortRange * - -$NetworkSecurityGroupName = $ResourceGroupName + '-NetworkSecurity' -$NetworkSecurityGroup = New-AzNetworkSecurityGroup ` - -Name $NetworkSecurityGroupName ` - -ResourceGroupName $ResourceGroupName ` - -Location $Location ` - -SecurityRules @($allowHttp, $allowDns, $denyEverythingElse) - -$SubnetName = $ResourceGroupName + '-Subnet' -$Subnet = New-AzVirtualNetworkSubnetConfig ` - -Name $SubnetName ` - -AddressPrefix "10.0.0.0/16" ` - -NetworkSecurityGroup $NetworkSecurityGroup - -$VirtualNetworkName = $ResourceGroupName + '-Network' -$VirtualNetwork = New-AzVirtualNetwork ` - -Name $VirtualNetworkName ` - -ResourceGroupName $ResourceGroupName ` - -Location $Location ` - -AddressPrefix "10.0.0.0/16" ` - -Subnet $Subnet - -#################################################################################################### -Write-Progress ` - -Activity 'Creating prototype VM' ` - -PercentComplete (100 / $TotalProgress * $CurrentProgress++) - -$NicName = $ResourceGroupName + '-NIC' -$Nic = New-AzNetworkInterface ` - -Name $NicName ` - -ResourceGroupName $ResourceGroupName ` - -Location $Location ` - -Subnet $VirtualNetwork.Subnets[0] - -$VM = New-AzVMConfig -Name $ProtoVMName -VMSize $VMSize -Priority 'Spot' -MaxPrice -1 -$VM = Set-AzVMOperatingSystem ` - -VM $VM ` - -Windows ` - -ComputerName $ProtoVMName ` - -Credential $Credential ` - -ProvisionVMAgent - -$VM = Add-AzVMNetworkInterface -VM $VM -Id $Nic.Id -$VM = Set-AzVMSourceImage ` - -VM $VM ` - -PublisherName 'MicrosoftWindowsServer' ` - -Offer 'WindowsServer' ` - -Skus $WindowsServerSku ` - -Version latest - -$VM = Set-AzVMBootDiagnostic -VM $VM -Disable -New-AzVm ` - -ResourceGroupName $ResourceGroupName ` - -Location $Location ` - -VM $VM - -#################################################################################################### -Write-Progress ` - -Activity $ProgressActivity ` - -Status 'Running provisioning script provision-image.ps1 in VM' ` - -PercentComplete (100 / $TotalProgress * $CurrentProgress++) - -$ProvisionImageResult = Invoke-AzVMRunCommand ` - -ResourceGroupName $ResourceGroupName ` - -VMName $ProtoVMName ` - -CommandId 'RunPowerShellScript' ` - -ScriptPath "$PSScriptRoot\provision-image.ps1" ` - -Parameter @{AdminUserPassword = $AdminPW } - -Write-Host "provision-image.ps1 output: $($ProvisionImageResult.value.Message)" - -#################################################################################################### -Write-Progress ` - -Activity $ProgressActivity ` - -Status 'Restarting VM' ` - -PercentComplete (100 / $TotalProgress * $CurrentProgress++) - -Restart-AzVM -ResourceGroupName $ResourceGroupName -Name $ProtoVMName - -#################################################################################################### -Write-Progress ` - -Activity $ProgressActivity ` - -Status 'Running provisioning script sysprep.ps1 in VM' ` - -PercentComplete (100 / $TotalProgress * $CurrentProgress++) - -Invoke-AzVMRunCommand ` - -ResourceGroupName $ResourceGroupName ` - -VMName $ProtoVMName ` - -CommandId 'RunPowerShellScript' ` - -ScriptPath "$PSScriptRoot\sysprep.ps1" - -#################################################################################################### -Write-Progress ` - -Activity $ProgressActivity ` - -Status 'Waiting for VM to shut down' ` - -PercentComplete (100 / $TotalProgress * $CurrentProgress++) - -Wait-Shutdown -ResourceGroupName $ResourceGroupName -Name $ProtoVMName - -#################################################################################################### -Write-Progress ` - -Activity $ProgressActivity ` - -Status 'Converting VM to Image' ` - -PercentComplete (100 / $TotalProgress * $CurrentProgress++) - -Stop-AzVM ` - -ResourceGroupName $ResourceGroupName ` - -Name $ProtoVMName ` - -Force - -Set-AzVM ` - -ResourceGroupName $ResourceGroupName ` - -Name $ProtoVMName ` - -Generalized - -$VM = Get-AzVM -ResourceGroupName $ResourceGroupName -Name $ProtoVMName -$PrototypeOSDiskName = $VM.StorageProfile.OsDisk.Name -$ImageConfig = New-AzImageConfig -Location $Location -SourceVirtualMachineId $VM.ID -$Image = New-AzImage -Image $ImageConfig -ImageName $ProtoVMName -ResourceGroupName $ResourceGroupName - -#################################################################################################### -Write-Progress ` - -Activity $ProgressActivity ` - -Status 'Deleting unused VM and disk' ` - -PercentComplete (100 / $TotalProgress * $CurrentProgress++) - -Remove-AzVM -Id $VM.ID -Force -Remove-AzDisk -ResourceGroupName $ResourceGroupName -DiskName $PrototypeOSDiskName -Force - -#################################################################################################### -Write-Progress ` - -Activity $ProgressActivity ` - -Status 'Creating scale set' ` - -PercentComplete (100 / $TotalProgress * $CurrentProgress++) - -$VmssIpConfigName = $ResourceGroupName + '-VmssIpConfig' -$VmssIpConfig = New-AzVmssIpConfig -SubnetId $Nic.IpConfigurations[0].Subnet.Id -Primary -Name $VmssIpConfigName -$VmssName = $ResourceGroupName + '-Vmss' -$Vmss = New-AzVmssConfig ` - -Location $Location ` - -SkuCapacity 0 ` - -SkuName $VMSize ` - -SkuTier 'Standard' ` - -Overprovision $false ` - -UpgradePolicyMode Manual ` - -EvictionPolicy Delete ` - -Priority Spot ` - -MaxPrice -1 - -$Vmss = Add-AzVmssNetworkInterfaceConfiguration ` - -VirtualMachineScaleSet $Vmss ` - -Primary $true ` - -IpConfiguration $VmssIpConfig ` - -NetworkSecurityGroupId $NetworkSecurityGroup.Id ` - -Name $NicName - -$Vmss = Set-AzVmssOsProfile ` - -VirtualMachineScaleSet $Vmss ` - -ComputerNamePrefix $LiveVMPrefix ` - -AdminUsername 'AdminUser' ` - -AdminPassword $AdminPW ` - -WindowsConfigurationProvisionVMAgent $true ` - -WindowsConfigurationEnableAutomaticUpdate $true - -$Vmss = Set-AzVmssStorageProfile ` - -VirtualMachineScaleSet $Vmss ` - -OsDiskCreateOption 'FromImage' ` - -OsDiskCaching ReadWrite ` - -ImageReferenceId $Image.Id - -New-AzVmss ` - -ResourceGroupName $ResourceGroupName ` - -Name $VmssName ` - -VirtualMachineScaleSet $Vmss - -#################################################################################################### -Write-Progress -Activity $ProgressActivity -Completed -Write-Host "Location: $Location" -Write-Host "Resource group name: $ResourceGroupName" -Write-Host 'Finished!' diff --git a/azure-devops/cross-build.yml b/azure-devops/cross-build.yml deleted file mode 100644 index 1bcae239d5b..00000000000 --- a/azure-devops/cross-build.yml +++ /dev/null @@ -1,51 +0,0 @@ -# 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/enforce-clang-format.cmd b/azure-devops/enforce-clang-format.cmd deleted file mode 100644 index 1e1010afe93..00000000000 --- a/azure-devops/enforce-clang-format.cmd +++ /dev/null @@ -1,14 +0,0 @@ -:: Copyright (c) Microsoft Corporation. -:: SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -call "%PROGRAMFILES(X86)%\Microsoft Visual Studio\2019\Preview\Common7\Tools\VsDevCmd.bat" ^ --host_arch=amd64 -arch=amd64 -no_logo -"%1" "clang-format.exe -style=file -i" ^ -stl/inc ^ -stl/src ^ -tests ^ -tools -@echo If your build fails here, you need to format the following files with: -@clang-format.exe --version -@git status --porcelain stl tests tools 1>&2 -@echo clang-format will produce the following diff: -@git diff stl tests tools 1>&2 diff --git a/azure-devops/format-validation.yml b/azure-devops/format-validation.yml new file mode 100644 index 00000000000..e5c695c4551 --- /dev/null +++ b/azure-devops/format-validation.yml @@ -0,0 +1,89 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +# run the `validator` tool, and ensure code is properly clang-formatted + +jobs: +- job: Code_Format_Validation + timeoutInMinutes: 5 + displayName: 'Validation' + steps: + - template: checkout-self.yml + - task: PowerShell@2 + displayName: 'Build Validation Tools' + inputs: + pwsh: true + targetType: inline + script: | + $PSNativeCommandUseErrorActionPreference = $true + if (Test-Path -LiteralPath "$(validationBuildOutputLocation)") { + Remove-Item -LiteralPath "$(validationBuildOutputLocation)" -Recurse -Force + } + & "$(launchVsDevShell)" -HostArch x64 -Arch x64 + cmake -G Ninja -S $(Build.SourcesDirectory)/tools -B "$(validationBuildOutputLocation)" + cmake --build "$(validationBuildOutputLocation)" + timeoutInMinutes: 5 + env: { TMP: $(tmpDir), TEMP: $(tmpDir) } + - task: PowerShell@2 + displayName: 'clang-format Files' + inputs: + pwsh: true + targetType: inline + script: | + $PSNativeCommandUseErrorActionPreference = $true + & "$(launchVsDevShell)" -HostArch x64 -Arch x64 + cmake --build "$(validationBuildOutputLocation)" --target run-format + timeoutInMinutes: 5 + env: { TMP: $(tmpDir), TEMP: $(tmpDir) } + - task: PowerShell@2 + displayName: 'Validate Files' + inputs: + pwsh: true + targetType: inline + script: | + $PSNativeCommandUseErrorActionPreference = $true + & "$(launchVsDevShell)" -HostArch x64 -Arch x64 + cmake --build "$(validationBuildOutputLocation)" --target run-validate + timeoutInMinutes: 2 + env: { TMP: $(tmpDir), TEMP: $(tmpDir) } + - task: PowerShell@2 + displayName: 'Create Diff' + inputs: + pwsh: true + targetType: inline + script: | + $PSNativeCommandUseErrorActionPreference = $true + $TempSubDir = Join-Path ([System.IO.Path]::GetTempPath()) ([System.IO.Path]::GetRandomFileName()) + mkdir $TempSubDir -Force | Out-Null + $DiffFile = Join-Path $TempSubDir 'format.diff' + git diff --ignore-submodules > $DiffFile + if ((Get-Item -LiteralPath $DiffFile).Length -ne 0) { + $message = @( + '##vso[task.logissue type=error]The files in the repo need to be properly formatted.' + '' + '##[section]To fix this, you can clang-format the entire repo with:' + ' cmake --preset x64' + ' cmake --build --preset x64 --target format' + '' + '##[section]Please avoid this in the future by configuring your editor to format-on-save.' + '' + '##[section]View expected formatting:' + '##[group] >>>>> Click this line to expand the diff: <<<<<' + Get-Content -LiteralPath $DiffFile -Raw + '##[endgroup]' + '' + '##[section]You can also download this as format.diff and apply it with `git apply`:' + ' 1. Click the failed Validation job (upper left, marked with a red X)' + ' 2. Click "1 artifact produced"' + ' 3. Click the ">" chevron to the left of "format-artifact"' + ' 4. Hover over "format.diff"' + ' 5. Click the three dots that appear on the right' + ' 6. Click "Download artifacts"' + '' + "##vso[artifact.upload artifactname=format-artifact]$DiffFile" + '##vso[task.complete result=Failed]' + ) + Write-Host ($message -join "`n") + } + condition: succeededOrFailed() + env: { TMP: $(tmpDir), TEMP: $(tmpDir) } diff --git a/azure-devops/native-build-test.yml b/azure-devops/native-build-test.yml deleted file mode 100644 index 17fa03732ae..00000000000 --- a/azure-devops/native-build-test.yml +++ /dev/null @@ -1,45 +0,0 @@ -# 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/provision-image.ps1 b/azure-devops/provision-image.ps1 index 8468b850ad6..5fa1a357764 100644 --- a/azure-devops/provision-image.ps1 +++ b/azure-devops/provision-image.ps1 @@ -3,403 +3,196 @@ <# .SYNOPSIS -Sets up a machine to be an image for a scale set. +Sets up a virtual machine to be an image for a hosted pool. .DESCRIPTION -provision-image.ps1 runs on an existing, freshly provisioned virtual machine, -and sets up that virtual machine as a build machine. After this is done, -(outside of this script), we take that machine and make it an image to be copied -for setting up new VMs in the scale set. - -This script must either be run as admin, or one must pass AdminUserPassword; -if the script is run with AdminUserPassword, it runs itself again as an -administrator. - -.PARAMETER AdminUserPassword -The administrator user's password; if this is $null, or not passed, then the -script assumes it's running on an administrator account. +create-1es-hosted-pool.ps1 (running on an STL maintainer's machine) creates a "prototype" virtual machine in Azure, +then runs provision-image.ps1 on that VM. This gives us full control over what we install for building and testing +the STL. After provision-image.ps1 is done, create-1es-hosted-pool.ps1 makes an image of the prototype VM, +creates a 1ES Hosted Pool that will spin up copies of the image as worker VMs, and finally deletes the prototype VM. + +.PARAMETER Arch +The architecture can be either x64 or arm64. #> -param( - [string]$AdminUserPassword = $null +[CmdletBinding(PositionalBinding=$false)] +Param( + [Parameter(Mandatory)][ValidateSet('x64', 'arm64')][String]$Arch ) $ErrorActionPreference = 'Stop' +$ProgressPreference = 'SilentlyContinue' -<# -.SYNOPSIS -Gets a random file path in the temp directory. - -.DESCRIPTION -Get-TempFilePath takes an extension, and returns a path with a random -filename component in the temporary directory with that extension. - -.PARAMETER Extension -The extension to use for the path. -#> -Function Get-TempFilePath { - Param( - [String]$Extension - ) - - if ([String]::IsNullOrWhiteSpace($Extension)) { - throw 'Missing Extension' - } - - $tempPath = [System.IO.Path]::GetTempPath() - $tempName = [System.IO.Path]::GetRandomFileName() + '.' + $Extension - return Join-Path $tempPath $tempName -} - -<# -.SYNOPSIS -Downloads and extracts a ZIP file to a newly created temporary subdirectory. - -.DESCRIPTION -DownloadAndExtractZip returns a path containing the extracted contents. - -.PARAMETER Url -The URL of the ZIP file to download. -#> -Function DownloadAndExtractZip { - Param( - [String]$Url - ) - - if ([String]::IsNullOrWhiteSpace($Url)) { - throw 'Missing Url' - } - - $ZipPath = Get-TempFilePath -Extension 'zip' - & curl.exe -L -o $ZipPath -s -S $Url - $TempSubdirPath = Get-TempFilePath -Extension 'dir' - Expand-Archive -Path $ZipPath -DestinationPath $TempSubdirPath -Force - - return $TempSubdirPath +if ($Env:COMPUTERNAME -cne 'PROTOTYPE') { + Write-Error 'You should not run provision-image.ps1 on your local machine.' } -$TranscriptPath = 'C:\provision-image-transcript.txt' - -if ([string]::IsNullOrEmpty($AdminUserPassword)) { - Start-Transcript -Path $TranscriptPath -UseMinimalHeader +if ($Arch -ieq 'x64') { + Write-Host 'Provisioning x64.' + $Provisioning_x64 = $true } else { - Write-Host 'AdminUser password supplied; switching to AdminUser.' - - # https://docs.microsoft.com/en-us/sysinternals/downloads/psexec - $PsToolsZipUrl = 'https://download.sysinternals.com/files/PSTools.zip' - Write-Host "Downloading: $PsToolsZipUrl" - $ExtractedPsToolsPath = DownloadAndExtractZip -Url $PsToolsZipUrl - $PsExecPath = Join-Path $ExtractedPsToolsPath 'PsExec64.exe' - - # https://github.com/PowerShell/PowerShell/releases/latest - $PowerShellZipUrl = 'https://github.com/PowerShell/PowerShell/releases/download/v7.1.1/PowerShell-7.1.1-win-x64.zip' - Write-Host "Downloading: $PowerShellZipUrl" - $ExtractedPowerShellPath = DownloadAndExtractZip -Url $PowerShellZipUrl - $PwshPath = Join-Path $ExtractedPowerShellPath 'pwsh.exe' - - $PsExecArgs = @( - '-u', - 'AdminUser', - '-p', - 'AdminUserPassword_REDACTED', - '-accepteula', - '-i', - '-h', - $PwshPath, - '-ExecutionPolicy', - 'Unrestricted', - '-File', - $PSCommandPath - ) - Write-Host "Executing: $PsExecPath $PsExecArgs" - $PsExecArgs[3] = $AdminUserPassword - - $proc = Start-Process -FilePath $PsExecPath -ArgumentList $PsExecArgs -Wait -PassThru - Write-Host 'Reading transcript...' - Get-Content -Path $TranscriptPath - Write-Host 'Cleaning up...' - Remove-Item -Recurse -Path $ExtractedPsToolsPath - Remove-Item -Recurse -Path $ExtractedPowerShellPath - exit $proc.ExitCode + Write-Host 'Provisioning ARM64.' + $Provisioning_x64 = $false } -$Workloads = @( - 'Microsoft.VisualStudio.Component.VC.CLI.Support', +$VisualStudioWorkloads = @( + 'Microsoft.VisualStudio.Component.VC.ASAN', 'Microsoft.VisualStudio.Component.VC.CMake.Project', 'Microsoft.VisualStudio.Component.VC.CoreIde', 'Microsoft.VisualStudio.Component.VC.Llvm.Clang', - 'Microsoft.VisualStudio.Component.VC.Runtimes.ARM.Spectre', - 'Microsoft.VisualStudio.Component.VC.Runtimes.ARM64.Spectre', - 'Microsoft.VisualStudio.Component.VC.Runtimes.x86.x64.Spectre', - 'Microsoft.VisualStudio.Component.VC.Tools.ARM', - 'Microsoft.VisualStudio.Component.VC.Tools.ARM64', - 'Microsoft.VisualStudio.Component.VC.Tools.x86.x64', - 'Microsoft.VisualStudio.Component.Windows10SDK.19041' + 'Microsoft.VisualStudio.Component.VC.Preview.ARM64', + 'Microsoft.VisualStudio.Component.VC.Preview.CLI.Support', + 'Microsoft.VisualStudio.Component.VC.Preview.Tools.x86.x64', + 'Microsoft.VisualStudio.Component.Windows11SDK.26100' ) -$ReleaseInPath = 'Preview' -$Sku = 'Enterprise' -$VisualStudioBootstrapperUrl = 'https://aka.ms/vs/16/pre/vs_enterprise.exe' -$PythonUrl = 'https://www.python.org/ftp/python/3.9.1/python-3.9.1-amd64.exe' - -# https://docs.microsoft.com/en-us/windows-hardware/drivers/download-the-wdk -$WindowsDriverKitUrl = 'https://go.microsoft.com/fwlink/?linkid=2128854' - -$CudaUrl = ` - 'https://developer.download.nvidia.com/compute/cuda/10.1/Prod/local_installers/cuda_10.1.243_426.00_win10.exe' -$CudaFeatures = 'nvcc_10.1 cuobjdump_10.1 nvprune_10.1 cupti_10.1 gpu_library_advisor_10.1 memcheck_10.1 ' + ` - 'nvdisasm_10.1 nvprof_10.1 visual_profiler_10.1 visual_studio_integration_10.1 cublas_10.1 cublas_dev_10.1 ' + ` - 'cudart_10.1 cufft_10.1 cufft_dev_10.1 curand_10.1 curand_dev_10.1 cusolver_10.1 cusolver_dev_10.1 cusparse_10.1 ' + ` - 'cusparse_dev_10.1 nvgraph_10.1 nvgraph_dev_10.1 npp_10.1 npp_dev_10.1 nvrtc_10.1 nvrtc_dev_10.1 nvml_dev_10.1 ' + ` - 'occupancy_calculator_10.1 fortran_examples_10.1' - -$ErrorActionPreference = 'Stop' -$ProgressPreference = 'SilentlyContinue' - -<# -.SYNOPSIS -Writes a message to the screen depending on ExitCode. - -.DESCRIPTION -Since msiexec can return either 0 or 3010 successfully, in both cases -we write that installation succeeded, and which exit code it exited with. -If msiexec returns anything else, we write an error. - -.PARAMETER ExitCode -The exit code that msiexec returned. -#> -Function PrintMsiExitCodeMessage { - Param( - $ExitCode - ) - - # 3010 is probably ERROR_SUCCESS_REBOOT_REQUIRED - if ($ExitCode -eq 0 -or $ExitCode -eq 3010) { - Write-Host "Installation successful! Exited with $ExitCode." - } - else { - Write-Error "Installation failed! Exited with $ExitCode." - } +# https://learn.microsoft.com/en-us/visualstudio/install/visual-studio-on-arm-devices +# "There's a single installer for both Visual Studio x64 and Visual Studio Arm64 architectures. +# The Visual Studio Installer detects whether the system architecture is Arm64. +# If it is, the installer downloads and installs the Arm64 version of Visual Studio." +$VisualStudioUrl = 'https://aka.ms/vs/18/insiders/vs_Community.exe' +$VisualStudioArgs = @('--quiet', '--norestart', '--wait', '--nocache') +foreach ($workload in $VisualStudioWorkloads) { + $VisualStudioArgs += '--add' + $VisualStudioArgs += $workload } -<# -.SYNOPSIS -Install Visual Studio. - -.DESCRIPTION -InstallVisualStudio takes the $Workloads array, and installs it with the -installer that's pointed at by $BootstrapperUrl. - -.PARAMETER Workloads -The set of VS workloads to install. - -.PARAMETER BootstrapperUrl -The URL of the Visual Studio installer, i.e. one of vs_*.exe. - -.PARAMETER InstallPath -The path to install Visual Studio at. - -.PARAMETER Nickname -The nickname to give the installation. -#> -Function InstallVisualStudio { - Param( - [String[]]$Workloads, - [String]$BootstrapperUrl, - [String]$InstallPath = $null, - [String]$Nickname = $null - ) - - try { - Write-Host 'Downloading Visual Studio...' - [string]$bootstrapperExe = Get-TempFilePath -Extension 'exe' - curl.exe -L -o $bootstrapperExe -s -S $BootstrapperUrl - Write-Host 'Installing Visual Studio...' - $args = @('/c', $bootstrapperExe, '--quiet', '--norestart', '--wait', '--nocache') - foreach ($workload in $Workloads) { - $args += '--add' - $args += $workload - } - - if (-not ([String]::IsNullOrWhiteSpace($InstallPath))) { - $args += '--installpath' - $args += $InstallPath - } - - if (-not ([String]::IsNullOrWhiteSpace($Nickname))) { - $args += '--nickname' - $args += $Nickname - } - - $proc = Start-Process -FilePath cmd.exe -ArgumentList $args -Wait -PassThru - PrintMsiExitCodeMessage $proc.ExitCode - } - catch { - Write-Error "Failed to install Visual Studio! $($_.Exception.Message)" - } +# https://github.com/PowerShell/PowerShell/releases/latest +if ($Provisioning_x64) { + $PowerShellUrl = 'https://github.com/PowerShell/PowerShell/releases/download/v7.5.4/PowerShell-7.5.4-win-x64.msi' +} else { + $PowerShellUrl = 'https://github.com/PowerShell/PowerShell/releases/download/v7.5.4/PowerShell-7.5.4-win-arm64.msi' } +$PowerShellArgs = @('/quiet', '/norestart') -<# -.SYNOPSIS -Installs Python. - -.DESCRIPTION -InstallPython installs Python from the supplied URL. - -.PARAMETER Url -The URL of the Python installer. -#> -Function InstallPython { - Param( - [String]$Url - ) - - Write-Host 'Downloading Python...' - [string]$installerPath = Get-TempFilePath -Extension 'exe' - curl.exe -L -o $installerPath -s -S $Url - Write-Host 'Installing Python...' - $proc = Start-Process -FilePath $installerPath -ArgumentList ` - @('/passive', 'InstallAllUsers=1', 'PrependPath=1', 'CompileAll=1') -Wait -PassThru - $exitCode = $proc.ExitCode - if ($exitCode -eq 0) { - Write-Host 'Installation successful!' - } - else { - Write-Error "Installation failed! Exited with $exitCode." - } +# https://www.python.org +if ($Provisioning_x64) { + $PythonUrl = 'https://www.python.org/ftp/python/3.14.3/python-3.14.3-amd64.exe' +} else { + $PythonUrl = 'https://www.python.org/ftp/python/3.14.3/python-3.14.3-arm64.exe' } +$PythonArgs = @('/quiet', 'InstallAllUsers=1', 'PrependPath=1', 'CompileAll=1', 'Include_doc=0') -<# -.SYNOPSIS -Installs the Windows Driver Kit. - -.DESCRIPTION -InstallWindowsDriverKit installs the Windows Driver Kit from the supplied URL. - -.PARAMETER Url -The URL of the Windows Driver Kit installer. -#> -Function InstallWindowsDriverKit { - Param( - [String]$Url - ) - - Write-Host 'Downloading the Windows Driver Kit...' - [string]$installerPath = Get-TempFilePath -Extension 'exe' - curl.exe -L -o $installerPath -s -S $Url - Write-Host 'Installing the Windows Driver Kit...' - $proc = Start-Process -FilePath cmd.exe -ArgumentList ` - @('/c', 'start', '/wait', $installerPath, '/quiet', '/features', '+') -Wait -PassThru - $exitCode = $proc.ExitCode - if ($exitCode -eq 0) { - Write-Host 'Installation successful!' - } - else { - Write-Error "Installation failed! Exited with $exitCode." - } +# https://developer.nvidia.com/cuda-toolkit +if ($Provisioning_x64) { + $CudaUrl = 'https://developer.download.nvidia.com/compute/cuda/12.4.0/local_installers/cuda_12.4.0_551.61_windows.exe' +} else { + $CudaUrl = 'CUDA is not installed for ARM64' } +$CudaArgs = @('-s', '-n') <# .SYNOPSIS -Installs NVIDIA's CUDA Toolkit. +Download and install a component. .DESCRIPTION -InstallCuda installs the CUDA Toolkit with the features specified as a -space-separated list of strings in $Features. +DownloadAndInstall downloads an executable from the given URL, and runs it with the given command-line arguments. + +.PARAMETER Name +The name of the component, to be displayed in logging messages. .PARAMETER Url -The URL of the CUDA installer. +The URL of the installer. -.PARAMETER Features -A space-separated list of features to install. +.PARAMETER Args +The command-line arguments to pass to the installer. #> -Function InstallCuda { +Function DownloadAndInstall { + [CmdletBinding(PositionalBinding=$false)] Param( - [String]$Url, - [String]$Features + [Parameter(Mandatory)][String]$Name, + [Parameter(Mandatory)][String]$Url, + [Parameter(Mandatory)][String[]]$Args ) try { - Write-Host 'Downloading CUDA...' - [string]$installerPath = Get-TempFilePath -Extension 'exe' + Write-Host "Downloading $Name..." + $tempPath = 'C:\installerTemp' + mkdir $tempPath -Force | Out-Null + $fileName = [uri]::new($Url).Segments[-1] + $installerPath = Join-Path $tempPath $fileName curl.exe -L -o $installerPath -s -S $Url - Write-Host 'Installing CUDA...' - $proc = Start-Process -FilePath $installerPath -ArgumentList @('-s ' + $Features) -Wait -PassThru + + Write-Host "Installing $Name..." + $proc = Start-Process -FilePath $installerPath -ArgumentList $Args -Wait -PassThru $exitCode = $proc.ExitCode + if ($exitCode -eq 0) { Write-Host 'Installation successful!' - } - else { + } elseif ($exitCode -eq 3010) { + Write-Host 'Installation successful! Exited with 3010 (ERROR_SUCCESS_REBOOT_REQUIRED).' + } else { Write-Error "Installation failed! Exited with $exitCode." } + } catch { + Write-Error "Installation failed! Exception: $($_.Exception.Message)" } - catch { - Write-Error "Failed to install CUDA! $($_.Exception.Message)" + + try { + # Briefly sleep before removing the installer, attempting to avoid "Access to the path '$installerPath' is denied." + Start-Sleep -Seconds 5 + Remove-Item -Path $installerPath + } catch { + Write-Error "Remove-Item failed! Exception: $($_.Exception.Message)" } } <# .SYNOPSIS -Install or upgrade a pip package. +Enables native NVMe support. .DESCRIPTION -Installs or upgrades a pip package specified in $Package. - -.PARAMETER Package -The name of the package to be installed or upgraded. +Native NVMe support is opt-in for Windows Server 2025. +TRANSITION, this will be enabled by default for the next version of Windows Server. #> -Function PipInstall { - Param( - [String]$Package - ) +Function EnableNativeNVMe { + $registryKey = 'HKLM:\SYSTEM\CurrentControlSet\Policies\Microsoft\FeatureManagement\Overrides' + $valueName = '1176759950' + $valueData = 1 - try { - Write-Host "Installing or upgrading $Package..." - python.exe -m pip install --progress-bar off --upgrade $Package - Write-Host "Done installing or upgrading $Package." - } - catch { - Write-Error "Failed to install or upgrade $Package." + if (!(Test-Path $registryKey)) { + New-Item -Path $registryKey -Force | Out-Null } + + New-ItemProperty -Path $registryKey -Name $valueName -Value $valueData -PropertyType DWORD -Force | Out-Null } -Write-Host 'AdminUser password not supplied; assuming already running as AdminUser.' +Write-Host "Old PowerShell version: $($PSVersionTable.PSVersion)" -Write-Host 'Configuring AntiVirus exclusions...' -Add-MpPreference -ExclusionPath C:\agent -Add-MpPreference -ExclusionPath D:\ -Add-MpPreference -ExclusionProcess ninja.exe -Add-MpPreference -ExclusionProcess clang-cl.exe -Add-MpPreference -ExclusionProcess cl.exe -Add-MpPreference -ExclusionProcess link.exe -Add-MpPreference -ExclusionProcess python.exe +# Print the Windows version, so we can verify whether Patch Tuesday has been picked up. +# Skip a blank line to improve the output. +(cmd /c ver)[1] -InstallPython $PythonUrl -InstallVisualStudio -Workloads $Workloads -BootstrapperUrl $VisualStudioBootstrapperUrl -InstallWindowsDriverKit $WindowsDriverKitUrl -InstallCuda -Url $CudaUrl -Features $CudaFeatures +DownloadAndInstall -Name 'PowerShell' -Url $PowerShellUrl -Args $PowerShellArgs +DownloadAndInstall -Name 'Python' -Url $PythonUrl -Args $PythonArgs +DownloadAndInstall -Name 'Visual Studio' -Url $VisualStudioUrl -Args $VisualStudioArgs +if ($Provisioning_x64) { + DownloadAndInstall -Name 'CUDA' -Url $CudaUrl -Args $CudaArgs +} -Write-Host 'Updating PATH...' +Write-Host 'Setting environment variables...' -# Step 1: Read the system path, which was just updated by installing Python. -$environmentKey = Get-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager\Environment' -Name Path +# The STL's PR/CI builds are totally unrepresentative of customer usage. +[Environment]::SetEnvironmentVariable('VSCMD_SKIP_SENDTELEMETRY', '1', 'Machine') -# Step 2: Update the local path (for this running script), so PipInstall can run python.exe. -# Additional directories can be added here (e.g. if we extracted a zip file -# or installed something that didn't update the system path). -$Env:PATH="$($environmentKey.Path)" +Write-Host 'Enabling long paths...' -# Step 3: Update the system path, permanently recording any additional directories that were added in the previous step. -Set-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager\Environment' ` - -Name Path ` - -Value "$Env:PATH" +# https://learn.microsoft.com/en-us/windows/win32/fileio/maximum-file-path-limitation?tabs=powershell +New-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Control\FileSystem' -Name 'LongPathsEnabled' ` + -Value 1 -PropertyType DWORD -Force | Out-Null -Write-Host 'Finished updating PATH!' +if ($Provisioning_x64) { + Write-Host 'Enabling native NVMe...' + EnableNativeNVMe +} -PipInstall pip -PipInstall psutil +# TRANSITION, patch Launch-VsDevShell.ps1 to pass `-vcvars_ver=preview` before a proper parameter is available. +Write-Host 'Patching Launch-VsDevShell.ps1...' +$launchVsDevShell = 'C:\Program Files\Microsoft Visual Studio\18\Insiders\Common7\Tools\Launch-VsDevShell.ps1' +$paramRegex = 'VsInstanceId = \$instanceId' +$paramSubst = '$&; DevCmdArguments = "-vcvars_ver=preview";' +(Get-Content -Raw $launchVsDevShell) -creplace $paramRegex, $paramSubst | Set-Content -NoNewLine $launchVsDevShell -# https://docs.microsoft.com/en-us/windows-hardware/drivers/devtest/bcdedit--set#verification-settings -Write-Host 'Enabling test-signed kernel-mode drivers...' -bcdedit /set testsigning on +# Tell create-1es-hosted-pool.ps1 that we succeeded. +Write-Host 'PROVISION_IMAGE_SUCCEEDED' -Write-Host 'Done!' +exit diff --git a/azure-devops/run-tests.yml b/azure-devops/run-tests.yml index a247bfc43c4..55a568ba9e5 100644 --- a/azure-devops/run-tests.yml +++ b/azure-devops/run-tests.yml @@ -2,47 +2,40 @@ # 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 +- name: targetPlatform + type: string +- name: testTargets type: string - default: 'Run Tests' -- name: publishArtifact +- name: runTesting type: boolean - default: false steps: -- task: CmdLine@2 - displayName: ${{ parameters.displayName }} - timeoutInMinutes: 120 - condition: succeeded() +- task: PowerShell@2 + displayName: 'Run Tests' inputs: - workingDirectory: $(${{ parameters.buildOutputLocationVar }}) + pwsh: true + workingDirectory: $(buildOutputLocation) + targetType: inline script: | - call "%PROGRAMFILES(X86)%\Microsoft Visual Studio\2019\Preview\Common7\Tools\VsDevCmd.bat" ^ - -host_arch=${{ parameters.hostArch }} -arch=${{ parameters.targetArch }} -no_logo - ctest -V + $PSNativeCommandUseErrorActionPreference = $true + & "$(launchVsDevShell)" -HostArch ${{ parameters.hostArch }} -Arch ${{ parameters.targetArch }} + ninja --verbose -k 0 ${{ parameters.testTargets }} + timeoutInMinutes: 30 + condition: and(succeeded(), ${{ parameters.runTesting }}) env: { TMP: $(tmpDir), TEMP: $(tmpDir) } - task: PublishTestResults@2 displayName: 'Publish Tests' - timeoutInMinutes: 10 - condition: succeededOrFailed() + timeoutInMinutes: 5 + condition: and(succeededOrFailed(), ${{ parameters.runTesting }}) inputs: - searchFolder: $(${{ parameters.buildOutputLocationVar }}) + searchFolder: $(buildOutputLocation) 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' +- publish: $(buildOutputLocation)/test-results.xml + artifact: '${{ parameters.targetPlatform }}-$(System.JobPositionInPhase)-xml-$(System.JobId)' + condition: and(failed(), ${{ parameters.runTesting }}) + displayName: 'Publish XML Artifact' diff --git a/azure-devops/sysprep.ps1 b/azure-devops/sysprep.ps1 deleted file mode 100644 index 285719366d4..00000000000 --- a/azure-devops/sysprep.ps1 +++ /dev/null @@ -1,6 +0,0 @@ -# Copyright (c) Microsoft Corporation. -# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - -$ErrorActionPreference = 'Stop' -Write-Host 'Running sysprep' -& C:\Windows\system32\sysprep\sysprep.exe /oobe /generalize /mode:vm /shutdown diff --git a/azure-devops/validate-files.cmd b/azure-devops/validate-files.cmd deleted file mode 100644 index e2f53c10f88..00000000000 --- a/azure-devops/validate-files.cmd +++ /dev/null @@ -1,4 +0,0 @@ -:: Copyright (c) Microsoft Corporation. -:: SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -"%1" -@echo If your build fails here, you need to fix the listed issues. diff --git a/azure-devops/vcpkg-dependencies.yml b/azure-devops/vcpkg-dependencies.yml deleted file mode 100644 index bd22c161de1..00000000000 --- a/azure-devops/vcpkg-dependencies.yml +++ /dev/null @@ -1,38 +0,0 @@ -# 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 481db224222..ac47cc3a498 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -1,96 +1,190 @@ # Copyright (c) Microsoft Corporation. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -# Build STL targeting x86, x64, arm, arm64 +# Build STL targeting x64, x86, arm64, arm64ec variables: - tmpDir: 'D:\Temp' - buildOutputLocation: 'D:\build' - vcpkgLocation: '$(Build.SourcesDirectory)/vcpkg' + - template: azure-devops/config.yml -pool: 'StlBuild-2021-02-09' +pr: + drafts: false stages: - stage: Code_Format + dependsOn: [] displayName: 'Code Format' + pool: + name: ${{ variables.poolName }} + demands: ${{ variables.poolDemands }} jobs: - - job: Code_Format_Validation - timeoutInMinutes: 90 - displayName: 'Validation' - variables: - buildOutputLocation: 'D:\tools' - steps: - - script: | - if exist "$(tmpDir)" ( - rmdir /S /Q $(tmpDir) - ) - mkdir $(tmpDir) - displayName: 'Setup TMP Directory' - - checkout: self - clean: true - submodules: false - - script: | - if exist "$(buildOutputLocation)" ( - rmdir /S /Q "$(buildOutputLocation)" - ) - call "%PROGRAMFILES(X86)%\Microsoft Visual Studio\2019\Preview\Common7\Tools\VsDevCmd.bat" ^ - -host_arch=amd64 -arch=amd64 -no_logo - cmake -G Ninja -DCMAKE_CXX_COMPILER=cl -DCMAKE_BUILD_TYPE=Release ^ - -S $(Build.SourcesDirectory)\tools -B $(buildOutputLocation) - cmake --build $(buildOutputLocation) - displayName: 'Build Support Tools' - env: { TMP: $(tmpDir), TEMP: $(tmpDir) } - - task: BatchScript@1 - displayName: 'Enforce clang-format' - timeoutInMinutes: 60 - condition: succeededOrFailed() - inputs: - filename: 'azure-devops/enforce-clang-format.cmd' - failOnStandardError: true - arguments: '$(buildOutputLocation)/parallelize/parallelize.exe' - env: { TMP: $(tmpDir), TEMP: $(tmpDir) } - - task: BatchScript@1 - displayName: 'Validate Files' - timeoutInMinutes: 2 - condition: succeededOrFailed() - inputs: - filename: 'azure-devops/validate-files.cmd' - failOnStandardError: true - arguments: '$(buildOutputLocation)/validate/validate.exe' - env: { TMP: $(tmpDir), TEMP: $(tmpDir) } + - template: azure-devops/format-validation.yml - - stage: Build_And_Test_x86 - dependsOn: Code_Format - displayName: 'Build and Test' + - stage: Build_x64 + dependsOn: [] + displayName: 'Build x64' + pool: + name: ${{ variables.poolName }} + demands: ${{ variables.poolDemands }} jobs: - - template: azure-devops/native-build-test.yml + - template: azure-devops/build-and-test.yml parameters: + hostArch: x64 + targetArch: x64 + targetPlatform: x64 + analyzeBuild: true + buildBenchmarks: true + numShards: 1 + configureTesting: false + runTesting: false + + - stage: Build_x86 + dependsOn: [] + displayName: 'Build x86' + pool: + name: ${{ variables.poolName }} + demands: ${{ variables.poolDemands }} + jobs: + - template: azure-devops/build-and-test.yml + parameters: + hostArch: x86 + targetArch: x86 targetPlatform: x86 - vsDevCmdArch: x86 + analyzeBuild: true + buildBenchmarks: true + numShards: 1 + configureTesting: false + runTesting: false + + - stage: Build_ARM64_Cross + dependsOn: [] + displayName: 'Build ARM64 (Cross)' + pool: + name: ${{ variables.poolName }} + demands: ${{ variables.poolDemands }} + jobs: + - template: azure-devops/build-and-test.yml + parameters: + hostArch: x64 + targetArch: arm64 + targetPlatform: arm64 + analyzeBuild: true + buildBenchmarks: true + numShards: 1 + configureTesting: false + runTesting: false + + - stage: Build_ARM64EC_Cross + dependsOn: [] + displayName: 'Build ARM64EC (Cross)' + pool: + name: ${{ variables.poolName }} + demands: ${{ variables.poolDemands }} + jobs: + - template: azure-devops/build-and-test.yml + parameters: + hostArch: x64 + targetArch: arm64 + targetPlatform: arm64ec + analyzeBuild: true + buildBenchmarks: true + numShards: 1 + configureTesting: false + runTesting: false - - stage: Build_And_Test_x64 - dependsOn: Build_And_Test_x86 - displayName: 'Build and Test' + # This ARM64-native build will detect problems with the ARM64 pool as early as possible. + # The stage dependencies are structured to optimize the critical path. + - stage: Build_ARM64_Native + dependsOn: [] + displayName: 'Build ARM64 (Native)' + pool: + name: ${{ variables.arm64PoolName }} + demands: ${{ variables.poolDemands }} jobs: - - template: azure-devops/native-build-test.yml + - template: azure-devops/build-and-test.yml parameters: + hostArch: arm64 + targetArch: arm64 + targetPlatform: arm64 + analyzeBuild: true + buildBenchmarks: true + numShards: 1 + configureTesting: false + runTesting: false + + - stage: Configure_Tests + dependsOn: [] + displayName: 'Configure Tests' + pool: + name: ${{ variables.poolName }} + demands: ${{ variables.poolDemands }} + jobs: + - template: azure-devops/build-and-test.yml + parameters: + hostArch: x64 + targetArch: x64 targetPlatform: x64 - vsDevCmdArch: amd64 + numShards: 1 + buildStl: false + runTesting: false - - stage: Build_ARM - dependsOn: Build_And_Test_x86 - displayName: 'Build' + - stage: Test_x64 + dependsOn: + - Code_Format + - Build_x64 + - Build_x86 + - Build_ARM64_Cross + - Build_ARM64EC_Cross + - Configure_Tests + displayName: 'Test x64' + pool: + name: ${{ variables.poolName }} + demands: ${{ variables.poolDemands }} jobs: - - template: azure-devops/cross-build.yml + - template: azure-devops/build-and-test.yml parameters: - targetPlatform: arm - vsDevCmdArch: arm + hostArch: x64 + targetArch: x64 + targetPlatform: x64 - - stage: Build_ARM64 - dependsOn: Build_And_Test_x86 - displayName: 'Build' + - stage: Test_x86 + dependsOn: Test_x64 + displayName: 'Test x86' + pool: + name: ${{ variables.poolName }} + demands: ${{ variables.poolDemands }} jobs: - - template: azure-devops/cross-build.yml + - template: azure-devops/build-and-test.yml parameters: + hostArch: x86 + targetArch: x86 + targetPlatform: x86 + + - stage: Test_ARM64 + dependsOn: + - Build_ARM64_Native + - Test_x64 + displayName: 'Test ARM64' + pool: + name: ${{ variables.arm64PoolName }} + demands: ${{ variables.poolDemands }} + jobs: + - template: azure-devops/build-and-test.yml + parameters: + hostArch: arm64 + targetArch: arm64 targetPlatform: arm64 - vsDevCmdArch: arm64 + + - stage: Test_ARM64EC + dependsOn: + - Build_ARM64_Native + - Test_x64 + displayName: 'Test ARM64EC' + pool: + name: ${{ variables.arm64PoolName }} + demands: ${{ variables.poolDemands }} + jobs: + - template: azure-devops/build-and-test.yml + parameters: + hostArch: arm64 + targetArch: arm64 + targetPlatform: arm64ec diff --git a/benchmarks/CMakeLists.txt b/benchmarks/CMakeLists.txt new file mode 100644 index 00000000000..ad9b1f0a436 --- /dev/null +++ b/benchmarks/CMakeLists.txt @@ -0,0 +1,149 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +cmake_minimum_required(VERSION 4.2.1) +project(msvc_standard_libraries_benchmarks LANGUAGES CXX) + +if(DEFINED STL_BINARY_DIR) + cmake_path(ABSOLUTE_PATH STL_BINARY_DIR + BASE_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/.." + NORMALIZE + ) + if(NOT EXISTS "${STL_BINARY_DIR}/out") + message(FATAL_ERROR "Invalid STL_BINARY_DIR '${STL_BINARY_DIR}'") + endif() + + if(NOT DEFINED VCLIBS_TARGET_ARCHITECTURE) + set(VCLIBS_TARGET_ARCHITECTURE "${CMAKE_CXX_COMPILER_ARCHITECTURE_ID}") + endif() + + string(TOLOWER "${VCLIBS_TARGET_ARCHITECTURE}" VCLIBS_TARGET_ARCHITECTURE) + + if(VCLIBS_TARGET_ARCHITECTURE STREQUAL "x86") + set(VCLIBS_I386_OR_AMD64 "i386") + elseif(VCLIBS_TARGET_ARCHITECTURE STREQUAL "x64") + set(VCLIBS_I386_OR_AMD64 "amd64") + elseif(VCLIBS_TARGET_ARCHITECTURE STREQUAL "arm64") + set(VCLIBS_I386_OR_AMD64 "arm64") + elseif(VCLIBS_TARGET_ARCHITECTURE STREQUAL "arm64ec") + set(VCLIBS_I386_OR_AMD64 "arm64ec") + add_compile_options($<$:/arm64EC>) + add_link_options("/machine:arm64ec") + set(CMAKE_STATIC_LINKER_FLAGS "/machine:arm64ec") + else() + message(FATAL_ERROR "Could not determine target architecture: VCLIBS_TARGET_ARCHITECTURE: ${VCLIBS_TARGET_ARCHITECTURE}") + endif() + + include_directories(BEFORE "${STL_BINARY_DIR}/out/inc") + link_directories(BEFORE "${STL_BINARY_DIR}/out/lib/${VCLIBS_I386_OR_AMD64}") +else() + message(WARNING "STL_BINARY_DIR not set; benchmarking the globally installed standard library") +endif() + +set(STL_BENCHMARK_MSVC_RUNTIME_LIBRARY + MultiThreaded + CACHE STRING "The flavor of the standard library to use; see https://cmake.org/cmake/help/latest/variable/CMAKE_MSVC_RUNTIME_LIBRARY.html for more information.") +set_property(CACHE STL_BENCHMARK_MSVC_RUNTIME_LIBRARY + PROPERTY STRINGS + "MultiThreaded;MultiThreadedDLL;MultiThreadedDebug;MultiThreadedDebugDLL" +) +set(CMAKE_MSVC_RUNTIME_LIBRARY "${STL_BENCHMARK_MSVC_RUNTIME_LIBRARY}") + +# Building the benchmarks as Release optimizes them with `/O2 /Ob2`. +# Compiling with `/Zi` and linking with `/DEBUG` below makes profiling possible. +# (RelWithDebInfo would use `/O2 /Ob1 /Zi`.) See GH-4496. +set(CMAKE_BUILD_TYPE Release) + +# /utf-8 affects . +add_compile_options("$<$:/Zi;/nologo;/diagnostics:caret;/W4;/WX;/w14265;/w15038;/w15262;/utf-8>") +add_compile_options("$<$:/Zc:preprocessor>") # TRANSITION, LLVM-48220 clang-cl: ignore /Zc:preprocessor + +add_link_options("/DEBUG") + +if(NOT EXISTS "${CMAKE_CURRENT_LIST_DIR}/google-benchmark/.git") + message(FATAL_ERROR "google-benchmark is not checked out; make sure to run\n git submodule update --init benchmarks/google-benchmark") +endif() + +set(BENCHMARK_ENABLE_DOXYGEN OFF) +set(BENCHMARK_ENABLE_INSTALL OFF) +set(BENCHMARK_ENABLE_TESTING OFF) + +add_subdirectory(google-benchmark EXCLUDE_FROM_ALL) + +set(benchmark_headers + "inc/lorem.hpp" + "inc/skewed_allocator.hpp" + "inc/udt.hpp" + "inc/utility.hpp" +) + +function(add_benchmark name) + cmake_parse_arguments(PARSE_ARGV 1 "arg" "" "CXX_STANDARD" "") + + if(NOT DEFINED arg_CXX_STANDARD) + set(arg_CXX_STANDARD 23) + elseif(NOT arg_CXX_STANDARD MATCHES "^[0-9][0-9]$") + message(FATAL_ERROR "Unexpected value for CXX_STANDARD: ${arg_CXX_STANDARD}") + endif() + + if(NOT DEFINED arg_UNPARSED_ARGUMENTS) + message(FATAL_ERROR "benchmark ${name} does not have any source files") + endif() + + add_executable(benchmark-${name} + ${benchmark_headers} + ${arg_UNPARSED_ARGUMENTS} + ) + + target_compile_features(benchmark-${name} PRIVATE cxx_std_${arg_CXX_STANDARD}) + target_include_directories(benchmark-${name} PRIVATE inc) + target_link_libraries(benchmark-${name} PRIVATE benchmark::benchmark) +endfunction() + +add_benchmark(adjacent_difference src/adjacent_difference.cpp) +add_benchmark(adjacent_find src/adjacent_find.cpp) +add_benchmark(any_swap src/any_swap.cpp) +add_benchmark(bitset_from_string src/bitset_from_string.cpp) +add_benchmark(bitset_to_string src/bitset_to_string.cpp) +add_benchmark(charconv_floats src/charconv_floats.cpp) +add_benchmark(efficient_nonlocking_print src/efficient_nonlocking_print.cpp) +add_benchmark(filesystem src/filesystem.cpp) +add_benchmark(fill src/fill.cpp) +add_benchmark(find_and_count src/find_and_count.cpp) +add_benchmark(find_first_of src/find_first_of.cpp) +add_benchmark(flat_meow_assign src/flat_meow_assign.cpp) +add_benchmark(has_single_bit src/has_single_bit.cpp) +add_benchmark(includes src/includes.cpp) +add_benchmark(integer_to_string src/integer_to_string.cpp) +add_benchmark(iota src/iota.cpp) +add_benchmark(is_sorted_until src/is_sorted_until.cpp) +add_benchmark(locale_classic src/locale_classic.cpp) +add_benchmark(locate_zone src/locate_zone.cpp) +add_benchmark(minmax_element src/minmax_element.cpp) +add_benchmark(mismatch src/mismatch.cpp) +add_benchmark(move_only_function src/move_only_function.cpp) +add_benchmark(nth_element src/nth_element.cpp) +add_benchmark(path_lexically_normal src/path_lexically_normal.cpp) +add_benchmark(priority_queue_push_range src/priority_queue_push_range.cpp) +add_benchmark(random_integer_generation src/random_integer_generation.cpp) +add_benchmark(ranges_div_ceil src/ranges_div_ceil.cpp) +add_benchmark(regex_match src/regex_match.cpp) +add_benchmark(regex_search src/regex_search.cpp) +add_benchmark(remove src/remove.cpp) +add_benchmark(replace src/replace.cpp) +add_benchmark(reverse src/reverse.cpp) +add_benchmark(rotate src/rotate.cpp) +add_benchmark(sample src/sample.cpp) +add_benchmark(search src/search.cpp) +add_benchmark(search_n src/search_n.cpp) +add_benchmark(shuffle src/shuffle.cpp) +add_benchmark(std_copy src/std_copy.cpp) +add_benchmark(sv_equal src/sv_equal.cpp) +add_benchmark(swap_ranges src/swap_ranges.cpp) +add_benchmark(unique src/unique.cpp) +add_benchmark(vector_bool_copy src/vector_bool_copy.cpp) +add_benchmark(vector_bool_copy_n src/vector_bool_copy_n.cpp) +add_benchmark(vector_bool_count src/vector_bool_count.cpp) +add_benchmark(vector_bool_meow_of src/vector_bool_meow_of.cpp) +add_benchmark(vector_bool_move src/vector_bool_move.cpp) +add_benchmark(vector_bool_transform src/vector_bool_transform.cpp) diff --git a/benchmarks/google-benchmark b/benchmarks/google-benchmark new file mode 160000 index 00000000000..192ef10025e --- /dev/null +++ b/benchmarks/google-benchmark @@ -0,0 +1 @@ +Subproject commit 192ef10025eb2c4cdd392bc502f0c852196baa48 diff --git a/benchmarks/inc/lorem.hpp b/benchmarks/inc/lorem.hpp new file mode 100644 index 00000000000..5671e2ae7de --- /dev/null +++ b/benchmarks/inc/lorem.hpp @@ -0,0 +1,37 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#pragma once + +#include + +inline constexpr std::string_view lorem_ipsum = + "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam mollis imperdiet massa, at dapibus elit interdum " + "ac. In eget sollicitudin mi. Nam at tellus at sapien tincidunt sollicitudin vel non eros. Pellentesque nunc nunc, " + "ullamcorper eu accumsan at, pulvinar non turpis. Quisque vel mauris pulvinar, pretium purus vel, ultricies erat. " + "Curabitur a magna in ligula tristique ornare. Quisque commodo, massa viverra laoreet luctus, sem nisi aliquam " + "velit, fermentum pulvinar velit leo eget justo. Suspendisse vel erat efficitur, pulvinar eros volutpat, vulputate " + "ex. Phasellus non purus vel velit tristique tristique id at ligula. Quisque mollis sodales magna. Mauris et quam " + "eu quam viverra tempus. Nullam tempus maximus porta. Nunc mattis eleifend fermentum. Nullam aliquam libero " + "accumsan velit elementum, eu laoreet metus convallis. Donec pellentesque lacus ut iaculis iaculis. Curabitur orci " + "elit, bibendum sit amet feugiat at, iaculis sit amet massa. Maecenas imperdiet lacus at vehicula iaculis. Donec " + "volutpat nunc sit amet accumsan tempor. Quisque pretium vestibulum ultricies. Suspendisse potenti. Aenean at diam " + "iaculis, condimentum felis venenatis, condimentum erat. Nam quis elit dui. Duis quis odio vitae metus hendrerit " + "rhoncus ut et magna. Cras ac augue quis nibh pharetra sagittis. Donec ullamcorper vel eros semper pretium. Proin " + "vel sollicitudin eros. Nulla sollicitudin mattis turpis id suscipit. Aliquam sed risus velit. Aliquam iaculis nec " + "nibh ac egestas. Duis finibus semper est sed consequat. Sed in sapien quis nibh dignissim mattis. Vestibulum nec " + "metus sodales, euismod mauris ac, sollicitudin libero. Maecenas non arcu ac velit ullamcorper fringilla et quis " + "nulla. Curabitur posuere leo eget ipsum tincidunt dignissim. Cras ultricies suscipit neque, quis suscipit tortor " + "venenatis non. Cras nisl mi, bibendum in vulputate quis, vestibulum ornare enim. Nunc hendrerit placerat dui, " + "aliquam mollis sem convallis et. Integer vitae urna diam. Phasellus et imperdiet est. Maecenas auctor facilisis " + "nibh non commodo. Suspendisse iaculis quam id bibendum feugiat. Pellentesque felis erat, egestas a libero ac, " + "laoreet consectetur elit. Cras ut suscipit ex. Etiam gravida sem quis ex porta, eu lacinia tortor fermentum. " + "Nulla consequat odio enim, sed condimentum est sagittis a. Quisque nec commodo tellus. Phasellus elementum " + "feugiat dolor et feugiat. Praesent sed mattis tortor. In vitae sodales purus. Morbi accumsan, ligula et interdum " + "lacinia, leo risus suscipit urna, non luctus mi justo eu ipsum. Curabitur venenatis pretium orci id porttitor. " + "Quisque dapibus nisl sit amet elit lobortis sagittis. Orci varius natoque penatibus et magnis dis parturient " + "montes, nascetur ridiculus mus. Mauris varius dui sit amet tortor facilisis vestibulum. Curabitur condimentum " + "justo nec orci mattis auctor. Quisque aliquet condimentum arcu ac sollicitudin. Maecenas elit elit, condimentum " + "vitae auctor a, cursus et sem. Cras vehicula ante in consequat fermentum. Praesent at massa nisi. Mauris pretium " + "euismod eros, ut posuere ligula ullamcorper id. Nullam aliquet malesuada est at dignissim. Pellentesque finibus " + "sagittis libero nec bibendum. Phasellus dolor ipsum, finibus quis turpis quis, mollis interdum felis."; diff --git a/benchmarks/inc/skewed_allocator.hpp b/benchmarks/inc/skewed_allocator.hpp new file mode 100644 index 00000000000..ad2c31ff4c3 --- /dev/null +++ b/benchmarks/inc/skewed_allocator.hpp @@ -0,0 +1,76 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#pragma once + +#include +#include +#include + +template +struct skewed_allocator { + using value_type = T; + static_assert(Alignment % alignof(T) == 0, "Chosen Alignment will produce unaligned T objects"); + static_assert(Skew % alignof(T) == 0, "Chosen Skew will produce unaligned T objects"); + + template + struct rebind { + using other = skewed_allocator; + }; + + skewed_allocator() = default; + template + skewed_allocator(const skewed_allocator&) {} + + template + bool operator==(const skewed_allocator&) const { + return true; + } + + T* allocate(const size_t n) { + const auto p = static_cast(_aligned_malloc(n * sizeof(T) + Skew, Alignment)); + if (!p) { + throw std::bad_alloc{}; + } + return reinterpret_cast(p + Skew); + } + + void deallocate(T* const p, size_t) { + if (p) { + _aligned_free(reinterpret_cast(p) - Skew); + } + } +}; + +// The purpose is to provide consistent behavior for benchmarks. +// 64 would be a reasonable alignment for practical perf uses, +// as it is both the cache line size and the maximum vector instruction size (on x64). +// However, aligning to the page size will provide even more consistency +// by ensuring that the same number of page boundaries is crossed each time. +inline constexpr size_t page_size = 4096; + +// A realistic skew relative to allocation granularity, when a variable is placed +// next to a pointer in a structure or on the stack. Also corresponds to the default packing. +inline constexpr size_t realistic_skew = 8; + +template +using highly_aligned_allocator = skewed_allocator; + +template +using not_highly_aligned_allocator = skewed_allocator; + +#pragma warning(push) +#pragma warning(disable : 4324) // structure was padded due to alignment specifier + +template +struct alignas(page_size) highly_aligned { + T value; +}; + +template +struct alignas(page_size) not_highly_aligned { + char pad[realistic_skew]; + T value; +}; + +#pragma warning(pop) diff --git a/benchmarks/inc/udt.hpp b/benchmarks/inc/udt.hpp new file mode 100644 index 00000000000..15e6e07f1d9 --- /dev/null +++ b/benchmarks/inc/udt.hpp @@ -0,0 +1,26 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#pragma once + +template +struct aggregate { + Data c; + + friend bool operator==(const aggregate&, const aggregate&) = default; +}; + +template +struct non_trivial { + Data c; + non_trivial() : c() {} + non_trivial(const Data& src) : c(src) {} + non_trivial(const non_trivial& other) : c(other.c) {} + non_trivial& operator=(const non_trivial& other) { + c = other.c; + return *this; + } + ~non_trivial() {} + + friend bool operator==(const non_trivial&, const non_trivial&) = default; +}; diff --git a/benchmarks/inc/utility.hpp b/benchmarks/inc/utility.hpp new file mode 100644 index 00000000000..54db900fbe0 --- /dev/null +++ b/benchmarks/inc/utility.hpp @@ -0,0 +1,32 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#pragma once + +#include +#include +#include +#include +#include +#include + +template class Alloc = std::allocator, class... Seed> +std::vector> random_vector(size_t n, Seed... seed) { + std::vector> res(n); + std::mt19937_64 prng{seed...}; + + if constexpr (std::is_same_v) { + std::generate(res.begin(), res.end(), [&prng] { return static_cast(prng() & 1); }); + } else { +// Here, the type Contained can be char, int, aggregate, or non_trivial where Data is char or int. +// (aggregate and non_trivial are defined in udt.hpp.) +// static_cast silences truncation warnings when Contained is directly char or int, +// but is insufficient for aggregate or non_trivial. +#pragma warning(push) +#pragma warning(disable : 4244) // warning C4244: conversion from 'uint64_t' to 'Data', possible loss of data + std::generate(res.begin(), res.end(), [&prng] { return static_cast(prng()); }); +#pragma warning(pop) + } + + return res; +} diff --git a/benchmarks/src/adjacent_difference.cpp b/benchmarks/src/adjacent_difference.cpp new file mode 100644 index 00000000000..9d38daf6cde --- /dev/null +++ b/benchmarks/src/adjacent_difference.cpp @@ -0,0 +1,59 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "skewed_allocator.hpp" + +using namespace std; + +template +void bm(benchmark::State& state) { + mt19937 gen(96337); + + const size_t size = static_cast(state.range(0)); + + vector> input(size); + vector> output(size); + + if constexpr (is_floating_point_v) { + normal_distribution dis(0, 100000.0); + ranges::generate(input, [&] { return dis(gen); }); + } else { + static_assert(is_unsigned_v, "This avoids signed integers to avoid UB; they shouldn't perform differently"); + uniform_int_distribution> dis(0, numeric_limits::max()); + ranges::generate(input, [&] { return static_cast(dis(gen)); }); + } + + for (auto _ : state) { + benchmark::DoNotOptimize(input); + adjacent_difference(input.begin(), input.end(), output.begin()); + benchmark::DoNotOptimize(output); + } +} + +void common_args(benchmark::Benchmark* bm) { + bm->Arg(2255); +} + +#pragma warning(push) +#pragma warning(disable : 4244) // warning C4244: '=': conversion from 'int' to 'unsigned char', possible loss of data +BENCHMARK(bm)->Apply(common_args); +BENCHMARK(bm)->Apply(common_args); +#pragma warning(pop) + +BENCHMARK(bm)->Apply(common_args); +BENCHMARK(bm)->Apply(common_args); + +BENCHMARK(bm)->Apply(common_args); +BENCHMARK(bm)->Apply(common_args); + +BENCHMARK_MAIN(); diff --git a/benchmarks/src/adjacent_find.cpp b/benchmarks/src/adjacent_find.cpp new file mode 100644 index 00000000000..4d436d35f9f --- /dev/null +++ b/benchmarks/src/adjacent_find.cpp @@ -0,0 +1,58 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include +#include +#include + +#include "skewed_allocator.hpp" + +using namespace std; + +enum class AlgType { Std, Rng }; + +template +void bm(benchmark::State& state) { + const size_t size = static_cast(state.range(0)); + const size_t pos = static_cast(state.range(1)); + + vector> v(size); + + for (size_t i = 0; i != size; ++i) { + v[i] = static_cast(i & 3); + } + + if (pos == 0 || pos >= size) { + abort(); + } + + v[pos] = v[pos - 1]; + + for (auto _ : state) { + benchmark::DoNotOptimize(v); + if constexpr (Alg == AlgType::Std) { + benchmark::DoNotOptimize(adjacent_find(v.begin(), v.end())); + } else { + benchmark::DoNotOptimize(ranges::adjacent_find(v)); + } + } +} + +void common_args(benchmark::Benchmark* bm) { + bm->ArgPair(2525, 1142); +} + +BENCHMARK(bm)->Apply(common_args); +BENCHMARK(bm)->Apply(common_args); +BENCHMARK(bm)->Apply(common_args); +BENCHMARK(bm)->Apply(common_args); + +BENCHMARK(bm)->Apply(common_args); +BENCHMARK(bm)->Apply(common_args); +BENCHMARK(bm)->Apply(common_args); +BENCHMARK(bm)->Apply(common_args); + +BENCHMARK_MAIN(); diff --git a/benchmarks/src/any_swap.cpp b/benchmarks/src/any_swap.cpp new file mode 100644 index 00000000000..4d2ec21744d --- /dev/null +++ b/benchmarks/src/any_swap.cpp @@ -0,0 +1,42 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include + +using trivial = std::array; +static_assert(std::is_trivially_copyable_v); + +struct small { + std::array c{}; + small() = default; + small(const small&) = default; + small& operator=(const small&) = default; + small(small&&) noexcept = default; + small& operator=(small&&) noexcept = default; + ~small() {} +}; +static_assert(!std::is_trivially_copyable_v); +static_assert(std::is_nothrow_move_constructible_v); + +using large = std::array; + +template +void bm(benchmark::State& state) { + std::any a = T{}; + std::any b = T{}; + + for (auto _ : state) { + a.swap(b); + benchmark::DoNotOptimize(a); + benchmark::DoNotOptimize(b); + } +} + +BENCHMARK(bm); +BENCHMARK(bm); +BENCHMARK(bm); + +BENCHMARK_MAIN(); diff --git a/benchmarks/src/bitset_from_string.cpp b/benchmarks/src/bitset_from_string.cpp new file mode 100644 index 00000000000..26703ecd803 --- /dev/null +++ b/benchmarks/src/bitset_from_string.cpp @@ -0,0 +1,138 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +template +auto random_digits_init() { + mt19937_64 rnd{}; + uniform_int_distribution<> dis('0', '1'); + + constexpr size_t number_of_bitsets = (Min_length + N - 1) / N; + static_assert(number_of_bitsets != 0); + + constexpr size_t actual_size = number_of_bitsets * (N + 1); // +1 for \0 + + array result; + + for (size_t i = 0; i < actual_size; ++i) { + if (i % (N + 1) == N) { + result[i] = charT{'\0'}; // write null terminators + } else { + result[i] = static_cast(dis(rnd)); // fill random digits + } + } + + return result; +} + +enum class length_type : bool { char_count, null_term }; + +template +const auto random_digits = random_digits_init(); + +template +void bitset_from_string(benchmark::State& state) { + auto digit_array = random_digits; + for (auto _ : state) { + benchmark::DoNotOptimize(digit_array); + const auto arr_data = digit_array.data(); + const auto arr_size = digit_array.size(); + for (size_t pos = 0; pos != arr_size; pos += N + 1) { + if constexpr (Length == length_type::char_count) { + bitset bs(arr_data + pos, N); + benchmark::DoNotOptimize(bs); + } else { + bitset bs(arr_data + pos); + benchmark::DoNotOptimize(bs); + } + } + } +} + +template +basic_string random_digits_contiguous_string_init() { + mt19937_64 rnd{}; + uniform_int_distribution<> dis('0', '1'); + + basic_string result; + + result.resize_and_overwrite(Length, [&](charT* ptr, size_t) { + generate_n(ptr, Length, [&] { return static_cast(dis(rnd)); }); + return Length; + }); + + return result; +} + +template +const auto random_digits_contiguous_string = random_digits_contiguous_string_init(); + +template +void bitset_from_stream(benchmark::State& state) { + constexpr size_t string_length = 2048; + constexpr size_t count = string_length / N; + basic_istringstream stream(random_digits_contiguous_string); + bitset bs; + for (auto _ : state) { + benchmark::DoNotOptimize(stream); + for (size_t i = 0; i != count; ++i) { + stream >> bs; + } + benchmark::DoNotOptimize(bs); + stream.seekg(0); + } +} + +BENCHMARK(bitset_from_string); +BENCHMARK(bitset_from_string); +BENCHMARK(bitset_from_string); +BENCHMARK(bitset_from_string); +BENCHMARK(bitset_from_string); +BENCHMARK(bitset_from_string); + +BENCHMARK(bitset_from_string); +BENCHMARK(bitset_from_string); +BENCHMARK(bitset_from_string); +BENCHMARK(bitset_from_string); +BENCHMARK(bitset_from_string); +BENCHMARK(bitset_from_string); + +BENCHMARK(bitset_from_string); +BENCHMARK(bitset_from_string); +BENCHMARK(bitset_from_string); +BENCHMARK(bitset_from_string); +BENCHMARK(bitset_from_string); +BENCHMARK(bitset_from_string); + +BENCHMARK(bitset_from_string); +BENCHMARK(bitset_from_string); +BENCHMARK(bitset_from_string); +BENCHMARK(bitset_from_string); +BENCHMARK(bitset_from_string); +BENCHMARK(bitset_from_string); + +BENCHMARK(bitset_from_stream<15, char>); +BENCHMARK(bitset_from_stream<16, char>); +BENCHMARK(bitset_from_stream<36, char>); +BENCHMARK(bitset_from_stream<64, char>); +BENCHMARK(bitset_from_stream<512, char>); +BENCHMARK(bitset_from_stream<2048, char>); + +BENCHMARK(bitset_from_stream<15, wchar_t>); +BENCHMARK(bitset_from_stream<16, wchar_t>); +BENCHMARK(bitset_from_stream<36, wchar_t>); +BENCHMARK(bitset_from_stream<64, wchar_t>); +BENCHMARK(bitset_from_stream<512, wchar_t>); +BENCHMARK(bitset_from_stream<2048, wchar_t>); + +BENCHMARK_MAIN(); diff --git a/benchmarks/src/bitset_to_string.cpp b/benchmarks/src/bitset_to_string.cpp new file mode 100644 index 00000000000..43a54c2b1d1 --- /dev/null +++ b/benchmarks/src/bitset_to_string.cpp @@ -0,0 +1,63 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +template +auto random_bits_init() { + mt19937_64 rnd{}; + array arr; + for (auto& d : arr) { + d = rnd(); + } + return arr; +} + +template +const auto random_bits = random_bits_init(); + +template +void BM_bitset_to_string(benchmark::State& state) { + static_assert(N <= 64); + + for (auto _ : state) { + // make a copy, so that it can be potentially modified by DoNotOptimize + for (auto bits : random_bits<>) { + benchmark::DoNotOptimize(bits); + bitset bs{bits}; + benchmark::DoNotOptimize(bs.template to_string()); + } + } +} + +template +void BM_bitset_to_string_large_single(benchmark::State& state) { + static_assert(N % 64 == 0 && N >= 64); + const auto& bitset_data = random_bits; + + auto large_bitset = bit_cast>(bitset_data); + for (auto _ : state) { + benchmark::DoNotOptimize(large_bitset); + benchmark::DoNotOptimize(large_bitset.template to_string()); + } +} + +BENCHMARK(BM_bitset_to_string<15, char>); +BENCHMARK(BM_bitset_to_string<64, char>); +BENCHMARK(BM_bitset_to_string_large_single<512, char>); +BENCHMARK(BM_bitset_to_string_large_single<2048, char>); +BENCHMARK(BM_bitset_to_string<7, wchar_t>); +BENCHMARK(BM_bitset_to_string<64, wchar_t>); +BENCHMARK(BM_bitset_to_string_large_single<512, wchar_t>); +BENCHMARK(BM_bitset_to_string_large_single<2048, wchar_t>); + +BENCHMARK_MAIN(); diff --git a/benchmarks/src/charconv_floats.cpp b/benchmarks/src/charconv_floats.cpp new file mode 100644 index 00000000000..7da1eb87fd0 --- /dev/null +++ b/benchmarks/src/charconv_floats.cpp @@ -0,0 +1,114 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +void verify(const bool b) { + if (!b) { + puts("FAIL"); + exit(EXIT_FAILURE); + } +} + +enum class RoundTrip { Sci, Fix, Gen, Hex, Lossy }; + +consteval chars_format chars_format_from_RoundTrip(const RoundTrip rt) { + switch (rt) { + case RoundTrip::Sci: + return chars_format::scientific; + case RoundTrip::Fix: + return chars_format::fixed; + case RoundTrip::Gen: + return chars_format::general; + case RoundTrip::Hex: + return chars_format::hex; + case RoundTrip::Lossy: + default: + exit(EXIT_FAILURE); + } +} + +template +void test_to_chars(benchmark::State& state) { + constexpr size_t n = 2'000'000; // how many floating-point values to test + vector vec; + vec.reserve(n); + + { + mt19937_64 mt64; + while (vec.size() < n) { + using Integral = conditional_t; + const Integral val = static_cast(mt64()); + constexpr Integral inf_nan = sizeof(Floating) == 4 ? 0x7F800000U : 0x7FF0000000000000ULL; + if ((val & inf_nan) == inf_nan) { + continue; // skip INF/NAN + } + vec.push_back(bit_cast(val)); + } + } + + char buf[2'000]; // more than enough + + { + auto it = vec.begin(); + for (auto _ : state) { + auto result = to_chars(buf, end(buf), *it, Args...); + + benchmark::DoNotOptimize(result.ptr); + benchmark::DoNotOptimize(buf); + + ++it; + if (it == vec.end()) { + it = vec.begin(); + } + } + } + + for (const auto& elem : vec) { + const auto result = to_chars(buf, end(buf), elem, Args...); + verify(result.ec == errc{}); + + if constexpr (Rt == RoundTrip::Lossy) { + // skip lossy conversions + } else { + Floating round_trip; + const auto from_result = from_chars(buf, result.ptr, round_trip, chars_format_from_RoundTrip(Rt)); + verify(from_result.ec == errc{}); + verify(from_result.ptr == result.ptr); + verify(round_trip == elem); + } + } +} + +BENCHMARK(test_to_chars)->Name("STL_float_plain_shortest"); +BENCHMARK(test_to_chars)->Name("STL_double_plain_shortest"); +BENCHMARK(test_to_chars)->Name("STL_float_scientific_shortest"); +BENCHMARK(test_to_chars)->Name("STL_double_scientific_shortest"); +BENCHMARK(test_to_chars)->Name("STL_float_fixed_shortest"); +BENCHMARK(test_to_chars)->Name("STL_double_fixed_shortest"); +BENCHMARK(test_to_chars)->Name("STL_float_general_shortest"); +BENCHMARK(test_to_chars)->Name("STL_double_general_shortest"); +BENCHMARK(test_to_chars)->Name("STL_float_hex_shortest"); +BENCHMARK(test_to_chars)->Name("STL_double_hex_shortest"); +BENCHMARK(test_to_chars)->Name("STL_float_scientific_8"); +BENCHMARK(test_to_chars)->Name("STL_double_scientific_16"); +BENCHMARK(test_to_chars)->Name("STL_float_fixed_6_lossy"); +BENCHMARK(test_to_chars)->Name("STL_double_fixed_6_lossy"); +BENCHMARK(test_to_chars)->Name("STL_float_general_9"); +BENCHMARK(test_to_chars)->Name("STL_double_general_17"); +BENCHMARK(test_to_chars)->Name("STL_float_hex_6"); +BENCHMARK(test_to_chars)->Name("STL_double_hex_13"); + +BENCHMARK_MAIN(); diff --git a/benchmarks/src/efficient_nonlocking_print.cpp b/benchmarks/src/efficient_nonlocking_print.cpp new file mode 100644 index 00000000000..1a6381f8436 --- /dev/null +++ b/benchmarks/src/efficient_nonlocking_print.cpp @@ -0,0 +1,42 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +// This benchmark inherently prints many lines to stdout. To view its results, run it with these options: +// --benchmark_out=efficient_nonlocking_print.log --benchmark_out_format=console + +#include +#include +#include +#include +#include +#include +#include + +using PrintType = void (*)(FILE*, std::string_view, std::format_args); + +template +void BM_vprint(benchmark::State& state) { + for (auto _ : state) { + PrintFunction(stdout, "Hello cool I am going to print as unicode\n", std::make_format_args()); + } +} +BENCHMARK(BM_vprint<&std::vprint_unicode>); +BENCHMARK(BM_vprint<&std::vprint_unicode_buffered>); + +template +void BM_vprint_complex(benchmark::State& state) { + const int i = 42; + const std::string str = "Hello world!!!!!!!!!!!!!!!!!!!!!!!!"; + const double f = -902.16283758; + const std::pair p{16, 2.073f}; + for (auto _ : state) { + PrintFunction(stdout, + "Hello cool I am going to print as unicode!! {:X}, {}, {:a}, " + "I am a big string, lots of words, multiple {} formats\n", + std::make_format_args(i, str, f, p)); + } +} +BENCHMARK(BM_vprint_complex<&std::vprint_unicode>); +BENCHMARK(BM_vprint_complex<&std::vprint_unicode_buffered>); + +BENCHMARK_MAIN(); diff --git a/benchmarks/src/filesystem.cpp b/benchmarks/src/filesystem.cpp new file mode 100644 index 00000000000..120aa107ca9 --- /dev/null +++ b/benchmarks/src/filesystem.cpp @@ -0,0 +1,22 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include + +void symlink_status(benchmark::State& state) { + auto path = std::filesystem::temp_directory_path(); + + for (auto _ : state) { + std::error_code ec; + benchmark::DoNotOptimize(path); + auto status = std::filesystem::symlink_status(path, ec); + benchmark::DoNotOptimize(status); + benchmark::DoNotOptimize(ec); + } +} + +BENCHMARK(symlink_status); + +BENCHMARK_MAIN(); diff --git a/benchmarks/src/fill.cpp b/benchmarks/src/fill.cpp new file mode 100644 index 00000000000..232a7841d3c --- /dev/null +++ b/benchmarks/src/fill.cpp @@ -0,0 +1,89 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include + +#include + +template +void handwritten_loop(benchmark::State& state) { + const size_t r0 = static_cast(state.range(0)); + std::vector> buffer(r0); + for ([[maybe_unused]] auto _ : state) { + benchmark::DoNotOptimize(buffer.data()); + Contained* ptr = buffer.data(); + const Contained* const ptr_end = ptr + r0; + while (ptr != ptr_end) { + *ptr++ = Value; + } + benchmark::DoNotOptimize(buffer.data()); + } +} + +template +void handwritten_loop_n(benchmark::State& state) { + const size_t r0 = static_cast(state.range(0)); + std::vector> buffer(r0); + for ([[maybe_unused]] auto _ : state) { + benchmark::DoNotOptimize(buffer.data()); + Contained* ptr = buffer.data(); + for (size_t idx = 0; idx < r0; ++idx) { + ptr[idx] = Value; + } + benchmark::DoNotOptimize(buffer.data()); + } +} + +// Ensure that Contained and Value are ok for std::memset. +template +void memset_call(benchmark::State& state) { + const size_t r0 = static_cast(state.range(0)); + std::vector> buffer(r0); + for ([[maybe_unused]] auto _ : state) { + benchmark::DoNotOptimize(buffer.data()); + Contained* ptr = buffer.data(); + std::memset(ptr, Value, r0 * sizeof(Contained)); + benchmark::DoNotOptimize(buffer.data()); + } +} + +template +void std_fill_call(benchmark::State& state) { + const size_t r0 = static_cast(state.range(0)); + std::vector> buffer(r0); + for ([[maybe_unused]] auto _ : state) { + benchmark::DoNotOptimize(buffer.data()); + auto begin_it = buffer.data(); + auto end_it = buffer.data() + r0; + std::fill(begin_it, end_it, Value); + benchmark::DoNotOptimize(buffer.data()); + } +} + +template +void std_fill_n_call(benchmark::State& state) { + const size_t r0 = static_cast(state.range(0)); + std::vector> buffer(r0); + for ([[maybe_unused]] auto _ : state) { + benchmark::DoNotOptimize(buffer.data()); + auto begin_it = buffer.data(); + std::fill_n(begin_it, r0, Value); + benchmark::DoNotOptimize(buffer.data()); + } +} + +BENCHMARK(handwritten_loop)->Range(0, 1 << 18); +BENCHMARK(handwritten_loop)->Range(0, 1 << 18); +BENCHMARK(handwritten_loop_n)->Range(0, 1 << 18); +BENCHMARK(handwritten_loop_n)->Range(0, 1 << 18); +BENCHMARK(memset_call)->Range(0, 1 << 18); +BENCHMARK(memset_call)->Range(0, 1 << 18); +BENCHMARK(std_fill_call)->Range(0, 1 << 18); +BENCHMARK(std_fill_call)->Range(0, 1 << 18); +BENCHMARK(std_fill_n_call)->Range(0, 1 << 18); +BENCHMARK(std_fill_n_call)->Range(0, 1 << 18); + +BENCHMARK_MAIN(); diff --git a/benchmarks/src/find_and_count.cpp b/benchmarks/src/find_and_count.cpp new file mode 100644 index 00000000000..e4735adf029 --- /dev/null +++ b/benchmarks/src/find_and_count.cpp @@ -0,0 +1,112 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "skewed_allocator.hpp" + +enum class Op { + FindSized, + FindUnsized, + Count, + StringFind, + StringRFind, + StringFindNotFirstOne, + StringFindNotLastOne, +}; + +using namespace std; + +template class Alloc, Op Operation, T FillVal = T{'0'}, T FoundVal = T{'1'}> +void bm(benchmark::State& state) { + const auto size = static_cast(state.range(0)); + const auto pos = static_cast(state.range(1)); + + using Container = + conditional_t= Op::StringFind, basic_string, Alloc>, vector>>; + + Container a(size, FillVal); + + if (pos < size) { + if constexpr (Operation == Op::StringRFind || Operation == Op::StringFindNotLastOne) { + a[size - pos - 1] = FoundVal; + } else { + a[pos] = FoundVal; + } + } else { + if constexpr (Operation == Op::FindUnsized) { + abort(); + } + } + + for (auto _ : state) { + if constexpr (Operation == Op::FindSized) { + benchmark::DoNotOptimize(ranges::find(a.begin(), a.end(), FoundVal)); + } else if constexpr (Operation == Op::FindUnsized) { + benchmark::DoNotOptimize(ranges::find(a.begin(), unreachable_sentinel, FoundVal)); + } else if constexpr (Operation == Op::Count) { + benchmark::DoNotOptimize(ranges::count(a.begin(), a.end(), FoundVal)); + } else if constexpr (Operation == Op::StringFind) { + benchmark::DoNotOptimize(a.find(FoundVal)); + } else if constexpr (Operation == Op::StringRFind) { + benchmark::DoNotOptimize(a.rfind(FoundVal)); + } else if constexpr (Operation == Op::StringFindNotFirstOne) { + benchmark::DoNotOptimize(a.find_first_not_of(FillVal)); + } else if constexpr (Operation == Op::StringFindNotLastOne) { + benchmark::DoNotOptimize(a.find_last_not_of(FillVal)); + } + } +} + +void common_args(benchmark::Benchmark* bm) { + bm->Args({8021, 3056}); + // AVX tail tests + bm->Args({63, 62})->Args({31, 30})->Args({15, 14})->Args({7, 6}); +} + +struct point { + int16_t x{}; + int16_t y{}; + + bool operator==(const point&) const = default; +}; + +BENCHMARK(bm)->Apply(common_args); +BENCHMARK(bm)->Apply(common_args); +BENCHMARK(bm)->Apply(common_args); +BENCHMARK(bm)->Apply(common_args); +BENCHMARK(bm)->Apply(common_args); +BENCHMARK(bm)->Apply(common_args); +BENCHMARK(bm)->Apply(common_args); +BENCHMARK(bm)->Apply(common_args); +BENCHMARK(bm)->Apply(common_args); + +BENCHMARK(bm)->Apply(common_args); +BENCHMARK(bm)->Apply(common_args); +BENCHMARK(bm)->Apply(common_args); +BENCHMARK(bm)->Apply(common_args); +BENCHMARK(bm)->Apply(common_args); +BENCHMARK(bm)->Apply(common_args); + +BENCHMARK(bm)->Apply(common_args); +BENCHMARK(bm)->Apply(common_args); +BENCHMARK(bm)->Apply(common_args); +BENCHMARK(bm)->Apply(common_args); +BENCHMARK(bm)->Apply(common_args); +BENCHMARK(bm)->Apply(common_args); + +BENCHMARK(bm)->Apply(common_args); +BENCHMARK(bm)->Apply(common_args); + +BENCHMARK(bm)->Apply(common_args); +BENCHMARK(bm)->Apply(common_args); + +BENCHMARK_MAIN(); diff --git a/benchmarks/src/find_first_of.cpp b/benchmarks/src/find_first_of.cpp new file mode 100644 index 00000000000..649c7934713 --- /dev/null +++ b/benchmarks/src/find_first_of.cpp @@ -0,0 +1,113 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "skewed_allocator.hpp" + +using namespace std; + +enum class AlgType { + std_func, + str_member_first, + str_member_last, + str_member_first_not, + str_member_last_not, +}; + +template +void bm(benchmark::State& state) { + const size_t Pos = static_cast(state.range(0)); + const size_t NSize = static_cast(state.range(1)); + const size_t HSize = Pos * 2; + const size_t Which = 0; + + using container = conditional_t>, + basic_string, not_highly_aligned_allocator>>; + + constexpr size_t IncrementCap = 16; + + constexpr T HaystackFillerBase = T{' '}; + static_assert( + NeedleFillerBase + IncrementCap <= HaystackFillerBase || HaystackFillerBase + IncrementCap <= NeedleFillerBase, + "Would match where it shouldn't"); + + container h(HSize, T{0}); + container n(NSize, T{0}); + + for (size_t i = 0; i != NSize; ++i) { + n[i] = NeedleFillerBase + i % IncrementCap; + } + + if (Pos >= HSize || Which >= NSize) { + abort(); + } + + if constexpr (Alg == AlgType::str_member_first_not || Alg == AlgType::str_member_last_not) { + for (size_t i = 0; i != HSize; ++i) { + h[i] = n[(i + Which) % NSize]; + } + + h[Pos] = HaystackFillerBase; + } else { + for (size_t i = 0; i != HSize; ++i) { + h[i] = HaystackFillerBase + i % IncrementCap; + } + + h[Pos] = n[Which]; + } + + for (auto _ : state) { + benchmark::DoNotOptimize(h); + benchmark::DoNotOptimize(n); + if constexpr (Alg == AlgType::str_member_first) { + benchmark::DoNotOptimize(h.find_first_of(n)); + } else if constexpr (Alg == AlgType::str_member_last) { + benchmark::DoNotOptimize(h.find_last_of(n)); + } else if constexpr (Alg == AlgType::str_member_first_not) { + benchmark::DoNotOptimize(h.find_first_not_of(n)); + } else if constexpr (Alg == AlgType::str_member_last_not) { + benchmark::DoNotOptimize(h.find_last_not_of(n)); + } else { + benchmark::DoNotOptimize(find_first_of(h.begin(), h.end(), n.begin(), n.end())); + } + } +} + +void common_args(benchmark::Benchmark* bm) { + bm->Args({2, 3})->Args({6, 81})->Args({7, 4})->Args({9, 3})->Args({22, 5})->Args({58, 2}); + bm->Args({75, 85})->Args({102, 4})->Args({200, 46})->Args({325, 1})->Args({400, 50}); + bm->Args({1011, 11})->Args({1280, 46})->Args({1502, 23})->Args({2203, 54})->Args({3056, 7}); +} + +BENCHMARK(bm)->Apply(common_args); +BENCHMARK(bm)->Apply(common_args); +BENCHMARK(bm)->Apply(common_args); +BENCHMARK(bm)->Apply(common_args); + +BENCHMARK(bm)->Apply(common_args); +BENCHMARK(bm)->Apply(common_args); +BENCHMARK(bm)->Apply(common_args); +BENCHMARK(bm)->Apply(common_args); +BENCHMARK(bm)->Apply(common_args); + +BENCHMARK(bm)->Apply(common_args); +BENCHMARK(bm)->Apply(common_args); +BENCHMARK(bm)->Apply(common_args); + +BENCHMARK(bm)->Apply(common_args); +BENCHMARK(bm)->Apply(common_args); +BENCHMARK(bm)->Apply(common_args); + +BENCHMARK(bm)->Apply(common_args); +BENCHMARK(bm)->Apply(common_args); +BENCHMARK(bm)->Apply(common_args); + +BENCHMARK_MAIN(); diff --git a/benchmarks/src/flat_meow_assign.cpp b/benchmarks/src/flat_meow_assign.cpp new file mode 100644 index 00000000000..980da7521ed --- /dev/null +++ b/benchmarks/src/flat_meow_assign.cpp @@ -0,0 +1,63 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include +#include + +using namespace std; + +void flat_map_strings_impl(benchmark::State& state, initializer_list> il) { + flat_map pieces; + for (auto _ : state) { + pieces = il; + benchmark::DoNotOptimize(pieces); + } +} + +void flat_map_strings(benchmark::State& state) { + flat_map_strings_impl( + state, {{"soldier"s, 1}, {"soldier"s, 2}, {"soldier"s, 3}, {"soldier"s, 4}, {"soldier"s, 5}, {"soldier"s, 6}, + {"soldier"s, 7}, {"soldier"s, 8}, {"tower"s, 9}, {"horse"s, 10}, {"elephant"s, 11}, {"vizier"s, 12}, + {"king"s, 13}, {"elephant"s, 14}, {"horse"s, 15}, {"tower"s, 16}}); +} + +void flat_set_strings_impl(benchmark::State& state, initializer_list il) { + flat_set pieces; + for (auto _ : state) { + pieces = il; + benchmark::DoNotOptimize(pieces); + } +} + +void flat_set_strings(benchmark::State& state) { + flat_set_strings_impl( + state, {"soldier"s, "soldier"s, "soldier"s, "soldier"s, "soldier"s, "soldier"s, "soldier"s, "soldier"s, + "tower"s, "horse"s, "elephant"s, "vizier"s, "king"s, "elephant"s, "horse"s, "tower"s}); +} + +void flat_map_integers(benchmark::State& state) { + flat_map pieces; + for (auto _ : state) { + pieces = {{'s', 1}, {'s', 2}, {'s', 3}, {'s', 4}, {'s', 5}, {'s', 6}, {'s', 7}, {'s', 8}, {'T', 9}, {'H', 10}, + {'E', 11}, {'V', 12}, {'K', 13}, {'E', 14}, {'H', 15}, {'T', 16}}; + benchmark::DoNotOptimize(pieces); + } +} + +void flat_set_integers(benchmark::State& state) { + flat_set pieces; + for (auto _ : state) { + pieces = {'s', 's', 's', 's', 's', 's', 's', 's', 'T', 'H', 'E', 'V', 'K', 'E', 'H', 'T'}; + benchmark::DoNotOptimize(pieces); + } +} + +BENCHMARK(flat_map_strings); +BENCHMARK(flat_set_strings); +BENCHMARK(flat_map_integers); +BENCHMARK(flat_set_integers); + +BENCHMARK_MAIN(); diff --git a/benchmarks/src/has_single_bit.cpp b/benchmarks/src/has_single_bit.cpp new file mode 100644 index 00000000000..3e8255b5343 --- /dev/null +++ b/benchmarks/src/has_single_bit.cpp @@ -0,0 +1,52 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include + +#include + +using namespace std; + +template +void bm_has_single_bit_if(benchmark::State& state) { + auto random_v = random_vector(8); + for (auto _ : state) { + benchmark::DoNotOptimize(random_v); + unsigned int count_true = 0; + unsigned int count_false = 0; + for (const auto& x : random_v) { + if (has_single_bit(x)) { + benchmark::DoNotOptimize(++count_true); + } else { + benchmark::DoNotOptimize(++count_false); + } + } + } +} + +template +void bm_has_single_bit(benchmark::State& state) { + auto random_v = random_vector(8); + for (auto _ : state) { + benchmark::DoNotOptimize(random_v); + unsigned int r = 0; + for (const auto& x : random_v) { + r += has_single_bit(x); + } + benchmark::DoNotOptimize(r); + } +} + +BENCHMARK(bm_has_single_bit_if); +BENCHMARK(bm_has_single_bit_if); +BENCHMARK(bm_has_single_bit_if); +BENCHMARK(bm_has_single_bit_if); + +BENCHMARK(bm_has_single_bit); +BENCHMARK(bm_has_single_bit); +BENCHMARK(bm_has_single_bit); +BENCHMARK(bm_has_single_bit); + +BENCHMARK_MAIN(); diff --git a/benchmarks/src/includes.cpp b/benchmarks/src/includes.cpp new file mode 100644 index 00000000000..3967af2d212 --- /dev/null +++ b/benchmarks/src/includes.cpp @@ -0,0 +1,134 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "skewed_allocator.hpp" +#include "utility.hpp" + +using namespace std; + +enum class alg_type { std_fn, rng }; + +enum class needle_spread { dense, dense_random, sparse, sparse_random }; + +template +void bm_includes(benchmark::State& state) { + const auto hay_size = static_cast(state.range(0)); + const auto needle_size = static_cast(state.range(1)); + const auto spread = static_cast(state.range(2)); + const auto expected_match = static_cast(state.range(3)); + + auto hay = random_vector(hay_size); + ranges::sort(hay); + + vector> needle; + switch (spread) { + case needle_spread::dense: + needle.assign(hay.begin() + hay_size / 2 - needle_size / 2, hay.begin() + hay_size / 2 + (needle_size + 1) / 2); + break; + + case needle_spread::dense_random: + { + mt19937 gen{}; + geometric_distribution dis_dis{}; + vector idx(needle_size); + const size_t mid = needle_size / 2; + idx[mid] = hay_size / 2; + + const size_t max_shift = hay_size / needle_size; + + for (size_t i = mid; i != 0; --i) { + idx[i - 1] = idx[i] - min(dis_dis(gen) + 1, max_shift); + } + + for (size_t i = mid; i != needle_size - 1; ++i) { + idx[i + 1] = idx[i] + min(dis_dis(gen) + 1, max_shift); + } + + needle.assign_range(idx | views::transform([&hay](const size_t i) { return hay[i]; })); + } + break; + + case needle_spread::sparse: + needle.resize(needle_size); + for (size_t i = 0; i != needle_size; ++i) { + needle[i] = hay[hay_size * i / needle_size + hay_size / (needle_size * 2)]; + } + break; + + case needle_spread::sparse_random: + needle.resize(needle_size); + ranges::sample(hay, needle.begin(), needle_size, mt19937{}); + break; + } + + if (!expected_match) { + const T v = needle[needle_size / 2]; + const T r = v != numeric_limits::max() ? v + 1 : v - 1; + ranges::replace(hay, v, r); + } + + for (auto _ : state) { + benchmark::DoNotOptimize(hay); + benchmark::DoNotOptimize(needle); + bool found; + if constexpr (Alg == alg_type::rng) { + found = ranges::includes(hay, needle); + } else { + found = includes(hay.begin(), hay.end(), needle.begin(), needle.end()); + } + benchmark::DoNotOptimize(found); + if (found != expected_match) { + cerr << "Unexpected 'includes' result: " << found << '\n'; + abort(); + } + } +} + +void common_args(benchmark::Benchmark* bm) { + for (const auto& spread : + {needle_spread::dense, needle_spread::dense_random, needle_spread::sparse, needle_spread::sparse_random}) { + for (const auto& expected_match : {true, false}) { + for (const auto& needle_size : {3, 22, 105, 1504, 2750}) { + bm->Args({3000, needle_size, static_cast>(spread), expected_match}); + } + + for (const auto& needle_size : {3, 22, 105, 290}) { + bm->Args({300, needle_size, static_cast>(spread), expected_match}); + } + } + } +} + +BENCHMARK(bm_includes)->Apply(common_args); +BENCHMARK(bm_includes)->Apply(common_args); +BENCHMARK(bm_includes)->Apply(common_args); +BENCHMARK(bm_includes)->Apply(common_args); + +BENCHMARK(bm_includes)->Apply(common_args); +BENCHMARK(bm_includes)->Apply(common_args); +BENCHMARK(bm_includes)->Apply(common_args); +BENCHMARK(bm_includes)->Apply(common_args); + +BENCHMARK(bm_includes)->Apply(common_args); +BENCHMARK(bm_includes)->Apply(common_args); +BENCHMARK(bm_includes)->Apply(common_args); +BENCHMARK(bm_includes)->Apply(common_args); + +BENCHMARK(bm_includes)->Apply(common_args); +BENCHMARK(bm_includes)->Apply(common_args); +BENCHMARK(bm_includes)->Apply(common_args); +BENCHMARK(bm_includes)->Apply(common_args); + +BENCHMARK_MAIN(); diff --git a/benchmarks/src/integer_to_string.cpp b/benchmarks/src/integer_to_string.cpp new file mode 100644 index 00000000000..8466545ba2d --- /dev/null +++ b/benchmarks/src/integer_to_string.cpp @@ -0,0 +1,100 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +template +auto generate_array() { + array a; + + mt19937_64 gen; + lognormal_distribution dis(M, S); + auto get_clamped_value = [&] { + for (;;) { + const double dbl = floor(dis(gen)); + constexpr auto max_val = static_cast(numeric_limits::max()); + if (dbl <= max_val) { + return static_cast(dbl); + } + } + }; + ranges::generate(a, get_clamped_value); + + if constexpr (is_signed_v) { + bernoulli_distribution b(0.5); + ranges::for_each(a, [&](T& v) { v *= (b(gen) ? -1 : 1); }); + } + + return a; +} + +template +void internal_integer_to_buff(benchmark::State& state) { + auto a = generate_array(); + + CharT buff[20]; // can hold -2^63 and 2^64 - 1 + auto buff_end = end(buff); + + auto it = a.begin(); + for (auto _ : state) { + auto i = *it; + benchmark::DoNotOptimize(i); + auto s = std::_UIntegral_to_buff(buff_end, i); + benchmark::DoNotOptimize(s); + + ++it; + if (it == a.end()) { + it = a.begin(); + } + } +} + +template +void integer_to_string(benchmark::State& state) { + auto a = generate_array(); + + auto it = a.begin(); + for (auto _ : state) { + auto i = *it; + benchmark::DoNotOptimize(i); + auto s = to_string(i); + benchmark::DoNotOptimize(s); + + ++it; + if (it == a.end()) { + it = a.begin(); + } + } +} + +BENCHMARK(internal_integer_to_buff); +BENCHMARK(internal_integer_to_buff); +BENCHMARK(internal_integer_to_buff); +BENCHMARK(internal_integer_to_buff); + +BENCHMARK(internal_integer_to_buff); +BENCHMARK(internal_integer_to_buff); +BENCHMARK(internal_integer_to_buff); +BENCHMARK(internal_integer_to_buff); + +BENCHMARK(integer_to_string); +BENCHMARK(integer_to_string); +BENCHMARK(integer_to_string); +BENCHMARK(integer_to_string); + +BENCHMARK(integer_to_string); +BENCHMARK(integer_to_string); +BENCHMARK(integer_to_string); +BENCHMARK(integer_to_string); + +BENCHMARK_MAIN(); diff --git a/benchmarks/src/iota.cpp b/benchmarks/src/iota.cpp new file mode 100644 index 00000000000..0cf9162bc8d --- /dev/null +++ b/benchmarks/src/iota.cpp @@ -0,0 +1,44 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include +#include + +#include "skewed_allocator.hpp" + +enum class Alg { + Std, + Rng, +}; + +template +void bm(benchmark::State& state) { + const auto size = static_cast(state.range(0)); + + std::vector> a(size); + + for (auto _ : state) { + if constexpr (Algorithm == Alg::Std) { + std::iota(a.begin(), a.end(), T{22}); + } else if constexpr (Algorithm == Alg::Rng) { + std::ranges::iota(a, T{22}); + } + + benchmark::DoNotOptimize(a); + } +} + +void common_args(benchmark::Benchmark* bm) { + bm->Arg(7)->Arg(18)->Arg(43)->Arg(131)->Arg(315)->Arg(1212); +} + +BENCHMARK(bm)->Apply(common_args); +BENCHMARK(bm)->Apply(common_args); + +BENCHMARK(bm)->Apply(common_args); +BENCHMARK(bm)->Apply(common_args); + +BENCHMARK_MAIN(); diff --git a/benchmarks/src/is_sorted_until.cpp b/benchmarks/src/is_sorted_until.cpp new file mode 100644 index 00000000000..66b60d897d6 --- /dev/null +++ b/benchmarks/src/is_sorted_until.cpp @@ -0,0 +1,73 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include +#include +#include +#include + +#include "skewed_allocator.hpp" +#include "utility.hpp" + +enum class AlgType { Std, Rng }; + +template +void bm_is_sorted_until(benchmark::State& state) { + const std::size_t size = static_cast(state.range(0)); + const std::size_t sort_pos = static_cast(state.range(1)); + + std::vector> v; + if constexpr (std::is_integral_v) { + v = random_vector(size); + } else if constexpr (std::is_floating_point_v) { + v.resize(size, 0.0); + std::mt19937 gen; + std::normal_distribution dis(0, 100000.0); + std::generate_n(v.begin(), size, [&dis, &gen] { return dis(gen); }); + } else { + static_assert(false); + } + + std::sort(v.begin(), v.begin() + sort_pos); + + for (auto _ : state) { + benchmark::DoNotOptimize(v); + if constexpr (Alg == AlgType::Std) { + benchmark::DoNotOptimize(std::is_sorted_until(v.begin(), v.end())); + } else { + benchmark::DoNotOptimize(std::ranges::is_sorted_until(v)); + } + } +} + +void common_args(benchmark::Benchmark* bm) { + bm->ArgPair(3000, 1800); +} + +BENCHMARK(bm_is_sorted_until)->Apply(common_args); +BENCHMARK(bm_is_sorted_until)->Apply(common_args); +BENCHMARK(bm_is_sorted_until)->Apply(common_args); +BENCHMARK(bm_is_sorted_until)->Apply(common_args); +BENCHMARK(bm_is_sorted_until)->Apply(common_args); +BENCHMARK(bm_is_sorted_until)->Apply(common_args); +BENCHMARK(bm_is_sorted_until)->Apply(common_args); +BENCHMARK(bm_is_sorted_until)->Apply(common_args); + +BENCHMARK(bm_is_sorted_until)->Apply(common_args); +BENCHMARK(bm_is_sorted_until)->Apply(common_args); +BENCHMARK(bm_is_sorted_until)->Apply(common_args); +BENCHMARK(bm_is_sorted_until)->Apply(common_args); +BENCHMARK(bm_is_sorted_until)->Apply(common_args); +BENCHMARK(bm_is_sorted_until)->Apply(common_args); +BENCHMARK(bm_is_sorted_until)->Apply(common_args); +BENCHMARK(bm_is_sorted_until)->Apply(common_args); + +BENCHMARK(bm_is_sorted_until)->Apply(common_args); +BENCHMARK(bm_is_sorted_until)->Apply(common_args); +BENCHMARK(bm_is_sorted_until)->Apply(common_args); +BENCHMARK(bm_is_sorted_until)->Apply(common_args); + +BENCHMARK_MAIN(); diff --git a/benchmarks/src/locale_classic.cpp b/benchmarks/src/locale_classic.cpp new file mode 100644 index 00000000000..aa4a739a27e --- /dev/null +++ b/benchmarks/src/locale_classic.cpp @@ -0,0 +1,17 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +using namespace std; + +// GH-3048 : Double-checked locking for locale::classic +void BM_locale_classic(benchmark::State& state) { + for (auto _ : state) { + auto v = locale::classic(); + benchmark::DoNotOptimize(v); + } +} +BENCHMARK(BM_locale_classic); + +BENCHMARK_MAIN(); diff --git a/benchmarks/src/locate_zone.cpp b/benchmarks/src/locate_zone.cpp new file mode 100644 index 00000000000..08eff0983ca --- /dev/null +++ b/benchmarks/src/locate_zone.cpp @@ -0,0 +1,19 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include "benchmark/benchmark.h" +#include + +void locate_zone(benchmark::State& state) { + const auto& db = std::chrono::get_tzdb(); + for (auto _ : state) { + for (const auto& z : db.zones) { + auto res = db.locate_zone(z.name()); + benchmark::DoNotOptimize(res); + } + } +} + +BENCHMARK(locate_zone); + +BENCHMARK_MAIN(); diff --git a/benchmarks/src/minmax_element.cpp b/benchmarks/src/minmax_element.cpp new file mode 100644 index 00000000000..3ade85d7ea8 --- /dev/null +++ b/benchmarks/src/minmax_element.cpp @@ -0,0 +1,136 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "skewed_allocator.hpp" + +enum class Op { + Min, + Max, + Both, + Min_val, + Max_val, + Both_val, +}; + +using namespace std; + +template +void bm(benchmark::State& state) { + vector> a(static_cast(state.range())); + + mt19937 gen(84710); + + if constexpr (is_floating_point_v) { + normal_distribution dis(0, 100000.0); + ranges::generate(a, [&] { return dis(gen); }); + } else { + uniform_int_distribution> dis(1, 20); + ranges::generate(a, [&] { return static_cast(dis(gen)); }); + } + + for (auto _ : state) { + benchmark::DoNotOptimize(a); + + if constexpr (Operation == Op::Min) { + benchmark::DoNotOptimize(ranges::min_element(a)); + } else if constexpr (Operation == Op::Max) { + benchmark::DoNotOptimize(ranges::max_element(a)); + } else if constexpr (Operation == Op::Both) { + benchmark::DoNotOptimize(ranges::minmax_element(a)); + } else if constexpr (Operation == Op::Min_val) { + benchmark::DoNotOptimize(ranges::min(a)); + } else if constexpr (Operation == Op::Max_val) { + benchmark::DoNotOptimize(ranges::max(a)); + } else if constexpr (Operation == Op::Both_val) { + benchmark::DoNotOptimize(ranges::minmax(a)); + } + } +} + +template +void common_arg(benchmark::Benchmark* bm) { + bm->Arg(8021); + // AVX tail tests + bm->Arg(63 / ElementSize); +} + +BENCHMARK(bm)->Apply(common_arg<1>); +BENCHMARK(bm)->Apply(common_arg<1>); +BENCHMARK(bm)->Apply(common_arg<1>); +BENCHMARK(bm)->Apply(common_arg<1>); +BENCHMARK(bm)->Apply(common_arg<1>); +BENCHMARK(bm)->Apply(common_arg<1>); + +BENCHMARK(bm)->Apply(common_arg<2>); +BENCHMARK(bm)->Apply(common_arg<2>); +BENCHMARK(bm)->Apply(common_arg<2>); +BENCHMARK(bm)->Apply(common_arg<2>); +BENCHMARK(bm)->Apply(common_arg<2>); +BENCHMARK(bm)->Apply(common_arg<2>); + +BENCHMARK(bm)->Apply(common_arg<4>); +BENCHMARK(bm)->Apply(common_arg<4>); +BENCHMARK(bm)->Apply(common_arg<4>); +BENCHMARK(bm)->Apply(common_arg<4>); +BENCHMARK(bm)->Apply(common_arg<4>); +BENCHMARK(bm)->Apply(common_arg<4>); + +BENCHMARK(bm)->Apply(common_arg<8>); +BENCHMARK(bm)->Apply(common_arg<8>); +BENCHMARK(bm)->Apply(common_arg<8>); +BENCHMARK(bm)->Apply(common_arg<8>); +BENCHMARK(bm)->Apply(common_arg<8>); +BENCHMARK(bm)->Apply(common_arg<8>); + +BENCHMARK(bm)->Apply(common_arg<1>); +BENCHMARK(bm)->Apply(common_arg<1>); +BENCHMARK(bm)->Apply(common_arg<1>); +BENCHMARK(bm)->Apply(common_arg<1>); +BENCHMARK(bm)->Apply(common_arg<1>); +BENCHMARK(bm)->Apply(common_arg<1>); + +BENCHMARK(bm)->Apply(common_arg<2>); +BENCHMARK(bm)->Apply(common_arg<2>); +BENCHMARK(bm)->Apply(common_arg<2>); +BENCHMARK(bm)->Apply(common_arg<2>); +BENCHMARK(bm)->Apply(common_arg<2>); +BENCHMARK(bm)->Apply(common_arg<2>); + +BENCHMARK(bm)->Apply(common_arg<4>); +BENCHMARK(bm)->Apply(common_arg<4>); +BENCHMARK(bm)->Apply(common_arg<4>); +BENCHMARK(bm)->Apply(common_arg<4>); +BENCHMARK(bm)->Apply(common_arg<4>); +BENCHMARK(bm)->Apply(common_arg<4>); + +BENCHMARK(bm)->Apply(common_arg<8>); +BENCHMARK(bm)->Apply(common_arg<8>); +BENCHMARK(bm)->Apply(common_arg<8>); +BENCHMARK(bm)->Apply(common_arg<8>); +BENCHMARK(bm)->Apply(common_arg<8>); +BENCHMARK(bm)->Apply(common_arg<8>); + +BENCHMARK(bm)->Apply(common_arg<4>); +BENCHMARK(bm)->Apply(common_arg<4>); +BENCHMARK(bm)->Apply(common_arg<4>); +BENCHMARK(bm)->Apply(common_arg<4>); +BENCHMARK(bm)->Apply(common_arg<4>); +BENCHMARK(bm)->Apply(common_arg<4>); + +BENCHMARK(bm)->Apply(common_arg<8>); +BENCHMARK(bm)->Apply(common_arg<8>); +BENCHMARK(bm)->Apply(common_arg<8>); +BENCHMARK(bm)->Apply(common_arg<8>); +BENCHMARK(bm)->Apply(common_arg<8>); +BENCHMARK(bm)->Apply(common_arg<8>); + +BENCHMARK_MAIN(); diff --git a/benchmarks/src/mismatch.cpp b/benchmarks/src/mismatch.cpp new file mode 100644 index 00000000000..0fbcd587fa1 --- /dev/null +++ b/benchmarks/src/mismatch.cpp @@ -0,0 +1,67 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include +#include +#include + +#include "skewed_allocator.hpp" + +using namespace std; + +constexpr int64_t no_pos = -1; + +enum class op { + mismatch, + lexi, +}; + +struct color { + uint16_t h; + uint16_t s; + uint16_t l; + + bool operator==(const color&) const = default; +}; + +constexpr color c1{30000, 40000, 20000}; +constexpr color c2{30000, 40000, 30000}; + +template +void bm(benchmark::State& state) { + vector> a(static_cast(state.range(0)), MatchVal); + vector> b(static_cast(state.range(0)), MatchVal); + + if (state.range(1) != no_pos) { + b.at(static_cast(state.range(1))) = MismatchVal; + } + + for (auto _ : state) { + if constexpr (Op == op::mismatch) { + benchmark::DoNotOptimize(ranges::mismatch(a, b)); + } else if constexpr (Op == op::lexi) { + benchmark::DoNotOptimize(ranges::lexicographical_compare(a, b)); + } + } +} + +void common_args(benchmark::Benchmark* bm) { + bm->Args({8, 3})->Args({24, 22})->Args({105, -1})->Args({4021, 3056}); +} + +BENCHMARK(bm)->Apply(common_args); +BENCHMARK(bm)->Apply(common_args); +BENCHMARK(bm)->Apply(common_args); +BENCHMARK(bm)->Apply(common_args); +BENCHMARK(bm)->Apply(common_args); + +BENCHMARK(bm)->Apply(common_args); // still optimized without vector algorithms using memcmp +BENCHMARK(bm)->Apply(common_args); // optimized with vector algorithms only +BENCHMARK(bm)->Apply(common_args); +BENCHMARK(bm)->Apply(common_args); +BENCHMARK(bm)->Apply(common_args); + +BENCHMARK_MAIN(); diff --git a/benchmarks/src/move_only_function.cpp b/benchmarks/src/move_only_function.cpp new file mode 100644 index 00000000000..c5f108d25c8 --- /dev/null +++ b/benchmarks/src/move_only_function.cpp @@ -0,0 +1,51 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include + +#ifdef __clang__ +#pragma clang diagnostic ignored "-Wunqualified-std-cast-call" +#endif // defined(__clang__) + +using namespace std; + +void mof_none(benchmark::State& state) { + move_only_function mof; + for (auto _ : state) { + benchmark::DoNotOptimize(mof); + } +} + +void mof_construct(benchmark::State& state) { + for (auto _ : state) { + move_only_function mof; + benchmark::DoNotOptimize(mof); + } +} + +void mof_move(benchmark::State& state) { + move_only_function mof; + for (auto _ : state) { + benchmark::DoNotOptimize(mof); + auto moved_mof = move(mof); + benchmark::DoNotOptimize(moved_mof); + } +} + +void mof_construct_and_move(benchmark::State& state) { + for (auto _ : state) { + move_only_function mof; + benchmark::DoNotOptimize(mof); + auto moved_mof = move(mof); + benchmark::DoNotOptimize(moved_mof); + } +} + +BENCHMARK(mof_none); +BENCHMARK(mof_construct); +BENCHMARK(mof_move); +BENCHMARK(mof_construct_and_move); + +BENCHMARK_MAIN(); diff --git a/benchmarks/src/nth_element.cpp b/benchmarks/src/nth_element.cpp new file mode 100644 index 00000000000..7c6cc99affb --- /dev/null +++ b/benchmarks/src/nth_element.cpp @@ -0,0 +1,140 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include +#include + +using namespace std; + +constexpr int tukey_ninther_adversary1[] = {0, 6, 12, 18, 22, 28, 34, 38, 44, 50, 54, 60, 66, 70, 76, 82, 86, 92, 98, + 102, 108, 114, 118, 124, 130, 134, 140, 146, 150, 156, 162, 166, 172, 178, 182, 188, 194, 198, 204, 210, 214, 220, + 226, 230, 236, 242, 246, 252, 258, 262, 268, 274, 278, 284, 290, 294, 300, 306, 310, 316, 322, 326, 332, 338, 342, + 348, 354, 358, 364, 370, 374, 380, 386, 390, 396, 402, 406, 412, 418, 422, 428, 434, 438, 444, 450, 454, 460, 466, + 470, 476, 482, 486, 492, 498, 502, 508, 514, 518, 524, 530, 534, 540, 546, 550, 556, 562, 566, 572, 578, 582, 588, + 594, 598, 604, 610, 614, 620, 626, 630, 636, 642, 646, 652, 658, 662, 668, 674, 678, 1, 7, 13, 684, 19, 23, 29, 690, + 35, 39, 45, 694, 51, 55, 61, 700, 67, 71, 77, 706, 83, 87, 93, 710, 99, 103, 109, 716, 115, 119, 125, 722, 131, 135, + 141, 726, 147, 151, 157, 732, 163, 167, 173, 738, 179, 183, 189, 742, 195, 199, 205, 748, 211, 215, 221, 754, 227, + 231, 237, 758, 243, 247, 253, 764, 259, 263, 269, 770, 275, 279, 285, 774, 291, 295, 301, 780, 307, 311, 317, 786, + 323, 327, 333, 790, 339, 343, 349, 796, 355, 359, 365, 802, 371, 375, 381, 806, 387, 391, 397, 812, 403, 407, 413, + 818, 419, 423, 429, 822, 435, 439, 445, 828, 451, 455, 461, 834, 467, 471, 477, 838, 483, 487, 493, 844, 499, 503, + 509, 850, 515, 519, 525, 854, 531, 535, 541, 860, 547, 551, 557, 866, 563, 567, 573, 870, 579, 583, 589, 876, 595, + 599, 605, 882, 611, 615, 621, 886, 627, 631, 637, 892, 643, 647, 653, 898, 659, 663, 669, 902, 675, 679, 685, 908, + 691, 695, 701, 914, 707, 711, 717, 918, 723, 727, 733, 924, 739, 743, 749, 930, 755, 759, 765, 934, 771, 775, 781, + 940, 787, 791, 797, 946, 803, 807, 813, 950, 819, 823, 829, 956, 835, 839, 845, 962, 851, 855, 861, 966, 867, 871, + 877, 972, 883, 887, 893, 978, 899, 903, 909, 982, 915, 919, 925, 988, 931, 935, 941, 990, 947, 951, 957, 992, 963, + 967, 973, 1024, 979, 983, 993, 994, 995, 996, 997, 998, 999, 1000, 1001, 1002, 2, 20, 8, 14, 24, 36, 30, 40, 52, 46, + 56, 68, 62, 72, 84, 78, 88, 100, 94, 104, 116, 110, 120, 132, 126, 136, 148, 142, 152, 164, 158, 168, 180, 174, 184, + 196, 190, 200, 212, 206, 216, 228, 222, 232, 244, 238, 248, 260, 254, 264, 276, 270, 280, 292, 286, 296, 308, 302, + 312, 324, 318, 328, 340, 334, 344, 356, 350, 360, 372, 366, 376, 388, 382, 392, 404, 398, 408, 420, 414, 424, 436, + 430, 440, 452, 446, 456, 468, 462, 472, 484, 478, 488, 500, 494, 504, 516, 510, 520, 532, 526, 536, 548, 542, 552, + 564, 558, 568, 580, 574, 584, 596, 590, 600, 612, 606, 616, 628, 622, 632, 644, 638, 648, 660, 654, 664, 676, 670, + 512, 3, 991, 9, 773, 768, 15, 680, 901, 21, 522, 25, 777, 527, 31, 692, 965, 37, 528, 41, 960, 778, 47, 686, 905, + 53, 538, 57, 936, 543, 63, 696, 1007, 69, 544, 73, 789, 784, 79, 708, 1014, 85, 554, 89, 793, 559, 95, 702, 969, + 101, 560, 105, 911, 794, 111, 712, 974, 117, 570, 121, 948, 575, 127, 724, 1015, 133, 576, 137, 805, 800, 143, 718, + 917, 149, 586, 153, 809, 591, 159, 728, 1008, 165, 592, 169, 970, 810, 175, 740, 921, 181, 602, 185, 942, 607, 191, + 734, 1009, 197, 608, 201, 821, 816, 207, 744, 975, 213, 618, 217, 825, 623, 223, 756, 1005, 229, 624, 233, 927, 826, + 239, 750, 984, 245, 634, 249, 952, 639, 255, 760, 1010, 261, 640, 265, 837, 832, 271, 772, 933, 277, 650, 281, 841, + 655, 287, 766, 981, 293, 656, 297, 976, 842, 303, 776, 937, 309, 666, 313, 964, 671, 319, 788, 1011, 325, 672, 329, + 853, 848, 335, 782, 1016, 341, 682, 345, 857, 687, 351, 792, 985, 357, 688, 361, 943, 858, 367, 804, 1003, 373, 698, + 377, 958, 703, 383, 798, 1017, 389, 704, 393, 869, 864, 399, 808, 949, 405, 714, 409, 873, 719, 415, 820, 1012, 421, + 720, 425, 986, 874, 431, 814, 953, 437, 730, 441, 968, 735, 447, 824, 1013, 453, 736, 457, 885, 880, 463, 836, 989, + 469, 746, 473, 889, 751, 479, 830, 1006, 485, 752, 489, 959, 890, 495, 840, 1004, 501, 762, 505, 980, 767, 511, 852, + 4, 517, 10, 521, 16, 896, 26, 846, 32, 533, 42, 537, 48, 783, 58, 856, 64, 549, 74, 553, 80, 906, 90, 868, 96, 565, + 106, 569, 112, 799, 122, 862, 128, 581, 138, 585, 144, 912, 154, 72, 160, 597, 170, 601, 176, 815, 186, 884, 192, + 613, 202, 617, 208, 922, 218, 878, 224, 629, 234, 633, 240, 831, 250, 888, 256, 645, 266, 649, 272, 928, 282, 900, + 288, 661, 298, 665, 304, 847, 314, 894, 320, 677, 330, 681, 336, 938, 346, 904, 352, 693, 362, 697, 368, 863, 378, + 916, 384, 709, 394, 713, 400, 944, 410, 910, 416, 725, 426, 729, 432, 879, 442, 920, 448, 741, 458, 745, 464, 954, + 474, 932, 480, 757, 490, 761, 496, 895, 506, 926, 5, 11, 17, 27, 33, 43, 49, 59, 65, 75, 81, 91, 97, 107, 113, 123, + 129, 139, 145, 155, 161, 71, 177, 187, 193, 203, 209, 219, 225, 235, 241, 251, 257, 267, 273, 283, 289, 299, 305, + 315, 321, 331, 337, 347, 353, 363, 369, 379, 385, 395, 401, 411, 417, 427, 433, 443, 449, 459, 465, 475, 481, 491, + 497, 507, 513, 523, 529, 539, 545, 555, 561, 571, 577, 587, 593, 603, 609, 619, 625, 635, 641, 651, 657, 667, 673, + 683, 689, 699, 705, 715, 721, 731, 737, 747, 753, 763, 769, 779, 785, 795, 801, 811, 817, 827, 833, 843, 849, 859, + 865, 875, 881, 891, 897, 907, 913, 923, 929, 939, 945, 955, 961, 971, 977, 987, 1018, 1019, 1020, 1021, 1022}; + +constexpr int tukey_ninther_adversary2[] = {1024, 31, 30, 29, 28, 36, 46, 51, 61, 67, 77, 82, 92, 98, 108, 118, 123, + 133, 139, 149, 154, 164, 170, 180, 190, 195, 205, 211, 221, 226, 236, 242, 252, 262, 267, 277, 283, 293, 298, 308, + 314, 324, 334, 339, 349, 355, 365, 370, 380, 386, 396, 406, 411, 421, 427, 437, 442, 452, 458, 468, 478, 483, 493, + 499, 509, 514, 524, 530, 540, 550, 555, 565, 571, 581, 586, 596, 602, 612, 622, 627, 637, 643, 653, 658, 668, 674, + 684, 694, 699, 709, 715, 725, 730, 740, 746, 756, 766, 771, 781, 787, 797, 802, 812, 818, 828, 838, 843, 853, 859, + 869, 874, 884, 890, 900, 910, 915, 925, 931, 941, 946, 956, 962, 972, 982, 987, 997, 1003, 1013, 1018, 343, 523, + 127, 529, 86, 539, 358, 549, 178, 554, 107, 564, 374, 570, 183, 580, 384, 585, 389, 595, 394, 601, 399, 611, 404, + 621, 409, 626, 18, 636, 419, 642, 425, 652, 318, 657, 435, 667, 440, 673, 169, 683, 450, 693, 224, 698, 256, 708, + 179, 714, 66, 724, 234, 729, 487, 739, 189, 745, 34, 755, 502, 765, 71, 770, 188, 780, 518, 786, 76, 796, 528, 801, + 533, 811, 538, 817, 543, 827, 548, 837, 553, 842, 163, 852, 563, 858, 569, 868, 286, 873, 579, 883, 584, 889, 70, + 899, 594, 909, 219, 914, 97, 924, 235, 930, 91, 940, 462, 945, 631, 955, 173, 961, 241, 971, 646, 981, 322, 986, + 272, 996, 662, 1002, 327, 1012, 672, 1017, 677, 1023, 682, 184, 687, 44, 692, 80, 697, 703, 390, 347, 707, 193, 713, + 718, 534, 276, 723, 26, 728, 734, 32, 200, 738, 744, 368, 749, 137, 754, 15, 759, 25, 764, 378, 769, 775, 575, 90, + 779, 148, 785, 790, 297, 215, 795, 225, 800, 806, 447, 56, 810, 816, 27, 821, 153, 826, 616, 831, 152, 836, 59, 841, + 847, 472, 632, 851, 116, 857, 862, 430, 214, 867, 647, 872, 878, 106, 251, 882, 888, 21, 893, 332, 898, 87, 903, + 132, 908, 678, 913, 919, 456, 168, 923, 230, 929, 934, 519, 466, 939, 19, 944, 950, 353, 471, 954, 960, 364, 965, + 719, 970, 271, 975, 544, 980, 369, 985, 991, 210, 491, 995, 282, 1001, 1006, 750, 250, 1011, 121, 1016, 1022, 385, + 292, 507, 65, 512, 255, 102, 776, 395, 45, 159, 287, 522, 260, 591, 791, 405, 117, 204, 307, 49, 265, 302, 807, 606, + 400, 22, 111, 16, 344, 822, 420, 313, 303, 415, 832, 275, 203, 559, 23, 416, 426, 323, 848, 281, 231, 209, 317, 574, + 436, 17, 863, 142, 333, 220, 488, 431, 441, 81, 879, 75, 590, 451, 663, 328, 446, 894, 296, 375, 600, 261, 904, 457, + 348, 605, 337, 610, 60, 688, 920, 467, 96, 615, 461, 620, 306, 354, 935, 477, 704, 625, 24, 312, 128, 143, 951, 476, + 635, 174, 131, 641, 240, 966, 492, 481, 138, 359, 976, 40, 363, 651, 735, 656, 498, 379, 992, 20, 497, 39, 560, 666, + 508, 112, 1007, 246, 158, 162, 760, 503, 513, 482, 291, 410, 245, 338, 199, 266, 147, 194, 101, 122, 55, 50, 14, 13, + 43, 48, 58, 64, 74, 79, 95, 105, 115, 120, 130, 136, 146, 151, 167, 177, 187, 192, 202, 208, 218, 223, 239, 249, + 259, 264, 274, 280, 290, 295, 311, 321, 331, 336, 346, 352, 362, 367, 383, 393, 403, 408, 418, 424, 434, 439, 455, + 465, 475, 480, 490, 496, 506, 511, 527, 537, 547, 552, 562, 568, 578, 583, 599, 609, 619, 624, 634, 640, 650, 655, + 671, 681, 691, 696, 706, 712, 722, 727, 743, 753, 763, 768, 778, 784, 794, 799, 815, 825, 835, 840, 850, 856, 866, + 871, 887, 897, 907, 912, 922, 928, 938, 943, 959, 969, 979, 984, 994, 1000, 1010, 1015, 1021, 1005, 990, 953, 974, + 964, 949, 933, 918, 881, 902, 892, 877, 861, 846, 809, 830, 820, 805, 789, 774, 737, 758, 748, 733, 717, 702, 665, + 686, 676, 661, 645, 630, 593, 614, 604, 589, 573, 558, 521, 542, 532, 517, 501, 486, 449, 470, 460, 445, 429, 414, + 377, 398, 388, 373, 357, 342, 305, 326, 316, 301, 285, 270, 233, 254, 244, 229, 213, 198, 161, 182, 172, 157, 141, + 126, 89, 110, 100, 85, 69, 54, 12, 38, 11, 10, 9, 8, 53, 84, 99, 125, 156, 171, 197, 228, 243, 269, 300, 315, 341, + 372, 387, 413, 444, 459, 485, 516, 531, 557, 588, 603, 629, 660, 675, 701, 732, 747, 773, 804, 819, 845, 876, 891, + 917, 948, 963, 989, 1020, 1014, 63, 253, 258, 263, 279, 273, 284, 289, 294, 310, 304, 320, 73, 325, 330, 335, 351, + 345, 356, 361, 366, 382, 376, 392, 88, 397, 402, 407, 423, 417, 428, 433, 438, 454, 448, 464, 109, 469, 474, 479, + 495, 489, 500, 505, 510, 526, 520, 536, 135, 541, 546, 551, 567, 561, 572, 577, 582, 598, 592, 608, 145, 613, 618, + 623, 639, 633, 644, 649, 654, 670, 664, 680, 160, 685, 690, 695, 711, 705, 716, 721, 726, 742, 736, 752, 181, 757, + 762, 767, 783, 777, 788, 793, 798, 814, 808, 824, 207, 829, 834, 839, 855, 849, 860, 865, 870, 886, 880, 896, 217, + 901, 906, 911, 927, 921, 932, 937, 942, 958, 952, 968, 232, 973, 978, 983, 999, 993, 1004, 1009, 248, 238, 222, 212, + 201, 191, 186, 37, 176, 166, 150, 140, 129, 119, 114, 3, 104, 94, 78, 68, 57, 47, 42, 6, 7, 4, 5, 2, -1, 33, 35, 41, + 52, 62, 72, 83, 93, 103, 113, 124, 134, 144, 155, 165, 175, 185, 196, 206, 216, 227, 237, 247, 257, 268, 278, 288, + 299, 309, 319, 329, 340, 350, 360, 371, 381, 391, 401, 412, 422, 432, 443, 453, 463, 473, 484, 494, 504, 515, 525, + 535, 545, 556, 566, 576, 587, 597, 607, 617, 628, 638, 648, 659, 669, 679, 689, 700, 710, 720, 731, 741, 751, 761, + 772, 782, 792, 803, 813, 823, 833, 844, 854, 864, 875, 885, 895, 905, 916, 926, 936, 947, 957, 967, 977, 988, 998, + 1008, 1019}; + +enum class alg_type { std_fn, rng }; + +template +void benchmark_common(benchmark::State& state, const Src& src) { + vector v; + v.reserve(size(src)); + + for (auto _ : state) { + v.assign(begin(src), end(src)); + benchmark::DoNotOptimize(v); + auto mid = v.begin() + (v.size() / 2); + if constexpr (Type == alg_type::std_fn) { + nth_element(v.begin(), mid, v.end()); + } else { + ranges::nth_element(v.begin(), mid, v.end()); + } + benchmark::DoNotOptimize(*mid); + } +} + +template +void bm_uniform(benchmark::State& state) { + vector src(static_cast(state.range())); + mt19937 gen(84710); + uniform_int_distribution dis(1, 580); + ranges::generate(src, [&] { return dis(gen); }); + benchmark_common(state, src); +} + +BENCHMARK(bm_uniform)->Arg(1024)->Arg(2048)->Arg(4096)->Arg(8192); +BENCHMARK(bm_uniform)->Arg(1024)->Arg(2048)->Arg(4096)->Arg(8192); + +BENCHMARK_CAPTURE(benchmark_common, adversary1, tukey_ninther_adversary1); +BENCHMARK_CAPTURE(benchmark_common, adversary1, tukey_ninther_adversary1); +BENCHMARK_CAPTURE(benchmark_common, adversary2, tukey_ninther_adversary2); +BENCHMARK_CAPTURE(benchmark_common, adversary2, tukey_ninther_adversary2); + +BENCHMARK_MAIN(); diff --git a/benchmarks/src/path_lexically_normal.cpp b/benchmarks/src/path_lexically_normal.cpp new file mode 100644 index 00000000000..24b308ab6c5 --- /dev/null +++ b/benchmarks/src/path_lexically_normal.cpp @@ -0,0 +1,27 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include + +void BM_lexically_normal(benchmark::State& state) { + using namespace std::literals; + static constexpr std::wstring_view args[5]{ + LR"(C:Snippets)"sv, + LR"(.\Snippets)"sv, + LR"(..\..\IDE\VC\Snippets)"sv, + LR"(C:\Program Files\Microsoft Visual Studio\2022\Community\Common7\IDE\VC\Snippets)"sv, + LR"(/\server/\share/\a/\b/\c/\./\./\d/\../\../\../\../\../\../\../\other/x/y/z/.././..\meow.txt)"sv, + }; + + const auto index = state.range(0); + const std::filesystem::path p(args[index]); + for (auto _ : state) { + benchmark::DoNotOptimize(p.lexically_normal()); + } +} + +BENCHMARK(BM_lexically_normal)->DenseRange(0, 4, 1); + +BENCHMARK_MAIN(); diff --git a/benchmarks/src/priority_queue_push_range.cpp b/benchmarks/src/priority_queue_push_range.cpp new file mode 100644 index 00000000000..c8d14957f80 --- /dev/null +++ b/benchmarks/src/priority_queue_push_range.cpp @@ -0,0 +1,75 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +using namespace std; + +constexpr size_t vec_size = 10'000; + +template +auto create_vec(Fn transformation) { + vector vec(vec_size); + for (mt19937_64 rnd(1); auto& e : vec) { + e = transformation(rnd()); + } + return vec; +} + +template +T cast_to(uint64_t val) { + return static_cast(val); +} + +const auto vec_u8 = create_vec(cast_to); +const auto vec_u16 = create_vec(cast_to); +const auto vec_u32 = create_vec(cast_to); +const auto vec_u64 = create_vec(cast_to); +const auto vec_float = create_vec(cast_to); +const auto vec_double = create_vec(cast_to); + +const auto vec_str = create_vec([](uint64_t val) { return to_string(static_cast(val)); }); +const auto vec_wstr = create_vec([](uint64_t val) { return to_wstring(static_cast(val)); }); + +template +void BM_push_range(benchmark::State& state) { + const size_t frag_size = static_cast(state.range(0)); + + for (auto _ : state) { + priority_queue que; + span spn{Data}; + + while (!spn.empty()) { + const size_t take_size = min(spn.size(), frag_size); + que.push_range(spn.first(take_size)); + spn = spn.subspan(take_size); + } + benchmark::DoNotOptimize(que); + } +} + +void common_args(benchmark::Benchmark* bm) { + bm->RangeMultiplier(100)->Range(1, vec_size)->Arg(vec_size / 2 + 1); +} + +BENCHMARK(BM_push_range)->Apply(common_args); +BENCHMARK(BM_push_range)->Apply(common_args); +BENCHMARK(BM_push_range)->Apply(common_args); +BENCHMARK(BM_push_range)->Apply(common_args); +BENCHMARK(BM_push_range)->Apply(common_args); +BENCHMARK(BM_push_range)->Apply(common_args); + +BENCHMARK(BM_push_range)->Apply(common_args); +BENCHMARK(BM_push_range)->Apply(common_args); +BENCHMARK(BM_push_range)->Apply(common_args); +BENCHMARK(BM_push_range)->Apply(common_args); + +BENCHMARK_MAIN(); diff --git a/benchmarks/src/random_integer_generation.cpp b/benchmarks/src/random_integer_generation.cpp new file mode 100644 index 00000000000..dcc441fa7a4 --- /dev/null +++ b/benchmarks/src/random_integer_generation.cpp @@ -0,0 +1,92 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include + +/// Test URBGs alone + +void BM_mt19937(benchmark::State& state) { + std::mt19937 gen; + for (auto _ : state) { + benchmark::DoNotOptimize(gen()); + } +} +BENCHMARK(BM_mt19937); + +void BM_mt19937_64(benchmark::State& state) { + std::mt19937_64 gen; + for (auto _ : state) { + benchmark::DoNotOptimize(gen()); + } +} +BENCHMARK(BM_mt19937_64); + +void BM_lcg(benchmark::State& state) { + std::minstd_rand gen; + for (auto _ : state) { + benchmark::DoNotOptimize(gen()); + } +} +BENCHMARK(BM_lcg); + +/// Test discard() + +template +void BM_discard(benchmark::State& state) { + Engine gen; + const auto n = static_cast(state.range(0)); + for (auto _ : state) { + gen.discard(n); + benchmark::DoNotOptimize(gen()); + } +} +BENCHMARK(BM_discard)->Range(0, 1 << 18); +BENCHMARK(BM_discard)->Range(0, 1 << 18); +BENCHMARK(BM_discard)->Range(0, 1 << 18); + +/// Support machinery for testing _Rng_from_urng_v2 + +std::uint32_t GetMax() { + std::mt19937 gen; + std::uniform_int_distribution dist(10'000'000, 20'000'000); + return dist(gen); +} + +const std::uint32_t maximum = GetMax(); // random divisor to prevent strength reduction + +/// Test mt19937 + +void BM_raw_mt19937_new(benchmark::State& state) { + std::mt19937 gen; + std::_Rng_from_urng_v2 rng(gen); + for (auto _ : state) { + benchmark::DoNotOptimize(rng(maximum)); + } +} +BENCHMARK(BM_raw_mt19937_new); + +/// Test mt19937_64 + +void BM_raw_mt19937_64_new(benchmark::State& state) { + std::mt19937_64 gen; + std::_Rng_from_urng_v2 rng(gen); + for (auto _ : state) { + benchmark::DoNotOptimize(rng(maximum)); + } +} +BENCHMARK(BM_raw_mt19937_64_new); + +/// Test minstd_rand + +void BM_raw_lcg_new(benchmark::State& state) { + std::minstd_rand gen; + std::_Rng_from_urng_v2 rng(gen); + for (auto _ : state) { + benchmark::DoNotOptimize(rng(maximum)); + } +} +BENCHMARK(BM_raw_lcg_new); + +BENCHMARK_MAIN(); diff --git a/benchmarks/src/ranges_div_ceil.cpp b/benchmarks/src/ranges_div_ceil.cpp new file mode 100644 index 00000000000..2d6a927e8c1 --- /dev/null +++ b/benchmarks/src/ranges_div_ceil.cpp @@ -0,0 +1,39 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include + +using namespace std; + +struct Data { + _Signed128 num; + _Signed128 den; +}; + +constexpr Data d1{_Signed128{0x0000'1111'2222'3333LL, 0x4444'5555'6666'7777LL}, 0x7777'8888}; +static_assert(d1.num > numeric_limits::max()); +static_assert(d1.den <= numeric_limits::max()); + +constexpr Data d2{_Signed128{0x0000'1111'2222'3333LL, 0x4444'5555'6666'7777LL}, 0x7777'8888'9999'AAAA}; +static_assert(d2.num > numeric_limits::max()); +static_assert(d2.den <= numeric_limits::max()); + +constexpr Data d3{ + _Signed128{0x0000'1111'2222'3333LL, 0x4444'5555'6666'7777LL}, _Signed128{0x7777'8888'9999'AAAA, 0xBBBB}}; +static_assert(d3.num > numeric_limits::max()); +static_assert(d3.den > numeric_limits::max()); + +void bm(benchmark::State& state, const Data& data) { + for (auto _ : state) { + benchmark::DoNotOptimize(ranges::_Div_ceil(data.num, data.den)); + } +} + +BENCHMARK_CAPTURE(bm, div_ceil_int128_uint32, d1); +BENCHMARK_CAPTURE(bm, div_ceil_int128_uint64, d2); +BENCHMARK_CAPTURE(bm, div_ceil_int128_int128, d3); + +BENCHMARK_MAIN(); diff --git a/benchmarks/src/regex_match.cpp b/benchmarks/src/regex_match.cpp new file mode 100644 index 00000000000..56fa702721e --- /dev/null +++ b/benchmarks/src/regex_match.cpp @@ -0,0 +1,58 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include + +using namespace std; +using namespace regex_constants; + +void bm_match_sequence_of_as(benchmark::State& state, const char* pattern, syntax_option_type syntax = ECMAScript) { + string input(static_cast(state.range()), 'a'); + regex re{pattern, syntax}; + + for (auto _ : state) { + benchmark::DoNotOptimize(input); + const char* pos = input.data(); + const char* end = input.data() + input.size(); + cmatch match; + regex_match(pos, end, match, re); + } +} + +void bm_match_sequence_of_9a1b(benchmark::State& state, const char* pattern, syntax_option_type syntax = ECMAScript) { + string input; + for (int i = 0; i < state.range(); ++i) { + input += "aaaaaaaaab"; + } + + regex re{pattern, syntax}; + + for (auto _ : state) { + benchmark::DoNotOptimize(input); + const char* pos = input.data(); + const char* end = input.data() + input.size(); + cmatch match; + regex_match(pos, end, match, re); + } +} + +void common_args(benchmark::Benchmark* bm) { + bm->Arg(100)->Arg(200)->Arg(400); +} + +BENCHMARK_CAPTURE(bm_match_sequence_of_as, "a*", "a*")->Apply(common_args); +BENCHMARK_CAPTURE(bm_match_sequence_of_as, "a*?", "a*?")->Apply(common_args); +BENCHMARK_CAPTURE(bm_match_sequence_of_as, "(?:a)*", "(?:a)*")->Apply(common_args); +BENCHMARK_CAPTURE(bm_match_sequence_of_as, "(a)*", "(a)*")->Apply(common_args); +BENCHMARK_CAPTURE(bm_match_sequence_of_as, "(a)*?", "(a)*?")->Apply(common_args); +BENCHMARK_CAPTURE(bm_match_sequence_of_as, "(?:b|a)*", "(?:b|a)*")->Apply(common_args); +BENCHMARK_CAPTURE(bm_match_sequence_of_as, "(b|a)*", "(b|a)*")->Apply(common_args); +BENCHMARK_CAPTURE(bm_match_sequence_of_as, "(a)(?:b|a)*", "(a)(?:b|a)*")->Apply(common_args); +BENCHMARK_CAPTURE(bm_match_sequence_of_as, "(a)(b|a)*", "(a)(b|a)*")->Apply(common_args); +BENCHMARK_CAPTURE(bm_match_sequence_of_as, "(a)(?:b|a)*c", "(a)(?:b|a)*c")->Apply(common_args); +BENCHMARK_CAPTURE(bm_match_sequence_of_9a1b, "(?:a*b)*", "(?:a*b)*")->Apply(common_args); + +BENCHMARK_MAIN(); diff --git a/benchmarks/src/regex_search.cpp b/benchmarks/src/regex_search.cpp new file mode 100644 index 00000000000..9fd341db64e --- /dev/null +++ b/benchmarks/src/regex_search.cpp @@ -0,0 +1,51 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include + +#include "lorem.hpp" + +using namespace std; +using namespace regex_constants; + +void bm_lorem_search(benchmark::State& state, const char* pattern, syntax_option_type syntax = ECMAScript) { + string repeated_lorem{lorem_ipsum}; + for (long long i = 0; i < state.range(); ++i) { + repeated_lorem += repeated_lorem; + } + regex re{pattern, syntax}; + + for (auto _ : state) { + benchmark::DoNotOptimize(repeated_lorem); + const char* pos = repeated_lorem.data(); + const char* end = repeated_lorem.data() + repeated_lorem.size(); + cmatch match; + for (; regex_search(pos, end, match, re); ++pos) { + benchmark::DoNotOptimize(match); + pos = match[0].second; + if (pos == end) { + break; + } + } + } +} + +void common_args(benchmark::Benchmark* bm) { + bm->Arg(2)->Arg(3)->Arg(4); +} + +BENCHMARK_CAPTURE(bm_lorem_search, "^bibe", "^bibe")->Apply(common_args); +BENCHMARK_CAPTURE(bm_lorem_search, "bibe", "bibe")->Apply(common_args); +BENCHMARK_CAPTURE(bm_lorem_search, "bibe".collate, "bibe", regex_constants::collate)->Apply(common_args); +BENCHMARK_CAPTURE(bm_lorem_search, "(bibe)", "(bibe)")->Apply(common_args); +BENCHMARK_CAPTURE(bm_lorem_search, "(bibe)+", "(bibe)+")->Apply(common_args); +BENCHMARK_CAPTURE(bm_lorem_search, "(?:bibe)+", "(?:bibe)+")->Apply(common_args); +BENCHMARK_CAPTURE(bm_lorem_search, R"(\bbibe)", R"(\bbibe)")->Apply(common_args); +BENCHMARK_CAPTURE(bm_lorem_search, R"(\Bibe)", R"(\Bibe)")->Apply(common_args); +BENCHMARK_CAPTURE(bm_lorem_search, R"((?=....)bibe)", R"((?=....)bibe)")->Apply(common_args); +BENCHMARK_CAPTURE(bm_lorem_search, R"((?=bibe)....)", R"((?=bibe)....)")->Apply(common_args); +BENCHMARK_CAPTURE(bm_lorem_search, R"((?!lorem)bibe)", R"((?!lorem)bibe)")->Apply(common_args); + +BENCHMARK_MAIN(); diff --git a/benchmarks/src/remove.cpp b/benchmarks/src/remove.cpp new file mode 100644 index 00000000000..61a7b772918 --- /dev/null +++ b/benchmarks/src/remove.cpp @@ -0,0 +1,65 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include + +#include "lorem.hpp" +#include "skewed_allocator.hpp" + +enum class alg_type { std_fn, rng }; + +template +void r(benchmark::State& state) { + const std::vector> src(lorem_ipsum.begin(), lorem_ipsum.end()); + std::vector> v; + v.reserve(lorem_ipsum.size()); + for (auto _ : state) { + v = src; + benchmark::DoNotOptimize(v); + if constexpr (Type == alg_type::std_fn) { + benchmark::DoNotOptimize(std::remove(v.begin(), v.end(), T{'l'})); + } else { + benchmark::DoNotOptimize(std::ranges::remove(v, T{'l'})); + } + } +} + +template +void rc(benchmark::State& state) { + std::vector> src(lorem_ipsum.begin(), lorem_ipsum.end()); + std::vector> v(lorem_ipsum.size()); + for (auto _ : state) { + benchmark::DoNotOptimize(src); + benchmark::DoNotOptimize(v); + if constexpr (Type == alg_type::std_fn) { + benchmark::DoNotOptimize(std::remove_copy(src.begin(), src.end(), v.begin(), T{'l'})); + } else { + benchmark::DoNotOptimize(std::ranges::remove_copy(src, v.begin(), T{'l'})); + } + } +} + +BENCHMARK(r); +BENCHMARK(r); +BENCHMARK(r); +BENCHMARK(r); + +BENCHMARK(r); +BENCHMARK(r); +BENCHMARK(r); +BENCHMARK(r); + +BENCHMARK(rc); +BENCHMARK(rc); +BENCHMARK(rc); +BENCHMARK(rc); + +BENCHMARK(rc); +BENCHMARK(rc); +BENCHMARK(rc); +BENCHMARK(rc); + +BENCHMARK_MAIN(); diff --git a/benchmarks/src/replace.cpp b/benchmarks/src/replace.cpp new file mode 100644 index 00000000000..28ab1c12ddb --- /dev/null +++ b/benchmarks/src/replace.cpp @@ -0,0 +1,46 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include + +#include "lorem.hpp" +#include "skewed_allocator.hpp" + +template +void r(benchmark::State& state) { + std::vector> a(lorem_ipsum.begin(), lorem_ipsum.end()); + std::vector> b(lorem_ipsum.size()); + + for (auto _ : state) { + benchmark::DoNotOptimize(a); + b = a; + std::replace(std::begin(b), std::end(b), T{'m'}, T{'w'}); + benchmark::DoNotOptimize(b); + } +} + +template +void rc(benchmark::State& state) { + std::vector> a(lorem_ipsum.begin(), lorem_ipsum.end()); + std::vector> b(lorem_ipsum.size()); + + for (auto _ : state) { + benchmark::DoNotOptimize(a); + std::replace_copy(std::begin(a), std::end(a), std::begin(b), T{'m'}, T{'w'}); + benchmark::DoNotOptimize(b); + } +} + +// replace() is vectorized for 4 and 8 bytes only. +BENCHMARK(r); +BENCHMARK(r); + +BENCHMARK(rc); +BENCHMARK(rc); +BENCHMARK(rc); +BENCHMARK(rc); + +BENCHMARK_MAIN(); diff --git a/benchmarks/src/reverse.cpp b/benchmarks/src/reverse.cpp new file mode 100644 index 00000000000..b0e0e6cefe0 --- /dev/null +++ b/benchmarks/src/reverse.cpp @@ -0,0 +1,53 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include + +#include "skewed_allocator.hpp" +#include "utility.hpp" + +template +void r(benchmark::State& state) { + const auto size = static_cast(state.range(0)); + auto v = random_vector(size); + + for (auto _ : state) { + benchmark::DoNotOptimize(v); + std::reverse(v.begin(), v.end()); + } +} + +template +void rc(benchmark::State& state) { + const auto size = static_cast(state.range(0)); + auto v = random_vector(size); + std::vector> d(size); + + for (auto _ : state) { + benchmark::DoNotOptimize(v); + std::reverse_copy(v.begin(), v.end(), d.begin()); + benchmark::DoNotOptimize(d); + } +} + +void common_args(benchmark::Benchmark* bm) { + bm->Arg(3449); + // AVX tail tests + bm->Arg(63)->Arg(31)->Arg(15)->Arg(7); +} + + +BENCHMARK(r)->Apply(common_args); +BENCHMARK(r)->Apply(common_args); +BENCHMARK(r)->Apply(common_args); +BENCHMARK(r)->Apply(common_args); + +BENCHMARK(rc)->Apply(common_args); +BENCHMARK(rc)->Apply(common_args); +BENCHMARK(rc)->Apply(common_args); +BENCHMARK(rc)->Apply(common_args); + +BENCHMARK_MAIN(); diff --git a/benchmarks/src/rotate.cpp b/benchmarks/src/rotate.cpp new file mode 100644 index 00000000000..8852956b47e --- /dev/null +++ b/benchmarks/src/rotate.cpp @@ -0,0 +1,60 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include + +#include "skewed_allocator.hpp" +#include "utility.hpp" + +using namespace std; + +enum class AlgType { Std, Rng }; + +template +void bm_rotate(benchmark::State& state) { + const auto size = static_cast(state.range(0)); + const auto n = static_cast(state.range(1)); + + auto v = random_vector(size); + benchmark::DoNotOptimize(v); + + for (auto _ : state) { + if constexpr (Alg == AlgType::Std) { + rotate(v.begin(), v.begin() + n, v.end()); + } else { + ranges::rotate(v, v.begin() + n); + } + benchmark::DoNotOptimize(v); + } +} + +void common_args(benchmark::Benchmark* bm) { + bm->Args({3333, 2242})->Args({3332, 1666})->Args({3333, 1111})->Args({3333, 501}); + bm->Args({3333, 3300})->Args({3333, 12})->Args({3333, 5})->Args({3333, 1}); + bm->Args({333, 101})->Args({123, 32})->Args({23, 7})->Args({12, 5})->Args({3, 2}); +} + +struct color { + uint16_t h; + uint16_t s; + uint16_t l; +}; + +BENCHMARK(bm_rotate)->Apply(common_args); +BENCHMARK(bm_rotate)->Apply(common_args); +BENCHMARK(bm_rotate)->Apply(common_args); +BENCHMARK(bm_rotate)->Apply(common_args); +BENCHMARK(bm_rotate)->Apply(common_args); +BENCHMARK(bm_rotate)->Apply(common_args); +BENCHMARK(bm_rotate)->Apply(common_args); +BENCHMARK(bm_rotate)->Apply(common_args); + +BENCHMARK(bm_rotate)->Apply(common_args); +BENCHMARK(bm_rotate)->Apply(common_args); + +BENCHMARK(bm_rotate)->Args({35000, 520})->Args({35000, 3000}); + +BENCHMARK_MAIN(); diff --git a/benchmarks/src/sample.cpp b/benchmarks/src/sample.cpp new file mode 100644 index 00000000000..c4afd351daf --- /dev/null +++ b/benchmarks/src/sample.cpp @@ -0,0 +1,53 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include +#include +#include +#include +#include +using namespace std; + +enum class alg_type { std_fn, rng }; + +template +void bm_sample(benchmark::State& state) { + static_assert(is_unsigned_v, "T must be unsigned so iota() doesn't have to worry about overflow."); + + const auto population_size = static_cast(state.range(0)); + const auto sampled_size = static_cast(state.range(1)); + + vector population(population_size); + vector sampled(sampled_size); + iota(population.begin(), population.end(), T{0}); + mt19937_64 urbg; + + for (auto _ : state) { + benchmark::DoNotOptimize(population); + if constexpr (Alg == alg_type::rng) { + ranges::sample(population, sampled.begin(), sampled_size, urbg); + } else { + sample(population.begin(), population.end(), sampled.begin(), sampled_size, urbg); + } + benchmark::DoNotOptimize(sampled); + } +} + +void common_args(benchmark::Benchmark* bm) { + bm->Args({1 << 20, 1 << 15}); +} + +BENCHMARK(bm_sample)->Apply(common_args); +BENCHMARK(bm_sample)->Apply(common_args); +BENCHMARK(bm_sample)->Apply(common_args); +BENCHMARK(bm_sample)->Apply(common_args); + +BENCHMARK(bm_sample)->Apply(common_args); +BENCHMARK(bm_sample)->Apply(common_args); +BENCHMARK(bm_sample)->Apply(common_args); +BENCHMARK(bm_sample)->Apply(common_args); + +BENCHMARK_MAIN(); diff --git a/benchmarks/src/search.cpp b/benchmarks/src/search.cpp new file mode 100644 index 00000000000..fe4296b9398 --- /dev/null +++ b/benchmarks/src/search.cpp @@ -0,0 +1,226 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "lorem.hpp" +#include "skewed_allocator.hpp" + +using namespace std::string_view_literals; + +template +constexpr auto make_fill_pattern_array() { + std::array result; + result.fill('*'); + + if constexpr (Last_is_different) { + result.back() = '!'; + } + + return result; +} + +template +constexpr std::array fill_pattern_array = make_fill_pattern_array(); + +template +constexpr std::string_view fill_pattern_view{ + fill_pattern_array.data(), fill_pattern_array.size()}; + +struct data_and_pattern { + std::string_view data; + std::string_view pattern; +}; + +constexpr data_and_pattern patterns[] = { + /* 0. Small, closer to end */ {lorem_ipsum, "aliquet"sv}, + /* 1. Large, closer to end */ {lorem_ipsum, "aliquet malesuada"sv}, + /* 2. Small, closer to begin */ {lorem_ipsum, "pulvinar"sv}, + /* 3. Large, closer to begin */ {lorem_ipsum, "dapibus elit interdum"sv}, + + /* 4. Small, evil */ {fill_pattern_view<3000, false>, fill_pattern_view<7, true>}, + /* 5. Large, evil */ {fill_pattern_view<3000, false>, fill_pattern_view<20, true>}, +}; + +template +using not_highly_aligned_basic_string = std::basic_string, not_highly_aligned_allocator>; + +using not_highly_aligned_string = not_highly_aligned_basic_string; +using not_highly_aligned_wstring = not_highly_aligned_basic_string; +using not_highly_aligned_u32string = not_highly_aligned_basic_string; + +void c_strstr(benchmark::State& state) { + const auto& src_haystack = patterns[static_cast(state.range())].data; + const auto& src_needle = patterns[static_cast(state.range())].pattern; + + not_highly_aligned_string haystack(src_haystack); + not_highly_aligned_string needle(src_needle); + + for (auto _ : state) { + benchmark::DoNotOptimize(haystack); + benchmark::DoNotOptimize(needle); + auto res = std::strstr(haystack.c_str(), needle.c_str()); + benchmark::DoNotOptimize(res); + } +} + +template +void classic_search(benchmark::State& state) { + const auto& src_haystack = patterns[static_cast(state.range())].data; + const auto& src_needle = patterns[static_cast(state.range())].pattern; + + std::vector> haystack(src_haystack.begin(), src_haystack.end()); + std::vector> needle(src_needle.begin(), src_needle.end()); + + for (auto _ : state) { + benchmark::DoNotOptimize(haystack); + benchmark::DoNotOptimize(needle); + auto res = std::search(haystack.begin(), haystack.end(), needle.begin(), needle.end()); + benchmark::DoNotOptimize(res); + } +} + +template +void ranges_search(benchmark::State& state) { + const auto& src_haystack = patterns[static_cast(state.range())].data; + const auto& src_needle = patterns[static_cast(state.range())].pattern; + + std::vector> haystack(src_haystack.begin(), src_haystack.end()); + std::vector> needle(src_needle.begin(), src_needle.end()); + + for (auto _ : state) { + benchmark::DoNotOptimize(haystack); + benchmark::DoNotOptimize(needle); + auto res = std::ranges::search(haystack, needle); + benchmark::DoNotOptimize(res); + } +} + +template +void search_default_searcher(benchmark::State& state) { + const auto& src_haystack = patterns[static_cast(state.range())].data; + const auto& src_needle = patterns[static_cast(state.range())].pattern; + + std::vector> haystack(src_haystack.begin(), src_haystack.end()); + std::vector> needle(src_needle.begin(), src_needle.end()); + + for (auto _ : state) { + benchmark::DoNotOptimize(haystack); + benchmark::DoNotOptimize(needle); + auto res = std::search(haystack.begin(), haystack.end(), std::default_searcher{needle.begin(), needle.end()}); + benchmark::DoNotOptimize(res); + } +} + +template +void member_find(benchmark::State& state) { + const auto& src_haystack = patterns[static_cast(state.range())].data; + const auto& src_needle = patterns[static_cast(state.range())].pattern; + + T haystack(src_haystack.begin(), src_haystack.end()); + T needle(src_needle.begin(), src_needle.end()); + + for (auto _ : state) { + benchmark::DoNotOptimize(haystack); + benchmark::DoNotOptimize(needle); + auto res = haystack.find(needle); + benchmark::DoNotOptimize(res); + } +} + +template +void classic_find_end(benchmark::State& state) { + const auto& src_haystack = patterns[static_cast(state.range())].data; + const auto& src_needle = patterns[static_cast(state.range())].pattern; + + std::vector> haystack(src_haystack.begin(), src_haystack.end()); + std::vector> needle(src_needle.begin(), src_needle.end()); + + for (auto _ : state) { + benchmark::DoNotOptimize(haystack); + benchmark::DoNotOptimize(needle); + auto res = std::find_end(haystack.begin(), haystack.end(), needle.begin(), needle.end()); + benchmark::DoNotOptimize(res); + } +} + +template +void ranges_find_end(benchmark::State& state) { + const auto& src_haystack = patterns[static_cast(state.range())].data; + const auto& src_needle = patterns[static_cast(state.range())].pattern; + + std::vector> haystack(src_haystack.begin(), src_haystack.end()); + std::vector> needle(src_needle.begin(), src_needle.end()); + + for (auto _ : state) { + benchmark::DoNotOptimize(haystack); + benchmark::DoNotOptimize(needle); + auto res = std::ranges::find_end(haystack, needle); + benchmark::DoNotOptimize(res); + } +} + +template +void member_rfind(benchmark::State& state) { + const auto& src_haystack = patterns[static_cast(state.range())].data; + const auto& src_needle = patterns[static_cast(state.range())].pattern; + + T haystack(src_haystack.begin(), src_haystack.end()); + T needle(src_needle.begin(), src_needle.end()); + + for (auto _ : state) { + benchmark::DoNotOptimize(haystack); + benchmark::DoNotOptimize(needle); + auto res = haystack.rfind(needle); + benchmark::DoNotOptimize(res); + } +} + +void common_args(benchmark::Benchmark* bm) { + bm->DenseRange(0, std::size(patterns) - 1, 1); +} + +BENCHMARK(c_strstr)->Apply(common_args); + +BENCHMARK(classic_search)->Apply(common_args); +BENCHMARK(classic_search)->Apply(common_args); +BENCHMARK(classic_search)->Apply(common_args); +BENCHMARK(classic_search)->Apply(common_args); + +BENCHMARK(ranges_search)->Apply(common_args); +BENCHMARK(ranges_search)->Apply(common_args); +BENCHMARK(ranges_search)->Apply(common_args); +BENCHMARK(ranges_search)->Apply(common_args); + +BENCHMARK(search_default_searcher)->Apply(common_args); +BENCHMARK(search_default_searcher)->Apply(common_args); +BENCHMARK(search_default_searcher)->Apply(common_args); +BENCHMARK(search_default_searcher)->Apply(common_args); + +BENCHMARK(member_find)->Apply(common_args); +BENCHMARK(member_find)->Apply(common_args); +BENCHMARK(member_find)->Apply(common_args); + +BENCHMARK(classic_find_end)->Apply(common_args); +BENCHMARK(classic_find_end)->Apply(common_args); +BENCHMARK(classic_find_end)->Apply(common_args); +BENCHMARK(classic_find_end)->Apply(common_args); + +BENCHMARK(ranges_find_end)->Apply(common_args); +BENCHMARK(ranges_find_end)->Apply(common_args); +BENCHMARK(ranges_find_end)->Apply(common_args); +BENCHMARK(ranges_find_end)->Apply(common_args); + +BENCHMARK(member_rfind)->Apply(common_args); +BENCHMARK(member_rfind)->Apply(common_args); +BENCHMARK(member_rfind)->Apply(common_args); + +BENCHMARK_MAIN(); diff --git a/benchmarks/src/search_n.cpp b/benchmarks/src/search_n.cpp new file mode 100644 index 00000000000..ee65c6d79a5 --- /dev/null +++ b/benchmarks/src/search_n.cpp @@ -0,0 +1,91 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include +#include +#include + +#include "skewed_allocator.hpp" + +using namespace std; + +// NB: This particular algorithm has std and ranges non-vectorized implementations with different perf characteristics! + +enum class AlgType { Std, Rng }; + +enum class PatternType { + TwoZones, + DenseSmallSequences, +}; + +template +void bm(benchmark::State& state) { + const auto size = static_cast(state.range(0)); + const auto n = static_cast(state.range(1)); + + constexpr T no_match{'-'}; + constexpr T match{'*'}; + + vector> v(size, no_match); + + if constexpr (Pattern == PatternType::TwoZones) { + fill(v.begin() + v.size() / 2, v.end(), match); + } else if constexpr (Pattern == PatternType::DenseSmallSequences) { + if (size != 0 && n != 0) { + mt19937 gen{7687239}; + + uniform_int_distribution len_dis(0, n - 1); + + size_t cur_len = len_dis(gen); + + for (size_t i = 0; i != size; ++i) { + if (cur_len != 0) { + v[i] = match; + --cur_len; + } else { + cur_len = len_dis(gen); + } + } + } + } + + for (auto _ : state) { + if constexpr (Alg == AlgType::Std) { + benchmark::DoNotOptimize(search_n(v.begin(), v.end(), n, match)); + } else if constexpr (Alg == AlgType::Rng) { + benchmark::DoNotOptimize(ranges::search_n(v, n, match)); + } + } +} + +void common_args(benchmark::Benchmark* bm) { + for (const auto& n : {40, 18, 16, 14, 10, 8, 5, 4, 3, 2, 1}) { + bm->ArgPair(3000, n); + } +} + +BENCHMARK(bm)->Apply(common_args); +BENCHMARK(bm)->Apply(common_args); +BENCHMARK(bm)->Apply(common_args); +BENCHMARK(bm)->Apply(common_args); + +BENCHMARK(bm)->Apply(common_args); +BENCHMARK(bm)->Apply(common_args); +BENCHMARK(bm)->Apply(common_args); +BENCHMARK(bm)->Apply(common_args); + +BENCHMARK(bm)->Apply(common_args); +BENCHMARK(bm)->Apply(common_args); +BENCHMARK(bm)->Apply(common_args); +BENCHMARK(bm)->Apply(common_args); + +BENCHMARK(bm)->Apply(common_args); +BENCHMARK(bm)->Apply(common_args); +BENCHMARK(bm)->Apply(common_args); +BENCHMARK(bm)->Apply(common_args); + + +BENCHMARK_MAIN(); diff --git a/benchmarks/src/shuffle.cpp b/benchmarks/src/shuffle.cpp new file mode 100644 index 00000000000..97fee454e42 --- /dev/null +++ b/benchmarks/src/shuffle.cpp @@ -0,0 +1,49 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include +#include +#include +#include +#include +using namespace std; + +enum class alg_type { std_fn, rng }; + +template +void bm_shuffle(benchmark::State& state) { + static_assert(is_unsigned_v, "T must be unsigned so iota() doesn't have to worry about overflow."); + + const auto n = static_cast(state.range(0)); + vector v(n); + iota(v.begin(), v.end(), T{0}); + mt19937_64 urbg; + + for (auto _ : state) { + benchmark::DoNotOptimize(v); + if constexpr (Alg == alg_type::rng) { + ranges::shuffle(v, urbg); + } else { + shuffle(v.begin(), v.end(), urbg); + } + } +} + +void common_args(benchmark::Benchmark* bm) { + bm->Arg(1 << 20); +} + +BENCHMARK(bm_shuffle)->Apply(common_args); +BENCHMARK(bm_shuffle)->Apply(common_args); +BENCHMARK(bm_shuffle)->Apply(common_args); +BENCHMARK(bm_shuffle)->Apply(common_args); + +BENCHMARK(bm_shuffle)->Apply(common_args); +BENCHMARK(bm_shuffle)->Apply(common_args); +BENCHMARK(bm_shuffle)->Apply(common_args); +BENCHMARK(bm_shuffle)->Apply(common_args); + +BENCHMARK_MAIN(); diff --git a/benchmarks/src/std_copy.cpp b/benchmarks/src/std_copy.cpp new file mode 100644 index 00000000000..eba6cbc2314 --- /dev/null +++ b/benchmarks/src/std_copy.cpp @@ -0,0 +1,121 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include +#include +#include + +#include "skewed_allocator.hpp" +#include "udt.hpp" +#include "utility.hpp" + +template +void handwritten_loop(benchmark::State& state) { + const size_t r0 = static_cast(state.range(0)); + const auto in_buffer = random_vector(r0); + std::vector> out_buffer(r0); + for ([[maybe_unused]] auto _ : state) { + benchmark::DoNotOptimize(in_buffer.data()); + const Contained* in_ptr = in_buffer.data(); + const Contained* const in_ptr_end = in_ptr + r0; + Contained* out_ptr = out_buffer.data(); + while (in_ptr != in_ptr_end) { + *out_ptr++ = *in_ptr++; + } + + benchmark::DoNotOptimize(out_buffer.data()); + } +} + +template +void handwritten_loop_n(benchmark::State& state) { + const size_t r0 = static_cast(state.range(0)); + const auto in_buffer = random_vector(r0); + std::vector> out_buffer(r0); + for ([[maybe_unused]] auto _ : state) { + benchmark::DoNotOptimize(in_buffer.data()); + const Contained* const in_ptr = in_buffer.data(); + Contained* const out_ptr = out_buffer.data(); + for (size_t idx = 0; idx < r0; ++idx) { + out_ptr[idx] = in_ptr[idx]; + } + + benchmark::DoNotOptimize(out_buffer.data()); + } +} + +template +void memcpy_call(benchmark::State& state) { + static_assert(std::is_trivially_copyable_v, "memcpy must only be called on trivially copyable types"); + const size_t r0 = static_cast(state.range(0)); + const auto in_buffer = random_vector(r0); + std::vector> out_buffer(r0); + for ([[maybe_unused]] auto _ : state) { + benchmark::DoNotOptimize(in_buffer.data()); + memcpy(out_buffer.data(), in_buffer.data(), r0 * sizeof(Contained)); + benchmark::DoNotOptimize(out_buffer.data()); + } +} + +template +void std_copy_call(benchmark::State& state) { + const size_t r0 = static_cast(state.range(0)); + const auto in_buffer = random_vector(r0); + std::vector> out_buffer(r0); + for ([[maybe_unused]] auto _ : state) { + benchmark::DoNotOptimize(in_buffer.data()); + std::copy(in_buffer.begin(), in_buffer.end(), out_buffer.begin()); + benchmark::DoNotOptimize(out_buffer.data()); + } +} + +template +void std_copy_n_call(benchmark::State& state) { + const size_t r0 = static_cast(state.range(0)); + const auto in_buffer = random_vector(r0); + std::vector> out_buffer(r0); + for ([[maybe_unused]] auto _ : state) { + benchmark::DoNotOptimize(in_buffer.data()); + std::copy_n(in_buffer.begin(), r0, out_buffer.begin()); + benchmark::DoNotOptimize(out_buffer.data()); + } +} + +BENCHMARK(handwritten_loop)->Range(0, 1 << 18); +BENCHMARK(handwritten_loop_n)->Range(0, 1 << 18); +BENCHMARK(memcpy_call)->Range(0, 1 << 18); +BENCHMARK(std_copy_call)->Range(0, 1 << 18); +BENCHMARK(std_copy_n_call)->Range(0, 1 << 18); + +BENCHMARK(handwritten_loop>)->Range(0, 1 << 18); +BENCHMARK(handwritten_loop_n>)->Range(0, 1 << 18); +BENCHMARK(memcpy_call>)->Range(0, 1 << 18); +BENCHMARK(std_copy_call>)->Range(0, 1 << 18); +BENCHMARK(std_copy_n_call>)->Range(0, 1 << 18); + +BENCHMARK(handwritten_loop>)->Range(0, 1 << 18); +BENCHMARK(handwritten_loop_n>)->Range(0, 1 << 18); +BENCHMARK(std_copy_call>)->Range(0, 1 << 18); +BENCHMARK(std_copy_n_call>)->Range(0, 1 << 18); + +BENCHMARK(handwritten_loop)->Range(0, 1 << 15); +BENCHMARK(handwritten_loop_n)->Range(0, 1 << 15); +BENCHMARK(memcpy_call)->Range(0, 1 << 15); +BENCHMARK(std_copy_call)->Range(0, 1 << 15); +BENCHMARK(std_copy_n_call)->Range(0, 1 << 15); + +BENCHMARK(handwritten_loop>)->Range(0, 1 << 15); +BENCHMARK(handwritten_loop_n>)->Range(0, 1 << 15); +BENCHMARK(memcpy_call>)->Range(0, 1 << 15); +BENCHMARK(std_copy_call>)->Range(0, 1 << 15); +BENCHMARK(std_copy_n_call>)->Range(0, 1 << 15); + +BENCHMARK(handwritten_loop>)->Range(0, 1 << 15); +BENCHMARK(handwritten_loop_n>)->Range(0, 1 << 15); +BENCHMARK(std_copy_call>)->Range(0, 1 << 15); +BENCHMARK(std_copy_n_call>)->Range(0, 1 << 15); + +BENCHMARK_MAIN(); diff --git a/benchmarks/src/sv_equal.cpp b/benchmarks/src/sv_equal.cpp new file mode 100644 index 00000000000..67e09846ccc --- /dev/null +++ b/benchmarks/src/sv_equal.cpp @@ -0,0 +1,56 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include +#include +#include + +#include "lorem.hpp" + +constexpr std::string_view haystack = lorem_ipsum.substr(0, 2048); + +constexpr std::size_t Count = 8u; + +template +constexpr std::array make_svs() { + std::array result{}; + + if constexpr (Length != 0) { + using namespace std::views; + + std::ranges::copy( + haystack | chunk(Length) | transform([](auto&& t) { return std::string_view(t); }) | take(Count), + result.begin()); + } + + return result; +} + +template +void sv_equal(benchmark::State& state) { + auto arr = make_svs(); + benchmark::DoNotOptimize(arr); + + for (auto _ : state) { + for (auto& i : arr) { + benchmark::DoNotOptimize(i); + auto res = (i == arr[0]); + benchmark::DoNotOptimize(res); + } + } +} + +BENCHMARK(sv_equal<0>); +BENCHMARK(sv_equal<8>); +BENCHMARK(sv_equal<16>); +BENCHMARK(sv_equal<32>); +BENCHMARK(sv_equal<64>); +BENCHMARK(sv_equal<128>); +BENCHMARK(sv_equal<256>); + +static_assert(haystack.size() >= Count * 256, "haystack is too small"); + +BENCHMARK_MAIN(); diff --git a/benchmarks/src/swap_ranges.cpp b/benchmarks/src/swap_ranges.cpp new file mode 100644 index 00000000000..19d3906e232 --- /dev/null +++ b/benchmarks/src/swap_ranges.cpp @@ -0,0 +1,88 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include +#include + +#include "skewed_allocator.hpp" + +using namespace std; + +template class Padder> +void std_swap(benchmark::State& state) { + Padder padded_a; + auto& a = padded_a.value; + memset(a, 'a', sizeof(a)); + Padder padded_b; + auto& b = padded_b.value; + memset(b, 'b', sizeof(b)); + + for (auto _ : state) { + swap(a, b); + benchmark::DoNotOptimize(a); + benchmark::DoNotOptimize(b); + } +} + +template class Alloc> +void std_swap_ranges(benchmark::State& state) { + vector> a(static_cast(state.range(0)), T{'a'}); + vector> b(static_cast(state.range(0)), T{'b'}); + + for (auto _ : state) { + swap_ranges(a.begin(), a.end(), b.begin()); + benchmark::DoNotOptimize(a); + benchmark::DoNotOptimize(b); + } +} + +BENCHMARK(std_swap<1, uint8_t, highly_aligned>); +BENCHMARK(std_swap<5, uint8_t, highly_aligned>); +BENCHMARK(std_swap<15, uint8_t, highly_aligned>); +BENCHMARK(std_swap<26, uint8_t, highly_aligned>); +BENCHMARK(std_swap<38, uint8_t, highly_aligned>); +BENCHMARK(std_swap<60, uint8_t, highly_aligned>); +BENCHMARK(std_swap<125, uint8_t, highly_aligned>); +BENCHMARK(std_swap<800, uint8_t, highly_aligned>); +BENCHMARK(std_swap<3000, uint8_t, highly_aligned>); +BENCHMARK(std_swap<9000, uint8_t, highly_aligned>); + +BENCHMARK(std_swap<1, uint8_t, not_highly_aligned>); +BENCHMARK(std_swap<5, uint8_t, not_highly_aligned>); +BENCHMARK(std_swap<15, uint8_t, not_highly_aligned>); +BENCHMARK(std_swap<26, uint8_t, not_highly_aligned>); +BENCHMARK(std_swap<38, uint8_t, not_highly_aligned>); +BENCHMARK(std_swap<60, uint8_t, not_highly_aligned>); +BENCHMARK(std_swap<125, uint8_t, not_highly_aligned>); +BENCHMARK(std_swap<800, uint8_t, not_highly_aligned>); +BENCHMARK(std_swap<3000, uint8_t, not_highly_aligned>); +BENCHMARK(std_swap<9000, uint8_t, not_highly_aligned>); + +BENCHMARK(std_swap_ranges) + ->Arg(1) + ->Arg(5) + ->Arg(15) + ->Arg(26) + ->Arg(38) + ->Arg(60) + ->Arg(125) + ->Arg(800) + ->Arg(3000) + ->Arg(9000); + +BENCHMARK(std_swap_ranges) + ->Arg(1) + ->Arg(5) + ->Arg(15) + ->Arg(26) + ->Arg(38) + ->Arg(60) + ->Arg(125) + ->Arg(800) + ->Arg(3000) + ->Arg(9000); + +BENCHMARK_MAIN(); diff --git a/benchmarks/src/unique.cpp b/benchmarks/src/unique.cpp new file mode 100644 index 00000000000..4baef63aa76 --- /dev/null +++ b/benchmarks/src/unique.cpp @@ -0,0 +1,81 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include +#include +#include +#include + +#include "skewed_allocator.hpp" + +enum class alg_type { std_fn, rng }; + +template +void u(benchmark::State& state) { + std::mt19937_64 gen(22033); + using TD = std::conditional_t; + std::binomial_distribution dis(5); + + std::vector> src(2552); + std::iota(src.begin(), src.begin() + 390, T{0}); + std::iota(src.end() - 390, src.end(), T{0}); + std::generate(src.begin() + 390, src.end() - 390, [&] { return static_cast(dis(gen)); }); + + std::vector> v; + v.reserve(src.size()); + for (auto _ : state) { + v = src; + benchmark::DoNotOptimize(v); + if constexpr (Type == alg_type::std_fn) { + benchmark::DoNotOptimize(std::unique(v.begin(), v.end())); + } else { + benchmark::DoNotOptimize(std::ranges::unique(v)); + } + } +} + +template +void uc(benchmark::State& state) { + std::mt19937_64 gen(22033); + using TD = std::conditional_t; + std::binomial_distribution dis(5); + + std::vector> src(2552); + std::generate(src.begin(), src.end(), [&] { return static_cast(dis(gen)); }); + + std::vector> v(src.size()); + for (auto _ : state) { + benchmark::DoNotOptimize(src); + benchmark::DoNotOptimize(v); + if constexpr (Type == alg_type::std_fn) { + benchmark::DoNotOptimize(std::unique_copy(src.begin(), src.end(), v.begin())); + } else { + benchmark::DoNotOptimize(std::ranges::unique_copy(src, v.begin())); + } + } +} + +BENCHMARK(u); +BENCHMARK(u); +BENCHMARK(u); +BENCHMARK(u); + +BENCHMARK(u); +BENCHMARK(u); +BENCHMARK(u); +BENCHMARK(u); + +BENCHMARK(uc); +BENCHMARK(uc); +BENCHMARK(uc); +BENCHMARK(uc); + +BENCHMARK(uc); +BENCHMARK(uc); +BENCHMARK(uc); +BENCHMARK(uc); + +BENCHMARK_MAIN(); diff --git a/benchmarks/src/vector_bool_copy.cpp b/benchmarks/src/vector_bool_copy.cpp new file mode 100644 index 00000000000..9c7bb5827d1 --- /dev/null +++ b/benchmarks/src/vector_bool_copy.cpp @@ -0,0 +1,110 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +// +#include +#include +#include +#include + +#include "utility.hpp" + +using namespace std; + +void copy_block_aligned(benchmark::State& state) { + const auto size = static_cast(state.range(0)); + vector source = random_vector(size); + vector dest(size, false); + + for (auto _ : state) { + benchmark::DoNotOptimize(source); + copy(source.cbegin(), source.cend(), dest.begin()); + benchmark::DoNotOptimize(dest); + } +} + +void copy_source_misaligned(benchmark::State& state) { + const auto size = static_cast(state.range(0)); + vector source = random_vector(size); + vector dest(size, false); + + for (auto _ : state) { + benchmark::DoNotOptimize(source); + copy(source.cbegin() + 1, source.cend(), dest.begin()); + benchmark::DoNotOptimize(dest); + } +} + +void copy_dest_misaligned(benchmark::State& state) { + const auto size = static_cast(state.range(0)); + vector source = random_vector(size); + vector dest(size, false); + + for (auto _ : state) { + benchmark::DoNotOptimize(source); + copy(source.cbegin(), source.cend() - 1, dest.begin() + 1); + benchmark::DoNotOptimize(dest); + } +} + +// Special benchmark for matching char alignment +void copy_matching_alignment(benchmark::State& state) { + const auto size = static_cast(state.range(0)); + vector source = random_vector(size); + vector dest(size, false); + + for (auto _ : state) { + benchmark::DoNotOptimize(source); + copy(source.cbegin() + 5, source.cend(), dest.begin() + 5); + benchmark::DoNotOptimize(dest); + } +} + +// Special benchmarks for single block corner case +void copy_both_single_blocks(benchmark::State& state) { + vector source = random_vector(50); + vector dest(50, false); + + const size_t length = 20; + for (auto _ : state) { + benchmark::DoNotOptimize(source); + copy(source.cbegin() + 5, source.cbegin() + 5 + length, dest.begin() + 5); + benchmark::DoNotOptimize(dest); + } +} + +void copy_source_single_block(benchmark::State& state) { + vector source = random_vector(50); + vector dest(50, false); + + const size_t length = 20; + for (auto _ : state) { + benchmark::DoNotOptimize(source); + copy(source.cbegin() + 5, source.cbegin() + 5 + length, dest.begin() + 25); + benchmark::DoNotOptimize(dest); + } +} + +void copy_dest_single_block(benchmark::State& state) { + vector source = random_vector(50); + vector dest(50, false); + + const size_t length = 20; + for (auto _ : state) { + benchmark::DoNotOptimize(source); + copy(source.cbegin() + 25, source.cbegin() + 25 + length, dest.begin() + 5); + benchmark::DoNotOptimize(dest); + } +} + +BENCHMARK(copy_block_aligned)->RangeMultiplier(64)->Range(64, 64 << 10); +BENCHMARK(copy_source_misaligned)->RangeMultiplier(64)->Range(64, 64 << 10); +BENCHMARK(copy_dest_misaligned)->RangeMultiplier(64)->Range(64, 64 << 10); +BENCHMARK(copy_matching_alignment)->RangeMultiplier(64)->Range(64, 64 << 10); + +BENCHMARK(copy_both_single_blocks); +BENCHMARK(copy_source_single_block); +BENCHMARK(copy_dest_single_block); + +BENCHMARK_MAIN(); diff --git a/benchmarks/src/vector_bool_copy_n.cpp b/benchmarks/src/vector_bool_copy_n.cpp new file mode 100644 index 00000000000..2ade38c90f4 --- /dev/null +++ b/benchmarks/src/vector_bool_copy_n.cpp @@ -0,0 +1,110 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +// +#include +#include +#include +#include + +#include "utility.hpp" + +using namespace std; + +void copy_n_block_aligned(benchmark::State& state) { + const auto size = static_cast(state.range(0)); + vector source = random_vector(size); + vector dest(size, false); + + for (auto _ : state) { + benchmark::DoNotOptimize(source); + copy_n(source.cbegin(), size, dest.begin()); + benchmark::DoNotOptimize(dest); + } +} + +void copy_n_source_misaligned(benchmark::State& state) { + const auto size = static_cast(state.range(0)); + vector source = random_vector(size); + vector dest(size, false); + + for (auto _ : state) { + benchmark::DoNotOptimize(source); + copy_n(source.cbegin() + 1, size - 1, dest.begin()); + benchmark::DoNotOptimize(dest); + } +} + +void copy_n_dest_misaligned(benchmark::State& state) { + const auto size = static_cast(state.range(0)); + vector source = random_vector(size); + vector dest(size, false); + + for (auto _ : state) { + benchmark::DoNotOptimize(source); + copy_n(source.cbegin(), size - 1, dest.begin() + 1); + benchmark::DoNotOptimize(dest); + } +} + +// Special benchmark for matching char alignment +void copy_n_matching_alignment(benchmark::State& state) { + const auto size = static_cast(state.range(0)); + vector source = random_vector(size); + vector dest(size, false); + + for (auto _ : state) { + benchmark::DoNotOptimize(source); + copy_n(source.cbegin() + 5, size - 5, dest.begin() + 5); + benchmark::DoNotOptimize(dest); + } +} + +// Special benchmarks for single block corner case +void copy_n_both_single_blocks(benchmark::State& state) { + vector source = random_vector(50); + vector dest(50, false); + + const size_t length = 20; + for (auto _ : state) { + benchmark::DoNotOptimize(source); + copy_n(source.cbegin() + 5, length, dest.begin() + 5); + benchmark::DoNotOptimize(dest); + } +} + +void copy_n_source_single_block(benchmark::State& state) { + vector source = random_vector(50); + vector dest(50, false); + + const size_t length = 20; + for (auto _ : state) { + benchmark::DoNotOptimize(source); + copy_n(source.cbegin() + 5, length, dest.begin() + 25); + benchmark::DoNotOptimize(dest); + } +} + +void copy_n_dest_single_block(benchmark::State& state) { + vector source = random_vector(50); + vector dest(50, false); + + const size_t length = 20; + for (auto _ : state) { + benchmark::DoNotOptimize(source); + copy_n(source.cbegin() + 25, length, dest.begin() + 5); + benchmark::DoNotOptimize(dest); + } +} + +BENCHMARK(copy_n_block_aligned)->RangeMultiplier(64)->Range(64, 64 << 10); +BENCHMARK(copy_n_source_misaligned)->RangeMultiplier(64)->Range(64, 64 << 10); +BENCHMARK(copy_n_dest_misaligned)->RangeMultiplier(64)->Range(64, 64 << 10); +BENCHMARK(copy_n_matching_alignment)->RangeMultiplier(64)->Range(64, 64 << 10); + +BENCHMARK(copy_n_both_single_blocks); +BENCHMARK(copy_n_source_single_block); +BENCHMARK(copy_n_dest_single_block); + +BENCHMARK_MAIN(); diff --git a/benchmarks/src/vector_bool_count.cpp b/benchmarks/src/vector_bool_count.cpp new file mode 100644 index 00000000000..65ad7fb9b91 --- /dev/null +++ b/benchmarks/src/vector_bool_count.cpp @@ -0,0 +1,32 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +// +#include +#include +#include +#include + +#include "utility.hpp" + +using namespace std; + +void count_aligned(benchmark::State& state) { + const auto size = static_cast(state.range(0)); + vector v = random_vector(size); + + bool b = false; + + for (auto _ : state) { + benchmark::DoNotOptimize(b); + benchmark::DoNotOptimize(v); + auto r = count(v.cbegin(), v.cend(), b); + benchmark::DoNotOptimize(r); + b = !b; + } +} + +BENCHMARK(count_aligned)->RangeMultiplier(64)->Range(64, 64 << 10); + +BENCHMARK_MAIN(); diff --git a/benchmarks/src/vector_bool_meow_of.cpp b/benchmarks/src/vector_bool_meow_of.cpp new file mode 100644 index 00000000000..dd5c87011a6 --- /dev/null +++ b/benchmarks/src/vector_bool_meow_of.cpp @@ -0,0 +1,54 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +// +#include +#include +#include +#include + +#include "skewed_allocator.hpp" + +using namespace std; + +enum class alg { all_, any_, none_ }; +enum class content { ones_then_zeros, zeros_then_ones }; + +template +void meow_of(benchmark::State& state) { + const auto n = static_cast(state.range(0)); + vector> source(n); + + if constexpr (Content == content::ones_then_zeros) { + fill(source.begin(), source.begin() + source.size() / 2, true); + } else { + fill(source.begin() + source.size() / 2, source.end(), true); + } + + for (auto _ : state) { + benchmark::DoNotOptimize(source); + bool result; + if constexpr (Alg == alg::all_) { + result = all_of(source.begin(), source.end(), Pred{}); + } else if constexpr (Alg == alg::any_) { + result = any_of(source.begin(), source.end(), Pred{}); + } else { + result = none_of(source.begin(), source.end(), Pred{}); + } + benchmark::DoNotOptimize(result); + } +} + +void common_args(benchmark::Benchmark* bm) { + bm->RangeMultiplier(64)->Range(64, 64 << 10); +} + +using not_ = logical_not<>; + +BENCHMARK(meow_of)->Apply(common_args); +BENCHMARK(meow_of)->Apply(common_args); +BENCHMARK(meow_of)->Apply(common_args); +BENCHMARK(meow_of)->Apply(common_args); + +BENCHMARK_MAIN(); diff --git a/benchmarks/src/vector_bool_move.cpp b/benchmarks/src/vector_bool_move.cpp new file mode 100644 index 00000000000..a8c3e693616 --- /dev/null +++ b/benchmarks/src/vector_bool_move.cpp @@ -0,0 +1,110 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +// +#include +#include +#include +#include + +#include "utility.hpp" + +using namespace std; + +void move_block_aligned(benchmark::State& state) { + const auto size = static_cast(state.range(0)); + vector source = random_vector(size); + vector dest(size, false); + + for (auto _ : state) { + benchmark::DoNotOptimize(source); + move(source.cbegin(), source.cend(), dest.begin()); + benchmark::DoNotOptimize(dest); + } +} + +void move_source_misaligned(benchmark::State& state) { + const auto size = static_cast(state.range(0)); + vector source = random_vector(size); + vector dest(size, false); + + for (auto _ : state) { + benchmark::DoNotOptimize(source); + move(source.cbegin() + 1, source.cend(), dest.begin()); + benchmark::DoNotOptimize(dest); + } +} + +void move_dest_misaligned(benchmark::State& state) { + const auto size = static_cast(state.range(0)); + vector source = random_vector(size); + vector dest(size, false); + + for (auto _ : state) { + benchmark::DoNotOptimize(source); + move(source.cbegin(), source.cend() - 1, dest.begin() + 1); + benchmark::DoNotOptimize(dest); + } +} + +// Special benchmark for matching char alignment +void move_matching_alignment(benchmark::State& state) { + const auto size = static_cast(state.range(0)); + vector source = random_vector(size); + vector dest(size, false); + + for (auto _ : state) { + benchmark::DoNotOptimize(source); + move(source.cbegin() + 5, source.cend(), dest.begin() + 5); + benchmark::DoNotOptimize(dest); + } +} + +// Special benchmarks for single block corner case +void move_both_single_blocks(benchmark::State& state) { + vector source = random_vector(50); + vector dest(50, false); + + const size_t length = 20; + for (auto _ : state) { + benchmark::DoNotOptimize(source); + move(source.cbegin() + 5, source.cbegin() + 5 + length, dest.begin() + 5); + benchmark::DoNotOptimize(dest); + } +} + +void move_source_single_block(benchmark::State& state) { + vector source = random_vector(50); + vector dest(50, false); + + const size_t length = 20; + for (auto _ : state) { + benchmark::DoNotOptimize(source); + move(source.cbegin() + 5, source.cbegin() + 5 + length, dest.begin() + 25); + benchmark::DoNotOptimize(dest); + } +} + +void move_dest_single_block(benchmark::State& state) { + vector source = random_vector(50); + vector dest(50, false); + + const size_t length = 20; + for (auto _ : state) { + benchmark::DoNotOptimize(source); + move(source.cbegin() + 25, source.cbegin() + 25 + length, dest.begin() + 5); + benchmark::DoNotOptimize(dest); + } +} + +BENCHMARK(move_block_aligned)->RangeMultiplier(64)->Range(64, 64 << 10); +BENCHMARK(move_source_misaligned)->RangeMultiplier(64)->Range(64, 64 << 10); +BENCHMARK(move_dest_misaligned)->RangeMultiplier(64)->Range(64, 64 << 10); +BENCHMARK(move_matching_alignment)->RangeMultiplier(64)->Range(64, 64 << 10); + +BENCHMARK(move_both_single_blocks); +BENCHMARK(move_source_single_block); +BENCHMARK(move_dest_single_block); + +BENCHMARK_MAIN(); diff --git a/benchmarks/src/vector_bool_transform.cpp b/benchmarks/src/vector_bool_transform.cpp new file mode 100644 index 00000000000..781b688a1c3 --- /dev/null +++ b/benchmarks/src/vector_bool_transform.cpp @@ -0,0 +1,54 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +// +#include +#include +#include +#include +#include + +#include "skewed_allocator.hpp" +#include "utility.hpp" + +using namespace std; + +template +void transform_one_input_aligned(benchmark::State& state) { + const auto size = static_cast(state.range(0)); + auto source = random_vector(size); + vector dest(size, false); + + for (auto _ : state) { + benchmark::DoNotOptimize(source); + transform(source.begin(), source.end(), dest.begin(), Pred{}); + benchmark::DoNotOptimize(dest); + } +} + +template +void transform_two_inputs_aligned(benchmark::State& state) { + const auto size = static_cast(state.range(0)); + auto source1 = random_vector(size); + auto source2 = random_vector(size, 1729u); + vector dest(size, false); + + for (auto _ : state) { + benchmark::DoNotOptimize(source1); + benchmark::DoNotOptimize(source2); + transform(source1.begin(), source1.end(), source2.begin(), dest.begin(), Pred{}); + benchmark::DoNotOptimize(dest); + } +} + +void common_args(benchmark::Benchmark* bm) { + bm->RangeMultiplier(64)->Range(64, 64 << 10); +} + +BENCHMARK(transform_two_inputs_aligned>)->Apply(common_args); +BENCHMARK(transform_two_inputs_aligned>)->Apply(common_args); +BENCHMARK(transform_two_inputs_aligned>)->Apply(common_args); +BENCHMARK(transform_one_input_aligned>)->Apply(common_args); + +BENCHMARK_MAIN(); diff --git a/boost-math b/boost-math new file mode 160000 index 00000000000..e0fcd19f722 --- /dev/null +++ b/boost-math @@ -0,0 +1 @@ +Subproject commit e0fcd19f7227d81391770ea46015acc3c80af810 diff --git a/docs/cgmanifest.json b/docs/cgmanifest.json index 6e1b6634269..9ad09bf1bca 100644 --- a/docs/cgmanifest.json +++ b/docs/cgmanifest.json @@ -1,11 +1,21 @@ { + "$schema": "https://json.schemastore.org/component-detection-manifest.json", "Registrations": [ + { + "component": { + "type": "git", + "git": { + "repositoryUrl": "https://github.com/boostorg/math", + "commitHash": "4d0885ae44f7d4ce94568339b2ae5501eb234e8f" + } + } + }, { "component": { "type": "git", "git": { "repositoryUrl": "https://github.com/llvm/llvm-project.git", - "commitHash": "fc2a5ef9c8754fe3fbdf96483901ca3f13406b35" + "commitHash": "12fcca0afeb08fbe41d79c5387cfacb249992bb4" } } }, @@ -14,7 +24,16 @@ "type": "git", "git": { "repositoryUrl": "https://github.com/microsoft/STL.git", - "commitHash": "355f8f560ecbde3a8832a5893ce7b4da7840549d" + "commitHash": "9bf8f3f9b03ff71ea83baff189eb1d6a46dd48e1" + } + } + }, + { + "component": { + "type": "git", + "git": { + "repositoryUrl": "https://github.com/fmtlib/fmt", + "commitHash": "273d8865e31659f69528623754c1742b2819ad26" } } }, diff --git a/docs/import_library.md b/docs/import_library.md new file mode 100644 index 00000000000..b4951bbba5a --- /dev/null +++ b/docs/import_library.md @@ -0,0 +1,52 @@ + + + +# Filenames + +Mode | Import Library | DLL (VS) | DLL (GitHub) | +--------|----------------|-----------------|---------------------| +Release | `msvcprt.lib` | `msvcp140.dll` | `msvcp140_oss.dll` | +Debug | `msvcprtd.lib` | `msvcp140d.dll` | `msvcp140d_oss.dll` | + +# Import Libraries + +An import library is a `.lib` file that defines its symbols as imported from a DLL. + +Usually there is one `.lib` file for one `.dll` file, with the same name. +The names are different for MSVC because it started encoding its ABI version into the DLL's filename, +but there was no reason to change the import library's filename. + +Also, an import library usually only contains references to DLL symbols and doesn't define anything on its own. +However, this is purely a convention - nothing technically stops an import library +from containing object files that are effectively statically linked. + +## Advantages of Injecting Additional Code + +This is what the STL's import library does - it defines some functions and variables on its own. +This allows us to: + +* Extend the STL implementation without altering the DLL export surface. + + This has been critical in allowing us to implement C++17 `` and much more. +* Separately compile functions and constant data for improved throughput. + + ``'s lookup tables are a notable example. + +## Limitations + +The caveats of this technique are: + +* It effectively defeats the purpose of the `/MD` and `/MDd` options by embedding part of + the STL implementation into the resulting user binaries, rather than staying in the STL's DLL. +* Due to the duplication in each user binary that links to the import library, + variables in the import library **cannot represent shared global state**. + + This limitation is subtle (not readily apparent from the source code) and critical. + If shared global state is necessary, our only option while preserving bincompat is adding a satellite DLL. +* Due to having just two flavors of the import library (debug and release), + we cannot use anything that depends on `_ITERATOR_DEBUG_LEVEL`. + +For these reasons, especially the last one, we need to strictly control what is used by the import library. +In particular, `basic_string` must not be used there. + +## Core Headers + +Restricting the import library to including core headers only is an effective way to avoid problems. +`locale0.cpp`'s inclusion of `` is currently a special case and should be treated with extreme caution. diff --git a/docs/msvc_libraries.plantuml b/docs/msvc_libraries.plantuml deleted file mode 100644 index c2798cf2e1b..00000000000 --- a/docs/msvc_libraries.plantuml +++ /dev/null @@ -1,50 +0,0 @@ -' Copyright (c) Microsoft Corporation. -' -' SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - -@startuml MSVC Library Block Diagram - -package "Visual Studio" { - - component STL [ - STL - This repo; provides C++ Standard Library headers, separately compiled - implementations of most of the iostreams functionality, and a few runtime - support components like std::exception_ptr. - ] - - package VCRuntime as VCRuntimePackage { - component VCStartup [ - VCStartup - Provides compiler support mechanisms that live in each binary; such as - machinery to call constructors and destructors for global variables, the - entry point, and the /GS cookie. - - Merged into static and import libraries of VCRuntime. - ] - - component VCRuntime [ - VCRuntime - Provides compiler support mechanisms that can be shared between - binaries; code that the compiler calls on your behalf, such as - the C++ exception handling runtime, string.h intrinsics, math - intrinsics, and declarations for CPU-vendor-specific intrinsics. - ] - - [VCStartup] --> [VCRuntime] - } -} - -package "Windows SDK" { - component UCRT [ - Universal CRT - Windows component that provides C library support, such as printf, - C locales, and some POSIX-like shims for the Windows API, like _stat. - ] -} - -STL --> UCRT -STL --> VCRuntimePackage -VCRuntime --> UCRT - -@enduml diff --git a/docs/msvc_libraries.plantuml.svg b/docs/msvc_libraries.plantuml.svg deleted file mode 100644 index 5a9aa8058df..00000000000 --- a/docs/msvc_libraries.plantuml.svg +++ /dev/null @@ -1 +0,0 @@ -Visual StudioVCRuntimeWindows SDKSTLThis repo; provides C++ Standard Library headers, separately compiledimplementations of most of the iostreams functionality, and a few runtimesupport components like std::exception_ptr.VCStartupProvides compiler support mechanisms that live in each binary; such asmachinery to call constructors and destructors for global variables, theentry point, and the /GS cookie.Merged into static and import libraries of VCRuntime.VCRuntimeProvides compiler support mechanisms that can be shared betweenbinaries; code that the compiler calls on your behalf, such asthe C++ exception handling runtime, string.h intrinsics, mathintrinsics, and declarations for CPU-vendor-specific intrinsics.Universal CRTWindows component that provides C library support, such as printf,C locales, and some POSIX-like shims for the Windows API, like _stat. diff --git a/llvm-project b/llvm-project index 60575179041..3bf2c8347e0 160000 --- a/llvm-project +++ b/llvm-project @@ -1 +1 @@ -Subproject commit 605751790418ca4fb1df1e94dfbac34cfcc1b96f +Subproject commit 3bf2c8347e04ba48dad1a7d73c5dd3b5e6dc8b7c diff --git a/stl/CMakeLists.txt b/stl/CMakeLists.txt index 6f2686e6de2..a6428797c01 100644 --- a/stl/CMakeLists.txt +++ b/stl/CMakeLists.txt @@ -1,9 +1,32 @@ # Copyright (c) Microsoft Corporation. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +################################################## +# Lists of files. (We can also copy files here.) # +################################################## + set(HEADERS ${CMAKE_CURRENT_LIST_DIR}/inc/__msvc_all_public_headers.hpp + ${CMAKE_CURRENT_LIST_DIR}/inc/__msvc_bit_utils.hpp + ${CMAKE_CURRENT_LIST_DIR}/inc/__msvc_chrono.hpp + ${CMAKE_CURRENT_LIST_DIR}/inc/__msvc_cxx_stdatomic.hpp + ${CMAKE_CURRENT_LIST_DIR}/inc/__msvc_filebuf.hpp + ${CMAKE_CURRENT_LIST_DIR}/inc/__msvc_format_ucd_tables.hpp + ${CMAKE_CURRENT_LIST_DIR}/inc/__msvc_formatter.hpp + ${CMAKE_CURRENT_LIST_DIR}/inc/__msvc_heap_algorithms.hpp + ${CMAKE_CURRENT_LIST_DIR}/inc/__msvc_int128.hpp + ${CMAKE_CURRENT_LIST_DIR}/inc/__msvc_iter_core.hpp + ${CMAKE_CURRENT_LIST_DIR}/inc/__msvc_minmax.hpp + ${CMAKE_CURRENT_LIST_DIR}/inc/__msvc_ostream.hpp + ${CMAKE_CURRENT_LIST_DIR}/inc/__msvc_print.hpp + ${CMAKE_CURRENT_LIST_DIR}/inc/__msvc_ranges_to.hpp + ${CMAKE_CURRENT_LIST_DIR}/inc/__msvc_ranges_tuple_formatter.hpp + ${CMAKE_CURRENT_LIST_DIR}/inc/__msvc_sanitizer_annotate_container.hpp + ${CMAKE_CURRENT_LIST_DIR}/inc/__msvc_string_view.hpp ${CMAKE_CURRENT_LIST_DIR}/inc/__msvc_system_error_abi.hpp + ${CMAKE_CURRENT_LIST_DIR}/inc/__msvc_threads_core.hpp + ${CMAKE_CURRENT_LIST_DIR}/inc/__msvc_tzdb.hpp + ${CMAKE_CURRENT_LIST_DIR}/inc/__msvc_xlocinfo_types.hpp ${CMAKE_CURRENT_LIST_DIR}/inc/algorithm ${CMAKE_CURRENT_LIST_DIR}/inc/any ${CMAKE_CURRENT_LIST_DIR}/inc/array @@ -43,109 +66,24 @@ set(HEADERS ${CMAKE_CURRENT_LIST_DIR}/inc/ctgmath ${CMAKE_CURRENT_LIST_DIR}/inc/ctime ${CMAKE_CURRENT_LIST_DIR}/inc/cuchar - ${CMAKE_CURRENT_LIST_DIR}/inc/cvt/8859_1 - ${CMAKE_CURRENT_LIST_DIR}/inc/cvt/8859_10 - ${CMAKE_CURRENT_LIST_DIR}/inc/cvt/8859_13 - ${CMAKE_CURRENT_LIST_DIR}/inc/cvt/8859_14 - ${CMAKE_CURRENT_LIST_DIR}/inc/cvt/8859_15 - ${CMAKE_CURRENT_LIST_DIR}/inc/cvt/8859_16 - ${CMAKE_CURRENT_LIST_DIR}/inc/cvt/8859_2 - ${CMAKE_CURRENT_LIST_DIR}/inc/cvt/8859_3 - ${CMAKE_CURRENT_LIST_DIR}/inc/cvt/8859_4 - ${CMAKE_CURRENT_LIST_DIR}/inc/cvt/8859_5 - ${CMAKE_CURRENT_LIST_DIR}/inc/cvt/8859_6 - ${CMAKE_CURRENT_LIST_DIR}/inc/cvt/8859_7 - ${CMAKE_CURRENT_LIST_DIR}/inc/cvt/8859_8 - ${CMAKE_CURRENT_LIST_DIR}/inc/cvt/8859_9 - ${CMAKE_CURRENT_LIST_DIR}/inc/cvt/baltic - ${CMAKE_CURRENT_LIST_DIR}/inc/cvt/big5 - ${CMAKE_CURRENT_LIST_DIR}/inc/cvt/cp037 - ${CMAKE_CURRENT_LIST_DIR}/inc/cvt/cp1006 - ${CMAKE_CURRENT_LIST_DIR}/inc/cvt/cp1026 - ${CMAKE_CURRENT_LIST_DIR}/inc/cvt/cp1250 - ${CMAKE_CURRENT_LIST_DIR}/inc/cvt/cp1251 - ${CMAKE_CURRENT_LIST_DIR}/inc/cvt/cp1252 - ${CMAKE_CURRENT_LIST_DIR}/inc/cvt/cp1253 - ${CMAKE_CURRENT_LIST_DIR}/inc/cvt/cp1254 - ${CMAKE_CURRENT_LIST_DIR}/inc/cvt/cp1255 - ${CMAKE_CURRENT_LIST_DIR}/inc/cvt/cp1256 - ${CMAKE_CURRENT_LIST_DIR}/inc/cvt/cp1257 - ${CMAKE_CURRENT_LIST_DIR}/inc/cvt/cp1258 - ${CMAKE_CURRENT_LIST_DIR}/inc/cvt/cp424 - ${CMAKE_CURRENT_LIST_DIR}/inc/cvt/cp437 - ${CMAKE_CURRENT_LIST_DIR}/inc/cvt/cp500 - ${CMAKE_CURRENT_LIST_DIR}/inc/cvt/cp737 - ${CMAKE_CURRENT_LIST_DIR}/inc/cvt/cp775 - ${CMAKE_CURRENT_LIST_DIR}/inc/cvt/cp850 - ${CMAKE_CURRENT_LIST_DIR}/inc/cvt/cp852 - ${CMAKE_CURRENT_LIST_DIR}/inc/cvt/cp855 - ${CMAKE_CURRENT_LIST_DIR}/inc/cvt/cp856 - ${CMAKE_CURRENT_LIST_DIR}/inc/cvt/cp857 - ${CMAKE_CURRENT_LIST_DIR}/inc/cvt/cp860 - ${CMAKE_CURRENT_LIST_DIR}/inc/cvt/cp861 - ${CMAKE_CURRENT_LIST_DIR}/inc/cvt/cp862 - ${CMAKE_CURRENT_LIST_DIR}/inc/cvt/cp863 - ${CMAKE_CURRENT_LIST_DIR}/inc/cvt/cp864 - ${CMAKE_CURRENT_LIST_DIR}/inc/cvt/cp865 - ${CMAKE_CURRENT_LIST_DIR}/inc/cvt/cp866 - ${CMAKE_CURRENT_LIST_DIR}/inc/cvt/cp869 - ${CMAKE_CURRENT_LIST_DIR}/inc/cvt/cp874 - ${CMAKE_CURRENT_LIST_DIR}/inc/cvt/cp875 - ${CMAKE_CURRENT_LIST_DIR}/inc/cvt/cp932 - ${CMAKE_CURRENT_LIST_DIR}/inc/cvt/cp936 - ${CMAKE_CURRENT_LIST_DIR}/inc/cvt/cp949 - ${CMAKE_CURRENT_LIST_DIR}/inc/cvt/cp950 - ${CMAKE_CURRENT_LIST_DIR}/inc/cvt/cyrillic - ${CMAKE_CURRENT_LIST_DIR}/inc/cvt/ebcdic - ${CMAKE_CURRENT_LIST_DIR}/inc/cvt/euc - ${CMAKE_CURRENT_LIST_DIR}/inc/cvt/euc_0208 - ${CMAKE_CURRENT_LIST_DIR}/inc/cvt/gb12345 - ${CMAKE_CURRENT_LIST_DIR}/inc/cvt/gb2312 - ${CMAKE_CURRENT_LIST_DIR}/inc/cvt/greek - ${CMAKE_CURRENT_LIST_DIR}/inc/cvt/iceland - ${CMAKE_CURRENT_LIST_DIR}/inc/cvt/jis - ${CMAKE_CURRENT_LIST_DIR}/inc/cvt/jis0201 - ${CMAKE_CURRENT_LIST_DIR}/inc/cvt/jis_0208 - ${CMAKE_CURRENT_LIST_DIR}/inc/cvt/ksc5601 - ${CMAKE_CURRENT_LIST_DIR}/inc/cvt/latin2 - ${CMAKE_CURRENT_LIST_DIR}/inc/cvt/one_one - ${CMAKE_CURRENT_LIST_DIR}/inc/cvt/roman - ${CMAKE_CURRENT_LIST_DIR}/inc/cvt/sjis - ${CMAKE_CURRENT_LIST_DIR}/inc/cvt/sjis_0208 - ${CMAKE_CURRENT_LIST_DIR}/inc/cvt/turkish - ${CMAKE_CURRENT_LIST_DIR}/inc/cvt/utf16 - ${CMAKE_CURRENT_LIST_DIR}/inc/cvt/utf8 - ${CMAKE_CURRENT_LIST_DIR}/inc/cvt/utf8_utf16 - ${CMAKE_CURRENT_LIST_DIR}/inc/cvt/wbuffer - ${CMAKE_CURRENT_LIST_DIR}/inc/cvt/wstring - ${CMAKE_CURRENT_LIST_DIR}/inc/cvt/xjis - ${CMAKE_CURRENT_LIST_DIR}/inc/cvt/xone_byte - ${CMAKE_CURRENT_LIST_DIR}/inc/cvt/xtwo_byte ${CMAKE_CURRENT_LIST_DIR}/inc/cwchar ${CMAKE_CURRENT_LIST_DIR}/inc/cwctype ${CMAKE_CURRENT_LIST_DIR}/inc/deque ${CMAKE_CURRENT_LIST_DIR}/inc/exception ${CMAKE_CURRENT_LIST_DIR}/inc/execution + ${CMAKE_CURRENT_LIST_DIR}/inc/expected ${CMAKE_CURRENT_LIST_DIR}/inc/experimental/coroutine - ${CMAKE_CURRENT_LIST_DIR}/inc/experimental/deque - ${CMAKE_CURRENT_LIST_DIR}/inc/experimental/filesystem - ${CMAKE_CURRENT_LIST_DIR}/inc/experimental/forward_list ${CMAKE_CURRENT_LIST_DIR}/inc/experimental/generator - ${CMAKE_CURRENT_LIST_DIR}/inc/experimental/list - ${CMAKE_CURRENT_LIST_DIR}/inc/experimental/map ${CMAKE_CURRENT_LIST_DIR}/inc/experimental/resumable - ${CMAKE_CURRENT_LIST_DIR}/inc/experimental/set - ${CMAKE_CURRENT_LIST_DIR}/inc/experimental/string - ${CMAKE_CURRENT_LIST_DIR}/inc/experimental/unordered_map - ${CMAKE_CURRENT_LIST_DIR}/inc/experimental/unordered_set - ${CMAKE_CURRENT_LIST_DIR}/inc/experimental/vector ${CMAKE_CURRENT_LIST_DIR}/inc/filesystem + ${CMAKE_CURRENT_LIST_DIR}/inc/flat_map + ${CMAKE_CURRENT_LIST_DIR}/inc/flat_set + ${CMAKE_CURRENT_LIST_DIR}/inc/format ${CMAKE_CURRENT_LIST_DIR}/inc/forward_list ${CMAKE_CURRENT_LIST_DIR}/inc/fstream ${CMAKE_CURRENT_LIST_DIR}/inc/functional ${CMAKE_CURRENT_LIST_DIR}/inc/future - ${CMAKE_CURRENT_LIST_DIR}/inc/hash_map - ${CMAKE_CURRENT_LIST_DIR}/inc/hash_set + ${CMAKE_CURRENT_LIST_DIR}/inc/generator ${CMAKE_CURRENT_LIST_DIR}/inc/header-units.json ${CMAKE_CURRENT_LIST_DIR}/inc/initializer_list ${CMAKE_CURRENT_LIST_DIR}/inc/iomanip @@ -160,6 +98,7 @@ set(HEADERS ${CMAKE_CURRENT_LIST_DIR}/inc/list ${CMAKE_CURRENT_LIST_DIR}/inc/locale ${CMAKE_CURRENT_LIST_DIR}/inc/map + ${CMAKE_CURRENT_LIST_DIR}/inc/mdspan ${CMAKE_CURRENT_LIST_DIR}/inc/memory ${CMAKE_CURRENT_LIST_DIR}/inc/memory_resource ${CMAKE_CURRENT_LIST_DIR}/inc/mutex @@ -168,6 +107,7 @@ set(HEADERS ${CMAKE_CURRENT_LIST_DIR}/inc/numeric ${CMAKE_CURRENT_LIST_DIR}/inc/optional ${CMAKE_CURRENT_LIST_DIR}/inc/ostream + ${CMAKE_CURRENT_LIST_DIR}/inc/print ${CMAKE_CURRENT_LIST_DIR}/inc/queue ${CMAKE_CURRENT_LIST_DIR}/inc/random ${CMAKE_CURRENT_LIST_DIR}/inc/ranges @@ -177,15 +117,20 @@ set(HEADERS ${CMAKE_CURRENT_LIST_DIR}/inc/semaphore ${CMAKE_CURRENT_LIST_DIR}/inc/set ${CMAKE_CURRENT_LIST_DIR}/inc/shared_mutex + ${CMAKE_CURRENT_LIST_DIR}/inc/source_location ${CMAKE_CURRENT_LIST_DIR}/inc/span + ${CMAKE_CURRENT_LIST_DIR}/inc/spanstream ${CMAKE_CURRENT_LIST_DIR}/inc/sstream ${CMAKE_CURRENT_LIST_DIR}/inc/stack + ${CMAKE_CURRENT_LIST_DIR}/inc/stacktrace ${CMAKE_CURRENT_LIST_DIR}/inc/stdexcept + ${CMAKE_CURRENT_LIST_DIR}/inc/stdfloat ${CMAKE_CURRENT_LIST_DIR}/inc/stop_token ${CMAKE_CURRENT_LIST_DIR}/inc/streambuf ${CMAKE_CURRENT_LIST_DIR}/inc/string ${CMAKE_CURRENT_LIST_DIR}/inc/string_view ${CMAKE_CURRENT_LIST_DIR}/inc/strstream + ${CMAKE_CURRENT_LIST_DIR}/inc/syncstream ${CMAKE_CURRENT_LIST_DIR}/inc/system_error ${CMAKE_CURRENT_LIST_DIR}/inc/thread ${CMAKE_CURRENT_LIST_DIR}/inc/tuple @@ -207,6 +152,7 @@ set(HEADERS ${CMAKE_CURRENT_LIST_DIR}/inc/xcharconv.h ${CMAKE_CURRENT_LIST_DIR}/inc/xcharconv_ryu.h ${CMAKE_CURRENT_LIST_DIR}/inc/xcharconv_ryu_tables.h + ${CMAKE_CURRENT_LIST_DIR}/inc/xcharconv_tables.h ${CMAKE_CURRENT_LIST_DIR}/inc/xerrc.h ${CMAKE_CURRENT_LIST_DIR}/inc/xfacet ${CMAKE_CURRENT_LIST_DIR}/inc/xfilesystem_abi.h @@ -216,7 +162,6 @@ set(HEADERS ${CMAKE_CURRENT_LIST_DIR}/inc/xlocale ${CMAKE_CURRENT_LIST_DIR}/inc/xlocbuf ${CMAKE_CURRENT_LIST_DIR}/inc/xlocinfo - ${CMAKE_CURRENT_LIST_DIR}/inc/xlocinfo.h ${CMAKE_CURRENT_LIST_DIR}/inc/xlocmes ${CMAKE_CURRENT_LIST_DIR}/inc/xlocmon ${CMAKE_CURRENT_LIST_DIR}/inc/xlocnum @@ -225,7 +170,6 @@ set(HEADERS ${CMAKE_CURRENT_LIST_DIR}/inc/xnode_handle.h ${CMAKE_CURRENT_LIST_DIR}/inc/xpolymorphic_allocator.h ${CMAKE_CURRENT_LIST_DIR}/inc/xsmf_control.h - ${CMAKE_CURRENT_LIST_DIR}/inc/xstddef ${CMAKE_CURRENT_LIST_DIR}/inc/xstring ${CMAKE_CURRENT_LIST_DIR}/inc/xthreads.h ${CMAKE_CURRENT_LIST_DIR}/inc/xtimec.h @@ -242,23 +186,54 @@ foreach(header ${HEADERS}) configure_file("${header}" "${PROJECT_BINARY_DIR}/out/inc/${_header_path}" COPYONLY) endforeach() +set(MODULE_FILES + ${CMAKE_CURRENT_LIST_DIR}/modules/modules.json + ${CMAKE_CURRENT_LIST_DIR}/modules/std.ixx + ${CMAKE_CURRENT_LIST_DIR}/modules/std.compat.ixx +) + +foreach(module_file ${MODULE_FILES}) + file(RELATIVE_PATH _module_file_path "${CMAKE_CURRENT_LIST_DIR}/modules" "${module_file}") + configure_file("${module_file}" "${PROJECT_BINARY_DIR}/out/modules/${_module_file_path}" COPYONLY) +endforeach() + +# Objs that implement aliases; these are completely independent of the configuration +set(ALIAS_SOURCES_X86_X64 + ${CMAKE_CURRENT_LIST_DIR}/src/alias_init_once_begin_initialize.asm + ${CMAKE_CURRENT_LIST_DIR}/src/alias_init_once_complete.asm +) + # Objs that exist in both libcpmt[d][01].lib and msvcprt[d].lib. set(IMPLIB_SOURCES + ${CMAKE_CURRENT_LIST_DIR}/src/asan_noop.cpp + ${CMAKE_CURRENT_LIST_DIR}/src/charconv.cpp ${CMAKE_CURRENT_LIST_DIR}/src/filesystem.cpp + ${CMAKE_CURRENT_LIST_DIR}/src/format.cpp ${CMAKE_CURRENT_LIST_DIR}/src/locale0_implib.cpp ${CMAKE_CURRENT_LIST_DIR}/src/nothrow.cpp + ${CMAKE_CURRENT_LIST_DIR}/src/print.cpp + ${CMAKE_CURRENT_LIST_DIR}/src/regex.cpp ${CMAKE_CURRENT_LIST_DIR}/src/sharedmutex.cpp + ${CMAKE_CURRENT_LIST_DIR}/src/stacktrace.cpp ${CMAKE_CURRENT_LIST_DIR}/src/syserror_import_lib.cpp ${CMAKE_CURRENT_LIST_DIR}/src/vector_algorithms.cpp + ${CMAKE_CURRENT_LIST_DIR}/src/xcharconv_ryu_tables.cpp + ${CMAKE_CURRENT_LIST_DIR}/src/xcharconv_tables_double.cpp + ${CMAKE_CURRENT_LIST_DIR}/src/xcharconv_tables_float.cpp ${CMAKE_CURRENT_LIST_DIR}/src/xonce2.cpp ) # The following files are linked in msvcp140[d][_clr].dll. -set (DLL_SOURCES +set(DLL_SOURCES ${CMAKE_CURRENT_LIST_DIR}/src/dllmain.cpp ${CMAKE_CURRENT_LIST_DIR}/src/instances.cpp ) +# Sources that must not be compiled with /GL, since they contain CRT initializers. +set(INITIALIZER_SOURCES + ${CMAKE_CURRENT_LIST_DIR}/src/winapisupp.cpp +) + set(SOURCES ${CMAKE_CURRENT_LIST_DIR}/src/StlCompareStringA.cpp ${CMAKE_CURRENT_LIST_DIR}/src/StlCompareStringW.cpp @@ -304,65 +279,30 @@ set(SOURCES ${CMAKE_CURRENT_LIST_DIR}/src/wclog.cpp ${CMAKE_CURRENT_LIST_DIR}/src/wcout.cpp ${CMAKE_CURRENT_LIST_DIR}/src/winapinls.cpp - ${CMAKE_CURRENT_LIST_DIR}/src/winapisupp.cpp ${CMAKE_CURRENT_LIST_DIR}/src/wiostrea.cpp ${CMAKE_CURRENT_LIST_DIR}/src/wlocale.cpp ${CMAKE_CURRENT_LIST_DIR}/src/xalloc.cpp ${CMAKE_CURRENT_LIST_DIR}/src/xcosh.cpp ${CMAKE_CURRENT_LIST_DIR}/src/xdateord.cpp - ${CMAKE_CURRENT_LIST_DIR}/src/xdint.cpp - ${CMAKE_CURRENT_LIST_DIR}/src/xdnorm.cpp - ${CMAKE_CURRENT_LIST_DIR}/src/xdscale.cpp - ${CMAKE_CURRENT_LIST_DIR}/src/xdtento.cpp ${CMAKE_CURRENT_LIST_DIR}/src/xdtest.cpp - ${CMAKE_CURRENT_LIST_DIR}/src/xdunscal.cpp ${CMAKE_CURRENT_LIST_DIR}/src/xexp.cpp - ${CMAKE_CURRENT_LIST_DIR}/src/xfcosh.cpp - ${CMAKE_CURRENT_LIST_DIR}/src/xfdint.cpp - ${CMAKE_CURRENT_LIST_DIR}/src/xfdnorm.cpp - ${CMAKE_CURRENT_LIST_DIR}/src/xfdscale.cpp - ${CMAKE_CURRENT_LIST_DIR}/src/xfdtento.cpp - ${CMAKE_CURRENT_LIST_DIR}/src/xfdtest.cpp - ${CMAKE_CURRENT_LIST_DIR}/src/xfdunsca.cpp - ${CMAKE_CURRENT_LIST_DIR}/src/xferaise.cpp - ${CMAKE_CURRENT_LIST_DIR}/src/xfexp.cpp - ${CMAKE_CURRENT_LIST_DIR}/src/xfprec.cpp - ${CMAKE_CURRENT_LIST_DIR}/src/xfsinh.cpp - ${CMAKE_CURRENT_LIST_DIR}/src/xfvalues.cpp ${CMAKE_CURRENT_LIST_DIR}/src/xgetwctype.cpp - ${CMAKE_CURRENT_LIST_DIR}/src/xlcosh.cpp - ${CMAKE_CURRENT_LIST_DIR}/src/xldint.cpp - ${CMAKE_CURRENT_LIST_DIR}/src/xldscale.cpp - ${CMAKE_CURRENT_LIST_DIR}/src/xldtento.cpp - ${CMAKE_CURRENT_LIST_DIR}/src/xldtest.cpp - ${CMAKE_CURRENT_LIST_DIR}/src/xldunsca.cpp - ${CMAKE_CURRENT_LIST_DIR}/src/xlexp.cpp ${CMAKE_CURRENT_LIST_DIR}/src/xlgamma.cpp ${CMAKE_CURRENT_LIST_DIR}/src/xlocale.cpp ${CMAKE_CURRENT_LIST_DIR}/src/xlock.cpp - ${CMAKE_CURRENT_LIST_DIR}/src/xlpoly.cpp - ${CMAKE_CURRENT_LIST_DIR}/src/xlprec.cpp - ${CMAKE_CURRENT_LIST_DIR}/src/xlsinh.cpp - ${CMAKE_CURRENT_LIST_DIR}/src/xlvalues.cpp ${CMAKE_CURRENT_LIST_DIR}/src/xmbtowc.cpp ${CMAKE_CURRENT_LIST_DIR}/src/xmtx.cpp ${CMAKE_CURRENT_LIST_DIR}/src/xnotify.cpp ${CMAKE_CURRENT_LIST_DIR}/src/xonce.cpp - ${CMAKE_CURRENT_LIST_DIR}/src/xpoly.cpp - ${CMAKE_CURRENT_LIST_DIR}/src/xprec.cpp ${CMAKE_CURRENT_LIST_DIR}/src/xrngabort.cpp ${CMAKE_CURRENT_LIST_DIR}/src/xrngdev.cpp ${CMAKE_CURRENT_LIST_DIR}/src/xsinh.cpp ${CMAKE_CURRENT_LIST_DIR}/src/xstod.cpp ${CMAKE_CURRENT_LIST_DIR}/src/xstof.cpp - ${CMAKE_CURRENT_LIST_DIR}/src/xstoflt.cpp ${CMAKE_CURRENT_LIST_DIR}/src/xstol.cpp - ${CMAKE_CURRENT_LIST_DIR}/src/xstold.cpp ${CMAKE_CURRENT_LIST_DIR}/src/xstoll.cpp - ${CMAKE_CURRENT_LIST_DIR}/src/xstopfx.cpp ${CMAKE_CURRENT_LIST_DIR}/src/xstoul.cpp ${CMAKE_CURRENT_LIST_DIR}/src/xstoull.cpp - ${CMAKE_CURRENT_LIST_DIR}/src/xstoxflt.cpp ${CMAKE_CURRENT_LIST_DIR}/src/xstrcoll.cpp ${CMAKE_CURRENT_LIST_DIR}/src/xstrxfrm.cpp ${CMAKE_CURRENT_LIST_DIR}/src/xthrow.cpp @@ -375,10 +315,10 @@ set(SOURCES ${CMAKE_CURRENT_LIST_DIR}/src/xwctomb.cpp ${CMAKE_CURRENT_LIST_DIR}/src/xwstod.cpp ${CMAKE_CURRENT_LIST_DIR}/src/xwstof.cpp - ${CMAKE_CURRENT_LIST_DIR}/src/xwstoflt.cpp - ${CMAKE_CURRENT_LIST_DIR}/src/xwstold.cpp - ${CMAKE_CURRENT_LIST_DIR}/src/xwstopfx.cpp - ${CMAKE_CURRENT_LIST_DIR}/src/xwstoxfl.cpp +) + +set(ASAN_SOURCES + ${CMAKE_CURRENT_LIST_DIR}/src/asan.cpp ) set(EHA_SOURCES @@ -396,6 +336,8 @@ set(SOURCES_SATELLITE_2 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 @@ -413,130 +355,236 @@ set(STATIC_SOURCES # Objs that exist in all satellite DLLs set(SATELLITE_DLL_SOURCES ${CMAKE_CURRENT_LIST_DIR}/src/dllmain_satellite.cpp - ) - -add_library(std_init_once_begin_initialize OBJECT IMPORTED) -add_library(std_init_once_complete OBJECT IMPORTED) -set_target_properties(std_init_once_begin_initialize PROPERTIES IMPORTED_OBJECTS "${CMAKE_CURRENT_LIST_DIR}/aliases/${VCLIBS_I386_OR_AMD64}/std_init_once_begin_initialize.obj") -set_target_properties(std_init_once_complete PROPERTIES IMPORTED_OBJECTS "${CMAKE_CURRENT_LIST_DIR}/aliases/${VCLIBS_I386_OR_AMD64}/std_init_once_complete.obj") +) -add_compile_definitions(_CRTBLD _VCRT_ALLOW_INTERNALS _HAS_OLD_IOSTREAMS_MEMBERS=1 _STL_CONCRT_SUPPORT) +#################### +# Toolset options. # +#################### + +set(CMAKE_CXX_FLAGS "") +set(CMAKE_CXX_FLAGS_DEBUG "") +set(CMAKE_CXX_FLAGS_RELEASE "") +set(CMAKE_MSVC_RUNTIME_CHECKS "") +set(CMAKE_CXX_STANDARD_LIBRARIES "kernel32.lib") +set(CMAKE_CXX_STANDARD_LIBRARIES_INIT "kernel32.lib") +set(CMAKE_MSVC_RUNTIME_LIBRARY "") + +set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${STL_ARCHIVE_OUTPUT_DIRECTORY}") +set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${STL_LIBRARY_OUTPUT_DIRECTORY}") +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${STL_RUNTIME_OUTPUT_DIRECTORY}") + +set(CMAKE_STATIC_LINKER_FLAGS "/WX") +set(CMAKE_STATIC_LINKER_FLAGS_DEBUG "") +set(CMAKE_STATIC_LINKER_FLAGS_RELEASE "") +set(CMAKE_SHARED_LINKER_FLAGS "/DEBUG:FULL /WX /RELEASE /SUBSYSTEM:Console /NODEFAULTLIB /INCREMENTAL:NO /MANIFEST:NO /DLL /profile /guard:cf /DEBUGTYPE:cv,fixup /LARGEADDRESSAWARE") +if(VCLIBS_TARGET_ARCHITECTURE STREQUAL "x64") + set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /CETCOMPAT") +endif() +if(VCLIBS_TARGET_ARCHITECTURE MATCHES "^(x64|arm64|arm64ec)$") + set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /guard:ehcont") +endif() +if(VCLIBS_TARGET_ARCHITECTURE MATCHES "^(arm64|arm64ec)$") + set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /guard:delayloadsignret") +endif() +set(CMAKE_SHARED_LINKER_FLAGS_DEBUG "") +set(CMAKE_SHARED_LINKER_FLAGS_RELEASE "") + +# Toolset options must appear before add_library() for the options to take effect. +add_compile_definitions(_CRTBLD _HAS_OLD_IOSTREAMS_MEMBERS=1) + +# /Z7 for MSVC, /Zi for MASM +set(CMAKE_MSVC_DEBUG_INFORMATION_FORMAT "Embedded") + +add_compile_options(/nologo /WX /Gy + "$<$:/diagnostics:caret;/W4;/w14265;/w15038;/fastfail;/guard:cf;/Zp8;/std:c++latest;/permissive-;/Zc:preprocessor;/Zc:threadSafeInit-;/Zl>" + "$<$,$>:/guard:ehcont>" + "$<$,$>:/guard:signret>" + "$<$:/W3;/quiet>" +) include_directories(BEFORE "${CMAKE_CURRENT_LIST_DIR}/inc" - "${TOOLSET_ROOT_DIR}/crt/src/concrt" "${TOOLSET_ROOT_DIR}/crt/src/vcruntime" ) -function(add_stl_dlls D_SUFFIX THIS_CONFIG_DEFINITIONS THIS_CONFIG_COMPILE_OPTIONS GL_FLAG THIS_CONFIG_LINK_OPTIONS) +########################### +# End of toolset options. # +########################### + +if(VCLIBS_TARGET_ARCHITECTURE MATCHES "^(x86|x64)$") + add_library(stl_alias_objects OBJECT ${ALIAS_SOURCES_X86_X64}) +else() + add_library(stl_alias_objects INTERFACE) +endif() + +if(STL_ASAN_BUILD) + set(DLL_ASAN_SOURCES ${ASAN_SOURCES}) +else() + set(DLL_ASAN_SOURCES "") +endif() + +function(target_stl_compile_options tgt rel_or_dbg) + if(rel_or_dbg STREQUAL "Release") + target_compile_options(${tgt} PRIVATE ${VCLIBS_RELEASE_OPTIONS}) + elseif(rel_or_dbg STREQUAL "Debug") + target_compile_options(${tgt} PRIVATE ${VCLIBS_DEBUG_OPTIONS}) + target_compile_definitions(${tgt} PRIVATE "_DEBUG") + else() + message(FATAL_ERROR "INTERNAL ERROR: unexpected value for rel_or_dbg: '${rel_or_dbg}'") + endif() +endfunction() + +function(generate_satellite_def SATELLITE_NAME D_SUFFIX) + set(full_satellite_name "msvcp140${D_SUFFIX}_${SATELLITE_NAME}${VCLIBS_SUFFIX}") + string(TOUPPER "${full_satellite_name}" upper_full_satellite_name) + set(satellite_input_src_file_path "${CMAKE_CURRENT_LIST_DIR}/src/msvcp_${SATELLITE_NAME}.src") + set(satellite_output_def_file_path "${CMAKE_BINARY_DIR}/msvcp_${SATELLITE_NAME}${D_SUFFIX}.def") + set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS "${satellite_input_src_file_path}") + + # We use the placeholder name "LIBRARYNAME" in the corresponding .src file of a satellite DLL + # (i.e., we write "LIBRARY LIBRARYNAME" as the first non-commented line in the file). + # + # Here, we dynamically replace this placeholder name with the name of the satellite DLL for + # the current build configuration. Then, we write out the new .def file to the binary output + # directory. + file(READ "${satellite_input_src_file_path}" satellite_def_file_contents) + string(REPLACE "LIBRARYNAME" "${upper_full_satellite_name}" satellite_def_file_contents "${satellite_def_file_contents}") + file(GENERATE OUTPUT "${satellite_output_def_file_path}" CONTENT "${satellite_def_file_contents}") +endfunction() + +function(add_stl_dlls D_SUFFIX REL_OR_DBG) + set(link_options_Release "/LTCG;/opt:ref,icf;${VCLIBS_EXPLICIT_MACHINE}") + set(link_options_Debug "/opt:ref,noicf;${VCLIBS_EXPLICIT_MACHINE}") + + set(gl_flag_Release "/GL") + set(gl_flag_Debug "") + # msvcp140.dll - add_library(msvcp${D_SUFFIX}_objects OBJECT ${DLL_SOURCES} ${SOURCES}) - target_compile_definitions(msvcp${D_SUFFIX}_objects PRIVATE "CRTDLL2;_DLL;${THIS_CONFIG_DEFINITIONS}") - target_compile_options(msvcp${D_SUFFIX}_objects PRIVATE "${THIS_CONFIG_COMPILE_OPTIONS};${GL_FLAG};/EHsc") + add_library(msvcp${D_SUFFIX}_objects OBJECT ${DLL_SOURCES} ${SOURCES} ${DLL_ASAN_SOURCES}) + target_compile_definitions(msvcp${D_SUFFIX}_objects PRIVATE CRTDLL2 _DLL) + target_compile_options(msvcp${D_SUFFIX}_objects PRIVATE ${gl_flag_${REL_OR_DBG}} /EHsc) + target_stl_compile_options(msvcp${D_SUFFIX}_objects ${REL_OR_DBG}) + + add_library(msvcp${D_SUFFIX}_init_objects OBJECT ${INITIALIZER_SOURCES}) + target_compile_definitions(msvcp${D_SUFFIX}_init_objects PRIVATE CRTDLL2 _DLL) + target_compile_options(msvcp${D_SUFFIX}_init_objects PRIVATE /EHsc) + target_stl_compile_options(msvcp${D_SUFFIX}_init_objects ${REL_OR_DBG}) add_library(msvcp${D_SUFFIX}_eha_objects OBJECT ${EHA_SOURCES}) - target_compile_definitions(msvcp${D_SUFFIX}_eha_objects PRIVATE "CRTDLL2;_DLL;${THIS_CONFIG_DEFINITIONS}") - target_compile_options(msvcp${D_SUFFIX}_eha_objects PRIVATE "${THIS_CONFIG_COMPILE_OPTIONS};${GL_FLAG};/EHa") + target_compile_definitions(msvcp${D_SUFFIX}_eha_objects PRIVATE CRTDLL2 _DLL) + target_compile_options(msvcp${D_SUFFIX}_eha_objects PRIVATE ${gl_flag_${REL_OR_DBG}} /EHa) + target_stl_compile_options(msvcp${D_SUFFIX}_eha_objects ${REL_OR_DBG}) add_library(msvcp${D_SUFFIX} SHARED) - target_link_libraries(msvcp${D_SUFFIX} PRIVATE msvcp${D_SUFFIX}_eha_objects msvcp${D_SUFFIX}_objects "${TOOLSET_LIB}/vcruntime${D_SUFFIX}.lib" "${TOOLSET_LIB}/msvcrt${D_SUFFIX}.lib" "ucrt${D_SUFFIX}.lib") + target_link_libraries(msvcp${D_SUFFIX} PRIVATE msvcp${D_SUFFIX}_eha_objects msvcp${D_SUFFIX}_objects msvcp${D_SUFFIX}_init_objects "${TOOLSET_LIB}/vcruntime${D_SUFFIX}.lib" "${TOOLSET_LIB}/msvcrt${D_SUFFIX}.lib" "ucrt${D_SUFFIX}.lib") + if(VCLIBS_TARGET_ARCHITECTURE MATCHES "^(arm64|arm64ec)$") + target_link_libraries(msvcp${D_SUFFIX} PRIVATE "softintrin.lib") + endif() set_target_properties(msvcp${D_SUFFIX} PROPERTIES ARCHIVE_OUTPUT_NAME "msvcp140_base${D_SUFFIX}${VCLIBS_SUFFIX}") set_target_properties(msvcp${D_SUFFIX} PROPERTIES ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}") set_target_properties(msvcp${D_SUFFIX} PROPERTIES OUTPUT_NAME "msvcp140${D_SUFFIX}${VCLIBS_SUFFIX}") - target_link_options(msvcp${D_SUFFIX} PRIVATE "${THIS_CONFIG_LINK_OPTIONS}") + target_link_options(msvcp${D_SUFFIX} PRIVATE ${link_options_${REL_OR_DBG}}) # import library 'statics' add_library(msvcp${D_SUFFIX}_implib_objects OBJECT ${IMPLIB_SOURCES}) - target_compile_definitions(msvcp${D_SUFFIX}_implib_objects PRIVATE "_DLL;${THIS_CONFIG_DEFINITIONS}") - target_compile_options(msvcp${D_SUFFIX}_implib_objects PRIVATE "${THIS_CONFIG_COMPILE_OPTIONS};/EHsc") # No /GL! + target_compile_definitions(msvcp${D_SUFFIX}_implib_objects PRIVATE _DLL _ENFORCE_ONLY_CORE_HEADERS) + target_compile_options(msvcp${D_SUFFIX}_implib_objects PRIVATE /EHsc) # No /GL! + target_stl_compile_options(msvcp${D_SUFFIX}_implib_objects ${REL_OR_DBG}) add_library(msvcp${D_SUFFIX}_satellite_objects OBJECT ${SATELLITE_DLL_SOURCES}) - target_compile_options(msvcp${D_SUFFIX}_satellite_objects PRIVATE "${THIS_CONFIG_COMPILE_OPTIONS};${GL_FLAG};/EHsc") - target_compile_definitions(msvcp${D_SUFFIX}_satellite_objects PRIVATE "_DLL;${THIS_CONFIG_DEFINITIONS}") + target_compile_definitions(msvcp${D_SUFFIX}_satellite_objects PRIVATE _DLL) + target_compile_options(msvcp${D_SUFFIX}_satellite_objects PRIVATE ${gl_flag_${REL_OR_DBG}} /EHsc) + target_stl_compile_options(msvcp${D_SUFFIX}_satellite_objects ${REL_OR_DBG}) # msvcp140_1.dll (the memory_resource satellite) add_library(msvcp_1${D_SUFFIX}_objects OBJECT ${SOURCES_SATELLITE_1}) - target_compile_definitions(msvcp_1${D_SUFFIX}_objects PRIVATE "_BUILDING_SATELLITE_1;_DLL;${THIS_CONFIG_DEFINITIONS}") - target_compile_options(msvcp_1${D_SUFFIX}_objects PRIVATE "${THIS_CONFIG_COMPILE_OPTIONS};${GL_FLAG};/EHsc") + target_compile_definitions(msvcp_1${D_SUFFIX}_objects PRIVATE _BUILDING_SATELLITE_1 _DLL) + target_compile_options(msvcp_1${D_SUFFIX}_objects PRIVATE ${gl_flag_${REL_OR_DBG}} /EHsc) + target_stl_compile_options(msvcp_1${D_SUFFIX}_objects ${REL_OR_DBG}) add_library(msvcp_1${D_SUFFIX} SHARED) target_link_libraries(msvcp_1${D_SUFFIX} PRIVATE msvcp_1${D_SUFFIX}_objects msvcp${D_SUFFIX}_satellite_objects "msvcp${D_SUFFIX}" "${TOOLSET_LIB}/vcruntime${D_SUFFIX}.lib" "${TOOLSET_LIB}/msvcrt${D_SUFFIX}.lib" "ucrt${D_SUFFIX}.lib") set_target_properties(msvcp_1${D_SUFFIX} PROPERTIES ARCHIVE_OUTPUT_NAME "msvcp140_1${D_SUFFIX}${VCLIBS_SUFFIX}") set_target_properties(msvcp_1${D_SUFFIX} PROPERTIES ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}") set_target_properties(msvcp_1${D_SUFFIX} PROPERTIES OUTPUT_NAME "msvcp140_1${D_SUFFIX}${VCLIBS_SUFFIX}") - target_link_options(msvcp_1${D_SUFFIX} PRIVATE "${THIS_CONFIG_LINK_OPTIONS}") + target_link_options(msvcp_1${D_SUFFIX} PRIVATE ${link_options_${REL_OR_DBG}}) # msvcp140_2.dll (the special math satellite) add_library(msvcp_2${D_SUFFIX}_objects OBJECT ${SOURCES_SATELLITE_2}) - target_compile_definitions(msvcp_2${D_SUFFIX}_objects PRIVATE "_BUILDING_SATELLITE_2;_DLL;${THIS_CONFIG_DEFINITIONS}") - target_compile_options(msvcp_2${D_SUFFIX}_objects PRIVATE "${THIS_CONFIG_COMPILE_OPTIONS};${GL_FLAG};/EHsc") - target_link_libraries(msvcp_2${D_SUFFIX}_objects PRIVATE Boost::headers Boost::disable_autolinking) + target_compile_definitions(msvcp_2${D_SUFFIX}_objects PRIVATE _BUILDING_SATELLITE_2 _DLL) + target_compile_options(msvcp_2${D_SUFFIX}_objects PRIVATE ${gl_flag_${REL_OR_DBG}} /EHsc) + target_link_libraries(msvcp_2${D_SUFFIX}_objects PRIVATE Boost::math) + target_stl_compile_options(msvcp_2${D_SUFFIX}_objects ${REL_OR_DBG}) add_library(msvcp_2${D_SUFFIX} SHARED) - target_link_libraries(msvcp_2${D_SUFFIX} PRIVATE msvcp_2${D_SUFFIX}_objects msvcp${D_SUFFIX}_satellite_objects msvcp${D_SUFFIX}_implib_objects std_init_once_begin_initialize std_init_once_complete "msvcp${D_SUFFIX}" "${TOOLSET_LIB}/vcruntime${D_SUFFIX}.lib" "${TOOLSET_LIB}/msvcrt${D_SUFFIX}.lib" "ucrt${D_SUFFIX}.lib") + target_link_libraries(msvcp_2${D_SUFFIX} PRIVATE msvcp_2${D_SUFFIX}_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") set_target_properties(msvcp_2${D_SUFFIX} PROPERTIES ARCHIVE_OUTPUT_NAME "msvcp140_2${D_SUFFIX}${VCLIBS_SUFFIX}") set_target_properties(msvcp_2${D_SUFFIX} PROPERTIES ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}") set_target_properties(msvcp_2${D_SUFFIX} PROPERTIES OUTPUT_NAME "msvcp140_2${D_SUFFIX}${VCLIBS_SUFFIX}") - target_link_options(msvcp_2${D_SUFFIX} PRIVATE "${THIS_CONFIG_LINK_OPTIONS}") + target_link_options(msvcp_2${D_SUFFIX} PRIVATE ${link_options_${REL_OR_DBG}}) # msvcp140_atomic_wait.dll (the atomic wait satellite) add_library(msvcp${D_SUFFIX}_atomic_wait_objects OBJECT ${SOURCES_SATELLITE_ATOMIC_WAIT}) - target_compile_definitions(msvcp${D_SUFFIX}_atomic_wait_objects PRIVATE "_BUILDING_SATELLITE_ATOMIC_WAIT;_DLL;${THIS_CONFIG_DEFINITIONS}") - target_compile_options(msvcp${D_SUFFIX}_atomic_wait_objects PRIVATE "${THIS_CONFIG_COMPILE_OPTIONS};${GL_FLAG};/EHsc") + target_compile_definitions(msvcp${D_SUFFIX}_atomic_wait_objects PRIVATE _BUILDING_SATELLITE_ATOMIC_WAIT _DLL) + target_compile_options(msvcp${D_SUFFIX}_atomic_wait_objects PRIVATE ${gl_flag_${REL_OR_DBG}} /EHsc) + target_stl_compile_options(msvcp${D_SUFFIX}_atomic_wait_objects ${REL_OR_DBG}) # generate the .def for msvcp140_atomic_wait.dll - set(_ATOMIC_WAIT_OUTPUT_NAME "msvcp140${D_SUFFIX}_atomic_wait${VCLIBS_SUFFIX}") - string(TOUPPER "${_ATOMIC_WAIT_OUTPUT_NAME}" _ATOMIC_WAIT_OUTPUT_NAME_UPPER) - set(_ATOMIC_WAIT_DEF_NAME "${CMAKE_BINARY_DIR}/msvcp_atomic_wait${D_SUFFIX}.def") - set(_ATOMIC_WAIT_DEF_FILE_SRC "${CMAKE_CURRENT_LIST_DIR}/src/msvcp_atomic_wait.src") - set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS "${_ATOMIC_WAIT_DEF_FILE_SRC}") - file(READ "${_ATOMIC_WAIT_DEF_FILE_SRC}" _ATOMIC_WAIT_SRC_CONTENTS) - string(REPLACE "LIBRARYNAME" "${_ATOMIC_WAIT_OUTPUT_NAME_UPPER}" _ATOMIC_WAIT_DEF_CONTENTS "${_ATOMIC_WAIT_SRC_CONTENTS}") - 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}" "${TOOLSET_LIB}/vcruntime${D_SUFFIX}.lib" "${TOOLSET_LIB}/msvcrt${D_SUFFIX}.lib" "ucrt${D_SUFFIX}.lib") + generate_satellite_def("atomic_wait" "${D_SUFFIX}") + + add_library(msvcp${D_SUFFIX}_atomic_wait SHARED "${CMAKE_BINARY_DIR}/msvcp_atomic_wait${D_SUFFIX}.def") + target_link_libraries(msvcp${D_SUFFIX}_atomic_wait PRIVATE msvcp${D_SUFFIX}_atomic_wait_objects msvcp${D_SUFFIX}_satellite_objects msvcp${D_SUFFIX}_implib_objects "msvcp${D_SUFFIX}" "${TOOLSET_LIB}/vcruntime${D_SUFFIX}.lib" "${TOOLSET_LIB}/msvcrt${D_SUFFIX}.lib" "ucrt${D_SUFFIX}.lib" "advapi32.lib" "synchronization.lib") set_target_properties(msvcp${D_SUFFIX}_atomic_wait PROPERTIES ARCHIVE_OUTPUT_NAME "msvcp140_atomic_wait${D_SUFFIX}${VCLIBS_SUFFIX}") set_target_properties(msvcp${D_SUFFIX}_atomic_wait PROPERTIES ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}") - set_target_properties(msvcp${D_SUFFIX}_atomic_wait PROPERTIES OUTPUT_NAME "${_ATOMIC_WAIT_OUTPUT_NAME}") - target_link_options(msvcp${D_SUFFIX}_atomic_wait PRIVATE "${THIS_CONFIG_LINK_OPTIONS}") + set_target_properties(msvcp${D_SUFFIX}_atomic_wait PROPERTIES OUTPUT_NAME "msvcp140${D_SUFFIX}_atomic_wait${VCLIBS_SUFFIX}") + target_link_options(msvcp${D_SUFFIX}_atomic_wait PRIVATE ${link_options_${REL_OR_DBG}}) # msvcp140_codecvt_ids.dll add_library(msvcp${D_SUFFIX}_codecvt_ids_objects OBJECT ${SOURCES_SATELLITE_CODECVT_IDS}) - target_compile_definitions(msvcp${D_SUFFIX}_codecvt_ids_objects PRIVATE "_BUILDING_SATELLITE_CODECVT_IDS;_DLL;${THIS_CONFIG_DEFINITIONS}") - target_compile_options(msvcp${D_SUFFIX}_codecvt_ids_objects PRIVATE "${THIS_CONFIG_COMPILE_OPTIONS};${GL_FLAG};/EHsc") + target_compile_definitions(msvcp${D_SUFFIX}_codecvt_ids_objects PRIVATE _BUILDING_SATELLITE_CODECVT_IDS _DLL) + target_compile_options(msvcp${D_SUFFIX}_codecvt_ids_objects PRIVATE ${gl_flag_${REL_OR_DBG}} /EHsc) + target_stl_compile_options(msvcp${D_SUFFIX}_codecvt_ids_objects ${REL_OR_DBG}) add_library(msvcp${D_SUFFIX}_codecvt_ids SHARED) target_link_libraries(msvcp${D_SUFFIX}_codecvt_ids PRIVATE msvcp${D_SUFFIX}_codecvt_ids_objects msvcp${D_SUFFIX}_satellite_objects "msvcp${D_SUFFIX}" "${TOOLSET_LIB}/vcruntime${D_SUFFIX}.lib" "${TOOLSET_LIB}/msvcrt${D_SUFFIX}.lib" "ucrt${D_SUFFIX}.lib") set_target_properties(msvcp${D_SUFFIX}_codecvt_ids PROPERTIES ARCHIVE_OUTPUT_NAME "msvcp140_codecvt_ids${D_SUFFIX}${VCLIBS_SUFFIX}") set_target_properties(msvcp${D_SUFFIX}_codecvt_ids PROPERTIES ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}") set_target_properties(msvcp${D_SUFFIX}_codecvt_ids PROPERTIES OUTPUT_NAME "msvcp140${D_SUFFIX}_codecvt_ids${VCLIBS_SUFFIX}") - target_link_options(msvcp${D_SUFFIX}_codecvt_ids PRIVATE "${THIS_CONFIG_LINK_OPTIONS}") + target_link_options(msvcp${D_SUFFIX}_codecvt_ids PRIVATE ${link_options_${REL_OR_DBG}}) # import library add_library(msvcp${D_SUFFIX}_implib STATIC ${HEADERS}) - target_link_libraries(msvcp${D_SUFFIX}_implib msvcp${D_SUFFIX}_implib_objects std_init_once_begin_initialize std_init_once_complete) + target_link_libraries(msvcp${D_SUFFIX}_implib stl_alias_objects msvcp${D_SUFFIX}_implib_objects) add_dependencies(msvcp${D_SUFFIX}_implib msvcp${D_SUFFIX} msvcp_1${D_SUFFIX} msvcp_2${D_SUFFIX} msvcp${D_SUFFIX}_atomic_wait msvcp${D_SUFFIX}_codecvt_ids) - set_target_properties(msvcp${D_SUFFIX}_implib PROPERTIES STATIC_LIBRARY_OPTIONS "/NOLOGO;/NODEFAULTLIB;/IGNORE:4006;$;$;$;$;$") + set_target_properties(msvcp${D_SUFFIX}_implib PROPERTIES STATIC_LIBRARY_OPTIONS "/NOLOGO;/NODEFAULTLIB;/IGNORE:4006;$;$;$;$;$;${VCLIBS_EXPLICIT_MACHINE}") set_target_properties(msvcp${D_SUFFIX}_implib PROPERTIES ARCHIVE_OUTPUT_NAME "msvcprt${D_SUFFIX}") endfunction() -add_stl_dlls("" "" "${VCLIBS_RELEASE_OPTIONS}" "/GL" "/LTCG;/opt:ref,icf") -add_stl_dlls("d" "_DEBUG" "${VCLIBS_DEBUG_OPTIONS}" "" "/opt:ref,noicf") +add_stl_dlls("" Release) +add_stl_dlls("d" Debug) -function(add_stl_statics FLAVOR_SUFFIX THIS_CONFIG_DEFINITIONS THIS_CONFIG_COMPILE_OPTIONS) +function(add_stl_statics FLAVOR_SUFFIX REL_OR_DBG IDL_VALUE) add_library(libcpmt${FLAVOR_SUFFIX}_eha OBJECT ${EHA_SOURCES}) - target_compile_definitions(libcpmt${FLAVOR_SUFFIX}_eha PRIVATE "${THIS_CONFIG_DEFINITIONS}") - target_compile_options(libcpmt${FLAVOR_SUFFIX}_eha PRIVATE "${THIS_CONFIG_COMPILE_OPTIONS};/EHa") - - add_library(libcpmt${FLAVOR_SUFFIX} STATIC ${HEADERS} ${IMPLIB_SOURCES} ${SOURCES} ${STATIC_SOURCES}) - target_compile_definitions(libcpmt${FLAVOR_SUFFIX} PRIVATE "${THIS_CONFIG_DEFINITIONS}") - target_compile_options(libcpmt${FLAVOR_SUFFIX} PRIVATE "${THIS_CONFIG_COMPILE_OPTIONS};/EHsc") - target_link_libraries(libcpmt${FLAVOR_SUFFIX} PRIVATE Boost::headers Boost::disable_autolinking libcpmt${FLAVOR_SUFFIX}_eha std_init_once_begin_initialize std_init_once_complete) + target_compile_definitions(libcpmt${FLAVOR_SUFFIX}_eha PRIVATE _ANNOTATE_STL "_ITERATOR_DEBUG_LEVEL=${IDL_VALUE}") + target_compile_options(libcpmt${FLAVOR_SUFFIX}_eha PRIVATE /EHa) + target_stl_compile_options(libcpmt${FLAVOR_SUFFIX}_eha ${REL_OR_DBG}) + + add_library(libcpmt${FLAVOR_SUFFIX} STATIC ${HEADERS} ${IMPLIB_SOURCES} ${SOURCES} ${INITIALIZER_SOURCES} ${STATIC_SOURCES}) + target_compile_definitions(libcpmt${FLAVOR_SUFFIX} PRIVATE _ANNOTATE_STL "_ITERATOR_DEBUG_LEVEL=${IDL_VALUE}") + target_compile_options(libcpmt${FLAVOR_SUFFIX} PRIVATE "$<$:/EHsc>") + target_link_libraries(libcpmt${FLAVOR_SUFFIX} PRIVATE Boost::math stl_alias_objects libcpmt${FLAVOR_SUFFIX}_eha) + target_stl_compile_options(libcpmt${FLAVOR_SUFFIX} ${REL_OR_DBG}) + set_target_properties(libcpmt${FLAVOR_SUFFIX} PROPERTIES STATIC_LIBRARY_OPTIONS "${VCLIBS_EXPLICIT_MACHINE}") endfunction() -add_stl_statics("" "_ITERATOR_DEBUG_LEVEL=0" "${VCLIBS_RELEASE_OPTIONS}") -add_stl_statics("1" "_ITERATOR_DEBUG_LEVEL=1" "${VCLIBS_RELEASE_OPTIONS}") -add_stl_statics("d" "_DEBUG;_ITERATOR_DEBUG_LEVEL=2" "${VCLIBS_DEBUG_OPTIONS}") -add_stl_statics("d1" "_DEBUG;_ITERATOR_DEBUG_LEVEL=1" "${VCLIBS_DEBUG_OPTIONS}") -add_stl_statics("d0" "_DEBUG;_ITERATOR_DEBUG_LEVEL=0" "${VCLIBS_DEBUG_OPTIONS}") +add_stl_statics("" Release 0) +add_stl_statics("1" Release 1) +add_stl_statics("d" Debug 2) +add_stl_statics("d1" Debug 1) +add_stl_statics("d0" Debug 0) + +add_library(stl_asan STATIC ${ASAN_SOURCES}) +set_target_properties(stl_asan PROPERTIES STATIC_LIBRARY_OPTIONS "${VCLIBS_EXPLICIT_MACHINE}") + +configure_file(set_environment.bat.in "${PROJECT_BINARY_DIR}/set_environment.bat" @ONLY) +configure_file(set_environment.ps1.in "${PROJECT_BINARY_DIR}/set_environment.ps1" @ONLY) diff --git a/stl/aliases/amd64/std_init_once_begin_initialize.obj b/stl/aliases/amd64/std_init_once_begin_initialize.obj deleted file mode 100644 index 5b310a11bf8..00000000000 Binary files a/stl/aliases/amd64/std_init_once_begin_initialize.obj and /dev/null differ diff --git a/stl/aliases/amd64/std_init_once_complete.obj b/stl/aliases/amd64/std_init_once_complete.obj deleted file mode 100644 index 31e048d3b76..00000000000 Binary files a/stl/aliases/amd64/std_init_once_complete.obj and /dev/null differ diff --git a/stl/aliases/arm/std_init_once_begin_initialize.obj b/stl/aliases/arm/std_init_once_begin_initialize.obj deleted file mode 100644 index 9279800efe2..00000000000 Binary files a/stl/aliases/arm/std_init_once_begin_initialize.obj and /dev/null differ diff --git a/stl/aliases/arm/std_init_once_complete.obj b/stl/aliases/arm/std_init_once_complete.obj deleted file mode 100644 index 746e0214d46..00000000000 Binary files a/stl/aliases/arm/std_init_once_complete.obj and /dev/null differ diff --git a/stl/aliases/arm64/std_init_once_begin_initialize.obj b/stl/aliases/arm64/std_init_once_begin_initialize.obj deleted file mode 100644 index 3c7dfc80dfd..00000000000 Binary files a/stl/aliases/arm64/std_init_once_begin_initialize.obj and /dev/null differ diff --git a/stl/aliases/arm64/std_init_once_complete.obj b/stl/aliases/arm64/std_init_once_complete.obj deleted file mode 100644 index 306df8aa000..00000000000 Binary files a/stl/aliases/arm64/std_init_once_complete.obj and /dev/null differ diff --git a/stl/aliases/arm64ec/std_init_once_begin_initialize.obj b/stl/aliases/arm64ec/std_init_once_begin_initialize.obj deleted file mode 100644 index 431291f2f90..00000000000 Binary files a/stl/aliases/arm64ec/std_init_once_begin_initialize.obj and /dev/null differ diff --git a/stl/aliases/arm64ec/std_init_once_complete.obj b/stl/aliases/arm64ec/std_init_once_complete.obj deleted file mode 100644 index 363bfe340e5..00000000000 Binary files a/stl/aliases/arm64ec/std_init_once_complete.obj and /dev/null differ diff --git a/stl/aliases/chpe/std_init_once_begin_initialize.obj b/stl/aliases/chpe/std_init_once_begin_initialize.obj deleted file mode 100644 index 40bfc75fdfd..00000000000 Binary files a/stl/aliases/chpe/std_init_once_begin_initialize.obj and /dev/null differ diff --git a/stl/aliases/chpe/std_init_once_complete.obj b/stl/aliases/chpe/std_init_once_complete.obj deleted file mode 100644 index 79707d2fc5b..00000000000 Binary files a/stl/aliases/chpe/std_init_once_complete.obj and /dev/null differ diff --git a/stl/aliases/generate.cmd b/stl/aliases/generate.cmd deleted file mode 100644 index 12cb87b3bc2..00000000000 --- a/stl/aliases/generate.cmd +++ /dev/null @@ -1,75 +0,0 @@ -:: Copyright (c) Microsoft Corporation. -:: SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -:: -:: Generates aliases for Windows API functions called by headers. -:: TRANSITION, VSO-1116868 "'aliasobj.exe' should be available with Visual Studio" - -cd %~dp0 - -rmdir /s /q i386 -rmdir /s /q amd64 -rmdir /s /q arm -rmdir /s /q arm64 -rmdir /s /q chpe -rmdir /s /q arm64ec - -mkdir i386 -mkdir amd64 -mkdir arm -mkdir arm64 -mkdir chpe -mkdir arm64ec - -:: __std_init_once_begin_initialize -..\..\..\..\..\tools\x86\aliasobj.exe ^ - __imp____std_init_once_begin_initialize@16 ^ - __imp__InitOnceBeginInitialize@16 ^ - i386\std_init_once_begin_initialize.obj -..\..\..\..\..\tools\amd64\aliasobj.exe ^ - __imp___std_init_once_begin_initialize ^ - __imp_InitOnceBeginInitialize ^ - amd64\std_init_once_begin_initialize.obj -..\..\..\..\..\tools\x86\aliasobj.exe ^ - __imp___std_init_once_begin_initialize ^ - __imp_InitOnceBeginInitialize ^ - arm\std_init_once_begin_initialize.obj -..\..\..\..\..\tools\amd64\aliasobj.exe ^ - /machine:arm64 ^ - __imp___std_init_once_begin_initialize ^ - __imp_InitOnceBeginInitialize ^ - arm64\std_init_once_begin_initialize.obj -..\..\..\..\..\tools\x86\aliasobj.exe ^ - __imp_#__std_init_once_begin_initialize@16 ^ - __imp_#InitOnceBeginInitialize@16 ^ - chpe\std_init_once_begin_initialize.obj -..\..\..\..\..\tools\amd64\aliasobj.exe ^ - /machine:arm64ec ^ - -m std_init_once_begin_initialize-arm64ec.txt ^ - arm64ec\std_init_once_begin_initialize.obj - -:: __std_init_once_complete -..\..\..\..\..\tools\x86\aliasobj.exe ^ - __imp____std_init_once_complete@12 ^ - __imp__InitOnceComplete@12 ^ - i386\std_init_once_complete.obj -..\..\..\..\..\tools\amd64\aliasobj.exe ^ - __imp___std_init_once_complete ^ - __imp_InitOnceComplete ^ - amd64\std_init_once_complete.obj -..\..\..\..\..\tools\x86\aliasobj.exe ^ - __imp___std_init_once_complete ^ - __imp_InitOnceComplete ^ - arm\std_init_once_complete.obj -..\..\..\..\..\tools\amd64\aliasobj.exe ^ - /machine:arm64 ^ - __imp___std_init_once_complete ^ - __imp_InitOnceComplete ^ - arm64\std_init_once_complete.obj -..\..\..\..\..\tools\x86\aliasobj.exe ^ - __imp_#__std_init_once_complete@12 ^ - __imp_#InitOnceComplete@12 ^ - chpe\std_init_once_complete.obj -..\..\..\..\..\tools\amd64\aliasobj.exe ^ - /machine:arm64ec ^ - -m std_init_once_complete-arm64ec.txt ^ - arm64ec\std_init_once_complete.obj diff --git a/stl/aliases/i386/std_init_once_begin_initialize.obj b/stl/aliases/i386/std_init_once_begin_initialize.obj deleted file mode 100644 index 139493af042..00000000000 Binary files a/stl/aliases/i386/std_init_once_begin_initialize.obj and /dev/null differ diff --git a/stl/aliases/i386/std_init_once_complete.obj b/stl/aliases/i386/std_init_once_complete.obj deleted file mode 100644 index c8a07b412d9..00000000000 Binary files a/stl/aliases/i386/std_init_once_complete.obj and /dev/null differ diff --git a/stl/aliases/std_init_once_begin_initialize-arm64ec.txt b/stl/aliases/std_init_once_begin_initialize-arm64ec.txt deleted file mode 100644 index 3431bdf51cf..00000000000 --- a/stl/aliases/std_init_once_begin_initialize-arm64ec.txt +++ /dev/null @@ -1,2 +0,0 @@ -#__std_init_once_begin_initialize #InitOnceBeginInitialize -__imp___std_init_once_begin_initialize __imp_InitOnceBeginInitialize diff --git a/stl/aliases/std_init_once_complete-arm64ec.txt b/stl/aliases/std_init_once_complete-arm64ec.txt deleted file mode 100644 index 4a146c7abfc..00000000000 --- a/stl/aliases/std_init_once_complete-arm64ec.txt +++ /dev/null @@ -1,2 +0,0 @@ -#__std_init_once_complete #InitOnceComplete -__imp___std_init_once_complete __imp_InitOnceComplete diff --git a/stl/debugger/STL.natvis b/stl/debugger/STL.natvis new file mode 100644 index 00000000000..48c6326a0ea --- /dev/null +++ b/stl/debugger/STL.natvis @@ -0,0 +1,2357 @@ + + + + + + + {*($T1 *)this} + + *($T1 *)this + + + + + + {_Myval1} + + _Myval1 + + + + + + [{name(),sb}] + + + Enable "Allow Function Calls In Value Formatting" if you see "???" here + + + + + + {{ value={_Myval}, category={*_Mycat} }} + + + Enable "Allow Function Calls In Value Formatting" if you see "???" here + + _Myval + _Mycat + + + + + + null + + + + + + {{ size={_Last - _First} }} + + + _Last - _First + _First + + + + + + + {first}, {second} + ({first}, {second}) + + first + second + + + + + + ({*this,view(noparens)}) + + + + + + + + {_Myfirst._Val}, {*((_Mybase *) this),view(noparens)} + + {_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 + + Next five elements: + + *((_Mybase::_Mybase::_Mybase::_Mybase::_Mybase *) this) + + + + + + {_Myfirst._Val}, {*((_Mybase *) this),view(noparensasptr)} + + {&_Myfirst._Val} + ({*this,view(noparensasptr)}) + + &_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),view(asptr) + + + + + 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 + + + + + {unex()} + + unex() + + + + + + {unex()} + + unex() + + + + + + + + {value()} + {unex()} + + value() + unex() + + + + + + + void + {unex()} + + unex() + + + + + + {{ 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 + + + + + + _Mypair._Myval2 + empty + unique_ptr void + + _Mypair._Myval2 + _Mypair + + + + + _Mypair._Myval2 + empty + unique_ptr {*_Mypair._Myval2} + + _Mypair._Myval2 + _Mypair + + + + + + + + + + + + + + {{empty}} + {_Mypair._Myval2} + _Mypair._Myval2 + + _Mypair + _Mypair._Myval2,hv + + + + + default + + _Ptr + + + + + + custom deleter + + _Mypair._Myval2 + _Mypair + + + + + + custom deleter, custom allocator + + _Mypair._Myval2._Myval2 + _Mypair + _Mypair._Myval2 + + + + + make_shared + + ($T1 *) &_Storage + + + + + + make_shared + + ($T1 *) &_Storage + + + + + + make_shared<T[N]> + + _Storage._Value + + + + + + + + make_shared<T[]> + + + size() + data() + + + + + + + make_shared<T[]> + + _Storage._Value + + + + + + allocate_shared + + ($T1 *) &_Mypair._Myval2 + _Mypair + + + + + + + + + + + + allocate_shared + + ($T1 *) &_Storage + allocator() + + + + + + + + + + allocate_shared<T[N]> + + _Storage._Value + allocator() + + + + + + + + + + + + allocate_shared<T[]> + + allocator() + + size() + data() + + + + + + + + + + + allocate_shared_for_overwrite + + ($T1 *) &_Storage + allocator() + + + + + + + + + + allocate_shared_for_overwrite<T[N]> + + _Storage._Value + allocator() + + + + + + + + + + + + allocate_shared_for_overwrite<T[]> + + allocator() + + size() + data() + + + + + + + custom deleter + + _Mypair._Myval2 + _Mypair + + + + + + custom deleter, custom allocator + + _Mypair._Myval2._Myval2 + _Mypair + _Mypair._Myval2 + + + + + + _Ptr + empty + nullptr + void + 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 + + + + + _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 + void + 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 + + + + + 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 + + + + + ranges::equal_to + ranges::not_equal_to + ranges::greater + ranges::less + ranges::greater_equal + ranges::less_equal + compare_three_way + + + 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({_Mypair}, {_Mypair._Myval2,view(noparens)}) + + _Mypair + _Mypair._Myval2 + + + + + bind_front({_Mypair}, {_Mypair._Myval2,view(noparens)}) + + _Mypair + _Mypair._Myval2 + + + + + bind_back({_Mypair}, {_Mypair._Myval2,view(noparens)}) + + _Mypair + _Mypair._Myval2 + + + + + + + mem_fn({_Pm}) + + + + + + + {_Mypair._Myval2} + + _Mypair._Myval2 + _Mypair + + + + + {_Callee} + + _Callee + + + + + + empty + {*_Mystorage._Ptrs[_EEN_IMPL]} + + *_Mystorage._Ptrs[_EEN_IMPL] + + + + + + hash + + + + + + {_MyRep} nanosecond + {_MyRep} nanoseconds + + + + + {_MyRep} microsecond + {_MyRep} microseconds + + + + + {_MyRep} millisecond + {_MyRep} milliseconds + + + + + {_MyRep} second + {_MyRep} seconds + + + + + {_MyRep} minute + {_MyRep} minutes + + + + + {_MyRep} hour + {_MyRep} hours + + + + + {_MyRep} day + {_MyRep} days + + + + + {_MyRep} week + {_MyRep} weeks + + + + + {_MyRep} month + {_MyRep} months + + + + + {_MyRep} year + {_MyRep} years + + + + + {(int)_Day}st + {(int)_Day}nd + {(int)_Day}rd + {(int)_Day}th + + + + + January + February + March + April + May + June + July + August + September + October + November + December + {_Month} + + + + + {_Year} + + + + + Sunday + Monday + Tuesday + Wednesday + Thursday + Friday + Saturday + {_Weekday} + + + + + {(int)_Index}st {_Weekday} + {(int)_Index}nd {_Weekday} + {(int)_Index}rd {_Weekday} + {(int)_Index}th {_Weekday} + {(int)_Index}, {_Weekday} + + _Weekday + (int)_Index + + + + + Last {_Weekday} + + _Weekday + + + + + {_Month} {_Day} + + _Month + _Day + + + + + Last day of {_Month} + + _Month + + + + + {_Weekday_index} of {_Month} + + _Month + _Weekday_index + + + + + Last {_Weekday_last._Weekday} of {_Month} + + _Month + _Weekday_last._Weekday + + + + + {_Year} {_Month} + + _Year + _Month + + + + + {_Year} {_Month} {_Day} + + _Year + _Month + _Day + + + + + {_Month_day_last}, {_Year} + + _Year + _Month_day_last._Month + + + + + {_Weekday_index} of {_Month}, {_Year} + + _Year + _Month + _Weekday_index + + + + + {_Weekday_last} of {_Month}, {_Year} + + _Year + _Month + _Weekday_last._Weekday + + + + + -{_Hours._MyRep}h {_Mins._MyRep}m {_Secs._MyRep}s {_Sub_secs._MyRep}ss + {_Hours._MyRep}h {_Mins._MyRep}m {_Secs._MyRep}s {_Sub_secs._MyRep}ss + + _Is_neg + _Hours + _Mins + _Secs + _Sub_secs + + + + + + + + + + + + + {_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 + + + + + + + _Ptr,na + + _Ptr + + + + + + + {_Mydata,[_Mysize]na} + _Mydata,[_Mysize]na + + size() + + size() + data() + + + + + + + _Myptr,na + + _Myptr + + + + + + {_Mydata + _Myoff,[_Mysize - _Myoff]na} + _Mydata + _Myoff,[_Mysize - _Myoff]na + + _Mydata + _Myoff + _Myoff + _Mydata,[_Mysize]na + + + + + + {{ size={$T2} }} + + + $T2 + _Elems + + + + + + + + _Ptr,na + {*_Ptr} + + _Ptr + + + + + + + _Ptr + _Idx + {_Ptr[_Idx]} + end + + _Ptr + _Idx + + + + + + {{ size={size()} }} + + _Mypair + + size() + _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 + + _Mypair + + _Mypair._Myval2._Myhead + _Next + _Myval + + + + + + + &_Ptr->_Myval,na + end + {**this} + + + + + {{ size={_Mypair._Myval2._Mysize} }} + + _Mypair + + _Mypair._Myval2._Mysize + _Mypair._Myval2._Myhead->_Next + _Next + _Myval + + + + + + + &_Ptr->_Myval,na + + + + + + + + {{ 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={size()} }} + + capacity() + _Mypair + + size() + _Mypair._Myval2._Myfirst + + + + + + + + + + + + + data() + {data(),[size()]na} + {{empty}} + + size() + capacity() + _Mypair + + size() + data() + + + + + + + + _Ptr,na + {*_Ptr} + + _Ptr + + + + + + + + _Ptr,na + end + {*_Ptr} + + _Ptr + + + + + + + + + {{ 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} + + _Maxidx + ((float)_List._Mypair._Myval2._Mysize) / ((float)_Maxidx) + _Traitsobj._Max_buckets + _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(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 + + + + + + &current._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 + + + + + + basic_const_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 + + _Mtx_storage._Thread_id + _Mtx_storage._Count + + + + + + unlocked + locked + + _My_owner + _My_locked + + + + + {&_MyMutex} + + &_MyMutex + + + + + empty + {*_Pmtx} - unowned + {*_Pmtx} - owned + + _Pmtx + _Owns + + + + + () + + + + ({&_MyMutex}) + + &_MyMutex + + + + + {_MyMutexes,view(asptr)} + + _MyMutexes,view(asptr) + + + + + std::defer_lock + + + + std::try_to_lock + + + + std::adopt_lock + + + + incomplete + complete + + + + + + _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) + + + + + + + + + + + + + {{ size={size()} }} + + + size() + data() + + + + + + + _Myptr,na + {*_Myptr} + + _Myptr + + + + + + _Myptr,na + end + {*_Myptr} + + _Myptr + + + + + default sentinel + + + + unreachable + + + + {{}} + + + + [{ _Val._Val }] + + + 1 + &_Val._Val + + + + + + + [{_Value}; {_Bound}) + + size() + + + + size() + + + val + ++val + + + + + + + [{_Value}; +∞) + + _Value + + + + + [{_Value._Val} x {_Bound}] + + _Bound + + + + + + _Value._Val + ++idx + + + + + + + [{_Value._Val} x +∞] + + _Value._Val + + + + + {*_Value} + + _Value + _Current + + + + + {*_Value} + + _Value + + + + + dangling + + + + {_Base} + + + + {_Stream} + + _Val + + + + + &_Current,na + + _Current + + + + + {&_Last,na} + + _Last + + + + + + + + + + + + + + + + + + + {_Range} + + _Pred + _Next + _Count + _Fun + _Pattern + _Stride + + + + + {{ id={_Thr._Id} }} + + + + {_Id} + + + + {_Impl} + + + + {_Text} + + + + {_Function,sb}: ({_Line}, {_Column}) + + _Line + _Column + _File,s + _Function,s + + + + + less + equal + greater + + + + + less + equivalent + greater + + + + + less + equivalent + greater + unordered + + + + + {_Format_string} + + _Num_args + _Next_arg_id + + + + + + + + + {{ size={_Num_args} }} + + + _Num_args + "None" + + + *(int*)(&storage()[_Index_array[$i]._Index]) + + + + *(unsigned int*)(&storage()[_Index_array[$i]._Index]) + + + + *(long long*)(&storage()[_Index_array[$i]._Index]) + + + + *(unsigned long long*)(&storage()[_Index_array[$i]._Index]) + + + + *(bool*)(&storage()[_Index_array[$i]._Index]) + + + + *(char*)(&storage()[_Index_array[$i]._Index]) + + + + *(float*)(&storage()[_Index_array[$i]._Index]) + + + + *(double*)(&storage()[_Index_array[$i]._Index]) + + + + *(long double*)(&storage()[_Index_array[$i]._Index]) + + + + *(void**)(&storage()[_Index_array[$i]._Index]) + + + + *(char**)(&storage()[_Index_array[$i]._Index]) + + + + *(std::string_view*)(&storage()[_Index_array[$i]._Index]) + + + + *(void**)(&storage()[_Index_array[$i]._Index]) + + + + + + + + + + + {{ size={_Num_args} }} + + + _Num_args + + + *(int*)(&storage()[_Index_array[$i]._Index]) + + + + *(unsigned int*)(&storage()[_Index_array[$i]._Index]) + + + + *(long long*)(&storage()[_Index_array[$i]._Index]) + + + + *(unsigned long long*)(&storage()[_Index_array[$i]._Index]) + + + + *(bool*)(&storage()[_Index_array[$i]._Index]) + + + + *(wchar_t*)(&storage()[_Index_array[$i]._Index]) + + + + *(float*)(&storage()[_Index_array[$i]._Index]) + + + + *(double*)(&storage()[_Index_array[$i]._Index]) + + + + *(long double*)(&storage()[_Index_array[$i]._Index]) + + + + *(void**)(&storage()[_Index_array[$i]._Index]) + + + + *(wchar_t**)(&storage()[_Index_array[$i]._Index]) + + + + *(std::wstring_view*)(&storage()[_Index_array[$i]._Index]) + + + + *(void**)(&storage()[_Index_array[$i]._Index]) + + + + + + + No state: {_No_state} + Int state: {_Int_state} + UInt state: {_UInt_state} + Long long state: {_Long_long_state} + ULong long state: {_ULong_long_state} + Bool state: {_Bool_state} + Char state: {_Char_state} + Float state: {_Float_state} + Double state: {_Double_state} + Long double state: {_Long_double_state} + Pointer state: {_Pointer_state} + CString state: {_CString_state} + String state: {_String_state} + Custom state: {_Custom_state} + Invalid state: {_Active_state} + + + + {_Args} + + _OutputIt + _Loc + + + + + {what()} + + + + + + {_Data} + + + + + + + + + + [empty] + [not empty (trivial)] + [not empty (small)] + [not empty (large)] + + (void*)(&_Storage._TrivialData) + (void*)(&_Storage._SmallStorage._Data) + _Storage._BigStorage._Ptr + + {has_value()} + + + {type()} + + + (Small and Trivial Object) + + + (Small Object) + + + (Dynamic Allocation) + + + + + + + + + + + + + + + + + + + + + {year(),d}-{month()/10,d}{month()%10,d}-{day()/10,d}{day()%10,d} { + (_MyDur._MyRep % (24 * 60 * 60 * 10000000ull))/(10 * 60 * 60 * 10000000ull),d + }{ + ((_MyDur._MyRep % (24 * 60 * 60 * 10000000ull))/(60 * 60 * 10000000ull)) % 10,d + }:{ + (_MyDur._MyRep % (60 * 60 * 10000000ull))/(10 * 60 * 10000000ull),d + }{ + (_MyDur._MyRep % (10 * 60 * 10000000ull)) / (60 * 10000000ull),d + }:{ + (_MyDur._MyRep % (60 * 10000000ull)) / (10 * 10000000ull),d + }{ + (_MyDur._MyRep % (10 * 10000000ull)) / 10000000ull,d + }.{ + (_MyDur._MyRep % 10000000) / 1000000,d + }{ + (_MyDur._MyRep % 1000000) / 100000,d + }{ + (_MyDur._MyRep % 100000) / 10000,d + }{ + (_MyDur._MyRep % 10000) / 1000,d + }{ + (_MyDur._MyRep % 1000) / 100,d + }{ + (_MyDur._MyRep % 100) / 10,d + }{ + _MyDur._MyRep % 10,d + } + + + _MyDur._MyRep + _MyDur._MyRep/10 + _MyDur._MyRep/(10 * 1000) + _MyDur._MyRep/(10 * 1000 * 1000) + UTC + + + + + {{ rank={_Rank}, rank_dynamic={_Rank_dynamic} }} + + + + + + + + + + *dynptr + ++dynptr + + ($T1) *statptr + ++idx, ++statptr + + + + + + + + + + *dynptr + ++idx, ++dynptr + + + + + + + + + + ($T1) *statptr + ++idx, ++statptr + + + + + + + + + + + + + + + + {{ size={size()} }} + + + size() + _Key_compare + + + size() + + *value_at(i) + ++i + + + + + + + + + + {{ size={size()} }} + + _Key_compare + _Data.keys + _Data.values + + + + + ({_Key_it}, {_Mapped_it}) + + _Key_it + _Mapped_it + + + + + + {_Data} + + _Key_compare + _Data + + + + diff --git a/stl/inc/__msvc_all_public_headers.hpp b/stl/inc/__msvc_all_public_headers.hpp index b238fdb7602..da0e1103797 100644 --- a/stl/inc/__msvc_all_public_headers.hpp +++ b/stl/inc/__msvc_all_public_headers.hpp @@ -13,29 +13,22 @@ #pragma warning(1 : 4668) // 'MEOW' is not defined as a preprocessor macro, replacing with '0' for '#if/#elif' // All STL headers should protect themselves from macroized new. +#if !(defined(__CUDACC__) && defined(__clang__)) #pragma push_macro("new") #undef new #define new WILL NOT COMPILE +#endif // !(defined(__CUDACC__) && defined(__clang__)) // VSO-768746: mbctype.h macroizes _MS, _MP, _M1, and _M2. Include it first for test coverage. #ifndef _MSVC_TESTING_NVCC #include -#endif // _MSVC_TESTING_NVCC - -#if 1 // TRANSITION, OS-17090155 (UCRT) -#define _CRT_DECLARE_NONSTDC_NAMES 0 -#ifndef _MSVC_TESTING_NVCC -#include -#include -#include -#endif // _MSVC_TESTING_NVCC -#undef _CRT_DECLARE_NONSTDC_NAMES -#endif // TRANSITION, OS-17090155 (UCRT) +#endif // !defined(_MSVC_TESTING_NVCC) +#ifndef _SILENCE_CXX17_C_HEADER_DEPRECATION_WARNING #define _SILENCE_CXX17_C_HEADER_DEPRECATION_WARNING -#define _SILENCE_CXX17_STRSTREAM_DEPRECATION_WARNING -#define _SILENCE_EXPERIMENTAL_FILESYSTEM_DEPRECATION_WARNING -#define _SILENCE_STDEXT_HASH_DEPRECATION_WARNINGS +#endif // !defined(_SILENCE_CXX17_C_HEADER_DEPRECATION_WARNING) + +#define _SILENCE_CXX20_CISO646_REMOVED_WARNING // Core STL Headers #include @@ -46,6 +39,9 @@ #include #include #include +#include +#include +#include #include #include #include @@ -85,12 +81,15 @@ #include #include #include +#include #include +#include +#include +#include #include #include #include -#include -#include +#include #include #include #include @@ -100,12 +99,14 @@ #include #include #include +#include #include #include #include #include #include #include +#include #include #include #include @@ -113,15 +114,17 @@ #include #include #include +#include #include #include +#include #include #include #include #include #include +#include #include -#include #include #include #include @@ -131,21 +134,19 @@ #include #ifndef _M_CEE_PURE +#include <__msvc_cxx_stdatomic.hpp> #include #include -#include -#include -#include -#endif // _M_CEE_PURE - -#ifndef _M_CEE #include #include #include +#include #include +#include #include +#include #include -#endif // _M_CEE +#endif // !defined(_M_CEE_PURE) // Non-Core C Wrapper Headers #include @@ -155,19 +156,7 @@ #include #include -// Non-Core Experimental Headers -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#endif // _CORE_HEADERS_ONLY +#endif // !defined(_CORE_HEADERS_ONLY) #ifndef _MSVC_TESTING_NVCC #include @@ -220,14 +209,16 @@ #ifndef _CORE_HEADERS_ONLY #include #include -#endif // _CORE_HEADERS_ONLY +#endif // !defined(_CORE_HEADERS_ONLY) #ifndef _M_CEE_PURE #include -#endif // _M_CEE_PURE -#endif // _MSVC_TESTING_NVCC +#endif // !defined(_M_CEE_PURE) +#endif // !defined(_MSVC_TESTING_NVCC) +#if !(defined(__CUDACC__) && defined(__clang__)) #pragma pop_macro("new") +#endif // !(defined(__CUDACC__) && defined(__clang__)) #pragma warning(pop) diff --git a/stl/inc/__msvc_bit_utils.hpp b/stl/inc/__msvc_bit_utils.hpp new file mode 100644 index 00000000000..0231603c9bc --- /dev/null +++ b/stl/inc/__msvc_bit_utils.hpp @@ -0,0 +1,406 @@ +// __msvc_bit_utils.hpp internal header (core) + +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#ifndef __MSVC_BIT_UTILS_HPP +#define __MSVC_BIT_UTILS_HPP +#include +#if _STL_COMPILER_PREPROCESSOR + +#include +#include + +#include _STL_INTRIN_HEADER + +#pragma pack(push, _CRT_PACKING) +#pragma warning(push, _STL_WARNING_LEVEL) +#pragma warning(disable : _STL_DISABLED_WARNINGS) +_STL_DISABLE_CLANG_WARNINGS +#pragma push_macro("new") +#undef new + +_STD_BEGIN +extern "C" { +extern int __isa_available; +} + +_INLINE_VAR constexpr int _Stl_isa_available_sse42 = 2; // equal to __ISA_AVAILABLE_SSE42 +_INLINE_VAR constexpr int _Stl_isa_available_avx2 = 5; // equal to __ISA_AVAILABLE_AVX2 + +template +constexpr int _Unsigned_integer_digits = sizeof(_UInt) * CHAR_BIT; + +// Implementation of countl_zero without using specialized CPU instructions. +// Used at compile time and when said instructions are not supported. +// see "Hacker's Delight" section 5-3 +template +_NODISCARD constexpr int _Countl_zero_fallback(_Ty _Val) noexcept { + _Ty _Yx = 0; + + unsigned int _Nx = _Unsigned_integer_digits<_Ty>; + unsigned int _Cx = _Unsigned_integer_digits<_Ty> / 2; + do { + _Yx = static_cast<_Ty>(_Val >> _Cx); + if (_Yx != 0) { + _Nx -= _Cx; + _Val = _Yx; + } + _Cx >>= 1; + } while (_Cx != 0); + return static_cast(_Nx) - static_cast(_Val); +} + +#if !defined(_M_CEE_PURE) && !defined(__CUDACC__) +#define _HAS_COUNTL_ZERO_INTRINSICS 1 +#else // ^^^ intrinsics available / intrinsics unavailable vvv +#define _HAS_COUNTL_ZERO_INTRINSICS 0 +#endif // ^^^ intrinsics unavailable ^^^ + +#if _HAS_COUNTL_ZERO_INTRINSICS +#if (defined(_M_IX86) && !defined(_M_HYBRID_X86_ARM64)) || (defined(_M_X64) && !defined(_M_ARM64EC)) +template +_NODISCARD int _Countl_zero_lzcnt(const _Ty _Val) noexcept { + constexpr int _Digits = _Unsigned_integer_digits<_Ty>; + + if constexpr (_Digits <= 16) { + return static_cast(__lzcnt16(_Val) - (16 - _Digits)); + } else if constexpr (_Digits == 32) { + return static_cast(__lzcnt(_Val)); + } else { +#ifdef _M_IX86 + const unsigned int _High = _Val >> 32; + const auto _Low = static_cast(_Val); + if (_High == 0) { + return 32 + _Countl_zero_lzcnt(_Low); + } else { + return _Countl_zero_lzcnt(_High); + } +#else // ^^^ defined(_M_IX86) / !defined(_M_IX86) vvv + return static_cast(__lzcnt64(_Val)); +#endif // ^^^ !defined(_M_IX86) ^^^ + } +} + +template +_NODISCARD int _Countl_zero_bsr(const _Ty _Val) noexcept { + constexpr int _Digits = _Unsigned_integer_digits<_Ty>; + + unsigned long _Result; + if constexpr (_Digits <= 32) { + if (!_BitScanReverse(&_Result, _Val)) { + return _Digits; + } + } else { +#ifdef _M_IX86 + const unsigned int _High = _Val >> 32; + if (_BitScanReverse(&_Result, _High)) { + return static_cast(31 - _Result); + } + + const auto _Low = static_cast(_Val); + if (!_BitScanReverse(&_Result, _Low)) { + return _Digits; + } +#else // ^^^ defined(_M_IX86) / !defined(_M_IX86) vvv + if (!_BitScanReverse64(&_Result, _Val)) { + return _Digits; + } +#endif // ^^^ !defined(_M_IX86) ^^^ + } + return static_cast(_Digits - 1 - _Result); +} + +template +_NODISCARD int _Checked_x86_x64_countl_zero(const _Ty _Val) noexcept { +#ifndef __AVX2__ + const bool _Definitely_have_lzcnt = __isa_available >= _Stl_isa_available_avx2; + if (!_Definitely_have_lzcnt) { + return _Countl_zero_bsr(_Val); + } +#endif // ^^^ !defined(__AVX2__) ^^^ + return _Countl_zero_lzcnt(_Val); +} +#endif // (defined(_M_IX86) && !defined(_M_HYBRID_X86_ARM64)) || (defined(_M_X64) && !defined(_M_ARM64EC)) + +#if defined(_M_ARM64) || defined(_M_ARM64EC) || defined(_M_HYBRID_X86_ARM64) +template +_NODISCARD int _Checked_arm64_countl_zero(const _Ty _Val) noexcept { + constexpr int _Digits = _Unsigned_integer_digits<_Ty>; + if (_Val == 0) { + return _Digits; + } + + if constexpr (_Digits <= 32) { + return static_cast(_CountLeadingZeros(_Val)) - (_Unsigned_integer_digits - _Digits); + } else { + return static_cast(_CountLeadingZeros64(_Val)); + } +} +#endif // defined(_M_ARM64) || defined(_M_ARM64EC) || defined(_M_HYBRID_X86_ARM64) +#endif // _HAS_COUNTL_ZERO_INTRINSICS + +// Implementation of countr_zero without using specialized CPU instructions. +// Used at compile time and when said instructions are not supported. +// see "Hacker's Delight" section 5-4 +template +_NODISCARD constexpr int _Countr_zero_fallback(const _Ty _Val) noexcept { + constexpr int _Digits = _Unsigned_integer_digits<_Ty>; + return _Digits - _Countl_zero_fallback(static_cast<_Ty>(static_cast<_Ty>(~_Val) & static_cast<_Ty>(_Val - 1))); +} + +// Implementation of popcount without using specialized CPU instructions. +// Used at compile time and when said instructions are not supported. +template +_NODISCARD constexpr int _Popcount_fallback(_Ty _Val) noexcept { + constexpr int _Digits = _Unsigned_integer_digits<_Ty>; +#if defined(_M_IX86) && !defined(_M_HYBRID_X86_ARM64) + if constexpr (_Digits == 64) { + // 64-bit bit operations on architectures without 64-bit registers are less efficient, + // hence we split the value so that it fits in 32-bit registers + return _Popcount_fallback(static_cast(_Val)) + + _Popcount_fallback(static_cast(_Val >> 32)); + } else +#endif // defined(_M_IX86) && !defined(_M_HYBRID_X86_ARM64) + { + // we static_cast these bit patterns in order to truncate them to the correct size + _Val = static_cast<_Ty>(_Val - ((_Val >> 1) & static_cast<_Ty>(0x5555'5555'5555'5555ull))); + _Val = static_cast<_Ty>((_Val & static_cast<_Ty>(0x3333'3333'3333'3333ull)) + + ((_Val >> 2) & static_cast<_Ty>(0x3333'3333'3333'3333ull))); + _Val = static_cast<_Ty>((_Val + (_Val >> 4)) & static_cast<_Ty>(0x0F0F'0F0F'0F0F'0F0Full)); + // Multiply by one in each byte, so that it will have the sum of all source bytes in the highest byte + _Val = static_cast<_Ty>(_Val * static_cast<_Ty>(0x0101'0101'0101'0101ull)); + // Extract highest byte + return static_cast(_Val >> (_Digits - 8)); + } +} + +#if ((defined(_M_IX86) && !defined(_M_HYBRID_X86_ARM64)) || (defined(_M_X64) && !defined(_M_ARM64EC))) \ + && !defined(_M_CEE_PURE) && !defined(__CUDACC__) +#define _HAS_TZCNT_BSF_INTRINSICS 1 +#else // ^^^ intrinsics available / intrinsics unavailable vvv +#define _HAS_TZCNT_BSF_INTRINSICS 0 +#endif // ^^^ intrinsics unavailable ^^^ + +#if _HAS_TZCNT_BSF_INTRINSICS +#ifdef __clang__ +#define _TZCNT_U32 __builtin_ia32_tzcnt_u32 +#define _TZCNT_U64 __builtin_ia32_tzcnt_u64 +#else // ^^^ __clang__ / !__clang__ vvv +#define _TZCNT_U32 _tzcnt_u32 +#define _TZCNT_U64 _tzcnt_u64 +#endif // __clang__ + +template +_NODISCARD int _Countr_zero_tzcnt(const _Ty _Val) noexcept { + constexpr int _Digits = _Unsigned_integer_digits<_Ty>; + constexpr _Ty _Max = static_cast<_Ty>(-1); // equal to (numeric_limits<_Ty>::max)() + + if constexpr (_Digits <= 32) { + // Intended widening to int. This operation means that a narrow 0 will widen + // to 0xFFFF....FFFF0... instead of 0. We need this to avoid counting all the zeros + // of the wider type. + return static_cast(_TZCNT_U32(static_cast(~_Max | _Val))); + } else { +#ifdef _M_IX86 + const auto _Low = static_cast(_Val); + if (_Low == 0) { + const unsigned int _High = _Val >> 32; + return static_cast(32 + _TZCNT_U32(_High)); + } else { + return static_cast(_TZCNT_U32(_Low)); + } +#else // ^^^ defined(_M_IX86) / !defined(_M_IX86) vvv + return static_cast(_TZCNT_U64(_Val)); +#endif // ^^^ !defined(_M_IX86) ^^^ + } +} + +#undef _TZCNT_U32 +#undef _TZCNT_U64 + +template +_NODISCARD int _Countr_zero_bsf(const _Ty _Val) noexcept { + constexpr int _Digits = _Unsigned_integer_digits<_Ty>; + constexpr _Ty _Max = static_cast<_Ty>(-1); // equal to (numeric_limits<_Ty>::max)() + + unsigned long _Result; + if constexpr (_Digits <= 32) { + // Intended widening to int. This operation means that a narrow 0 will widen + // to 0xFFFF....FFFF0... instead of 0. We need this to avoid counting all the zeros + // of the wider type. + if (!_BitScanForward(&_Result, static_cast(~_Max | _Val))) { + return _Digits; + } + } else { +#ifdef _M_IX86 + const auto _Low = static_cast(_Val); + if (_BitScanForward(&_Result, _Low)) { + return static_cast(_Result); + } + + const unsigned int _High = _Val >> 32; + if (!_BitScanForward(&_Result, _High)) { + return _Digits; + } else { + return static_cast(_Result + 32); + } +#else // ^^^ defined(_M_IX86) / !defined(_M_IX86) vvv + if (!_BitScanForward64(&_Result, _Val)) { + return _Digits; + } +#endif // ^^^ !defined(_M_IX86) ^^^ + } + return static_cast(_Result); +} + +template +_NODISCARD int _Checked_x86_x64_countr_zero(const _Ty _Val) noexcept { +#ifndef __AVX2__ + const bool _Definitely_have_tzcnt = __isa_available >= _Stl_isa_available_avx2; + if (!_Definitely_have_tzcnt) { + return _Countr_zero_bsf(_Val); + } +#endif // ^^^ !defined(__AVX2__) ^^^ + return _Countr_zero_tzcnt(_Val); +} + +#endif // _HAS_TZCNT_BSF_INTRINSICS + +#if (defined(_M_IX86) || defined(_M_X64) || defined(_M_ARM64)) && !defined(_M_CEE_PURE) && !defined(__CUDACC__) +#define _HAS_POPCNT_INTRINSICS 1 +#if defined(__AVX__) || defined(_M_ARM64) || defined(_M_ARM64EC) +#define _POPCNT_INTRINSICS_ALWAYS_AVAILABLE 1 +#else // ^^^ intrinsics always available / intrinsics not always available vvv +#define _POPCNT_INTRINSICS_ALWAYS_AVAILABLE 0 +#endif // ^^^ intrinsics not always available ^^^ +#else // ^^^ intrinsics available / intrinsics unavailable vvv +#define _HAS_POPCNT_INTRINSICS 0 +#define _POPCNT_INTRINSICS_ALWAYS_AVAILABLE 0 +#endif // ^^^ intrinsics unavailable ^^^ + +#if _HAS_POPCNT_INTRINSICS +template +_NODISCARD int _Unchecked_popcount(const _Ty _Val) noexcept { + constexpr int _Digits = _Unsigned_integer_digits<_Ty>; + if constexpr (_Digits <= 16) { + return static_cast(__popcnt16(_Val)); + } else if constexpr (_Digits == 32) { + return static_cast(__popcnt(_Val)); + } else { +#ifdef _M_IX86 + return static_cast(__popcnt(_Val >> 32) + __popcnt(static_cast(_Val))); +#else // ^^^ defined(_M_IX86) / !defined(_M_IX86) vvv + return static_cast(__popcnt64(_Val)); +#endif // ^^^ !defined(_M_IX86) ^^^ + } +} + +template +_NODISCARD int _Checked_popcount(const _Ty _Val) noexcept { +#if !_POPCNT_INTRINSICS_ALWAYS_AVAILABLE + const bool _Definitely_have_popcnt = __isa_available >= _Stl_isa_available_sse42; + if (!_Definitely_have_popcnt) { + return _Popcount_fallback(_Val); + } +#endif // ^^^ !_POPCNT_INTRINSICS_ALWAYS_AVAILABLE ^^^ + return _Unchecked_popcount(_Val); +} +#endif // ^^^ _HAS_POPCNT_INTRINSICS ^^^ + +template +constexpr bool _Is_standard_unsigned_integer = + _Is_any_of_v<_Ty, unsigned char, unsigned short, unsigned int, unsigned long, unsigned long long>; + +template , int> = 0> +_NODISCARD _CONSTEXPR20 int _Countr_zero(const _Ty _Val) noexcept { +#if _HAS_TZCNT_BSF_INTRINSICS +#if _HAS_CXX20 + if (!_STD is_constant_evaluated()) +#endif // _HAS_CXX20 + { + return _Checked_x86_x64_countr_zero(_Val); + } +#endif // _HAS_TZCNT_BSF_INTRINSICS + return _Countr_zero_fallback(_Val); +} + +template +constexpr decltype(auto) _Select_countr_zero_impl(_Fn _Callback) { + // TRANSITION, DevCom-1527995: Lambdas in this function ensure inlining +#if _HAS_TZCNT_BSF_INTRINSICS && _HAS_CXX20 + if (!_STD is_constant_evaluated()) { +#ifndef __AVX2__ + const bool _Definitely_have_tzcnt = __isa_available >= _Stl_isa_available_avx2; + if (!_Definitely_have_tzcnt) { + return _Callback([](_Ty _Val) _STATIC_CALL_OPERATOR { return _Countr_zero_bsf(_Val); }); + } +#endif // ^^^ !defined(__AVX2__) ^^^ + return _Callback([](_Ty _Val) _STATIC_CALL_OPERATOR { return _Countr_zero_tzcnt(_Val); }); + } +#endif // ^^^ _HAS_TZCNT_BSF_INTRINSICS && _HAS_CXX20 ^^^ + // C++17 constexpr gcd() calls this function, so it should be constexpr unless we detect runtime evaluation. + return _Callback([](_Ty _Val) _STATIC_CALL_OPERATOR { return _Countr_zero_fallback(_Val); }); +} + +template +_NODISCARD constexpr int _Countl_zero(const _Ty _Val) noexcept { + _STL_INTERNAL_STATIC_ASSERT(_Is_standard_unsigned_integer<_Ty>); +#if _HAS_COUNTL_ZERO_INTRINSICS +#if (defined(_M_IX86) && !defined(_M_HYBRID_X86_ARM64)) || (defined(_M_X64) && !defined(_M_ARM64EC)) + if (!_Is_constant_evaluated()) { + return _Checked_x86_x64_countl_zero(_Val); + } +#elif defined(_M_ARM64) || defined(_M_ARM64EC) || defined(_M_HYBRID_X86_ARM64) + if (!_Is_constant_evaluated()) { + return _Checked_arm64_countl_zero(_Val); + } +#endif // defined(_M_ARM64) || defined(_M_ARM64EC) || defined(_M_HYBRID_X86_ARM64) +#endif // _HAS_COUNTL_ZERO_INTRINSICS + + return _Countl_zero_fallback(_Val); +} + +template , int> = 0> +_NODISCARD _CONSTEXPR20 int _Popcount(const _Ty _Val) noexcept { +#if _HAS_POPCNT_INTRINSICS +#if _HAS_CXX20 + if (!_STD is_constant_evaluated()) +#endif // _HAS_CXX20 + { + return _Checked_popcount(_Val); + } +#endif // ^^^ _HAS_POPCNT_INTRINSICS ^^^ + return _Popcount_fallback(_Val); +} + +template +_CONSTEXPR20 decltype(auto) _Select_popcount_impl(_Fn _Callback) { + // TRANSITION, DevCom-1527995: Lambdas in this function ensure inlining +#if _HAS_POPCNT_INTRINSICS +#if _HAS_CXX20 + if (!_STD is_constant_evaluated()) +#endif // _HAS_CXX20 + { +#if !_POPCNT_INTRINSICS_ALWAYS_AVAILABLE + const bool _Definitely_have_popcnt = __isa_available >= _Stl_isa_available_sse42; + if (!_Definitely_have_popcnt) { + return _Callback([](_Ty _Val) _STATIC_CALL_OPERATOR { return _Popcount_fallback(_Val); }); + } +#endif // ^^^ !_POPCNT_INTRINSICS_ALWAYS_AVAILABLE ^^^ + return _Callback([](_Ty _Val) _STATIC_CALL_OPERATOR { return _Unchecked_popcount(_Val); }); + } +#endif // ^^^ _HAS_POPCNT_INTRINSICS ^^^ + return _Callback([](_Ty _Val) _STATIC_CALL_OPERATOR { return _Popcount_fallback(_Val); }); +} + +#undef _HAS_TZCNT_BSF_INTRINSICS + +_STD_END + +#pragma pop_macro("new") +_STL_RESTORE_CLANG_WARNINGS +#pragma warning(pop) +#pragma pack(pop) +#endif // _STL_COMPILER_PREPROCESSOR +#endif // __MSVC_BIT_UTILS_HPP diff --git a/stl/inc/__msvc_chrono.hpp b/stl/inc/__msvc_chrono.hpp new file mode 100644 index 00000000000..b4368dd9530 --- /dev/null +++ b/stl/inc/__msvc_chrono.hpp @@ -0,0 +1,729 @@ +// __msvc_chrono.hpp internal header + +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#ifndef __MSVC_CHRONO_HPP +#define __MSVC_CHRONO_HPP +#include +#if _STL_COMPILER_PREPROCESSOR +#include +#include +#include +#include +#include +#include + +#if _HAS_CXX20 +#include +#endif + +#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 + +// TRANSITION, non-_Ugly attribute tokens +#pragma push_macro("msvc") +#pragma push_macro("no_specializations") +#undef msvc +#undef no_specializations + +_STD_BEGIN +namespace chrono { + _EXPORT_STD template + struct treat_as_floating_point : is_floating_point<_Rep> {}; // tests for floating-point type + + _EXPORT_STD template + _NO_SPECIALIZATIONS_OF_VARIABLE_TEMPLATES constexpr bool treat_as_floating_point_v = + treat_as_floating_point<_Rep>::value; + + _EXPORT_STD template + struct duration_values { // gets arithmetic properties of a type + _NODISCARD static constexpr _Rep zero() noexcept { + // get zero value + return _Rep(0); + } + + _NODISCARD static constexpr _Rep(min)() noexcept { + // get smallest value + return numeric_limits<_Rep>::lowest(); + } + + _NODISCARD static constexpr _Rep(max)() noexcept { + // get largest value + return (numeric_limits<_Rep>::max)(); + } + }; + + _EXPORT_STD template > + class duration; + + _EXPORT_STD template + class time_point; + +#if _HAS_CXX20 + _EXPORT_STD template + _NO_SPECIALIZATIONS_OF_VARIABLE_TEMPLATES constexpr bool is_clock_v = requires { + // Basic checks from N5014 [time.traits.is.clock]/1 + typename _Clock::rep; + typename _Clock::period; + typename _Clock::duration; + typename _Clock::time_point; + _Clock::is_steady; + _Clock::now(); + + // Additional stricter checks from N5014 [time.clock.req]/2 + // "An arithmetic type or a class emulating an arithmetic type" is not checked + requires _Is_ratio_v; + requires same_as>; + requires same_as> + || same_as>; + { _Clock::is_steady } -> std::same_as; + { _Clock::now() } -> std::same_as; + }; + _EXPORT_STD template + struct _NO_SPECIALIZATIONS_CITING("N5014 [time.traits.is.clock]/2") is_clock : bool_constant> {}; + + template + constexpr bool _Is_clock_v = is_clock_v<_Clock>; +#else // ^^^ _HAS_CXX20 / !_HAS_CXX20 vvv + template + constexpr bool _Is_clock_v = false; + + template + constexpr bool + _Is_clock_v<_Clock, void_t> = + true; +#endif // ^^^ !_HAS_CXX20 ^^^ + + template + constexpr bool _Is_duration_v = _Is_specialization_v<_Ty, duration>; + + _EXPORT_STD template , int> = 0> + constexpr _To duration_cast(const duration<_Rep, _Period>&) + noexcept(is_arithmetic_v<_Rep> && is_arithmetic_v); // strengthened + + _EXPORT_STD template + class duration { // represents a time duration + public: + using rep = _Rep; + using period = typename _Period::type; + + static_assert(!_Is_duration_v<_Rep>, "duration can't have duration as first template argument"); + static_assert(_Is_ratio_v<_Period>, "period not an instance of std::ratio"); + static_assert(0 < _Period::num, "period negative or zero"); + + constexpr duration() = default; + + template + && (treat_as_floating_point_v<_Rep> || !treat_as_floating_point_v<_Rep2>), + int> = 0> + constexpr explicit duration(const _Rep2& _Val) + noexcept(is_arithmetic_v<_Rep> && is_arithmetic_v<_Rep2>) // strengthened + : _MyRep(static_cast<_Rep>(_Val)) {} + + template + && (treat_as_floating_point_v<_Rep> + || (_Ratio_divide_sfinae<_Period2, _Period>::den == 1 + && !treat_as_floating_point_v<_Rep2>) ), + 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()) {} + + _NODISCARD constexpr _Rep count() const noexcept(is_arithmetic_v<_Rep>) /* strengthened */ { + return _MyRep; + } + + _NODISCARD constexpr common_type_t operator+() const + noexcept(is_arithmetic_v<_Rep>) /* strengthened */ { + return common_type_t(*this); + } + + _NODISCARD constexpr common_type_t operator-() const + noexcept(is_arithmetic_v<_Rep>) /* strengthened */ { + return common_type_t(-_MyRep); + } + + _CONSTEXPR17 duration& operator++() noexcept(is_arithmetic_v<_Rep>) /* strengthened */ { + ++_MyRep; + return *this; + } + + _CONSTEXPR17 duration operator++(int) noexcept(is_arithmetic_v<_Rep>) /* strengthened */ { + return duration(_MyRep++); + } + + _CONSTEXPR17 duration& operator--() noexcept(is_arithmetic_v<_Rep>) /* strengthened */ { + --_MyRep; + return *this; + } + + _CONSTEXPR17 duration operator--(int) noexcept(is_arithmetic_v<_Rep>) /* strengthened */ { + return duration(_MyRep--); + } + + _CONSTEXPR17 duration& operator+=(const duration& _Right) noexcept(is_arithmetic_v<_Rep>) /* strengthened */ { + _MyRep += _Right._MyRep; + return *this; + } + + _CONSTEXPR17 duration& operator-=(const duration& _Right) noexcept(is_arithmetic_v<_Rep>) /* strengthened */ { + _MyRep -= _Right._MyRep; + return *this; + } + + _CONSTEXPR17 duration& operator*=(const _Rep& _Right) noexcept(is_arithmetic_v<_Rep>) /* strengthened */ { + _MyRep *= _Right; + return *this; + } + + _CONSTEXPR17 duration& operator/=(const _Rep& _Right) noexcept(is_arithmetic_v<_Rep>) /* strengthened */ { + _MyRep /= _Right; + return *this; + } + + _CONSTEXPR17 duration& operator%=(const _Rep& _Right) noexcept(is_arithmetic_v<_Rep>) /* strengthened */ { + _MyRep %= _Right; + return *this; + } + + _CONSTEXPR17 duration& operator%=(const duration& _Right) noexcept(is_arithmetic_v<_Rep>) /* strengthened */ { + _MyRep %= _Right.count(); + return *this; + } + + _NODISCARD static constexpr duration zero() noexcept { + // get zero value + return duration(duration_values<_Rep>::zero()); + } + + _NODISCARD static constexpr duration(min)() noexcept { + // get minimum value + return duration((duration_values<_Rep>::min)()); + } + + _NODISCARD static constexpr duration(max)() noexcept { + // get maximum value + return duration((duration_values<_Rep>::max)()); + } + + private: + _Rep _MyRep; // the stored rep + }; + + _EXPORT_STD template + class time_point { // represents a point in time + public: + using clock = _Clock; + using duration = _Duration; + using rep = typename _Duration::rep; + using period = typename _Duration::period; + + static_assert(_Is_duration_v<_Duration>, + "N4950 [time.point.general]/1 mandates Duration to be a specialization of chrono::duration."); + + constexpr time_point() = default; + + constexpr explicit time_point(const _Duration& _Other) noexcept(is_arithmetic_v) // strengthened + : _MyDur(_Other) {} + + template , int> = 0> + constexpr time_point(const time_point<_Clock, _Duration2>& _Tp) + noexcept(is_arithmetic_v && is_arithmetic_v) // strengthened + : _MyDur(_Tp.time_since_epoch()) {} + + _NODISCARD constexpr _Duration time_since_epoch() const noexcept(is_arithmetic_v) /* strengthened */ { + 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; + } + + _CONSTEXPR17 time_point& operator-=(const _Duration& _Dur) noexcept(is_arithmetic_v) /* strengthened */ { + _MyDur -= _Dur; + return *this; + } + + _NODISCARD static constexpr time_point(min)() noexcept { + return time_point((_Duration::min) ()); + } + + _NODISCARD static constexpr time_point(max)() noexcept { + return time_point((_Duration::max) ()); + } + + private: + _Duration _MyDur{duration::zero()}; // duration since the epoch + }; +} // namespace chrono + +template +constexpr bool _Is_trivially_swappable_v> = _Is_trivially_swappable_v<_Rep>; + +template +constexpr bool _Is_trivially_swappable_v> = _Is_trivially_swappable_v<_Duration>; + +_NODISCARD constexpr intmax_t _Lcm(const intmax_t _Ax, const intmax_t _Bx) noexcept { + return (_Ax / _Gcd(_Ax, _Bx)) * _Bx; +} + +template +struct common_type<_CHRONO duration<_Rep1, _Period1>, _CHRONO duration<_Rep2, _Period2>> { + using type = _CHRONO duration, + ratio<_Gcd(_Period1::num, _Period2::num), _Lcm(_Period1::den, _Period2::den)>>; +}; + +template +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 { + _EXPORT_STD template + _NODISCARD constexpr common_type_t, duration<_Rep2, _Period2>> operator+( + const duration<_Rep1, _Period1>& _Left, const duration<_Rep2, _Period2>& _Right) + noexcept(is_arithmetic_v<_Rep1> && is_arithmetic_v<_Rep2>) /* strengthened */ { + using _CD = common_type_t, duration<_Rep2, _Period2>>; + return _CD(_CD(_Left).count() + _CD(_Right).count()); + } + + _EXPORT_STD template + _NODISCARD constexpr common_type_t, duration<_Rep2, _Period2>> operator-( + const duration<_Rep1, _Period1>& _Left, const duration<_Rep2, _Period2>& _Right) + noexcept(is_arithmetic_v<_Rep1> && is_arithmetic_v<_Rep2>) /* strengthened */ { + using _CD = common_type_t, duration<_Rep2, _Period2>>; + return _CD(_CD(_Left).count() - _CD(_Right).count()); + } + + _EXPORT_STD template >, int> = 0> + _NODISCARD constexpr duration, _Period1> operator*( + const duration<_Rep1, _Period1>& _Left, const _Rep2& _Right) + noexcept(is_arithmetic_v<_Rep1> && is_arithmetic_v<_Rep2>) /* strengthened */ { + using _CR = common_type_t<_Rep1, _Rep2>; + using _CD = duration<_CR, _Period1>; + return _CD(_CD(_Left).count() * _Right); + } + + _EXPORT_STD template >, int> = 0> + _NODISCARD constexpr duration, _Period2> operator*( + const _Rep1& _Left, const duration<_Rep2, _Period2>& _Right) + noexcept(is_arithmetic_v<_Rep1> && is_arithmetic_v<_Rep2>) /* strengthened */ { + return _Right * _Left; + } + + template > + struct _Duration_div_mod1 { // return type for duration / rep and duration % rep + using type = duration<_CR, _Period1>; + }; + + template + struct _Duration_div_mod1<_CR, _Period1, _Rep2, false> {}; // no return type + + template > + struct _Duration_div_mod {}; // no return type + + template + struct _Duration_div_mod<_CR, _Period1, _Rep2, false> : _Duration_div_mod1<_CR, _Period1, _Rep2> { + // return type for duration / rep and duration % rep + }; + + _EXPORT_STD template + _NODISCARD constexpr typename _Duration_div_mod, _Period1, _Rep2>::type operator/( + const duration<_Rep1, _Period1>& _Left, const _Rep2& _Right) + noexcept(is_arithmetic_v<_Rep1> && is_arithmetic_v<_Rep2>) /* strengthened */ { + using _CR = common_type_t<_Rep1, _Rep2>; + using _CD = duration<_CR, _Period1>; + return _CD(_CD(_Left).count() / _Right); + } + + _EXPORT_STD template + _NODISCARD constexpr common_type_t<_Rep1, _Rep2> operator/( + const duration<_Rep1, _Period1>& _Left, const duration<_Rep2, _Period2>& _Right) + noexcept(is_arithmetic_v<_Rep1> && is_arithmetic_v<_Rep2>) /* strengthened */ { + using _CD = common_type_t, duration<_Rep2, _Period2>>; + return _CD(_Left).count() / _CD(_Right).count(); + } + + _EXPORT_STD template + _NODISCARD constexpr typename _Duration_div_mod, _Period1, _Rep2>::type operator%( + const duration<_Rep1, _Period1>& _Left, const _Rep2& _Right) + noexcept(is_arithmetic_v<_Rep1> && is_arithmetic_v<_Rep2>) /* strengthened */ { + using _CR = common_type_t<_Rep1, _Rep2>; + using _CD = duration<_CR, _Period1>; + return _CD(_CD(_Left).count() % _Right); + } + + _EXPORT_STD template + _NODISCARD constexpr common_type_t, duration<_Rep2, _Period2>> operator%( + const duration<_Rep1, _Period1>& _Left, const duration<_Rep2, _Period2>& _Right) + noexcept(is_arithmetic_v<_Rep1> && is_arithmetic_v<_Rep2>) /* strengthened */ { + using _CD = common_type_t, duration<_Rep2, _Period2>>; + return _CD(_CD(_Left).count() % _CD(_Right).count()); + } + + _EXPORT_STD template + _NODISCARD constexpr bool operator==( + const duration<_Rep1, _Period1>& _Left, const duration<_Rep2, _Period2>& _Right) + noexcept(is_arithmetic_v<_Rep1> && is_arithmetic_v<_Rep2>) /* strengthened */ { + using _CT = common_type_t, duration<_Rep2, _Period2>>; + return _CT(_Left).count() == _CT(_Right).count(); + } + +#if !_HAS_CXX20 + template + _NODISCARD constexpr bool operator!=( + const duration<_Rep1, _Period1>& _Left, const duration<_Rep2, _Period2>& _Right) + noexcept(is_arithmetic_v<_Rep1> && is_arithmetic_v<_Rep2>) /* strengthened */ { + return !(_Left == _Right); + } +#endif // !_HAS_CXX20 + + _EXPORT_STD template + _NODISCARD constexpr bool operator<(const duration<_Rep1, _Period1>& _Left, const duration<_Rep2, _Period2>& _Right) + noexcept(is_arithmetic_v<_Rep1> && is_arithmetic_v<_Rep2>) /* strengthened */ { + using _CT = common_type_t, duration<_Rep2, _Period2>>; + return _CT(_Left).count() < _CT(_Right).count(); + } + + _EXPORT_STD template + _NODISCARD constexpr bool operator<=( + const duration<_Rep1, _Period1>& _Left, const duration<_Rep2, _Period2>& _Right) + noexcept(is_arithmetic_v<_Rep1> && is_arithmetic_v<_Rep2>) /* strengthened */ { + return !(_Right < _Left); + } + + _EXPORT_STD template + _NODISCARD constexpr bool operator>(const duration<_Rep1, _Period1>& _Left, const duration<_Rep2, _Period2>& _Right) + noexcept(is_arithmetic_v<_Rep1> && is_arithmetic_v<_Rep2>) /* strengthened */ { + return _Right < _Left; + } + + _EXPORT_STD template + _NODISCARD constexpr bool operator>=( + const duration<_Rep1, _Period1>& _Left, const duration<_Rep2, _Period2>& _Right) + noexcept(is_arithmetic_v<_Rep1> && is_arithmetic_v<_Rep2>) /* strengthened */ { + return !(_Left < _Right); + } + +#if _HAS_CXX20 + _EXPORT_STD template + requires three_way_comparable, duration<_Rep2, _Period2>>::rep> + _NODISCARD constexpr auto operator<=>( + const duration<_Rep1, _Period1>& _Left, const duration<_Rep2, _Period2>& _Right) + noexcept(is_arithmetic_v<_Rep1> && is_arithmetic_v<_Rep2>) /* strengthened */ { + using _CT = common_type_t, duration<_Rep2, _Period2>>; + return _CT(_Left).count() <=> _CT(_Right).count(); + } +#endif // _HAS_CXX20 + + _EXPORT_STD template , int> /* = 0 */> + _NODISCARD constexpr _To duration_cast(const duration<_Rep, _Period>& _Dur) + noexcept(is_arithmetic_v<_Rep> && is_arithmetic_v) /* strengthened */ { + // convert duration to another duration; truncate + using _CF = ratio_divide<_Period, typename _To::period>; + + using _ToRep = typename _To::rep; + using _CR = common_type_t<_ToRep, _Rep, intmax_t>; + + constexpr bool _Num_is_one = _CF::num == 1; + constexpr bool _Den_is_one = _CF::den == 1; + + if constexpr (_Den_is_one) { + if constexpr (_Num_is_one) { + return static_cast<_To>(static_cast<_ToRep>(_Dur.count())); + } else { + return static_cast<_To>( + static_cast<_ToRep>(static_cast<_CR>(_Dur.count()) * static_cast<_CR>(_CF::num))); + } + } else { + if constexpr (_Num_is_one) { + return static_cast<_To>( + static_cast<_ToRep>(static_cast<_CR>(_Dur.count()) / static_cast<_CR>(_CF::den))); + } else { + return static_cast<_To>(static_cast<_ToRep>( + static_cast<_CR>(_Dur.count()) * static_cast<_CR>(_CF::num) / static_cast<_CR>(_CF::den))); + } + } + } + + _EXPORT_STD template , int> = 0> + _NODISCARD constexpr _To floor(const duration<_Rep, _Period>& _Dur) + noexcept(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)}; + if (_Casted > _Dur) { + return _To{_Casted.count() - static_cast(1)}; + } + + return _Casted; + } + + _EXPORT_STD template , int> = 0> + _NODISCARD constexpr _To ceil(const duration<_Rep, _Period>& _Dur) + noexcept(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)}; + if (_Casted < _Dur) { + return _To{_Casted.count() + static_cast(1)}; + } + + return _Casted; + } + + template + constexpr bool _Is_even(_Rep _Val) noexcept(is_arithmetic_v<_Rep>) /* strengthened */ { + // Tests whether _Val is even + return _Val % 2 == 0; + } + + _EXPORT_STD template && !treat_as_floating_point_v, int> = 0> + _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 _Ceiled{_Floored + _To{1}}; + const auto _Floor_adjustment = _Dur - _Floored; + const auto _Ceil_adjustment = _Ceiled - _Dur; + if (_Floor_adjustment < _Ceil_adjustment + || (_Floor_adjustment == _Ceil_adjustment && _Is_even(_Floored.count()))) { + return _Floored; + } + + return _Ceiled; + } + + _EXPORT_STD template ::is_signed, int> = 0> + _NODISCARD constexpr duration<_Rep, _Period> abs(const duration<_Rep, _Period> _Dur) + noexcept(is_arithmetic_v<_Rep>) /* strengthened */ { + // create a duration whose count() is the absolute value of _Dur.count() + if (_Dur < duration<_Rep, _Period>::zero()) { + return -_Dur; + } else { + return _Dur; + } + } + + _EXPORT_STD using nanoseconds = duration; + _EXPORT_STD using microseconds = duration; + _EXPORT_STD using milliseconds = duration; + _EXPORT_STD using seconds = duration; + _EXPORT_STD using minutes = duration>; + _EXPORT_STD using hours = duration>; +#if _HAS_CXX20 + _EXPORT_STD using days = duration, hours::period>>; + _EXPORT_STD using weeks = duration, days::period>>; + _EXPORT_STD using years = duration, days::period>>; + _EXPORT_STD using months = duration>>; +#endif // _HAS_CXX20 + + _EXPORT_STD template + _NODISCARD constexpr time_point<_Clock, common_type_t<_Duration, duration<_Rep, _Period>>> operator+( + const time_point<_Clock, _Duration>& _Left, const duration<_Rep, _Period>& _Right) + noexcept(is_arithmetic_v && is_arithmetic_v<_Rep>) /* strengthened */ { + using _RT = time_point<_Clock, common_type_t<_Duration, duration<_Rep, _Period>>>; + return _RT(_Left.time_since_epoch() + _Right); + } + + _EXPORT_STD template + _NODISCARD constexpr time_point<_Clock, common_type_t, _Duration>> operator+( + const duration<_Rep, _Period>& _Left, const time_point<_Clock, _Duration>& _Right) + noexcept(is_arithmetic_v<_Rep> && is_arithmetic_v) /* strengthened */ { + return _Right + _Left; + } + + _EXPORT_STD template + _NODISCARD constexpr time_point<_Clock, common_type_t<_Duration, duration<_Rep, _Period>>> operator-( + const time_point<_Clock, _Duration>& _Left, const duration<_Rep, _Period>& _Right) + noexcept(is_arithmetic_v && is_arithmetic_v<_Rep>) /* strengthened */ { + using _RT = time_point<_Clock, common_type_t<_Duration, duration<_Rep, _Period>>>; + return _RT(_Left.time_since_epoch() - _Right); + } + + _EXPORT_STD template + _NODISCARD constexpr common_type_t<_Duration1, _Duration2> operator-( + const time_point<_Clock, _Duration1>& _Left, const time_point<_Clock, _Duration2>& _Right) + noexcept( + is_arithmetic_v && is_arithmetic_v) /* strengthened */ { + return _Left.time_since_epoch() - _Right.time_since_epoch(); + } + + _EXPORT_STD template + _NODISCARD constexpr bool operator==( + const time_point<_Clock, _Duration1>& _Left, const time_point<_Clock, _Duration2>& _Right) + noexcept( + is_arithmetic_v && is_arithmetic_v) /* strengthened */ { + return _Left.time_since_epoch() == _Right.time_since_epoch(); + } + +#if !_HAS_CXX20 + template + _NODISCARD constexpr bool operator!=( + const time_point<_Clock, _Duration1>& _Left, const time_point<_Clock, _Duration2>& _Right) + noexcept( + is_arithmetic_v && is_arithmetic_v) /* strengthened */ { + return !(_Left == _Right); + } +#endif // !_HAS_CXX20 + + _EXPORT_STD template + _NODISCARD constexpr bool operator<( + const time_point<_Clock, _Duration1>& _Left, const time_point<_Clock, _Duration2>& _Right) + noexcept( + is_arithmetic_v && is_arithmetic_v) /* strengthened */ { + return _Left.time_since_epoch() < _Right.time_since_epoch(); + } + + _EXPORT_STD template + _NODISCARD constexpr bool operator<=( + const time_point<_Clock, _Duration1>& _Left, const time_point<_Clock, _Duration2>& _Right) + noexcept( + is_arithmetic_v && is_arithmetic_v) /* strengthened */ { + return !(_Right < _Left); + } + + _EXPORT_STD template + _NODISCARD constexpr bool operator>( + const time_point<_Clock, _Duration1>& _Left, const time_point<_Clock, _Duration2>& _Right) + noexcept( + is_arithmetic_v && is_arithmetic_v) /* strengthened */ { + return _Right < _Left; + } + + _EXPORT_STD template + _NODISCARD constexpr bool operator>=( + const time_point<_Clock, _Duration1>& _Left, const time_point<_Clock, _Duration2>& _Right) + noexcept( + is_arithmetic_v && is_arithmetic_v) /* strengthened */ { + return !(_Left < _Right); + } + +#if _HAS_CXX20 + _EXPORT_STD template _Duration2> + _NODISCARD constexpr auto operator<=>( + const time_point<_Clock, _Duration1>& _Left, const time_point<_Clock, _Duration2>& _Right) + noexcept( + is_arithmetic_v && is_arithmetic_v) /* strengthened */ { + return _Left.time_since_epoch() <=> _Right.time_since_epoch(); + } +#endif // _HAS_CXX20 + + _EXPORT_STD template , int> = 0> + _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())); + } + + _EXPORT_STD template , int> = 0> + _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())); + } + + _EXPORT_STD template , int> = 0> + _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())); + } + + _EXPORT_STD template && !treat_as_floating_point_v, int> = 0> + _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())); + } + + _EXPORT_STD struct steady_clock { // wraps QueryPerformanceCounter + using rep = long long; + using period = nano; + using duration = nanoseconds; + using time_point = _CHRONO time_point; + static constexpr bool is_steady = true; + + _NODISCARD static time_point now() noexcept { // get current time + const long long _Freq = _Query_perf_frequency(); // doesn't change after system boot + const long long _Ctr = _Query_perf_counter(); + _STL_INTERNAL_STATIC_ASSERT(period::num == 1); + // The compiler recognizes the constants for frequency and time period and uses shifts and + // multiplies instead of divides to calculate the nanosecond value. + constexpr long long _TenMHz = 10'000'000; + constexpr long long _TwentyFourMHz = 24'000'000; + if (_Freq == _TenMHz) { + // 10 MHz is a very common QPC frequency on modern x86/x64 PCs. Optimizing for + // this specific frequency can double the performance of this function by + // avoiding the expensive frequency conversion path. + _STL_INTERNAL_STATIC_ASSERT(period::den % _TenMHz == 0); + constexpr long long _Multiplier = period::den / _TenMHz; + return time_point(duration(_Ctr * _Multiplier)); + } else if (_Freq == _TwentyFourMHz) { + // 24 MHz is a common frequency on ARM64, including cases where it emulates x86/x64. + constexpr long long _Multiplier_whole = period::den / _TwentyFourMHz; + using _Multiplier_part = ratio; + constexpr long long _Multiplier_num = _Multiplier_part::num; + constexpr long long _Multiplier_den = _Multiplier_part::den; + // This assumes that _Ctr * _Multiplier_num doesn't overflow. + _STL_INTERNAL_STATIC_ASSERT(_Multiplier_num <= _Multiplier_whole); + const long long _Whole = _Ctr * _Multiplier_whole; + const long long _Part = _Ctr * _Multiplier_num / _Multiplier_den; + return time_point(duration(_Whole + _Part)); + } else { + // Instead of just having "(_Ctr * period::den) / _Freq", + // the algorithm below prevents overflow when _Ctr is sufficiently large. + // It assumes that _Freq * period::den does not overflow, which is currently true for nano period. + // It is not realistic for _Ctr to accumulate to large values from zero with this assumption, + // but the initial value of _Ctr could be large. + const long long _Whole = (_Ctr / _Freq) * period::den; + const long long _Part = (_Ctr % _Freq) * period::den / _Freq; + return time_point(duration(_Whole + _Part)); + } + } + }; +} // namespace chrono +_STD_END + +// TRANSITION, non-_Ugly attribute tokens +#pragma pop_macro("no_specializations") +#pragma pop_macro("msvc") + +#pragma pop_macro("new") +_STL_RESTORE_CLANG_WARNINGS +#pragma warning(pop) +#pragma pack(pop) +#endif // _STL_COMPILER_PREPROCESSOR +#endif // __MSVC_CHRONO_HPP diff --git a/stl/inc/__msvc_cxx_stdatomic.hpp b/stl/inc/__msvc_cxx_stdatomic.hpp new file mode 100644 index 00000000000..f6874f70a22 --- /dev/null +++ b/stl/inc/__msvc_cxx_stdatomic.hpp @@ -0,0 +1,138 @@ +// __msvc_cxx_stdatomic.hpp internal header + +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#ifndef __MSVC_CXX_STDATOMIC_HPP +#define __MSVC_CXX_STDATOMIC_HPP + +// see _STL_COMPILER_PREPROCESSOR in yvals_core.h +#if !defined(RC_INVOKED) && !defined(Q_MOC_RUN) && !defined(__midl) + +// provide a specific error message for C compilers, before the general error message in yvals_core.h +#ifndef __cplusplus +#error <__msvc_cxx_stdatomic.hpp> is an internal header. It is incompatible with C and should not be directly included. +#endif // !defined(__cplusplus) + +#include + +#ifdef _M_CEE_PURE +#error is not supported when compiling with /clr:pure. +#endif // defined(_M_CEE_PURE) + +#if !_HAS_CXX23 +_EMIT_STL_WARNING(STL4038, "The contents of are available only with C++23 or later."); +#else // ^^^ !_HAS_CXX23 / _HAS_CXX23 vvv + +#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 + +template +using _Std_atomic = _STD atomic<_Ty>; + +#define _Atomic(T) _Std_atomic + +using _STD memory_order; +using _STD memory_order_relaxed; +using _STD memory_order_consume; +using _STD memory_order_acquire; +using _STD memory_order_release; +using _STD memory_order_acq_rel; +using _STD memory_order_seq_cst; + +using _STD atomic_flag; + +using _STD atomic_bool; +using _STD atomic_char; +using _STD atomic_schar; +using _STD atomic_uchar; +using _STD atomic_short; +using _STD atomic_ushort; +using _STD atomic_int; +using _STD atomic_uint; +using _STD atomic_long; +using _STD atomic_ulong; +using _STD atomic_llong; +using _STD atomic_ullong; + +#ifdef __cpp_lib_char8_t +using _STD atomic_char8_t; +#endif // defined(__cpp_lib_char8_t) + +using _STD atomic_char16_t; +using _STD atomic_char32_t; +using _STD atomic_wchar_t; +using _STD atomic_int8_t; +using _STD atomic_uint8_t; +using _STD atomic_int16_t; +using _STD atomic_uint16_t; +using _STD atomic_int32_t; +using _STD atomic_uint32_t; +using _STD atomic_int64_t; +using _STD atomic_uint64_t; +using _STD atomic_int_least8_t; +using _STD atomic_uint_least8_t; +using _STD atomic_int_least16_t; +using _STD atomic_uint_least16_t; +using _STD atomic_int_least32_t; +using _STD atomic_uint_least32_t; +using _STD atomic_int_least64_t; +using _STD atomic_uint_least64_t; +using _STD atomic_int_fast8_t; +using _STD atomic_uint_fast8_t; +using _STD atomic_int_fast16_t; +using _STD atomic_uint_fast16_t; +using _STD atomic_int_fast32_t; +using _STD atomic_uint_fast32_t; +using _STD atomic_int_fast64_t; +using _STD atomic_uint_fast64_t; +using _STD atomic_intptr_t; +using _STD atomic_uintptr_t; +using _STD atomic_size_t; +using _STD atomic_ptrdiff_t; +using _STD atomic_intmax_t; +using _STD atomic_uintmax_t; + +using _STD atomic_is_lock_free; +using _STD atomic_load; +using _STD atomic_load_explicit; +using _STD atomic_store; +using _STD atomic_store_explicit; +using _STD atomic_exchange; +using _STD atomic_exchange_explicit; +using _STD atomic_compare_exchange_strong; +using _STD atomic_compare_exchange_strong_explicit; +using _STD atomic_compare_exchange_weak; +using _STD atomic_compare_exchange_weak_explicit; +using _STD atomic_fetch_add; +using _STD atomic_fetch_add_explicit; +using _STD atomic_fetch_sub; +using _STD atomic_fetch_sub_explicit; +using _STD atomic_fetch_or; +using _STD atomic_fetch_or_explicit; +using _STD atomic_fetch_xor; +using _STD atomic_fetch_xor_explicit; +using _STD atomic_fetch_and; +using _STD atomic_fetch_and_explicit; +using _STD atomic_flag_test_and_set; +using _STD atomic_flag_test_and_set_explicit; +using _STD atomic_flag_clear; +using _STD atomic_flag_clear_explicit; + +using _STD atomic_thread_fence; +using _STD atomic_signal_fence; + +#pragma pop_macro("new") +_STL_RESTORE_CLANG_WARNINGS +#pragma warning(pop) +#pragma pack(pop) +#endif // ^^^ _HAS_CXX23 ^^^ + +#endif // !defined(RC_INVOKED) && !defined(Q_MOC_RUN) && !defined(__midl) +#endif // __MSVC_CXX_STDATOMIC_HPP diff --git a/stl/inc/__msvc_filebuf.hpp b/stl/inc/__msvc_filebuf.hpp new file mode 100644 index 00000000000..fd6069db015 --- /dev/null +++ b/stl/inc/__msvc_filebuf.hpp @@ -0,0 +1,751 @@ +// __msvc_filebuf.hpp internal header + +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#ifndef __MSVC_FILEBUF_HPP +#define __MSVC_FILEBUF_HPP +#include +#if _STL_COMPILER_PREPROCESSOR + +#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 + +// TRANSITION, ABI: The _Path_ish functions accepting filesystem::path are templates +// which always use the same types as a workaround for user code deriving from iostreams types and +// __declspec(dllexport)ing the derived types. Adding member functions to iostreams broke the ABI of such DLLs. +// Deriving and __declspec(dllexport)ing standard library types is not supported, but in this particular case +// the workaround was inexpensive. The workaround will be removed in the next ABI breaking release of the +// Visual C++ Libraries. +_STD_BEGIN +#if _HAS_CXX17 +namespace filesystem { + _EXPORT_STD class path; +} +#endif // _HAS_CXX17 + +extern "C++" _CRTIMP2_PURE FILE* __CLRCALL_PURE_OR_CDECL _Fiopen(const char*, ios_base::openmode, int); +extern "C++" _CRTIMP2_PURE FILE* __CLRCALL_PURE_OR_CDECL _Fiopen(const wchar_t*, ios_base::openmode, int); + +template +bool _Fgetc(_Elem& _Ch, FILE* _File) { // get an element from a C stream + return _CSTD fread(&_Ch, sizeof(_Elem), 1, _File) == 1; +} + +template <> +inline bool _Fgetc(char& _Byte, FILE* _File) { // get a char element from a C stream + int _Meta; + if ((_Meta = _CSTD fgetc(_File)) == EOF) { + return false; + } else { // got one, convert to char + _Byte = static_cast(_Meta); + return true; + } +} + +template <> +inline bool _Fgetc(wchar_t& _Wchar, FILE* _File) { // get a wchar_t element from a C stream + wint_t _Meta; + if ((_Meta = _CSTD fgetwc(_File)) == WEOF) { + return false; + } else { // got one, convert to wchar_t + _Wchar = static_cast(_Meta); + return true; + } +} + +#ifdef _CRTBLD +template <> +inline bool _Fgetc(unsigned short& _Wchar, FILE* _File) { // get an unsigned short element from a C stream + wint_t _Meta; + if ((_Meta = _CSTD fgetwc(_File)) == WEOF) { + return false; + } else { // got one, convert to unsigned short + _Wchar = static_cast(_Meta); + return true; + } +} +#endif // defined(_CRTBLD) + +template +bool _Fputc(_Elem _Ch, FILE* _File) { // put an element to a C stream + return _CSTD fwrite(&_Ch, 1, sizeof(_Elem), _File) == sizeof(_Elem); +} + +template <> +inline bool _Fputc(char _Byte, FILE* _File) { // put a char element to a C stream + return _CSTD fputc(_Byte, _File) != EOF; +} + +template <> +inline bool _Fputc(wchar_t _Wchar, FILE* _File) { // put a wchar_t element to a C stream + return _CSTD fputwc(_Wchar, _File) != WEOF; +} + +#ifdef _CRTBLD +template <> +inline bool _Fputc(unsigned short _Wchar, FILE* _File) { // put an unsigned short element to a C stream + return _CSTD fputwc(_Wchar, _File) != WEOF; +} +#endif // defined(_CRTBLD) + +template +bool _Ungetc(const _Elem&, FILE*) { // put back an arbitrary element to a C stream (always fail) + return false; +} + +template <> +inline bool _Ungetc(const char& _Byte, FILE* _File) { // put back a char element to a C stream + return _CSTD ungetc(static_cast(_Byte), _File) != EOF; +} + +template <> +inline bool _Ungetc(const signed char& _Byte, FILE* _File) { // put back a signed char element to a C stream + return _CSTD ungetc(static_cast(_Byte), _File) != EOF; +} + +template <> +inline bool _Ungetc(const unsigned char& _Byte, FILE* _File) { // put back an unsigned char element to a C stream + return _CSTD ungetc(_Byte, _File) != EOF; +} + +template <> +inline bool _Ungetc(const wchar_t& _Wchar, FILE* _File) { // put back a wchar_t element to a C stream + return _CSTD ungetwc(_Wchar, _File) != WEOF; +} + +#ifdef _CRTBLD +template <> +inline bool _Ungetc(const unsigned short& _Wchar, FILE* _File) { // put back an unsigned short element to a C stream + return _CSTD ungetwc(_Wchar, _File) != WEOF; +} +#endif // defined(_CRTBLD) + +_EXPORT_STD template +class basic_filebuf : public basic_streambuf<_Elem, _Traits> { // stream buffer associated with a C stream +public: + using _Mysb = basic_streambuf<_Elem, _Traits>; + using _Cvt = codecvt<_Elem, char, typename _Traits::state_type>; + + basic_filebuf() : _Mysb() { + _Init(nullptr, _Newfl); + } + + explicit basic_filebuf(FILE* const _File) : _Mysb() { // extension, no ownership taking + _Init(_File, _Newfl); + } + + __CLR_OR_THIS_CALL ~basic_filebuf() noexcept override { + if (_Myfile) { + _Reset_back(); // revert from _Mychar buffer + } + + if (_Closef) { + close(); + } + } + + using int_type = typename _Traits::int_type; + using pos_type = typename _Traits::pos_type; + using off_type = typename _Traits::off_type; + + basic_filebuf(_Uninitialized) noexcept : _Mysb(_Noinit) {} + + basic_filebuf(basic_filebuf&& _Right) { + _Init(_Right._Myfile, _Newfl); // match buffering styles + _Init(static_cast(nullptr), _Closefl); // then make *this look closed + _Assign_rv(_STD move(_Right)); + } + + basic_filebuf& operator=(basic_filebuf&& _Right) { + _Assign_rv(_STD move(_Right)); + return *this; + } + + void _Assign_rv(basic_filebuf&& _Right) { + if (this != _STD addressof(_Right)) { + close(); + this->swap(_Right); + } + } + + void swap(basic_filebuf& _Right) noexcept /* strengthened */ { + if (this != _STD addressof(_Right)) { + FILE* _Myfile_sav = _Myfile; + const _Cvt* _Pcvt_sav = _Pcvt; + typename _Traits::state_type _State_sav = _State; + bool _Wrotesome_sav = _Wrotesome; + bool _Closef_sav = _Closef; + bool _Set_eback_sav = _Mysb::eback() == &_Mychar; + bool _Set_eback_live = _Mysb::gptr() == &_Mychar; + + _Elem* _Pfirst0 = _Mysb::pbase(); + _Elem* _Pnext0 = _Mysb::pptr(); + _Elem* _Pend = _Mysb::epptr(); + _Elem* _Gfirst0 = _Mysb::eback(); + _Elem* _Gnext0 = _Mysb::gptr(); + _Elem* _Gend = _Mysb::egptr(); + + // reinitialize *this + _Init(_Right._Myfile, _Right._Myfile ? _Openfl : _Newfl); + _Mysb::setp(_Right.pbase(), _Right.pptr(), _Right.epptr()); + if (_Right.eback() != &_Right._Mychar) { + _Mysb::setg(_Right.eback(), _Right.gptr(), _Right.egptr()); + } else if (_Right.gptr() != &_Right._Mychar) { + _Mysb::setg(&_Mychar, &_Mychar + 1, &_Mychar + 1); + } else { + _Mysb::setg(&_Mychar, &_Mychar, &_Mychar + 1); + } + + _Pcvt = _Right._Pcvt; + _State = _Right._State; + _Wrotesome = _Right._Wrotesome; + _Closef = _Right._Closef; + + // reinitialize _Right + _Right._Init(_Myfile_sav, _Myfile_sav ? _Openfl : _Newfl); + _Right.setp(_Pfirst0, _Pnext0, _Pend); + if (!_Set_eback_sav) { + _Right.setg(_Gfirst0, _Gnext0, _Gend); + } else if (!_Set_eback_live) { + _Right.setg(&_Right._Mychar, &_Right._Mychar + 1, &_Right._Mychar + 1); + } else { + _Right.setg(&_Right._Mychar, &_Right._Mychar, &_Right._Mychar + 1); + } + + _Right._Pcvt = _Pcvt_sav; + _Right._State = _State_sav; + _Right._Wrotesome = _Wrotesome_sav; + _Right._Closef = _Closef_sav; + + // swap ancillary data + _STD swap(_Set_eback, _Right._Set_eback); + _STD swap(_Set_egptr, _Right._Set_egptr); + + _STD swap(_Mychar, _Right._Mychar); + _STD swap(_Mysb::_Plocale, _Right._Plocale); + } + } + + basic_filebuf(const basic_filebuf&) = delete; + basic_filebuf& operator=(const basic_filebuf&) = delete; + + enum _Initfl { // reasons for a call to _Init + _Newfl, + _Openfl, + _Closefl + }; + + _NODISCARD bool is_open() const noexcept /* strengthened */ { + return static_cast(_Myfile); + } + + basic_filebuf* open(const char* _Filename, ios_base::openmode _Mode, int _Prot = ios_base::_Default_open_prot) { + // _Prot is an extension + if (_Myfile) { + return nullptr; + } + + const auto _File = _Fiopen(_Filename, _Mode, _Prot); + if (!_File) { + return nullptr; // open failed + } + + _Init(_File, _Openfl); + _Initcvt(_STD use_facet<_Cvt>(_Mysb::getloc())); + return this; // open succeeded + } + + basic_filebuf* open(const string& _Str, ios_base::openmode _Mode, int _Prot = ios_base::_Default_open_prot) { + // _Prot is an extension + return open(_Str.c_str(), _Mode, _Prot); + } + +#if _HAS_OLD_IOSTREAMS_MEMBERS + basic_filebuf* open(const char* _Filename, ios_base::open_mode _Mode) { + return open(_Filename, static_cast(_Mode)); + } +#endif // _HAS_OLD_IOSTREAMS_MEMBERS + + basic_filebuf* open(const wchar_t* _Filename, ios_base::openmode _Mode, int _Prot = ios_base::_Default_open_prot) { + // in standard as const std::filesystem::path::value_type *; _Prot is an extension + if (_Myfile) { + return nullptr; + } + + const auto _File = _Fiopen(_Filename, _Mode, _Prot); + if (!_File) { + return nullptr; // open failed + } + + _Init(_File, _Openfl); + _Initcvt(_STD use_facet<_Cvt>(_Mysb::getloc())); + return this; // open succeeded + } + + basic_filebuf* open(const wstring& _Str, ios_base::openmode _Mode, int _Prot = ios_base::_Default_open_prot) { + // extension + return open(_Str.c_str(), _Mode, _Prot); + } + +#if _HAS_CXX17 + template + basic_filebuf* open( + const _Identity_t<_Path_ish>& _Path, ios_base::openmode _Mode, int _Prot = ios_base::_Default_open_prot) { + // _Prot is an extension + return open(_Path.c_str(), _Mode, _Prot); + } +#endif // _HAS_CXX17 + +#if _HAS_OLD_IOSTREAMS_MEMBERS + basic_filebuf* open(const wchar_t* _Filename, ios_base::open_mode _Mode) { + // in standard as const std::filesystem::path::value_type * + return open(_Filename, static_cast(_Mode)); + } +#endif // _HAS_OLD_IOSTREAMS_MEMBERS + + basic_filebuf* close() { + basic_filebuf* _Ans; + if (_Myfile) { // put any homing sequence and close file + _Reset_back(); // revert from _Mychar buffer + + _Ans = this; + if (!_Endwrite()) { + _Ans = nullptr; + } + + if (_CSTD fclose(_Myfile) != 0) { + _Ans = nullptr; + } + } else { + _Ans = nullptr; + } + + _Init(nullptr, _Closefl); + return _Ans; + } + + void __CLR_OR_THIS_CALL _Lock() override { // lock file instead of stream buffer + if (_Myfile) { + _CSTD _lock_file(_Myfile); + } + } + + void __CLR_OR_THIS_CALL _Unlock() override { // unlock file instead of stream buffer + if (_Myfile) { + _CSTD _unlock_file(_Myfile); + } + } + +#if _HAS_CXX23 && defined(_CPPRTTI) + template + friend ios_base::iostate _Do_on_maybe_unicode_console(ostream&, _UnicodeConsoleFn, _FallbackFn); +#endif // ^^^ _HAS_CXX23 && defined(_CPPRTTI) ^^^ + +protected: + int_type __CLR_OR_THIS_CALL overflow(int_type _Meta = _Traits::eof()) override { // put an element to stream + if (_Traits::eq_int_type(_Traits::eof(), _Meta)) { + return _Traits::not_eof(_Meta); // EOF, return success code + } + + if (_Mysb::pptr() && _Mysb::pptr() < _Mysb::epptr()) { // room in buffer, store it + *_Mysb::_Pninc() = _Traits::to_char_type(_Meta); + return _Meta; + } + + if (!_Myfile) { + return _Traits::eof(); // no open C stream, fail + } + + _Reset_back(); // revert from _Mychar buffer + if (!_Pcvt) { // no codecvt facet, put as is + return _Fputc(_Traits::to_char_type(_Meta), _Myfile) ? _Meta : _Traits::eof(); + } + + // put using codecvt facet + constexpr size_t _Codecvt_temp_buf = 32; + char _Str[_Codecvt_temp_buf]; + const _Elem _Ch = _Traits::to_char_type(_Meta); + const _Elem* _Src; + char* _Dest; + + // test result of converting one element + switch (_Pcvt->out(_State, &_Ch, &_Ch + 1, _Src, _Str, _Str + _Codecvt_temp_buf, _Dest)) { + case codecvt_base::partial: + case codecvt_base::ok: + { // converted something, try to put it out + const auto _Count = static_cast(_Dest - _Str); + if (0 < _Count && _Count != static_cast(_CSTD fwrite(_Str, 1, _Count, _Myfile))) { + return _Traits::eof(); // write failed + } + + _Wrotesome = true; // write succeeded + if (_Src != &_Ch) { + return _Meta; // converted whole element + } + + return _Traits::eof(); // conversion failed + } + + case codecvt_base::noconv: + // no conversion, put as is + return _Fputc(_Ch, _Myfile) ? _Meta : _Traits::eof(); + + default: + return _Traits::eof(); // conversion failed + } + } + + int_type __CLR_OR_THIS_CALL pbackfail(int_type _Meta = _Traits::eof()) override { + // put an element back to stream + if (_Mysb::gptr() && _Mysb::eback() < _Mysb::gptr() + && (_Traits::eq_int_type(_Traits::eof(), _Meta) + || _Traits::eq_int_type(_Traits::to_int_type(_Mysb::gptr()[-1]), + _Meta))) { // just back up position + _Mysb::_Gndec(); + return _Traits::not_eof(_Meta); + } else if (!_Myfile || _Traits::eq_int_type(_Traits::eof(), _Meta)) { + return _Traits::eof(); // no open C stream or EOF, fail + } else if (!_Pcvt && _Ungetc(_Traits::to_char_type(_Meta), _Myfile)) { + return _Meta; // no facet and unget succeeded, return + } else if (_Mysb::gptr() != &_Mychar) { // putback to _Mychar + _Mychar = _Traits::to_char_type(_Meta); + _Set_back(); // switch to _Mychar buffer + return _Meta; + } else { + return _Traits::eof(); // nowhere to put back + } + } + + int_type __CLR_OR_THIS_CALL underflow() override { // get an element from stream, but don't point past it + int_type _Meta; + if (_Mysb::gptr() && _Mysb::gptr() < _Mysb::egptr()) { + return _Traits::to_int_type(*_Mysb::gptr()); // return buffered + } else if (_Traits::eq_int_type(_Traits::eof(), _Meta = uflow())) { + return _Meta; // uflow failed, return EOF + } else { // get a char, don't point past it + pbackfail(_Meta); + return _Meta; + } + } + + int_type __CLR_OR_THIS_CALL uflow() override { // get an element from stream, point past it + if (_Mysb::gptr() && _Mysb::gptr() < _Mysb::egptr()) { + return _Traits::to_int_type(*_Mysb::_Gninc()); // return buffered + } + + if (!_Myfile) { + return _Traits::eof(); // no open C stream, fail + } + + _Reset_back(); // revert from _Mychar buffer + if (!_Pcvt) { // no codecvt facet, just get it + _Elem _Ch; + return _Fgetc(_Ch, _Myfile) ? _Traits::to_int_type(_Ch) : _Traits::eof(); + } + + // build string until codecvt succeeds + string _Str; + + for (;;) { // get using codecvt facet + const char* _Src; + int _Meta = _CSTD fgetc(_Myfile); + + if (_Meta == EOF) { + return _Traits::eof(); // partial char? + } + + _Str.push_back(static_cast(_Meta)); // append byte and convert + + _Elem _Ch; + _Elem* _Dest; + + // test result of converting one element + switch (_Pcvt->in(_State, _Str.data(), _Str.data() + _Str.size(), _Src, &_Ch, &_Ch + 1, _Dest)) { + case codecvt_base::partial: + case codecvt_base::ok: + if (_Dest != &_Ch) { // got an element, put back excess and deliver it + auto _Nleft = _Str.data() + _Str.size() - _Src; + while (0 < _Nleft) { + _CSTD ungetc(_Src[--_Nleft], _Myfile); + } + + return _Traits::to_int_type(_Ch); + } + + _Str.erase(0, static_cast(_Src - _Str.data())); // partial, discard used input + break; + + case codecvt_base::noconv: + // noconv is only possible if _Elem is char, so we can use it directly + return static_cast(_Str.front()); + + default: + return _Traits::eof(); // conversion failed + } + } + } + + streamsize __CLR_OR_THIS_CALL xsgetn(_Elem* _Ptr, streamsize _Count) override { + // get _Count characters from stream + if constexpr (sizeof(_Elem) == 1) { + if (_Count <= 0) { + return 0; + } + + if (_Pcvt) { // if we need a nontrivial codecvt transform, do the default expensive thing + return _Mysb::xsgetn(_Ptr, _Count); + } + + // assuming this is OK because _Ptr + _Count must be valid + auto _Count_s = static_cast(_Count); + const auto _Start_count = _Count; + const auto _Available = static_cast(_Mysb::_Gnavail()); + if (0 < _Available) { // copy from get area + const auto _Read_size = (_STD min) (_Count_s, _Available); + _Traits::copy(_Ptr, _Mysb::gptr(), _Read_size); + _Ptr += _Read_size; + _Count_s -= _Read_size; + _Mysb::gbump(static_cast(_Read_size)); + } + + if (_Myfile) { // open C stream, attempt read + _Reset_back(); // revert from _Mychar buffer + // process in 4k - 1 chunks to avoid tripping over fread's clobber-the-end behavior when + // doing \r\n -> \n translation + constexpr size_t _Read_size = 4095; // _INTERNAL_BUFSIZ - 1 + while (_Read_size < _Count_s) { + const auto _Actual_read = _CSTD fread(_Ptr, sizeof(_Elem), _Read_size, _Myfile); + _Ptr += _Actual_read; + _Count_s -= _Actual_read; + if (_Actual_read != _Read_size) { + return static_cast(_Start_count - _Count_s); + } + } + + if (0 < _Count_s) { + _Count_s -= _CSTD fread(_Ptr, sizeof(_Elem), _Count_s, _Myfile); + } + } + + return static_cast(_Start_count - _Count_s); + } else { // non-chars always get element-by-element processing + return _Mysb::xsgetn(_Ptr, _Count); + } + } + + streamsize __CLR_OR_THIS_CALL xsputn(const _Elem* _Ptr, streamsize _Count) override { + // put _Count characters to stream + if constexpr (sizeof(_Elem) == 1) { + if (_Pcvt) { // if we need a nontrivial codecvt transform, do the default expensive thing + return _Mysb::xsputn(_Ptr, _Count); + } + + const streamsize _Start_count = _Count; + streamsize _Size = _Mysb::_Pnavail(); + if (0 < _Count && 0 < _Size) { // copy to write buffer + if (_Count < _Size) { + _Size = _Count; + } + + _Traits::copy(_Mysb::pptr(), _Ptr, static_cast(_Size)); + _Ptr += _Size; + _Count -= _Size; + _Mysb::pbump(static_cast(_Size)); + } + + if (0 < _Count && _Myfile) { // open C stream, attempt write + _Count -= _CSTD fwrite(_Ptr, sizeof(_Elem), static_cast(_Count), _Myfile); + } + + return _Start_count - _Count; + } else { // non-chars always get element-by-element processing + return _Mysb::xsputn(_Ptr, _Count); + } + } + + pos_type __CLR_OR_THIS_CALL seekoff(off_type _Off, ios_base::seekdir _Way, + ios_base::openmode = ios_base::in | ios_base::out) override { // change position by _Off + fpos_t _Fileposition; + + if (_Mysb::gptr() == &_Mychar // something putback + && _Way == ios_base::cur // a relative seek + && !_Pcvt) { // not converting + _Off -= static_cast(sizeof(_Elem)); // back up over _Elem bytes + } + + if (!_Myfile || !_Endwrite() + || ((_Off != 0 || _Way != ios_base::cur) && _CSTD _fseeki64(_Myfile, _Off, _Way) != 0) + || _CSTD fgetpos(_Myfile, &_Fileposition) != 0) { + return pos_type{off_type{-1}}; // report failure + } + + _Reset_back(); // revert from _Mychar buffer, discarding any putback + return pos_type{_State, _Fileposition}; // return new position + } + + pos_type __CLR_OR_THIS_CALL seekpos(pos_type _Pos, ios_base::openmode = ios_base::in | ios_base::out) override { + // change position to _Pos + off_type _Off = static_cast(_Pos); + + if (!_Myfile || !_Endwrite() || _CSTD fsetpos(_Myfile, &_Off) != 0) { + return pos_type{off_type{-1}}; // report failure + } + + _State = _Pos.state(); + _Reset_back(); // revert from _Mychar buffer, discarding any putback + return pos_type{_State, _Off}; // return new position + } + + _Mysb* __CLR_OR_THIS_CALL setbuf(_Elem* _Buffer, streamsize _Count) override { // offer _Buffer to C stream + int _Mode; + if (!_Buffer && _Count == 0) { + _Mode = _IONBF; + } else { + _Mode = _IOFBF; + } + + const size_t _Size = static_cast(_Count) * sizeof(_Elem); + + if (!_Myfile || _CSTD setvbuf(_Myfile, reinterpret_cast(_Buffer), _Mode, _Size) != 0) { + return nullptr; // failed + } + + // new buffer, reinitialize pointers + _Init(_Myfile, _Openfl); + return this; + } + + int __CLR_OR_THIS_CALL sync() override { // synchronize C stream with external file + if (!_Myfile || _Traits::eq_int_type(_Traits::eof(), overflow()) || 0 <= _CSTD fflush(_Myfile)) { + return 0; + } + + return -1; + } + + void __CLR_OR_THIS_CALL imbue(const locale& _Loc) override { + // set locale to argument (capture nontrivial codecvt facet) + _Initcvt(_STD use_facet<_Cvt>(_Loc)); + } + + void _Init(FILE* _File, _Initfl _Which) noexcept { // initialize to C stream _File after {new, open, close} + using _State_type = typename _Traits::state_type; + + __PURE_APPDOMAIN_GLOBAL static _State_type _Stinit; // initial state + + _Closef = _Which == _Openfl; + _Wrotesome = false; + + _Mysb::_Init(); // initialize stream buffer base object + + if (_File && sizeof(_Elem) == 1) { // point inside C stream with [first, first + count) buffer + _Elem** _Pb = nullptr; + _Elem** _Pn = nullptr; + int* _Nr = nullptr; + + ::_get_stream_buffer_pointers( + _File, reinterpret_cast(&_Pb), reinterpret_cast(&_Pn), &_Nr); + int* _Nw = _Nr; + + _Mysb::_Init(_Pb, _Pn, _Nr, _Pb, _Pn, _Nw); + } + + _Myfile = _File; + _State = _Stinit; + _Pcvt = nullptr; // pointer to codecvt facet + } + + bool _Endwrite() { // put shift to initial conversion state, as needed + if (!_Pcvt || !_Wrotesome) { + return true; + } + + // may have to put + if (_Traits::eq_int_type(_Traits::eof(), overflow())) { + return false; + } + + constexpr size_t _Codecvt_temp_buf = 32; + char _Str[_Codecvt_temp_buf]; + char* _Dest; + switch (_Pcvt->unshift(_State, _Str, _Str + _Codecvt_temp_buf, _Dest)) { // test result of homing conversion + case codecvt_base::ok: + _Wrotesome = false; // homed successfully + _FALLTHROUGH; + + case codecvt_base::partial: + { // put any generated bytes + const auto _Count = static_cast(_Dest - _Str); + if (0 < _Count && _Count != static_cast(_CSTD fwrite(_Str, 1, _Count, _Myfile))) { + return false; // write failed + } + + return !_Wrotesome; + } + + case codecvt_base::noconv: + _Wrotesome = false; // homed successfully + return true; // nothing else to do + + default: + return false; // conversion failed + } + } + + void _Initcvt(const _Cvt& _Newcvt) noexcept { // initialize codecvt pointer + if (_Newcvt.always_noconv()) { + _Pcvt = nullptr; // nothing to do + } else { // set up for nontrivial codecvt facet + _Pcvt = _STD addressof(_Newcvt); + _Mysb::_Init(); // reset any buffering + } + } + +private: + const _Cvt* _Pcvt; // pointer to codecvt facet (may be null) + _Elem _Mychar; // putback character, when _Ungetc fails + bool _Wrotesome; // true if homing sequence may be needed + typename _Traits::state_type _State; // current conversion state + bool _Closef; // true if C stream must be closed + FILE* _Myfile; // pointer to C stream + + void _Reset_back() noexcept { // restore buffer after putback + if (_Mysb::eback() == &_Mychar) { + _Mysb::setg(_Set_eback, _Set_eback, _Set_egptr); + } + } + + void _Set_back() noexcept { // set up putback area + if (_Mysb::eback() != &_Mychar) { // save current get buffer + _Set_eback = _Mysb::eback(); + _Set_egptr = _Mysb::egptr(); + } + _Mysb::setg(&_Mychar, &_Mychar, &_Mychar + 1); + } + + _Elem* _Set_eback; // saves eback() during one-element putback + _Elem* _Set_egptr; // saves egptr() +}; + +_EXPORT_STD template +void swap(basic_filebuf<_Elem, _Traits>& _Left, basic_filebuf<_Elem, _Traits>& _Right) noexcept /* strengthened */ { + _Left.swap(_Right); +} + +_STD_END + +#pragma pop_macro("new") +_STL_RESTORE_CLANG_WARNINGS +#pragma warning(pop) +#pragma pack(pop) + +#endif // _STL_COMPILER_PREPROCESSOR +#endif // __MSVC_FILEBUF_HPP diff --git a/stl/inc/__msvc_format_ucd_tables.hpp b/stl/inc/__msvc_format_ucd_tables.hpp new file mode 100644 index 00000000000..a4ebf52a0ad --- /dev/null +++ b/stl/inc/__msvc_format_ucd_tables.hpp @@ -0,0 +1,659 @@ +// __msvc_format_ucd_tables.hpp internal header + +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +// WARNING, this entire header is generated by +// tools/unicode_properties_parse/unicode_properties_data_gen.py +// DO NOT MODIFY! + +// UNICODE, INC. LICENSE AGREEMENT - DATA FILES AND SOFTWARE +// +// See Terms of Use +// for definitions of Unicode Inc.'s Data Files and Software. +// +// NOTICE TO USER: Carefully read the following legal agreement. +// BY DOWNLOADING, INSTALLING, COPYING OR OTHERWISE USING UNICODE INC.'S +// DATA FILES ("DATA FILES"), AND/OR SOFTWARE ("SOFTWARE"), +// YOU UNEQUIVOCALLY ACCEPT, AND AGREE TO BE BOUND BY, ALL OF THE +// TERMS AND CONDITIONS OF THIS AGREEMENT. +// IF YOU DO NOT AGREE, DO NOT DOWNLOAD, INSTALL, COPY, DISTRIBUTE OR USE +// THE DATA FILES OR SOFTWARE. +// +// COPYRIGHT AND PERMISSION NOTICE +// +// Copyright (c) 1991-2022 Unicode, Inc. All rights reserved. +// Distributed under the Terms of Use in https://www.unicode.org/copyright.html. +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of the Unicode data files and any associated documentation +// (the "Data Files") or Unicode software and any associated documentation +// (the "Software") to deal in the Data Files or Software +// without restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, and/or sell copies of +// the Data Files or Software, and to permit persons to whom the Data Files +// or Software are furnished to do so, provided that either +// (a) this copyright and permission notice appear with all copies +// of the Data Files or Software, or +// (b) this copyright and permission notice appear in associated +// Documentation. +// +// THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF +// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT OF THIRD PARTY RIGHTS. +// IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS +// NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL +// DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, +// DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER +// TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +// PERFORMANCE OF THE DATA FILES OR SOFTWARE. +// +// Except as contained in this notice, the name of a copyright holder +// shall not be used in advertising or otherwise to promote the sale, +// use or other dealings in these Data Files or Software without prior +// written authorization of the copyright holder. + +#ifndef __MSVC_FORMAT_UCD_TABLES_HPP +#define __MSVC_FORMAT_UCD_TABLES_HPP +#include +#if _STL_COMPILER_PREPROCESSOR + +#include +#include + +#pragma pack(push, _CRT_PACKING) +#pragma warning(push, _STL_WARNING_LEVEL) +#pragma warning(disable : _STL_DISABLED_WARNINGS) +_STL_DISABLE_CLANG_WARNINGS +#pragma push_macro("new") +#undef new + +_STD_BEGIN + +template +struct _Unicode_property_data { + uint32_t _Lower_bounds[_NumRanges]; + uint16_t _Props_and_size[_NumRanges]; + _NODISCARD constexpr _ValueEnum _Get_property_for_codepoint(const uint32_t _Code_point) const noexcept { + ptrdiff_t _Upper_idx = _STD upper_bound(_Lower_bounds, _STD end(_Lower_bounds), _Code_point) - _Lower_bounds; + constexpr auto _No_value_constant = static_cast<_ValueEnum>(UINT8_MAX); + if (_Upper_idx == 0) { + return _No_value_constant; + } + --_Upper_idx; + const uint32_t _Lower_bound = _Lower_bounds[_Upper_idx]; + const uint16_t _Data = _Props_and_size[_Upper_idx]; + _STL_INTERNAL_CHECK(_Code_point >= _Lower_bound); + if constexpr (_Is_binary_property) { + if (_Code_point < _Lower_bound + _Data) { + return static_cast<_ValueEnum>(0); + } + } else { + const uint16_t _Size = static_cast(_Data & 0x0FFF); + const _ValueEnum _Prop = static_cast<_ValueEnum>((_Data & 0xF000) >> 12); + if (_Code_point < _Lower_bound + _Size) { + return _Prop; + } + } + return _No_value_constant; + } +}; + +// The following static data tables are generated from the Unicode character database. +// _Grapheme_Break_property_data comes from ucd/auxiliary/GraphemeBreakProperty.txt. +// +// _Indic_Conjunct_Break_property_data comes from ucd/DerivedCoreProperties.txt. +// +// _Extended_Pictographic_property_data comes from ucd/emoji/emoji-data.txt. +// +// __printable_property_data comes from ucd/extracted/DerivedGeneralCategory.txt. +// +// _Grapheme_Extend_property_data comes from ucd/DerivedCoreProperties.txt. +// +// The enums containing the values for the properties are also generated, in order to ensure they match +// up correctly with how we're parsing them. +// +// All sets of data tables are generated by tools/unicode_properties_parse/unicode_properties_data_gen.py in the +// https://github.com/microsoft/stl repository. +// +// The data format is a set of arrays for each character property. The first is an array of uint32_t encoding +// the lower bound of each range of codepoints that has the given property. +// The second is an array of uint16_t. +// - For enumerated properties, this array encodes both the range size and property value as follows: +// 16 12 0 +// +-----------------------------------------------------+ +// | property_value | range_size | +// +-----------------------------------------------------+ +// that is: the size is stored in the least significant 12 bits +// (leading to a max size of 4095), and the property value is stored in the most significant 4 bits, +// leading to a maximum of 16 property values. +// - For binary properties, this array simply stores the range size. +// +// Codepoint ranges may not overlap, and, within one property, a codepoint may only appear once. Furthermore the +// codepoint lower bounds appear in sorted (ascending) order. + +// GraphemeBreakProperty-17.0.0.txt +// Date: 2025-06-30, 06:20:23 GMT +enum class _Grapheme_Break_property_values : uint8_t { + _CR_value, + _Control_value, + _Extend_value, + _L_value, + _LF_value, + _LV_value, + _LVT_value, + _Prepend_value, + _Regional_Indicator_value, + _SpacingMark_value, + _T_value, + _V_value, + _ZWJ_value, + _No_value = 255 +}; + +// GraphemeBreakProperty-17.0.0.txt +// Date: 2025-06-30, 06:20:23 GMT +inline constexpr _Unicode_property_data<_Grapheme_Break_property_values, 1386, false> _Grapheme_Break_property_data{ + {0x0, 0xa, 0xb, 0xd, 0xe, 0x7f, 0xad, 0x300, 0x483, 0x591, 0x5bf, 0x5c1, 0x5c4, 0x5c7, 0x600, 0x610, 0x61c, 0x64b, + 0x670, 0x6d6, 0x6dd, 0x6df, 0x6e7, 0x6ea, 0x70f, 0x711, 0x730, 0x7a6, 0x7eb, 0x7fd, 0x816, 0x81b, 0x825, 0x829, + 0x859, 0x890, 0x897, 0x8ca, 0x8e2, 0x8e3, 0x903, 0x93a, 0x93b, 0x93c, 0x93e, 0x941, 0x949, 0x94d, 0x94e, 0x951, + 0x962, 0x981, 0x982, 0x9bc, 0x9be, 0x9bf, 0x9c1, 0x9c7, 0x9cb, 0x9cd, 0x9d7, 0x9e2, 0x9fe, 0xa01, 0xa03, 0xa3c, + 0xa3e, 0xa41, 0xa47, 0xa4b, 0xa51, 0xa70, 0xa75, 0xa81, 0xa83, 0xabc, 0xabe, 0xac1, 0xac7, 0xac9, 0xacb, 0xacd, + 0xae2, 0xafa, 0xb01, 0xb02, 0xb3c, 0xb3e, 0xb40, 0xb41, 0xb47, 0xb4b, 0xb4d, 0xb55, 0xb62, 0xb82, 0xbbe, 0xbbf, + 0xbc0, 0xbc1, 0xbc6, 0xbca, 0xbcd, 0xbd7, 0xc00, 0xc01, 0xc04, 0xc3c, 0xc3e, 0xc41, 0xc46, 0xc4a, 0xc55, 0xc62, + 0xc81, 0xc82, 0xcbc, 0xcbe, 0xcbf, 0xcc1, 0xcc2, 0xcc3, 0xcc6, 0xcca, 0xcd5, 0xce2, 0xcf3, 0xd00, 0xd02, 0xd3b, + 0xd3e, 0xd3f, 0xd41, 0xd46, 0xd4a, 0xd4d, 0xd4e, 0xd57, 0xd62, 0xd81, 0xd82, 0xdca, 0xdcf, 0xdd0, 0xdd2, 0xdd6, + 0xdd8, 0xddf, 0xdf2, 0xe31, 0xe33, 0xe34, 0xe47, 0xeb1, 0xeb3, 0xeb4, 0xec8, 0xf18, 0xf35, 0xf37, 0xf39, 0xf3e, + 0xf71, 0xf7f, 0xf80, 0xf86, 0xf8d, 0xf99, 0xfc6, 0x102d, 0x1031, 0x1032, 0x1039, 0x103b, 0x103d, 0x1056, 0x1058, + 0x105e, 0x1071, 0x1082, 0x1084, 0x1085, 0x108d, 0x109d, 0x1100, 0x1160, 0x11a8, 0x135d, 0x1712, 0x1732, 0x1752, + 0x1772, 0x17b4, 0x17b6, 0x17b7, 0x17be, 0x17c6, 0x17c7, 0x17c9, 0x17dd, 0x180b, 0x180e, 0x180f, 0x1885, 0x18a9, + 0x1920, 0x1923, 0x1927, 0x1929, 0x1930, 0x1932, 0x1933, 0x1939, 0x1a17, 0x1a19, 0x1a1b, 0x1a55, 0x1a56, 0x1a57, + 0x1a58, 0x1a60, 0x1a62, 0x1a65, 0x1a6d, 0x1a73, 0x1a7f, 0x1ab0, 0x1ae0, 0x1b00, 0x1b04, 0x1b34, 0x1b3e, 0x1b42, + 0x1b6b, 0x1b80, 0x1b82, 0x1ba1, 0x1ba2, 0x1ba6, 0x1ba8, 0x1be6, 0x1be7, 0x1be8, 0x1bea, 0x1bed, 0x1bee, 0x1bef, + 0x1c24, 0x1c2c, 0x1c34, 0x1c36, 0x1cd0, 0x1cd4, 0x1ce1, 0x1ce2, 0x1ced, 0x1cf4, 0x1cf7, 0x1cf8, 0x1dc0, 0x200b, + 0x200c, 0x200d, 0x200e, 0x2028, 0x2060, 0x20d0, 0x2cef, 0x2d7f, 0x2de0, 0x302a, 0x3099, 0xa66f, 0xa674, 0xa69e, + 0xa6f0, 0xa802, 0xa806, 0xa80b, 0xa823, 0xa825, 0xa827, 0xa82c, 0xa880, 0xa8b4, 0xa8c4, 0xa8e0, 0xa8ff, 0xa926, + 0xa947, 0xa952, 0xa953, 0xa960, 0xa980, 0xa983, 0xa9b3, 0xa9b4, 0xa9b6, 0xa9ba, 0xa9bc, 0xa9be, 0xa9c0, 0xa9e5, + 0xaa29, 0xaa2f, 0xaa31, 0xaa33, 0xaa35, 0xaa43, 0xaa4c, 0xaa4d, 0xaa7c, 0xaab0, 0xaab2, 0xaab7, 0xaabe, 0xaac1, + 0xaaeb, 0xaaec, 0xaaee, 0xaaf5, 0xaaf6, 0xabe3, 0xabe5, 0xabe6, 0xabe8, 0xabe9, 0xabec, 0xabed, 0xac00, 0xac01, + 0xac1c, 0xac1d, 0xac38, 0xac39, 0xac54, 0xac55, 0xac70, 0xac71, 0xac8c, 0xac8d, 0xaca8, 0xaca9, 0xacc4, 0xacc5, + 0xace0, 0xace1, 0xacfc, 0xacfd, 0xad18, 0xad19, 0xad34, 0xad35, 0xad50, 0xad51, 0xad6c, 0xad6d, 0xad88, 0xad89, + 0xada4, 0xada5, 0xadc0, 0xadc1, 0xaddc, 0xaddd, 0xadf8, 0xadf9, 0xae14, 0xae15, 0xae30, 0xae31, 0xae4c, 0xae4d, + 0xae68, 0xae69, 0xae84, 0xae85, 0xaea0, 0xaea1, 0xaebc, 0xaebd, 0xaed8, 0xaed9, 0xaef4, 0xaef5, 0xaf10, 0xaf11, + 0xaf2c, 0xaf2d, 0xaf48, 0xaf49, 0xaf64, 0xaf65, 0xaf80, 0xaf81, 0xaf9c, 0xaf9d, 0xafb8, 0xafb9, 0xafd4, 0xafd5, + 0xaff0, 0xaff1, 0xb00c, 0xb00d, 0xb028, 0xb029, 0xb044, 0xb045, 0xb060, 0xb061, 0xb07c, 0xb07d, 0xb098, 0xb099, + 0xb0b4, 0xb0b5, 0xb0d0, 0xb0d1, 0xb0ec, 0xb0ed, 0xb108, 0xb109, 0xb124, 0xb125, 0xb140, 0xb141, 0xb15c, 0xb15d, + 0xb178, 0xb179, 0xb194, 0xb195, 0xb1b0, 0xb1b1, 0xb1cc, 0xb1cd, 0xb1e8, 0xb1e9, 0xb204, 0xb205, 0xb220, 0xb221, + 0xb23c, 0xb23d, 0xb258, 0xb259, 0xb274, 0xb275, 0xb290, 0xb291, 0xb2ac, 0xb2ad, 0xb2c8, 0xb2c9, 0xb2e4, 0xb2e5, + 0xb300, 0xb301, 0xb31c, 0xb31d, 0xb338, 0xb339, 0xb354, 0xb355, 0xb370, 0xb371, 0xb38c, 0xb38d, 0xb3a8, 0xb3a9, + 0xb3c4, 0xb3c5, 0xb3e0, 0xb3e1, 0xb3fc, 0xb3fd, 0xb418, 0xb419, 0xb434, 0xb435, 0xb450, 0xb451, 0xb46c, 0xb46d, + 0xb488, 0xb489, 0xb4a4, 0xb4a5, 0xb4c0, 0xb4c1, 0xb4dc, 0xb4dd, 0xb4f8, 0xb4f9, 0xb514, 0xb515, 0xb530, 0xb531, + 0xb54c, 0xb54d, 0xb568, 0xb569, 0xb584, 0xb585, 0xb5a0, 0xb5a1, 0xb5bc, 0xb5bd, 0xb5d8, 0xb5d9, 0xb5f4, 0xb5f5, + 0xb610, 0xb611, 0xb62c, 0xb62d, 0xb648, 0xb649, 0xb664, 0xb665, 0xb680, 0xb681, 0xb69c, 0xb69d, 0xb6b8, 0xb6b9, + 0xb6d4, 0xb6d5, 0xb6f0, 0xb6f1, 0xb70c, 0xb70d, 0xb728, 0xb729, 0xb744, 0xb745, 0xb760, 0xb761, 0xb77c, 0xb77d, + 0xb798, 0xb799, 0xb7b4, 0xb7b5, 0xb7d0, 0xb7d1, 0xb7ec, 0xb7ed, 0xb808, 0xb809, 0xb824, 0xb825, 0xb840, 0xb841, + 0xb85c, 0xb85d, 0xb878, 0xb879, 0xb894, 0xb895, 0xb8b0, 0xb8b1, 0xb8cc, 0xb8cd, 0xb8e8, 0xb8e9, 0xb904, 0xb905, + 0xb920, 0xb921, 0xb93c, 0xb93d, 0xb958, 0xb959, 0xb974, 0xb975, 0xb990, 0xb991, 0xb9ac, 0xb9ad, 0xb9c8, 0xb9c9, + 0xb9e4, 0xb9e5, 0xba00, 0xba01, 0xba1c, 0xba1d, 0xba38, 0xba39, 0xba54, 0xba55, 0xba70, 0xba71, 0xba8c, 0xba8d, + 0xbaa8, 0xbaa9, 0xbac4, 0xbac5, 0xbae0, 0xbae1, 0xbafc, 0xbafd, 0xbb18, 0xbb19, 0xbb34, 0xbb35, 0xbb50, 0xbb51, + 0xbb6c, 0xbb6d, 0xbb88, 0xbb89, 0xbba4, 0xbba5, 0xbbc0, 0xbbc1, 0xbbdc, 0xbbdd, 0xbbf8, 0xbbf9, 0xbc14, 0xbc15, + 0xbc30, 0xbc31, 0xbc4c, 0xbc4d, 0xbc68, 0xbc69, 0xbc84, 0xbc85, 0xbca0, 0xbca1, 0xbcbc, 0xbcbd, 0xbcd8, 0xbcd9, + 0xbcf4, 0xbcf5, 0xbd10, 0xbd11, 0xbd2c, 0xbd2d, 0xbd48, 0xbd49, 0xbd64, 0xbd65, 0xbd80, 0xbd81, 0xbd9c, 0xbd9d, + 0xbdb8, 0xbdb9, 0xbdd4, 0xbdd5, 0xbdf0, 0xbdf1, 0xbe0c, 0xbe0d, 0xbe28, 0xbe29, 0xbe44, 0xbe45, 0xbe60, 0xbe61, + 0xbe7c, 0xbe7d, 0xbe98, 0xbe99, 0xbeb4, 0xbeb5, 0xbed0, 0xbed1, 0xbeec, 0xbeed, 0xbf08, 0xbf09, 0xbf24, 0xbf25, + 0xbf40, 0xbf41, 0xbf5c, 0xbf5d, 0xbf78, 0xbf79, 0xbf94, 0xbf95, 0xbfb0, 0xbfb1, 0xbfcc, 0xbfcd, 0xbfe8, 0xbfe9, + 0xc004, 0xc005, 0xc020, 0xc021, 0xc03c, 0xc03d, 0xc058, 0xc059, 0xc074, 0xc075, 0xc090, 0xc091, 0xc0ac, 0xc0ad, + 0xc0c8, 0xc0c9, 0xc0e4, 0xc0e5, 0xc100, 0xc101, 0xc11c, 0xc11d, 0xc138, 0xc139, 0xc154, 0xc155, 0xc170, 0xc171, + 0xc18c, 0xc18d, 0xc1a8, 0xc1a9, 0xc1c4, 0xc1c5, 0xc1e0, 0xc1e1, 0xc1fc, 0xc1fd, 0xc218, 0xc219, 0xc234, 0xc235, + 0xc250, 0xc251, 0xc26c, 0xc26d, 0xc288, 0xc289, 0xc2a4, 0xc2a5, 0xc2c0, 0xc2c1, 0xc2dc, 0xc2dd, 0xc2f8, 0xc2f9, + 0xc314, 0xc315, 0xc330, 0xc331, 0xc34c, 0xc34d, 0xc368, 0xc369, 0xc384, 0xc385, 0xc3a0, 0xc3a1, 0xc3bc, 0xc3bd, + 0xc3d8, 0xc3d9, 0xc3f4, 0xc3f5, 0xc410, 0xc411, 0xc42c, 0xc42d, 0xc448, 0xc449, 0xc464, 0xc465, 0xc480, 0xc481, + 0xc49c, 0xc49d, 0xc4b8, 0xc4b9, 0xc4d4, 0xc4d5, 0xc4f0, 0xc4f1, 0xc50c, 0xc50d, 0xc528, 0xc529, 0xc544, 0xc545, + 0xc560, 0xc561, 0xc57c, 0xc57d, 0xc598, 0xc599, 0xc5b4, 0xc5b5, 0xc5d0, 0xc5d1, 0xc5ec, 0xc5ed, 0xc608, 0xc609, + 0xc624, 0xc625, 0xc640, 0xc641, 0xc65c, 0xc65d, 0xc678, 0xc679, 0xc694, 0xc695, 0xc6b0, 0xc6b1, 0xc6cc, 0xc6cd, + 0xc6e8, 0xc6e9, 0xc704, 0xc705, 0xc720, 0xc721, 0xc73c, 0xc73d, 0xc758, 0xc759, 0xc774, 0xc775, 0xc790, 0xc791, + 0xc7ac, 0xc7ad, 0xc7c8, 0xc7c9, 0xc7e4, 0xc7e5, 0xc800, 0xc801, 0xc81c, 0xc81d, 0xc838, 0xc839, 0xc854, 0xc855, + 0xc870, 0xc871, 0xc88c, 0xc88d, 0xc8a8, 0xc8a9, 0xc8c4, 0xc8c5, 0xc8e0, 0xc8e1, 0xc8fc, 0xc8fd, 0xc918, 0xc919, + 0xc934, 0xc935, 0xc950, 0xc951, 0xc96c, 0xc96d, 0xc988, 0xc989, 0xc9a4, 0xc9a5, 0xc9c0, 0xc9c1, 0xc9dc, 0xc9dd, + 0xc9f8, 0xc9f9, 0xca14, 0xca15, 0xca30, 0xca31, 0xca4c, 0xca4d, 0xca68, 0xca69, 0xca84, 0xca85, 0xcaa0, 0xcaa1, + 0xcabc, 0xcabd, 0xcad8, 0xcad9, 0xcaf4, 0xcaf5, 0xcb10, 0xcb11, 0xcb2c, 0xcb2d, 0xcb48, 0xcb49, 0xcb64, 0xcb65, + 0xcb80, 0xcb81, 0xcb9c, 0xcb9d, 0xcbb8, 0xcbb9, 0xcbd4, 0xcbd5, 0xcbf0, 0xcbf1, 0xcc0c, 0xcc0d, 0xcc28, 0xcc29, + 0xcc44, 0xcc45, 0xcc60, 0xcc61, 0xcc7c, 0xcc7d, 0xcc98, 0xcc99, 0xccb4, 0xccb5, 0xccd0, 0xccd1, 0xccec, 0xcced, + 0xcd08, 0xcd09, 0xcd24, 0xcd25, 0xcd40, 0xcd41, 0xcd5c, 0xcd5d, 0xcd78, 0xcd79, 0xcd94, 0xcd95, 0xcdb0, 0xcdb1, + 0xcdcc, 0xcdcd, 0xcde8, 0xcde9, 0xce04, 0xce05, 0xce20, 0xce21, 0xce3c, 0xce3d, 0xce58, 0xce59, 0xce74, 0xce75, + 0xce90, 0xce91, 0xceac, 0xcead, 0xcec8, 0xcec9, 0xcee4, 0xcee5, 0xcf00, 0xcf01, 0xcf1c, 0xcf1d, 0xcf38, 0xcf39, + 0xcf54, 0xcf55, 0xcf70, 0xcf71, 0xcf8c, 0xcf8d, 0xcfa8, 0xcfa9, 0xcfc4, 0xcfc5, 0xcfe0, 0xcfe1, 0xcffc, 0xcffd, + 0xd018, 0xd019, 0xd034, 0xd035, 0xd050, 0xd051, 0xd06c, 0xd06d, 0xd088, 0xd089, 0xd0a4, 0xd0a5, 0xd0c0, 0xd0c1, + 0xd0dc, 0xd0dd, 0xd0f8, 0xd0f9, 0xd114, 0xd115, 0xd130, 0xd131, 0xd14c, 0xd14d, 0xd168, 0xd169, 0xd184, 0xd185, + 0xd1a0, 0xd1a1, 0xd1bc, 0xd1bd, 0xd1d8, 0xd1d9, 0xd1f4, 0xd1f5, 0xd210, 0xd211, 0xd22c, 0xd22d, 0xd248, 0xd249, + 0xd264, 0xd265, 0xd280, 0xd281, 0xd29c, 0xd29d, 0xd2b8, 0xd2b9, 0xd2d4, 0xd2d5, 0xd2f0, 0xd2f1, 0xd30c, 0xd30d, + 0xd328, 0xd329, 0xd344, 0xd345, 0xd360, 0xd361, 0xd37c, 0xd37d, 0xd398, 0xd399, 0xd3b4, 0xd3b5, 0xd3d0, 0xd3d1, + 0xd3ec, 0xd3ed, 0xd408, 0xd409, 0xd424, 0xd425, 0xd440, 0xd441, 0xd45c, 0xd45d, 0xd478, 0xd479, 0xd494, 0xd495, + 0xd4b0, 0xd4b1, 0xd4cc, 0xd4cd, 0xd4e8, 0xd4e9, 0xd504, 0xd505, 0xd520, 0xd521, 0xd53c, 0xd53d, 0xd558, 0xd559, + 0xd574, 0xd575, 0xd590, 0xd591, 0xd5ac, 0xd5ad, 0xd5c8, 0xd5c9, 0xd5e4, 0xd5e5, 0xd600, 0xd601, 0xd61c, 0xd61d, + 0xd638, 0xd639, 0xd654, 0xd655, 0xd670, 0xd671, 0xd68c, 0xd68d, 0xd6a8, 0xd6a9, 0xd6c4, 0xd6c5, 0xd6e0, 0xd6e1, + 0xd6fc, 0xd6fd, 0xd718, 0xd719, 0xd734, 0xd735, 0xd750, 0xd751, 0xd76c, 0xd76d, 0xd788, 0xd789, 0xd7b0, 0xd7cb, + 0xfb1e, 0xfe00, 0xfe20, 0xfeff, 0xff9e, 0xfff0, 0x101fd, 0x102e0, 0x10376, 0x10a01, 0x10a05, 0x10a0c, 0x10a38, + 0x10a3f, 0x10ae5, 0x10d24, 0x10d69, 0x10eab, 0x10efa, 0x10f46, 0x10f82, 0x11000, 0x11001, 0x11002, 0x11038, + 0x11070, 0x11073, 0x1107f, 0x11082, 0x110b0, 0x110b3, 0x110b7, 0x110b9, 0x110bd, 0x110c2, 0x110cd, 0x11100, + 0x11127, 0x1112c, 0x1112d, 0x11145, 0x11173, 0x11180, 0x11182, 0x111b3, 0x111b6, 0x111bf, 0x111c0, 0x111c2, + 0x111c9, 0x111ce, 0x111cf, 0x1122c, 0x1122f, 0x11232, 0x11234, 0x1123e, 0x11241, 0x112df, 0x112e0, 0x112e3, + 0x11300, 0x11302, 0x1133b, 0x1133e, 0x1133f, 0x11340, 0x11341, 0x11347, 0x1134b, 0x1134d, 0x11357, 0x11362, + 0x11366, 0x11370, 0x113b8, 0x113b9, 0x113bb, 0x113c2, 0x113c5, 0x113c7, 0x113ca, 0x113cc, 0x113ce, 0x113d1, + 0x113d2, 0x113e1, 0x11435, 0x11438, 0x11440, 0x11442, 0x11445, 0x11446, 0x1145e, 0x114b0, 0x114b1, 0x114b3, + 0x114b9, 0x114ba, 0x114bb, 0x114bd, 0x114be, 0x114bf, 0x114c1, 0x114c2, 0x115af, 0x115b0, 0x115b2, 0x115b8, + 0x115bc, 0x115be, 0x115bf, 0x115dc, 0x11630, 0x11633, 0x1163b, 0x1163d, 0x1163e, 0x1163f, 0x116ab, 0x116ac, + 0x116ad, 0x116ae, 0x116b0, 0x1171d, 0x1171e, 0x1171f, 0x11722, 0x11726, 0x11727, 0x1182c, 0x1182f, 0x11838, + 0x11839, 0x11930, 0x11931, 0x11937, 0x1193b, 0x1193f, 0x11940, 0x11941, 0x11942, 0x11943, 0x119d1, 0x119d4, + 0x119da, 0x119dc, 0x119e0, 0x119e4, 0x11a01, 0x11a33, 0x11a39, 0x11a3b, 0x11a47, 0x11a51, 0x11a57, 0x11a59, + 0x11a84, 0x11a8a, 0x11a97, 0x11a98, 0x11b60, 0x11b61, 0x11b62, 0x11b65, 0x11b66, 0x11b67, 0x11c2f, 0x11c30, + 0x11c38, 0x11c3e, 0x11c3f, 0x11c92, 0x11ca9, 0x11caa, 0x11cb1, 0x11cb2, 0x11cb4, 0x11cb5, 0x11d31, 0x11d3a, + 0x11d3c, 0x11d3f, 0x11d46, 0x11d47, 0x11d8a, 0x11d90, 0x11d93, 0x11d95, 0x11d96, 0x11d97, 0x11ef3, 0x11ef5, + 0x11f00, 0x11f02, 0x11f03, 0x11f34, 0x11f36, 0x11f3e, 0x11f40, 0x11f5a, 0x13430, 0x13440, 0x13447, 0x1611e, + 0x1612a, 0x1612d, 0x16af0, 0x16b30, 0x16d63, 0x16d67, 0x16f4f, 0x16f51, 0x16f8f, 0x16fe4, 0x16ff0, 0x1bc9d, + 0x1bca0, 0x1cf00, 0x1cf30, 0x1d165, 0x1d16d, 0x1d173, 0x1d17b, 0x1d185, 0x1d1aa, 0x1d242, 0x1da00, 0x1da3b, + 0x1da75, 0x1da84, 0x1da9b, 0x1daa1, 0x1e000, 0x1e008, 0x1e01b, 0x1e023, 0x1e026, 0x1e08f, 0x1e130, 0x1e2ae, + 0x1e2ec, 0x1e4ec, 0x1e5ee, 0x1e6e3, 0x1e6e6, 0x1e6ee, 0x1e6f5, 0x1e8d0, 0x1e944, 0x1f1e6, 0x1f3fb, 0xe0000, + 0xe0020, 0xe0080, 0xe0100, 0xe01f0}, + {0x100a, 0x4001, 0x1002, 0x1, 0x1012, 0x1021, 0x1001, 0x2070, 0x2007, 0x202d, 0x2001, 0x2002, 0x2002, 0x2001, + 0x7006, 0x200b, 0x1001, 0x2015, 0x2001, 0x2007, 0x7001, 0x2006, 0x2002, 0x2004, 0x7001, 0x2001, 0x201b, 0x200b, + 0x2009, 0x2001, 0x2004, 0x2009, 0x2003, 0x2005, 0x2003, 0x7002, 0x2009, 0x2018, 0x7001, 0x2020, 0x9001, 0x2001, + 0x9001, 0x2001, 0x9003, 0x2008, 0x9004, 0x2001, 0x9002, 0x2007, 0x2002, 0x2001, 0x9002, 0x2001, 0x2001, 0x9002, + 0x2004, 0x9002, 0x9002, 0x2001, 0x2001, 0x2002, 0x2001, 0x2002, 0x9001, 0x2001, 0x9003, 0x2002, 0x2002, 0x2003, + 0x2001, 0x2002, 0x2001, 0x2002, 0x9001, 0x2001, 0x9003, 0x2005, 0x2002, 0x9001, 0x9002, 0x2001, 0x2002, 0x2006, + 0x2001, 0x9002, 0x2001, 0x2002, 0x9001, 0x2004, 0x9002, 0x9002, 0x2001, 0x2003, 0x2002, 0x2001, 0x2001, 0x9001, + 0x2001, 0x9002, 0x9003, 0x9003, 0x2001, 0x2001, 0x2001, 0x9003, 0x2001, 0x2001, 0x2003, 0x9004, 0x2003, 0x2004, + 0x2002, 0x2002, 0x2001, 0x9002, 0x2001, 0x9001, 0x2002, 0x9001, 0x2001, 0x9002, 0x2003, 0x2004, 0x2002, 0x2002, + 0x9001, 0x2002, 0x9002, 0x2002, 0x2001, 0x9002, 0x2004, 0x9003, 0x9003, 0x2001, 0x7001, 0x2001, 0x2002, 0x2001, + 0x9002, 0x2001, 0x2001, 0x9002, 0x2003, 0x2001, 0x9007, 0x2001, 0x9002, 0x2001, 0x9001, 0x2007, 0x2008, 0x2001, + 0x9001, 0x2009, 0x2007, 0x2002, 0x2001, 0x2001, 0x2001, 0x9002, 0x200e, 0x9001, 0x2005, 0x2002, 0x200b, 0x2024, + 0x2001, 0x2004, 0x9001, 0x2006, 0x2002, 0x9002, 0x2002, 0x9002, 0x2002, 0x2003, 0x2004, 0x2001, 0x9001, 0x2002, + 0x2001, 0x2001, 0x3060, 0xb048, 0xa058, 0x2003, 0x2004, 0x2003, 0x2002, 0x2002, 0x2002, 0x9001, 0x2007, 0x9008, + 0x2001, 0x9002, 0x200b, 0x2001, 0x2003, 0x1001, 0x2001, 0x2002, 0x2001, 0x2003, 0x9004, 0x2002, 0x9003, 0x9002, + 0x2001, 0x9006, 0x2003, 0x2002, 0x9002, 0x2001, 0x9001, 0x2001, 0x9001, 0x2007, 0x2001, 0x2001, 0x2008, 0x9006, + 0x200a, 0x2001, 0x202e, 0x200c, 0x2004, 0x9001, 0x200a, 0x9004, 0x2003, 0x2009, 0x2002, 0x9001, 0x9001, 0x2004, + 0x9002, 0x2006, 0x2001, 0x9001, 0x2002, 0x9003, 0x2001, 0x9001, 0x2005, 0x9008, 0x2008, 0x9002, 0x2002, 0x2003, + 0x200d, 0x9001, 0x2007, 0x2001, 0x2001, 0x9001, 0x2002, 0x2040, 0x1001, 0x2001, 0xc001, 0x1002, 0x1007, 0x1010, + 0x2021, 0x2003, 0x2001, 0x2020, 0x2006, 0x2002, 0x2004, 0x200a, 0x2002, 0x2002, 0x2001, 0x2001, 0x2001, 0x9002, + 0x2002, 0x9001, 0x2001, 0x9002, 0x9010, 0x2002, 0x2012, 0x2001, 0x2008, 0x200b, 0x9001, 0x2001, 0x301d, 0x2003, + 0x9001, 0x2001, 0x9002, 0x2004, 0x9002, 0x2002, 0x9002, 0x2001, 0x2001, 0x2006, 0x9002, 0x2002, 0x9002, 0x2002, + 0x2001, 0x2001, 0x9001, 0x2001, 0x2001, 0x2003, 0x2002, 0x2002, 0x2001, 0x9001, 0x2002, 0x9002, 0x9001, 0x2001, + 0x9002, 0x2001, 0x9002, 0x2001, 0x9002, 0x9001, 0x2001, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, + 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, + 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, + 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, + 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, + 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, + 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, + 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, + 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, + 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, + 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, + 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, + 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, + 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, + 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, + 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, + 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, + 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, + 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, + 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, + 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, + 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, + 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, + 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, + 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, + 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, + 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, + 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, + 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, + 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, + 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, + 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, + 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, + 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, + 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, + 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, + 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, + 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, + 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, + 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, + 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, + 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, + 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, + 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, + 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, + 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, + 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, + 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, + 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, + 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, + 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, + 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, + 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, + 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, + 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, + 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, + 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, + 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0x5001, 0x601b, 0xb017, 0xa031, 0x2001, 0x2010, 0x2010, 0x1001, 0x2002, + 0x100c, 0x2001, 0x2001, 0x2005, 0x2003, 0x2002, 0x2004, 0x2003, 0x2001, 0x2002, 0x2004, 0x2005, 0x2002, 0x2006, + 0x200b, 0x2004, 0x9001, 0x2001, 0x9001, 0x200f, 0x2001, 0x2002, 0x2003, 0x9001, 0x9003, 0x2004, 0x9002, 0x2002, + 0x7001, 0x2001, 0x7001, 0x2003, 0x2005, 0x9001, 0x2008, 0x9002, 0x2001, 0x2002, 0x9001, 0x9003, 0x2009, 0x9001, + 0x2001, 0x7002, 0x2004, 0x9001, 0x2001, 0x9003, 0x2003, 0x9002, 0x2004, 0x2001, 0x2001, 0x2001, 0x9003, 0x2008, + 0x2002, 0x9002, 0x2002, 0x2001, 0x9001, 0x2001, 0x9004, 0x9002, 0x9002, 0x2001, 0x2001, 0x9002, 0x2007, 0x2005, + 0x2001, 0x9002, 0x2006, 0x2001, 0x2001, 0x2003, 0x9001, 0x9002, 0x2003, 0x7001, 0x2001, 0x2002, 0x9003, 0x2008, + 0x9002, 0x2003, 0x9001, 0x2001, 0x2001, 0x2001, 0x9002, 0x2006, 0x9001, 0x2001, 0x9002, 0x2001, 0x9001, 0x2002, + 0x9001, 0x2002, 0x2001, 0x9002, 0x2004, 0x9004, 0x2002, 0x9001, 0x2002, 0x2002, 0x9003, 0x2008, 0x9002, 0x2001, + 0x9001, 0x2002, 0x2001, 0x9001, 0x2001, 0x9002, 0x2008, 0x2001, 0x9001, 0x2001, 0x2004, 0x9001, 0x2005, 0x9003, + 0x2009, 0x9001, 0x2002, 0x2001, 0x9005, 0x9002, 0x2004, 0x7001, 0x9001, 0x7001, 0x9001, 0x2001, 0x9003, 0x2004, + 0x2002, 0x9004, 0x2001, 0x9001, 0x200a, 0x2006, 0x9001, 0x2004, 0x2001, 0x2006, 0x9002, 0x2003, 0x7006, 0x200d, + 0x9001, 0x2002, 0x2001, 0x9001, 0x2003, 0x9001, 0x2001, 0x9001, 0x9001, 0x2007, 0x2006, 0x9001, 0x2001, 0x2016, + 0x9001, 0x2007, 0x9001, 0x2002, 0x9001, 0x2002, 0x2006, 0x2001, 0x2002, 0x2007, 0x7001, 0x2001, 0x9005, 0x2002, + 0x9002, 0x2001, 0x9001, 0x2001, 0x2002, 0x9002, 0x2002, 0x7001, 0x9001, 0x9002, 0x2005, 0x9002, 0x2003, 0x2001, + 0x1010, 0x2001, 0x200f, 0x200c, 0x9003, 0x2003, 0x2005, 0x2007, 0xb001, 0xb004, 0x2001, 0x9037, 0x2004, 0x2001, + 0x2002, 0x2002, 0x1004, 0x202e, 0x2017, 0x2005, 0x2006, 0x1008, 0x2008, 0x2007, 0x2004, 0x2003, 0x2037, 0x2032, + 0x2001, 0x2001, 0x2005, 0x200f, 0x2007, 0x2011, 0x2007, 0x2002, 0x2005, 0x2001, 0x2007, 0x2001, 0x2004, 0x2004, + 0x2002, 0x2001, 0x2001, 0x2002, 0x2001, 0x2007, 0x2007, 0x801a, 0x2005, 0x1020, 0x2060, 0x1080, 0x20f0, + 0x1e10}}; + +// DerivedCoreProperties-17.0.0.txt +// Date: 2025-07-30, 23:55:08 GMT +enum class _Indic_Conjunct_Break_property_values : uint8_t { + _Consonant_value, + _Extend_value, + _Linker_value, + _No_value = 255 +}; + +// DerivedCoreProperties-17.0.0.txt +// Date: 2025-07-30, 23:55:08 GMT +inline constexpr _Unicode_property_data<_Indic_Conjunct_Break_property_values, 473, false> + _Indic_Conjunct_Break_property_data{ + {0x300, 0x483, 0x591, 0x5bf, 0x5c1, 0x5c4, 0x5c7, 0x610, 0x64b, 0x670, 0x6d6, 0x6df, 0x6e7, 0x6ea, 0x711, 0x730, + 0x7a6, 0x7eb, 0x7fd, 0x816, 0x81b, 0x825, 0x829, 0x859, 0x897, 0x8ca, 0x8e3, 0x915, 0x93a, 0x93c, 0x941, + 0x94d, 0x951, 0x958, 0x962, 0x978, 0x981, 0x995, 0x9aa, 0x9b2, 0x9b6, 0x9bc, 0x9be, 0x9c1, 0x9cd, 0x9d7, + 0x9dc, 0x9df, 0x9e2, 0x9f0, 0x9fe, 0xa01, 0xa3c, 0xa41, 0xa47, 0xa4b, 0xa51, 0xa70, 0xa75, 0xa81, 0xa95, + 0xaaa, 0xab2, 0xab5, 0xabc, 0xac1, 0xac7, 0xacd, 0xae2, 0xaf9, 0xafa, 0xb01, 0xb15, 0xb2a, 0xb32, 0xb35, + 0xb3c, 0xb3e, 0xb41, 0xb4d, 0xb55, 0xb5c, 0xb5f, 0xb62, 0xb71, 0xb82, 0xbbe, 0xbc0, 0xbcd, 0xbd7, 0xc00, + 0xc04, 0xc15, 0xc2a, 0xc3c, 0xc3e, 0xc46, 0xc4a, 0xc4d, 0xc55, 0xc58, 0xc62, 0xc81, 0xcbc, 0xcbf, 0xcc2, + 0xcc6, 0xcca, 0xcd5, 0xce2, 0xd00, 0xd15, 0xd3b, 0xd3e, 0xd41, 0xd4d, 0xd57, 0xd62, 0xd81, 0xdca, 0xdcf, + 0xdd2, 0xdd6, 0xddf, 0xe31, 0xe34, 0xe47, 0xeb1, 0xeb4, 0xec8, 0xf18, 0xf35, 0xf37, 0xf39, 0xf71, 0xf80, + 0xf86, 0xf8d, 0xf99, 0xfc6, 0x1000, 0x102d, 0x1032, 0x1039, 0x103a, 0x103d, 0x103f, 0x1050, 0x1058, 0x105a, + 0x105e, 0x1061, 0x1065, 0x106e, 0x1071, 0x1075, 0x1082, 0x1085, 0x108d, 0x108e, 0x109d, 0x135d, 0x1712, + 0x1732, 0x1752, 0x1772, 0x1780, 0x17b4, 0x17b7, 0x17c6, 0x17c9, 0x17d2, 0x17d3, 0x17dd, 0x180b, 0x180f, + 0x1885, 0x18a9, 0x1920, 0x1927, 0x1932, 0x1939, 0x1a17, 0x1a1b, 0x1a20, 0x1a56, 0x1a58, 0x1a60, 0x1a62, + 0x1a65, 0x1a73, 0x1a7f, 0x1ab0, 0x1ae0, 0x1b00, 0x1b0b, 0x1b13, 0x1b34, 0x1b42, 0x1b44, 0x1b45, 0x1b6b, + 0x1b80, 0x1b83, 0x1ba2, 0x1ba8, 0x1bab, 0x1bac, 0x1bae, 0x1bbb, 0x1be6, 0x1be8, 0x1bed, 0x1bef, 0x1c2c, + 0x1c36, 0x1cd0, 0x1cd4, 0x1ce2, 0x1ced, 0x1cf4, 0x1cf8, 0x1dc0, 0x200d, 0x20d0, 0x2cef, 0x2d7f, 0x2de0, + 0x302a, 0x3099, 0xa66f, 0xa674, 0xa69e, 0xa6f0, 0xa802, 0xa806, 0xa80b, 0xa825, 0xa82c, 0xa8c4, 0xa8e0, + 0xa8ff, 0xa926, 0xa947, 0xa953, 0xa980, 0xa989, 0xa98f, 0xa9b3, 0xa9b6, 0xa9bc, 0xa9c0, 0xa9e0, 0xa9e5, + 0xa9e7, 0xa9fa, 0xaa29, 0xaa31, 0xaa35, 0xaa43, 0xaa4c, 0xaa60, 0xaa71, 0xaa7a, 0xaa7c, 0xaa7e, 0xaab0, + 0xaab2, 0xaab7, 0xaabe, 0xaac1, 0xaae0, 0xaaec, 0xaaf6, 0xabc0, 0xabe5, 0xabe8, 0xabed, 0xfb1e, 0xfe00, + 0xfe20, 0xff9e, 0x101fd, 0x102e0, 0x10376, 0x10a00, 0x10a01, 0x10a05, 0x10a0c, 0x10a10, 0x10a15, 0x10a19, + 0x10a38, 0x10a3f, 0x10ae5, 0x10d24, 0x10d69, 0x10eab, 0x10efa, 0x10f46, 0x10f82, 0x11001, 0x11038, 0x11070, + 0x11073, 0x1107f, 0x110b3, 0x110b9, 0x110c2, 0x11100, 0x11103, 0x11127, 0x1112d, 0x11133, 0x11134, 0x11144, + 0x11147, 0x11173, 0x11180, 0x111b6, 0x111c0, 0x111c9, 0x111cf, 0x1122f, 0x11234, 0x1123e, 0x11241, 0x112df, + 0x112e3, 0x11300, 0x1133b, 0x1133e, 0x11340, 0x1134d, 0x11357, 0x11366, 0x11370, 0x11380, 0x1138b, 0x1138e, + 0x11390, 0x113b8, 0x113bb, 0x113c2, 0x113c5, 0x113c7, 0x113ce, 0x113d0, 0x113d2, 0x113e1, 0x11438, 0x11442, + 0x11446, 0x1145e, 0x114b0, 0x114b3, 0x114ba, 0x114bd, 0x114bf, 0x114c2, 0x115af, 0x115b2, 0x115bc, 0x115bf, + 0x115dc, 0x11633, 0x1163d, 0x1163f, 0x116ab, 0x116ad, 0x116b0, 0x1171d, 0x1171f, 0x11722, 0x11727, 0x1182f, + 0x11839, 0x11900, 0x11909, 0x1190c, 0x11915, 0x11918, 0x11930, 0x1193b, 0x1193e, 0x11943, 0x119d4, 0x119da, + 0x119e0, 0x11a00, 0x11a01, 0x11a0b, 0x11a33, 0x11a3b, 0x11a47, 0x11a50, 0x11a51, 0x11a59, 0x11a5c, 0x11a8a, + 0x11a98, 0x11a99, 0x11b60, 0x11b62, 0x11b66, 0x11c30, 0x11c38, 0x11c3f, 0x11c92, 0x11caa, 0x11cb2, 0x11cb5, + 0x11d31, 0x11d3a, 0x11d3c, 0x11d3f, 0x11d47, 0x11d90, 0x11d95, 0x11d97, 0x11ef3, 0x11f00, 0x11f04, 0x11f12, + 0x11f36, 0x11f40, 0x11f42, 0x11f5a, 0x13440, 0x13447, 0x1611e, 0x1612d, 0x16af0, 0x16b30, 0x16f4f, 0x16f8f, + 0x16fe4, 0x16ff0, 0x1bc9d, 0x1cf00, 0x1cf30, 0x1d165, 0x1d16d, 0x1d17b, 0x1d185, 0x1d1aa, 0x1d242, 0x1da00, + 0x1da3b, 0x1da75, 0x1da84, 0x1da9b, 0x1daa1, 0x1e000, 0x1e008, 0x1e01b, 0x1e023, 0x1e026, 0x1e08f, 0x1e130, + 0x1e2ae, 0x1e2ec, 0x1e4ec, 0x1e5ee, 0x1e6e3, 0x1e6e6, 0x1e6ee, 0x1e6f5, 0x1e8d0, 0x1e944, 0x1f3fb, 0xe0020, + 0xe0100}, + {0x1070, 0x1007, 0x102d, 0x1001, 0x1002, 0x1002, 0x1001, 0x100b, 0x1015, 0x1001, 0x1007, 0x1006, 0x1002, 0x1004, + 0x1001, 0x101b, 0x100b, 0x1009, 0x1001, 0x1004, 0x1009, 0x1003, 0x1005, 0x1003, 0x1009, 0x1018, 0x1020, + 0x25, 0x1001, 0x1001, 0x1008, 0x2001, 0x1007, 0x8, 0x1002, 0x8, 0x1001, 0x14, 0x7, 0x1, 0x4, 0x1001, 0x1001, + 0x1004, 0x2001, 0x1001, 0x2, 0x1, 0x1002, 0x2, 0x1001, 0x1002, 0x1001, 0x1002, 0x1002, 0x1003, 0x1001, + 0x1002, 0x1001, 0x1002, 0x14, 0x7, 0x2, 0x5, 0x1001, 0x1005, 0x1002, 0x2001, 0x1002, 0x1, 0x1006, 0x1001, + 0x14, 0x7, 0x2, 0x5, 0x1001, 0x1002, 0x1004, 0x2001, 0x1003, 0x2, 0x1, 0x1002, 0x1, 0x1001, 0x1001, 0x1001, + 0x1001, 0x1001, 0x1001, 0x1001, 0x14, 0x10, 0x1001, 0x1003, 0x1003, 0x1003, 0x2001, 0x1002, 0x3, 0x1002, + 0x1001, 0x1001, 0x1002, 0x1001, 0x1003, 0x1004, 0x1002, 0x1002, 0x1002, 0x26, 0x1002, 0x1001, 0x1004, + 0x2001, 0x1001, 0x1002, 0x1001, 0x1001, 0x1001, 0x1003, 0x1001, 0x1001, 0x1001, 0x1007, 0x1008, 0x1001, + 0x1009, 0x1007, 0x1002, 0x1001, 0x1001, 0x1001, 0x100e, 0x1005, 0x1002, 0x100b, 0x1024, 0x1001, 0x2b, + 0x1004, 0x1006, 0x2001, 0x1001, 0x1002, 0x1, 0x6, 0x1002, 0x4, 0x1003, 0x1, 0x2, 0x3, 0x1004, 0xd, 0x1001, + 0x1002, 0x1001, 0x1, 0x1001, 0x1003, 0x1004, 0x1003, 0x1002, 0x1002, 0x34, 0x1002, 0x1007, 0x1001, 0x1009, + 0x2001, 0x1001, 0x1001, 0x1003, 0x1001, 0x1002, 0x1001, 0x1003, 0x1002, 0x1001, 0x1003, 0x1002, 0x1001, + 0x35, 0x1001, 0x1007, 0x2001, 0x1001, 0x1008, 0x100a, 0x1001, 0x102e, 0x100c, 0x1004, 0x2, 0x21, 0x100a, + 0x1002, 0x2001, 0x8, 0x1009, 0x1002, 0x1e, 0x1004, 0x1003, 0x2001, 0x1002, 0x2, 0x3, 0x1001, 0x1002, 0x1001, + 0x1005, 0x1008, 0x1002, 0x1003, 0x100d, 0x1007, 0x1001, 0x1001, 0x1002, 0x1040, 0x1001, 0x1021, 0x1003, + 0x1001, 0x1020, 0x1006, 0x1002, 0x1004, 0x100a, 0x1002, 0x1002, 0x1001, 0x1001, 0x1001, 0x1002, 0x1001, + 0x1002, 0x1012, 0x1001, 0x1008, 0x100b, 0x1001, 0x1003, 0x3, 0x24, 0x1001, 0x1004, 0x1002, 0x2001, 0x5, + 0x1001, 0x9, 0x5, 0x1006, 0x1002, 0x1002, 0x1001, 0x1001, 0x10, 0x3, 0x1, 0x1001, 0x2, 0x1001, 0x1003, + 0x1002, 0x1002, 0x1001, 0xb, 0x1002, 0x2001, 0x1b, 0x1001, 0x1001, 0x1001, 0x1001, 0x1010, 0x1010, 0x1002, + 0x1001, 0x1001, 0x1005, 0x1, 0x1003, 0x1002, 0x1004, 0x4, 0x3, 0x1d, 0x1003, 0x2001, 0x1002, 0x1004, 0x1005, + 0x1002, 0x1006, 0x100b, 0x1004, 0x1001, 0x100f, 0x1001, 0x1002, 0x1003, 0x1004, 0x1002, 0x1001, 0x1003, + 0x24, 0x1005, 0x1006, 0x2001, 0x1001, 0x1, 0x1, 0x1001, 0x1002, 0x1009, 0x1001, 0x1004, 0x1001, 0x1003, + 0x1004, 0x1001, 0x1001, 0x1001, 0x1008, 0x1002, 0x1002, 0x1001, 0x1001, 0x1001, 0x1001, 0x1007, 0x1005, 0xa, + 0x1, 0x1, 0x26, 0x1001, 0x1006, 0x1001, 0x1001, 0x1003, 0x1002, 0x2001, 0x1001, 0x1002, 0x1008, 0x1003, + 0x1001, 0x1001, 0x1001, 0x1006, 0x1001, 0x1001, 0x1002, 0x1002, 0x1001, 0x1004, 0x1002, 0x1002, 0x1002, + 0x1008, 0x1001, 0x1002, 0x1001, 0x1001, 0x1008, 0x1001, 0x1001, 0x1004, 0x1005, 0x1009, 0x1002, 0x7, 0x1, + 0x8, 0x2, 0x18, 0x1001, 0x1003, 0x2001, 0x1001, 0x1004, 0x1002, 0x1001, 0x1, 0x100a, 0x28, 0x1006, 0x1004, + 0x2001, 0x1, 0x1006, 0x1003, 0x28, 0x100d, 0x1001, 0x2001, 0x1001, 0x1003, 0x1001, 0x1007, 0x1006, 0x1001, + 0x1016, 0x1007, 0x1002, 0x1002, 0x1006, 0x1001, 0x1002, 0x1007, 0x1001, 0x1002, 0x1001, 0x1001, 0x1002, + 0x1002, 0xd, 0x22, 0x1005, 0x1002, 0x2001, 0x1001, 0x1001, 0x100f, 0x100c, 0x1003, 0x1005, 0x1007, 0x1001, + 0x1004, 0x1001, 0x1002, 0x1002, 0x102e, 0x1017, 0x1005, 0x1006, 0x1008, 0x1007, 0x1004, 0x1003, 0x1037, + 0x1032, 0x1001, 0x1001, 0x1005, 0x100f, 0x1007, 0x1011, 0x1007, 0x1002, 0x1005, 0x1001, 0x1007, 0x1001, + 0x1004, 0x1004, 0x1002, 0x1001, 0x1001, 0x1002, 0x1001, 0x1007, 0x1007, 0x1005, 0x1060, 0x10f0}}; + +// emoji-data.txt +// Date: 2025-07-25, 17:54:31 GMT +enum class _Extended_Pictographic_property_values : uint8_t { _Extended_Pictographic_value, _No_value = 255 }; + +// emoji-data.txt +// Date: 2025-07-25, 17:54:31 GMT +inline constexpr _Unicode_property_data<_Extended_Pictographic_property_values, 156, true> + _Extended_Pictographic_property_data{ + {0xa9, 0xae, 0x203c, 0x2049, 0x2122, 0x2139, 0x2194, 0x21a9, 0x231a, 0x2328, 0x23cf, 0x23e9, 0x23f8, 0x24c2, + 0x25aa, 0x25b6, 0x25c0, 0x25fb, 0x2600, 0x260e, 0x2611, 0x2614, 0x2618, 0x261d, 0x2620, 0x2622, 0x2626, + 0x262a, 0x262e, 0x2638, 0x2640, 0x2642, 0x2648, 0x265f, 0x2663, 0x2665, 0x2668, 0x267b, 0x267e, 0x2692, + 0x2699, 0x269b, 0x26a0, 0x26a7, 0x26aa, 0x26b0, 0x26bd, 0x26c4, 0x26c8, 0x26ce, 0x26d1, 0x26d3, 0x26e9, + 0x26f0, 0x26f7, 0x26fd, 0x2702, 0x2705, 0x2708, 0x270f, 0x2712, 0x2714, 0x2716, 0x271d, 0x2721, 0x2728, + 0x2733, 0x2744, 0x2747, 0x274c, 0x274e, 0x2753, 0x2757, 0x2763, 0x2795, 0x27a1, 0x27b0, 0x27bf, 0x2934, + 0x2b05, 0x2b1b, 0x2b50, 0x2b55, 0x3030, 0x303d, 0x3297, 0x3299, 0x1f004, 0x1f02c, 0x1f094, 0x1f0af, 0x1f0c0, + 0x1f0cf, 0x1f0f6, 0x1f170, 0x1f17e, 0x1f18e, 0x1f191, 0x1f1ae, 0x1f201, 0x1f21a, 0x1f22f, 0x1f232, 0x1f23c, + 0x1f249, 0x1f266, 0x1f324, 0x1f396, 0x1f399, 0x1f39e, 0x1f3f3, 0x1f3f7, 0x1f400, 0x1f4ff, 0x1f549, 0x1f550, + 0x1f56f, 0x1f573, 0x1f587, 0x1f58a, 0x1f590, 0x1f595, 0x1f5a4, 0x1f5a8, 0x1f5b1, 0x1f5bc, 0x1f5c2, 0x1f5d1, + 0x1f5dc, 0x1f5e1, 0x1f5e3, 0x1f5e8, 0x1f5ef, 0x1f5f3, 0x1f5fa, 0x1f680, 0x1f6cb, 0x1f6d5, 0x1f6e9, 0x1f6eb, + 0x1f6f3, 0x1f7da, 0x1f80c, 0x1f848, 0x1f85a, 0x1f888, 0x1f8ae, 0x1f8bc, 0x1f8c2, 0x1f8d9, 0x1f90c, 0x1f93c, + 0x1f947, 0x1fa58, 0x1fa6e, 0x1fc00}, + {0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x6, 0x2, 0x2, 0x1, 0x1, 0xb, 0x3, 0x1, 0x2, 0x1, 0x1, 0x4, 0x5, 0x1, 0x1, 0x2, + 0x1, 0x1, 0x1, 0x2, 0x1, 0x1, 0x2, 0x3, 0x1, 0x1, 0xc, 0x2, 0x1, 0x2, 0x1, 0x1, 0x2, 0x6, 0x1, 0x2, 0x2, + 0x1, 0x2, 0x2, 0x2, 0x2, 0x1, 0x2, 0x1, 0x2, 0x2, 0x6, 0x4, 0x1, 0x1, 0x1, 0x6, 0x1, 0x1, 0x1, 0x1, 0x1, + 0x1, 0x1, 0x2, 0x1, 0x1, 0x1, 0x1, 0x3, 0x1, 0x2, 0x3, 0x1, 0x1, 0x1, 0x2, 0x3, 0x2, 0x1, 0x1, 0x1, 0x1, + 0x1, 0x1, 0x1, 0x4, 0xc, 0x2, 0x1, 0x2, 0xa, 0x2, 0x2, 0x1, 0xa, 0x38, 0xf, 0x1, 0x1, 0x9, 0x4, 0x17, 0xbc, + 0x70, 0x2, 0x3, 0x53, 0x3, 0x4, 0xfe, 0x3f, 0x6, 0x18, 0x2, 0x8, 0x1, 0x4, 0x1, 0x2, 0x2, 0x1, 0x2, 0x1, + 0x3, 0x3, 0x3, 0x1, 0x1, 0x1, 0x1, 0x1, 0x56, 0x46, 0x8, 0x11, 0x1, 0x6, 0xd, 0x26, 0x4, 0x8, 0x6, 0x8, 0x2, + 0x4, 0xe, 0x27, 0x2f, 0xa, 0xb9, 0x8, 0x92, 0x3fe}}; + +// DerivedGeneralCategory-17.0.0.txt +// Date: 2025-07-24, 00:12:50 GMT +enum class __printable_property_values : uint8_t { _Yes_value, _No_value = 255 }; + +// DerivedGeneralCategory-17.0.0.txt +// Date: 2025-07-24, 00:12:50 GMT +inline constexpr _Unicode_property_data<__printable_property_values, 741, true> __printable_property_data{ + {0x20, 0xa1, 0xae, 0x37a, 0x384, 0x38c, 0x38e, 0x3a3, 0x531, 0x559, 0x58d, 0x591, 0x5d0, 0x5ef, 0x606, 0x61d, 0x6de, + 0x710, 0x74d, 0x7c0, 0x7fd, 0x830, 0x840, 0x85e, 0x860, 0x870, 0x897, 0x8e3, 0x985, 0x98f, 0x993, 0x9aa, 0x9b2, + 0x9b6, 0x9bc, 0x9c7, 0x9cb, 0x9d7, 0x9dc, 0x9df, 0x9e6, 0xa01, 0xa05, 0xa0f, 0xa13, 0xa2a, 0xa32, 0xa35, 0xa38, + 0xa3c, 0xa3e, 0xa47, 0xa4b, 0xa51, 0xa59, 0xa5e, 0xa66, 0xa81, 0xa85, 0xa8f, 0xa93, 0xaaa, 0xab2, 0xab5, 0xabc, + 0xac7, 0xacb, 0xad0, 0xae0, 0xae6, 0xaf9, 0xb01, 0xb05, 0xb0f, 0xb13, 0xb2a, 0xb32, 0xb35, 0xb3c, 0xb47, 0xb4b, + 0xb55, 0xb5c, 0xb5f, 0xb66, 0xb82, 0xb85, 0xb8e, 0xb92, 0xb99, 0xb9c, 0xb9e, 0xba3, 0xba8, 0xbae, 0xbbe, 0xbc6, + 0xbca, 0xbd0, 0xbd7, 0xbe6, 0xc00, 0xc0e, 0xc12, 0xc2a, 0xc3c, 0xc46, 0xc4a, 0xc55, 0xc58, 0xc5c, 0xc60, 0xc66, + 0xc77, 0xc8e, 0xc92, 0xcaa, 0xcb5, 0xcbc, 0xcc6, 0xcca, 0xcd5, 0xcdc, 0xce0, 0xce6, 0xcf1, 0xd00, 0xd0e, 0xd12, + 0xd46, 0xd4a, 0xd54, 0xd66, 0xd81, 0xd85, 0xd9a, 0xdb3, 0xdbd, 0xdc0, 0xdca, 0xdcf, 0xdd6, 0xdd8, 0xde6, 0xdf2, + 0xe01, 0xe3f, 0xe81, 0xe84, 0xe86, 0xe8c, 0xea5, 0xea7, 0xec0, 0xec6, 0xec8, 0xed0, 0xedc, 0xf00, 0xf49, 0xf71, + 0xf99, 0xfbe, 0xfce, 0x1000, 0x10c7, 0x10cd, 0x10d0, 0x124a, 0x1250, 0x1258, 0x125a, 0x1260, 0x128a, 0x1290, + 0x12b2, 0x12b8, 0x12c0, 0x12c2, 0x12c8, 0x12d8, 0x1312, 0x1318, 0x135d, 0x1380, 0x13a0, 0x13f8, 0x1400, 0x1681, + 0x16a0, 0x1700, 0x171f, 0x1740, 0x1760, 0x176e, 0x1772, 0x1780, 0x17e0, 0x17f0, 0x1800, 0x180f, 0x1820, 0x1880, + 0x18b0, 0x1900, 0x1920, 0x1930, 0x1940, 0x1944, 0x1970, 0x1980, 0x19b0, 0x19d0, 0x19de, 0x1a1e, 0x1a60, 0x1a7f, + 0x1a90, 0x1aa0, 0x1ab0, 0x1ae0, 0x1b00, 0x1b4e, 0x1bfc, 0x1c3b, 0x1c4d, 0x1c90, 0x1cbd, 0x1cd0, 0x1d00, 0x1f18, + 0x1f20, 0x1f48, 0x1f50, 0x1f59, 0x1f5b, 0x1f5d, 0x1f5f, 0x1f80, 0x1fb6, 0x1fc6, 0x1fd6, 0x1fdd, 0x1ff2, 0x1ff6, + 0x2010, 0x2030, 0x2070, 0x2074, 0x2090, 0x20a0, 0x20d0, 0x2100, 0x2190, 0x2440, 0x2460, 0x2b76, 0x2cf9, 0x2d27, + 0x2d2d, 0x2d30, 0x2d6f, 0x2d7f, 0x2da0, 0x2da8, 0x2db0, 0x2db8, 0x2dc0, 0x2dc8, 0x2dd0, 0x2dd8, 0x2de0, 0x2e80, + 0x2e9b, 0x2f00, 0x2ff0, 0x3001, 0x3041, 0x3099, 0x3105, 0x3131, 0x3190, 0x31ef, 0x3220, 0xa490, 0xa4d0, 0xa640, + 0xa700, 0xa7f1, 0xa830, 0xa840, 0xa880, 0xa8ce, 0xa8e0, 0xa95f, 0xa980, 0xa9cf, 0xa9de, 0xaa00, 0xaa40, 0xaa50, + 0xaa5c, 0xaadb, 0xab01, 0xab09, 0xab11, 0xab20, 0xab28, 0xab30, 0xab70, 0xabf0, 0xac00, 0xd7b0, 0xd7cb, 0xf900, + 0xfa70, 0xfb00, 0xfb13, 0xfb1d, 0xfb38, 0xfb3e, 0xfb40, 0xfb43, 0xfb46, 0xfdf0, 0xfe20, 0xfe54, 0xfe68, 0xfe70, + 0xfe76, 0xff01, 0xffc2, 0xffca, 0xffd2, 0xffda, 0xffe0, 0xffe8, 0xfffc, 0x10000, 0x1000d, 0x10028, 0x1003c, + 0x1003f, 0x10050, 0x10080, 0x10100, 0x10107, 0x10137, 0x10190, 0x101a0, 0x101d0, 0x10280, 0x102a0, 0x102e0, + 0x10300, 0x1032d, 0x10350, 0x10380, 0x1039f, 0x103c8, 0x10400, 0x104a0, 0x104b0, 0x104d8, 0x10500, 0x10530, + 0x1056f, 0x1057c, 0x1058c, 0x10594, 0x10597, 0x105a3, 0x105b3, 0x105bb, 0x105c0, 0x10600, 0x10740, 0x10760, + 0x10780, 0x10787, 0x107b2, 0x10800, 0x10808, 0x1080a, 0x10837, 0x1083c, 0x1083f, 0x10857, 0x108a7, 0x108e0, + 0x108f4, 0x108fb, 0x1091f, 0x1093f, 0x10980, 0x109bc, 0x109d2, 0x10a05, 0x10a0c, 0x10a15, 0x10a19, 0x10a38, + 0x10a3f, 0x10a50, 0x10a60, 0x10ac0, 0x10aeb, 0x10b00, 0x10b39, 0x10b58, 0x10b78, 0x10b99, 0x10ba9, 0x10c00, + 0x10c80, 0x10cc0, 0x10cfa, 0x10d30, 0x10d40, 0x10d69, 0x10d8e, 0x10e60, 0x10e80, 0x10eab, 0x10eb0, 0x10ec2, + 0x10ed0, 0x10efa, 0x10f30, 0x10f70, 0x10fb0, 0x10fe0, 0x11000, 0x11052, 0x1107f, 0x110be, 0x110d0, 0x110f0, + 0x11100, 0x11136, 0x11150, 0x11180, 0x111e1, 0x11200, 0x11213, 0x11280, 0x11288, 0x1128a, 0x1128f, 0x1129f, + 0x112b0, 0x112f0, 0x11300, 0x11305, 0x1130f, 0x11313, 0x1132a, 0x11332, 0x11335, 0x1133b, 0x11347, 0x1134b, + 0x11350, 0x11357, 0x1135d, 0x11366, 0x11370, 0x11380, 0x1138b, 0x1138e, 0x11390, 0x113b7, 0x113c2, 0x113c5, + 0x113c7, 0x113cc, 0x113d7, 0x113e1, 0x11400, 0x1145d, 0x11480, 0x114d0, 0x11580, 0x115b8, 0x11600, 0x11650, + 0x11660, 0x11680, 0x116c0, 0x116d0, 0x11700, 0x1171d, 0x11730, 0x11800, 0x118a0, 0x118ff, 0x11909, 0x1190c, + 0x11915, 0x11918, 0x11937, 0x1193b, 0x11950, 0x119a0, 0x119aa, 0x119da, 0x11a00, 0x11a50, 0x11ab0, 0x11b00, + 0x11b60, 0x11bc0, 0x11bf0, 0x11c00, 0x11c0a, 0x11c38, 0x11c50, 0x11c70, 0x11c92, 0x11ca9, 0x11d00, 0x11d08, + 0x11d0b, 0x11d3a, 0x11d3c, 0x11d3f, 0x11d50, 0x11d60, 0x11d67, 0x11d6a, 0x11d90, 0x11d93, 0x11da0, 0x11db0, + 0x11de0, 0x11ee0, 0x11f00, 0x11f12, 0x11f3e, 0x11fb0, 0x11fc0, 0x11fff, 0x12400, 0x12470, 0x12480, 0x12f90, + 0x13000, 0x13440, 0x13460, 0x14400, 0x16100, 0x16800, 0x16a40, 0x16a60, 0x16a6e, 0x16ac0, 0x16ad0, 0x16af0, + 0x16b00, 0x16b50, 0x16b5b, 0x16b63, 0x16b7d, 0x16d40, 0x16e40, 0x16ea0, 0x16ebb, 0x16f00, 0x16f4f, 0x16f8f, + 0x16fe0, 0x16ff0, 0x17000, 0x18cff, 0x18d80, 0x1aff0, 0x1aff5, 0x1affd, 0x1b000, 0x1b132, 0x1b150, 0x1b155, + 0x1b164, 0x1b170, 0x1bc00, 0x1bc70, 0x1bc80, 0x1bc90, 0x1bc9c, 0x1cc00, 0x1cd00, 0x1ceba, 0x1cee0, 0x1cf00, + 0x1cf30, 0x1cf50, 0x1d000, 0x1d100, 0x1d129, 0x1d17b, 0x1d200, 0x1d2c0, 0x1d2e0, 0x1d300, 0x1d360, 0x1d400, + 0x1d456, 0x1d49e, 0x1d4a2, 0x1d4a5, 0x1d4a9, 0x1d4ae, 0x1d4bb, 0x1d4bd, 0x1d4c5, 0x1d507, 0x1d50d, 0x1d516, + 0x1d51e, 0x1d53b, 0x1d540, 0x1d546, 0x1d54a, 0x1d552, 0x1d6a8, 0x1d7ce, 0x1da9b, 0x1daa1, 0x1df00, 0x1df25, + 0x1e000, 0x1e008, 0x1e01b, 0x1e023, 0x1e026, 0x1e030, 0x1e08f, 0x1e100, 0x1e130, 0x1e140, 0x1e14e, 0x1e290, + 0x1e2c0, 0x1e2ff, 0x1e4d0, 0x1e5d0, 0x1e5ff, 0x1e6c0, 0x1e6e0, 0x1e6fe, 0x1e7e0, 0x1e7e8, 0x1e7ed, 0x1e7f0, + 0x1e800, 0x1e8c7, 0x1e900, 0x1e950, 0x1e95e, 0x1ec71, 0x1ed01, 0x1ee00, 0x1ee05, 0x1ee21, 0x1ee24, 0x1ee27, + 0x1ee29, 0x1ee34, 0x1ee39, 0x1ee3b, 0x1ee42, 0x1ee47, 0x1ee49, 0x1ee4b, 0x1ee4d, 0x1ee51, 0x1ee54, 0x1ee57, + 0x1ee59, 0x1ee5b, 0x1ee5d, 0x1ee5f, 0x1ee61, 0x1ee64, 0x1ee67, 0x1ee6c, 0x1ee74, 0x1ee79, 0x1ee7e, 0x1ee80, + 0x1ee8b, 0x1eea1, 0x1eea5, 0x1eeab, 0x1eef0, 0x1f000, 0x1f030, 0x1f0a0, 0x1f0b1, 0x1f0c1, 0x1f0d1, 0x1f100, + 0x1f1e6, 0x1f210, 0x1f240, 0x1f250, 0x1f260, 0x1f300, 0x1f6dc, 0x1f6f0, 0x1f700, 0x1f7e0, 0x1f7f0, 0x1f800, + 0x1f810, 0x1f850, 0x1f860, 0x1f890, 0x1f8b0, 0x1f8c0, 0x1f8d0, 0x1f900, 0x1fa60, 0x1fa70, 0x1fa80, 0x1fa8e, + 0x1fac8, 0x1facd, 0x1fadf, 0x1faef, 0x1fb00, 0x1fb94, 0x20000, 0x2a700, 0x2b820, 0x2ceb0, 0x2ebf0, 0x2f800, + 0x30000, 0x31350, 0xe0100}, + {0x5f, 0xc, 0x2ca, 0x6, 0x7, 0x1, 0x14, 0x18d, 0x26, 0x32, 0x3, 0x37, 0x1b, 0x6, 0x16, 0xc0, 0x30, 0x3b, 0x65, 0x3b, + 0x31, 0xf, 0x1c, 0x1, 0xb, 0x20, 0x4b, 0xa1, 0x8, 0x2, 0x16, 0x7, 0x1, 0x4, 0x9, 0x2, 0x4, 0x1, 0x2, 0x5, 0x19, + 0x3, 0x6, 0x2, 0x16, 0x7, 0x2, 0x2, 0x2, 0x1, 0x5, 0x2, 0x3, 0x1, 0x4, 0x1, 0x11, 0x3, 0x9, 0x3, 0x16, 0x7, 0x2, + 0x5, 0xa, 0x3, 0x3, 0x1, 0x4, 0xc, 0x7, 0x3, 0x8, 0x2, 0x16, 0x7, 0x2, 0x5, 0x9, 0x2, 0x3, 0x3, 0x2, 0x5, 0x12, + 0x2, 0x6, 0x3, 0x4, 0x2, 0x1, 0x2, 0x2, 0x3, 0xc, 0x5, 0x3, 0x4, 0x1, 0x1, 0x15, 0xd, 0x3, 0x17, 0x10, 0x9, 0x3, + 0x4, 0x2, 0x3, 0x2, 0x4, 0xa, 0x16, 0x3, 0x17, 0xa, 0x5, 0x9, 0x3, 0x4, 0x2, 0x3, 0x4, 0xa, 0x3, 0xd, 0x3, 0x33, + 0x3, 0x6, 0x10, 0x1a, 0x3, 0x12, 0x18, 0x9, 0x1, 0x7, 0x1, 0x6, 0x1, 0x8, 0xa, 0x3, 0x3a, 0x1d, 0x2, 0x1, 0x5, + 0x18, 0x1, 0x17, 0x5, 0x1, 0x7, 0xa, 0x4, 0x48, 0x24, 0x27, 0x24, 0xf, 0xd, 0xc6, 0x1, 0x1, 0x179, 0x4, 0x7, + 0x1, 0x4, 0x29, 0x4, 0x21, 0x4, 0x7, 0x1, 0x4, 0xf, 0x39, 0x4, 0x43, 0x20, 0x1a, 0x56, 0x6, 0x280, 0x1c, 0x59, + 0x16, 0x18, 0x14, 0xd, 0x3, 0x2, 0x5e, 0xa, 0xa, 0xe, 0xb, 0x59, 0x2b, 0x46, 0x1f, 0xc, 0xc, 0x1, 0x2a, 0x5, + 0x2c, 0x1a, 0xb, 0x3e, 0x41, 0x1d, 0xb, 0xa, 0xe, 0x2e, 0xc, 0x4d, 0xa6, 0x3c, 0xf, 0x3e, 0x2b, 0xb, 0x2b, + 0x216, 0x6, 0x26, 0x6, 0x8, 0x1, 0x1, 0x1, 0x1f, 0x35, 0xf, 0xe, 0x6, 0x13, 0x3, 0x9, 0x18, 0x2f, 0x2, 0x1b, + 0xd, 0x22, 0x21, 0x8c, 0x29a, 0xb, 0x714, 0x17e, 0x2d, 0x1, 0x1, 0x38, 0x2, 0x18, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, + 0x7, 0x7, 0x7e, 0x1a, 0x59, 0xd6, 0x10, 0x3f, 0x56, 0x67, 0x2b, 0x5e, 0x56, 0x30, 0x726d, 0x37, 0x15c, 0xb8, + 0xdd, 0x3c, 0xa, 0x38, 0x46, 0xc, 0x74, 0x1e, 0x4e, 0xb, 0x21, 0x37, 0xe, 0xa, 0x67, 0x1c, 0x6, 0x6, 0x6, 0x7, + 0x7, 0x3c, 0x7e, 0xa, 0x2ba4, 0x17, 0x31, 0x16e, 0x6a, 0x7, 0x5, 0x1a, 0x5, 0x1, 0x2, 0x2, 0x28a, 0x2a, 0x33, + 0x13, 0x4, 0x5, 0x87, 0xbe, 0x6, 0x6, 0x6, 0x3, 0x7, 0x7, 0x2, 0xc, 0x1a, 0x13, 0x2, 0xf, 0xe, 0x7b, 0x3, 0x2d, + 0x58, 0xd, 0x1, 0x2e, 0x1d, 0x31, 0x1c, 0x24, 0x1e, 0x2b, 0x1e, 0x25, 0xe, 0x9e, 0xa, 0x24, 0x24, 0x28, 0x34, + 0xc, 0xf, 0x7, 0x2, 0xb, 0xf, 0x7, 0x2, 0x34, 0x137, 0x16, 0x8, 0x6, 0x2a, 0x9, 0x6, 0x1, 0x2c, 0x2, 0x1, 0x17, + 0x48, 0x9, 0x13, 0x2, 0x21, 0x1b, 0x1b, 0x38, 0x14, 0x32, 0x2, 0x8, 0x3, 0x1d, 0x3, 0xa, 0x9, 0x40, 0x27, 0xc, + 0x36, 0x1d, 0x1b, 0x1a, 0x4, 0x7, 0x49, 0x33, 0x33, 0x2e, 0xa, 0x26, 0x1d, 0x2, 0x1f, 0x2a, 0x3, 0x2, 0x6, 0x9, + 0x2e, 0x2a, 0x1a, 0x1c, 0x17, 0x4e, 0x24, 0x3e, 0x5, 0x19, 0xa, 0x35, 0x12, 0x27, 0x60, 0x14, 0x12, 0x2f, 0x7, + 0x1, 0x4, 0xf, 0xb, 0x3b, 0xa, 0x4, 0x8, 0x2, 0x16, 0x7, 0x2, 0x5, 0xa, 0x2, 0x3, 0x1, 0x1, 0x7, 0x7, 0x5, 0xa, + 0x1, 0x1, 0x26, 0xa, 0x1, 0x1, 0x4, 0xa, 0x2, 0x2, 0x5c, 0x5, 0x48, 0xa, 0x36, 0x26, 0x45, 0xa, 0xd, 0x3a, 0xa, + 0x14, 0x1b, 0xf, 0x17, 0x3c, 0x53, 0x8, 0x1, 0x8, 0x2, 0x1e, 0x2, 0xc, 0xa, 0x8, 0x2e, 0xb, 0x48, 0x53, 0x49, + 0xa, 0x8, 0x22, 0xa, 0x9, 0x2d, 0xe, 0x1d, 0x20, 0x16, 0xe, 0x7, 0x2, 0x2c, 0x1, 0x2, 0x9, 0xa, 0x6, 0x2, 0x25, + 0x2, 0x6, 0xa, 0x2c, 0xa, 0x19, 0x11, 0x29, 0x1d, 0x1, 0x32, 0x39b, 0x6f, 0x5, 0xc4, 0x63, 0x430, 0x16, 0xf9b, + 0x247, 0x3a, 0x239, 0x1f, 0xa, 0x51, 0xa, 0x1e, 0x6, 0x46, 0xa, 0x7, 0x15, 0x13, 0x3a, 0x5b, 0x19, 0x19, 0x4b, + 0x39, 0x11, 0x5, 0x7, 0x1cd6, 0x20, 0x73, 0x4, 0x7, 0x2, 0x123, 0x1, 0x3, 0x1, 0x4, 0x18c, 0x6b, 0xd, 0x9, 0xa, + 0x4, 0xfd, 0x1b4, 0x17, 0x11, 0x2e, 0x17, 0x74, 0xf6, 0x27, 0x4a, 0x70, 0x46, 0x14, 0x14, 0x57, 0x19, 0x55, + 0x47, 0x2, 0x1, 0x2, 0x4, 0xc, 0x1, 0x7, 0x41, 0x4, 0x8, 0x7, 0x1c, 0x4, 0x5, 0x1, 0x7, 0x154, 0x124, 0x2be, + 0x5, 0xf, 0x1f, 0x6, 0x7, 0x11, 0x7, 0x2, 0x5, 0x3e, 0x1, 0x2d, 0xe, 0xa, 0x2, 0x1f, 0x3a, 0x1, 0x2a, 0x2b, 0x1, + 0x1f, 0x16, 0x2, 0x7, 0x4, 0x2, 0xf, 0xc5, 0x10, 0x4c, 0xa, 0x2, 0x44, 0x3d, 0x4, 0x1b, 0x2, 0x1, 0x1, 0xa, 0x4, + 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x3, 0x2, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x2, 0x1, 0x4, 0x7, 0x4, 0x4, 0x1, 0xa, + 0x11, 0x3, 0x5, 0x11, 0x2, 0x2c, 0x64, 0xf, 0xf, 0xf, 0x25, 0xae, 0x1d, 0x2c, 0x9, 0x2, 0x6, 0x3d9, 0x11, 0xd, + 0xda, 0xc, 0x1, 0xc, 0x38, 0xa, 0x28, 0x1e, 0xc, 0x2, 0x9, 0x158, 0xe, 0xd, 0xb, 0x39, 0x1, 0x10, 0xc, 0xa, + 0x93, 0x67, 0xa6e0, 0x111e, 0x168e, 0x1d31, 0x26e, 0x21e, 0x134b, 0x212a, 0xf0}}; + +// DerivedCoreProperties-17.0.0.txt +// Date: 2025-07-30, 23:55:08 GMT +enum class _Grapheme_Extend_property_values : uint8_t { _Grapheme_Extend_value, _No_value = 255 }; + +// DerivedCoreProperties-17.0.0.txt +// Date: 2025-07-30, 23:55:08 GMT +inline constexpr _Unicode_property_data<_Grapheme_Extend_property_values, 383, true> _Grapheme_Extend_property_data{ + {0x300, 0x483, 0x591, 0x5bf, 0x5c1, 0x5c4, 0x5c7, 0x610, 0x64b, 0x670, 0x6d6, 0x6df, 0x6e7, 0x6ea, 0x711, 0x730, + 0x7a6, 0x7eb, 0x7fd, 0x816, 0x81b, 0x825, 0x829, 0x859, 0x897, 0x8ca, 0x8e3, 0x93a, 0x93c, 0x941, 0x94d, 0x951, + 0x962, 0x981, 0x9bc, 0x9be, 0x9c1, 0x9cd, 0x9d7, 0x9e2, 0x9fe, 0xa01, 0xa3c, 0xa41, 0xa47, 0xa4b, 0xa51, 0xa70, + 0xa75, 0xa81, 0xabc, 0xac1, 0xac7, 0xacd, 0xae2, 0xafa, 0xb01, 0xb3c, 0xb3e, 0xb41, 0xb4d, 0xb55, 0xb62, 0xb82, + 0xbbe, 0xbc0, 0xbcd, 0xbd7, 0xc00, 0xc04, 0xc3c, 0xc3e, 0xc46, 0xc4a, 0xc55, 0xc62, 0xc81, 0xcbc, 0xcbf, 0xcc2, + 0xcc6, 0xcca, 0xcd5, 0xce2, 0xd00, 0xd3b, 0xd3e, 0xd41, 0xd4d, 0xd57, 0xd62, 0xd81, 0xdca, 0xdcf, 0xdd2, 0xdd6, + 0xddf, 0xe31, 0xe34, 0xe47, 0xeb1, 0xeb4, 0xec8, 0xf18, 0xf35, 0xf37, 0xf39, 0xf71, 0xf80, 0xf86, 0xf8d, 0xf99, + 0xfc6, 0x102d, 0x1032, 0x1039, 0x103d, 0x1058, 0x105e, 0x1071, 0x1082, 0x1085, 0x108d, 0x109d, 0x135d, 0x1712, + 0x1732, 0x1752, 0x1772, 0x17b4, 0x17b7, 0x17c6, 0x17c9, 0x17dd, 0x180b, 0x180f, 0x1885, 0x18a9, 0x1920, 0x1927, + 0x1932, 0x1939, 0x1a17, 0x1a1b, 0x1a56, 0x1a58, 0x1a60, 0x1a62, 0x1a65, 0x1a73, 0x1a7f, 0x1ab0, 0x1ae0, 0x1b00, + 0x1b34, 0x1b42, 0x1b6b, 0x1b80, 0x1ba2, 0x1ba8, 0x1be6, 0x1be8, 0x1bed, 0x1bef, 0x1c2c, 0x1c36, 0x1cd0, 0x1cd4, + 0x1ce2, 0x1ced, 0x1cf4, 0x1cf8, 0x1dc0, 0x200c, 0x20d0, 0x2cef, 0x2d7f, 0x2de0, 0x302a, 0x3099, 0xa66f, 0xa674, + 0xa69e, 0xa6f0, 0xa802, 0xa806, 0xa80b, 0xa825, 0xa82c, 0xa8c4, 0xa8e0, 0xa8ff, 0xa926, 0xa947, 0xa953, 0xa980, + 0xa9b3, 0xa9b6, 0xa9bc, 0xa9c0, 0xa9e5, 0xaa29, 0xaa31, 0xaa35, 0xaa43, 0xaa4c, 0xaa7c, 0xaab0, 0xaab2, 0xaab7, + 0xaabe, 0xaac1, 0xaaec, 0xaaf6, 0xabe5, 0xabe8, 0xabed, 0xfb1e, 0xfe00, 0xfe20, 0xff9e, 0x101fd, 0x102e0, + 0x10376, 0x10a01, 0x10a05, 0x10a0c, 0x10a38, 0x10a3f, 0x10ae5, 0x10d24, 0x10d69, 0x10eab, 0x10efa, 0x10f46, + 0x10f82, 0x11001, 0x11038, 0x11070, 0x11073, 0x1107f, 0x110b3, 0x110b9, 0x110c2, 0x11100, 0x11127, 0x1112d, + 0x11173, 0x11180, 0x111b6, 0x111c0, 0x111c9, 0x111cf, 0x1122f, 0x11234, 0x1123e, 0x11241, 0x112df, 0x112e3, + 0x11300, 0x1133b, 0x1133e, 0x11340, 0x1134d, 0x11357, 0x11366, 0x11370, 0x113b8, 0x113bb, 0x113c2, 0x113c5, + 0x113c7, 0x113ce, 0x113d2, 0x113e1, 0x11438, 0x11442, 0x11446, 0x1145e, 0x114b0, 0x114b3, 0x114ba, 0x114bd, + 0x114bf, 0x114c2, 0x115af, 0x115b2, 0x115bc, 0x115bf, 0x115dc, 0x11633, 0x1163d, 0x1163f, 0x116ab, 0x116ad, + 0x116b0, 0x1171d, 0x1171f, 0x11722, 0x11727, 0x1182f, 0x11839, 0x11930, 0x1193b, 0x11943, 0x119d4, 0x119da, + 0x119e0, 0x11a01, 0x11a33, 0x11a3b, 0x11a47, 0x11a51, 0x11a59, 0x11a8a, 0x11a98, 0x11b60, 0x11b62, 0x11b66, + 0x11c30, 0x11c38, 0x11c3f, 0x11c92, 0x11caa, 0x11cb2, 0x11cb5, 0x11d31, 0x11d3a, 0x11d3c, 0x11d3f, 0x11d47, + 0x11d90, 0x11d95, 0x11d97, 0x11ef3, 0x11f00, 0x11f36, 0x11f40, 0x11f5a, 0x13440, 0x13447, 0x1611e, 0x1612d, + 0x16af0, 0x16b30, 0x16f4f, 0x16f8f, 0x16fe4, 0x16ff0, 0x1bc9d, 0x1cf00, 0x1cf30, 0x1d165, 0x1d16d, 0x1d17b, + 0x1d185, 0x1d1aa, 0x1d242, 0x1da00, 0x1da3b, 0x1da75, 0x1da84, 0x1da9b, 0x1daa1, 0x1e000, 0x1e008, 0x1e01b, + 0x1e023, 0x1e026, 0x1e08f, 0x1e130, 0x1e2ae, 0x1e2ec, 0x1e4ec, 0x1e5ee, 0x1e6e3, 0x1e6e6, 0x1e6ee, 0x1e6f5, + 0x1e8d0, 0x1e944, 0xe0020, 0xe0100}, + {0x70, 0x7, 0x2d, 0x1, 0x2, 0x2, 0x1, 0xb, 0x15, 0x1, 0x7, 0x6, 0x2, 0x4, 0x1, 0x1b, 0xb, 0x9, 0x1, 0x4, 0x9, 0x3, + 0x5, 0x3, 0x9, 0x18, 0x20, 0x1, 0x1, 0x8, 0x1, 0x7, 0x2, 0x1, 0x1, 0x1, 0x4, 0x1, 0x1, 0x2, 0x1, 0x2, 0x1, 0x2, + 0x2, 0x3, 0x1, 0x2, 0x1, 0x2, 0x1, 0x5, 0x2, 0x1, 0x2, 0x6, 0x1, 0x1, 0x2, 0x4, 0x1, 0x3, 0x2, 0x1, 0x1, 0x1, + 0x1, 0x1, 0x1, 0x1, 0x1, 0x3, 0x3, 0x4, 0x2, 0x2, 0x1, 0x1, 0x2, 0x1, 0x3, 0x4, 0x2, 0x2, 0x2, 0x2, 0x1, 0x4, + 0x1, 0x1, 0x2, 0x1, 0x1, 0x1, 0x3, 0x1, 0x1, 0x1, 0x7, 0x8, 0x1, 0x9, 0x7, 0x2, 0x1, 0x1, 0x1, 0xe, 0x5, 0x2, + 0xb, 0x24, 0x1, 0x4, 0x6, 0x2, 0x2, 0x2, 0x3, 0x4, 0x1, 0x2, 0x1, 0x1, 0x3, 0x4, 0x3, 0x2, 0x2, 0x2, 0x7, 0x1, + 0xb, 0x1, 0x3, 0x1, 0x2, 0x1, 0x3, 0x2, 0x1, 0x3, 0x2, 0x1, 0x1, 0x7, 0x1, 0x1, 0x8, 0xa, 0x1, 0x2e, 0xc, 0x4, + 0xa, 0x3, 0x9, 0x2, 0x4, 0x6, 0x1, 0x2, 0x1, 0x5, 0x8, 0x2, 0x3, 0xd, 0x7, 0x1, 0x1, 0x2, 0x40, 0x1, 0x21, 0x3, + 0x1, 0x20, 0x6, 0x2, 0x4, 0xa, 0x2, 0x2, 0x1, 0x1, 0x1, 0x2, 0x1, 0x2, 0x12, 0x1, 0x8, 0xb, 0x1, 0x3, 0x1, 0x4, + 0x2, 0x1, 0x1, 0x6, 0x2, 0x2, 0x1, 0x1, 0x1, 0x1, 0x3, 0x2, 0x2, 0x1, 0x2, 0x1, 0x1, 0x1, 0x1, 0x1, 0x10, 0x10, + 0x2, 0x1, 0x1, 0x5, 0x3, 0x2, 0x4, 0x3, 0x1, 0x2, 0x4, 0x5, 0x2, 0x6, 0xb, 0x4, 0x1, 0xf, 0x1, 0x2, 0x3, 0x4, + 0x2, 0x1, 0x3, 0x5, 0x8, 0x1, 0x2, 0x9, 0x1, 0x4, 0x1, 0x3, 0x4, 0x1, 0x1, 0x1, 0x8, 0x2, 0x2, 0x1, 0x1, 0x1, + 0x1, 0x7, 0x5, 0x1, 0x6, 0x1, 0x1, 0x3, 0x3, 0x1, 0x2, 0x8, 0x3, 0x1, 0x1, 0x1, 0x6, 0x1, 0x1, 0x2, 0x2, 0x1, + 0x4, 0x2, 0x2, 0x2, 0x8, 0x1, 0x2, 0x1, 0x1, 0x8, 0x1, 0x1, 0x4, 0x5, 0x9, 0x2, 0x1, 0x4, 0x1, 0x4, 0x2, 0x1, + 0xa, 0x6, 0x4, 0x1, 0x6, 0x3, 0xd, 0x2, 0x1, 0x3, 0x1, 0x7, 0x6, 0x1, 0x16, 0x7, 0x2, 0x2, 0x6, 0x1, 0x2, 0x7, + 0x1, 0x2, 0x1, 0x1, 0x2, 0x2, 0x5, 0x3, 0x1, 0x1, 0xf, 0xc, 0x3, 0x5, 0x7, 0x1, 0x4, 0x1, 0x2, 0x2, 0x2e, 0x17, + 0x5, 0x6, 0x8, 0x7, 0x4, 0x3, 0x37, 0x32, 0x1, 0x1, 0x5, 0xf, 0x7, 0x11, 0x7, 0x2, 0x5, 0x1, 0x7, 0x1, 0x4, 0x4, + 0x2, 0x1, 0x1, 0x2, 0x1, 0x7, 0x7, 0x60, 0xf0}}; + +// EastAsianWidth-17.0.0.txt +// Date: 2025-07-24, 00:12:54 GMT +inline constexpr char32_t _Width_estimate_intervals_v2[] = {0x1100, 0x1160, 0x231a, 0x231c, 0x2329, 0x232b, 0x23e9, + 0x23ed, 0x23f0, 0x23f1, 0x23f3, 0x23f4, 0x25fd, 0x25ff, 0x2614, 0x2616, 0x2630, 0x2638, 0x2648, 0x2654, 0x267f, + 0x2680, 0x268a, 0x2690, 0x2693, 0x2694, 0x26a1, 0x26a2, 0x26aa, 0x26ac, 0x26bd, 0x26bf, 0x26c4, 0x26c6, 0x26ce, + 0x26cf, 0x26d4, 0x26d5, 0x26ea, 0x26eb, 0x26f2, 0x26f4, 0x26f5, 0x26f6, 0x26fa, 0x26fb, 0x26fd, 0x26fe, 0x2705, + 0x2706, 0x270a, 0x270c, 0x2728, 0x2729, 0x274c, 0x274d, 0x274e, 0x274f, 0x2753, 0x2756, 0x2757, 0x2758, 0x2795, + 0x2798, 0x27b0, 0x27b1, 0x27bf, 0x27c0, 0x2b1b, 0x2b1d, 0x2b50, 0x2b51, 0x2b55, 0x2b56, 0x2e80, 0x2e9a, 0x2e9b, + 0x2ef4, 0x2f00, 0x2fd6, 0x2ff0, 0x303f, 0x3041, 0x3097, 0x3099, 0x3100, 0x3105, 0x3130, 0x3131, 0x318f, 0x3190, + 0x31e6, 0x31ef, 0x321f, 0x3220, 0x3248, 0x3250, 0xa48d, 0xa490, 0xa4c7, 0xa960, 0xa97d, 0xac00, 0xd7a4, 0xf900, + 0xfb00, 0xfe10, 0xfe1a, 0xfe30, 0xfe53, 0xfe54, 0xfe67, 0xfe68, 0xfe6c, 0xff01, 0xff61, 0xffe0, 0xffe7, 0x16fe0, + 0x16fe5, 0x16ff0, 0x16ff7, 0x17000, 0x18cd6, 0x18cff, 0x18d1f, 0x18d80, 0x18df3, 0x1aff0, 0x1aff4, 0x1aff5, 0x1affc, + 0x1affd, 0x1afff, 0x1b000, 0x1b123, 0x1b132, 0x1b133, 0x1b150, 0x1b153, 0x1b155, 0x1b156, 0x1b164, 0x1b168, 0x1b170, + 0x1b2fc, 0x1d300, 0x1d357, 0x1d360, 0x1d377, 0x1f004, 0x1f005, 0x1f0cf, 0x1f0d0, 0x1f18e, 0x1f18f, 0x1f191, 0x1f19b, + 0x1f200, 0x1f203, 0x1f210, 0x1f23c, 0x1f240, 0x1f249, 0x1f250, 0x1f252, 0x1f260, 0x1f266, 0x1f300, 0x1f650, 0x1f680, + 0x1f6c6, 0x1f6cc, 0x1f6cd, 0x1f6d0, 0x1f6d3, 0x1f6d5, 0x1f6d9, 0x1f6dc, 0x1f6e0, 0x1f6eb, 0x1f6ed, 0x1f6f4, 0x1f6fd, + 0x1f7e0, 0x1f7ec, 0x1f7f0, 0x1f7f1, 0x1f900, 0x1fa00, 0x1fa70, 0x1fa7d, 0x1fa80, 0x1fa8b, 0x1fa8e, 0x1fac7, 0x1fac8, + 0x1fac9, 0x1facd, 0x1fadd, 0x1fadf, 0x1faeb, 0x1faef, 0x1faf9, 0x20000, 0x2fffe, 0x30000, 0x3fffe}; + +_STD_END + +#pragma pop_macro("new") +_STL_RESTORE_CLANG_WARNINGS +#pragma warning(pop) +#pragma pack(pop) + +#endif // _STL_COMPILER_PREPROCESSOR +#endif // __MSVC_FORMAT_UCD_TABLES_HPP diff --git a/stl/inc/__msvc_formatter.hpp b/stl/inc/__msvc_formatter.hpp new file mode 100644 index 00000000000..0f70edd3590 --- /dev/null +++ b/stl/inc/__msvc_formatter.hpp @@ -0,0 +1,438 @@ +// __msvc_formatter.hpp internal header + +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +// NOTE: +// The contents of this header are derived in part from libfmt under the following license: + +// Copyright (c) 2012 - present, Victor Zverovich +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// --- Optional exception to the license --- +// +// As an exception, if, as a result of your compiling your source code, portions +// of this Software are embedded into a machine-executable object form of such +// source code, you may redistribute such embedded portions in such object form +// without including the above copyright and permission notices. + +#ifndef __MSVC_FORMATTER_HPP +#define __MSVC_FORMATTER_HPP +#include +#if _STL_COMPILER_PREPROCESSOR + +#if !_HAS_CXX20 +#error The contents of are only available with C++20. (Also, you should not include this internal header.) +#endif // !_HAS_CXX20 + +#include +#include +#include +#include + +#if _HAS_CXX23 +#include +#endif // _HAS_CXX23 + +#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 + +// TRANSITION, non-_Ugly attribute tokens +#pragma push_macro("msvc") +#pragma push_macro("no_specializations") +#undef msvc +#undef no_specializations + +_STD_BEGIN +#if _HAS_CXX23 +#define _FMT_P2286_BEGIN inline namespace __p2286 { +#define _FMT_P2286_END } +#else // ^^^ _HAS_CXX23 / !_HAS_CXX23 vvv +#define _FMT_P2286_BEGIN +#define _FMT_P2286_END +#endif // ^^^ !_HAS_CXX23 ^^^ + +enum class _Fmt_align : uint8_t { _None, _Left, _Right, _Center }; + +enum class _Fmt_sign : uint8_t { _None, _Plus, _Minus, _Space }; + +enum class _Basic_format_arg_type : uint8_t { + _None, + _Int_type, + _UInt_type, + _Long_long_type, + _ULong_long_type, + _Bool_type, + _Char_type, + _Float_type, + _Double_type, + _Long_double_type, + _Pointer_type, + _CString_type, + _String_type, + _Custom_type, +}; +static_assert(static_cast(_Basic_format_arg_type::_Custom_type) < 16, "must fit in 4-bit bitfield"); + +#if _HAS_CXX23 +_EXPORT_STD template // specializations allowed by N5014 [format.formatter.locking]/1 +constexpr bool enable_nonlocking_formatter_optimization = false; + +_NODISCARD consteval bool _Is_debug_enabled_fmt_type(_Basic_format_arg_type _Ty) { + return _Ty == _Basic_format_arg_type::_Char_type || _Ty == _Basic_format_arg_type::_CString_type + || _Ty == _Basic_format_arg_type::_String_type; +} +#endif // _HAS_CXX23 + +template +struct _Basic_format_specs { + int _Width = 0; + int _Precision = -1; + char _Type = '\0'; + _Fmt_align _Alignment = _Fmt_align::_None; + _Fmt_sign _Sgn = _Fmt_sign::_None; + bool _Alt = false; + bool _Localized = false; + bool _Leading_zero = false; + uint8_t _Fill_length = 1; + // At most one codepoint (so one char32_t or four utf-8 char8_t). + _CharT _Fill[4 / sizeof(_CharT)] = {_CharT{' '}}; +}; + +// Adds width and precision references to _Basic_format_specs. +// This is required for std::formatter implementations because we must +// parse the format specs without having access to the format args (via a format context). +template +struct _Dynamic_format_specs : _Basic_format_specs<_CharT> { + int _Dynamic_width_index = -1; + int _Dynamic_precision_index = -1; +}; + +[[noreturn]] inline void _Throw_format_error(const char* _Message); + +_EXPORT_STD template +class _NO_SPECIALIZATIONS_CITING("N5014 [format.parse.ctx]/2") basic_format_parse_context; + +template +concept _Format_supported_charT = _Is_any_of_v<_CharT, char, wchar_t>; + +_EXPORT_STD template +struct formatter { + formatter() = delete; + formatter(const formatter&) = delete; + formatter& operator=(const formatter&) = delete; +}; + +_FMT_P2286_BEGIN +template +struct _Formatter_base { +public: +#if _HAS_CXX23 + constexpr void _Set_debug_format() noexcept + requires (_Is_debug_enabled_fmt_type(_ArgType)) + { + _Specs._Type = '?'; + } +#endif // _HAS_CXX23 + + template > + constexpr _ParseContext::iterator parse(type_identity_t<_ParseContext&> _Parse_ctx); // defined in + + template + _FormatContext::iterator format(const _Ty& _Val, _FormatContext& _Format_ctx) const; // defined in + +private: + _Dynamic_format_specs<_CharT> _Specs; +}; +_FMT_P2286_END + +#if _HAS_CXX23 +#define _FORMAT_SPECIALIZE_NONLOCKING_FOR(_Type) \ + template <> \ + inline constexpr bool enable_nonlocking_formatter_optimization<_Type> = true; +#else // ^^^ _HAS_CXX23 / !_HAS_CXX23 vvv +#define _FORMAT_SPECIALIZE_NONLOCKING_FOR(_Type) +#endif // ^^^ !_HAS_CXX23 ^^^ + +#define _FORMAT_SPECIALIZE_FOR(_Type, _ArgType) \ + _FORMAT_SPECIALIZE_NONLOCKING_FOR(_Type) \ + template <_Format_supported_charT _CharT> \ + struct formatter<_Type, _CharT> : _Formatter_base<_Type, _CharT, _ArgType> {} + +_FORMAT_SPECIALIZE_FOR(int, _Basic_format_arg_type::_Int_type); +_FORMAT_SPECIALIZE_FOR(unsigned int, _Basic_format_arg_type::_UInt_type); +_FORMAT_SPECIALIZE_FOR(long long, _Basic_format_arg_type::_Long_long_type); +_FORMAT_SPECIALIZE_FOR(unsigned long long, _Basic_format_arg_type::_ULong_long_type); +_FORMAT_SPECIALIZE_FOR(bool, _Basic_format_arg_type::_Bool_type); +_FORMAT_SPECIALIZE_FOR(float, _Basic_format_arg_type::_Float_type); +_FORMAT_SPECIALIZE_FOR(double, _Basic_format_arg_type::_Double_type); +_FORMAT_SPECIALIZE_FOR(long double, _Basic_format_arg_type::_Long_double_type); +_FORMAT_SPECIALIZE_FOR(nullptr_t, _Basic_format_arg_type::_Pointer_type); +_FORMAT_SPECIALIZE_FOR(void*, _Basic_format_arg_type::_Pointer_type); +_FORMAT_SPECIALIZE_FOR(const void*, _Basic_format_arg_type::_Pointer_type); +_FORMAT_SPECIALIZE_FOR(short, _Basic_format_arg_type::_Int_type); +_FORMAT_SPECIALIZE_FOR(unsigned short, _Basic_format_arg_type::_UInt_type); +_FORMAT_SPECIALIZE_FOR(long, _Basic_format_arg_type::_Int_type); +_FORMAT_SPECIALIZE_FOR(unsigned long, _Basic_format_arg_type::_UInt_type); +_FORMAT_SPECIALIZE_FOR(signed char, _Basic_format_arg_type::_Int_type); +_FORMAT_SPECIALIZE_FOR(unsigned char, _Basic_format_arg_type::_UInt_type); + +#undef _FORMAT_SPECIALIZE_FOR +#undef _FORMAT_SPECIALIZE_NONLOCKING_FOR + +// not using the macro because we'd like to add 'set_debug_format' member function in C++23 mode +template <_Format_supported_charT _CharT> +struct formatter : _Formatter_base { +#if _HAS_CXX23 + constexpr void set_debug_format() noexcept { + this->_Set_debug_format(); + } +#endif // _HAS_CXX23 +}; + +// not using the macro because we'd like to avoid the formatter specialization +template <> +struct formatter : _Formatter_base { +#if _HAS_CXX23 + constexpr void set_debug_format() noexcept { + _Set_debug_format(); + } +#endif // _HAS_CXX23 +}; + +// We could use the macro for these specializations, but it's confusing to refer to symbols that are defined +// inside the macro in the macro's "call". +template <_Format_supported_charT _CharT> +struct formatter<_CharT*, _CharT> : _Formatter_base<_CharT*, _CharT, _Basic_format_arg_type::_CString_type> { +#if _HAS_CXX23 + constexpr void set_debug_format() noexcept { + this->_Set_debug_format(); + } +#endif // _HAS_CXX23 +}; + +template <_Format_supported_charT _CharT> +struct formatter + : _Formatter_base { +#if _HAS_CXX23 + constexpr void set_debug_format() noexcept { + this->_Set_debug_format(); + } +#endif // _HAS_CXX23 +}; + +template <_Format_supported_charT _CharT, size_t _Nx> +struct formatter<_CharT[_Nx], _CharT> : _Formatter_base<_CharT[_Nx], _CharT, _Basic_format_arg_type::_CString_type> { +#if _HAS_CXX23 + constexpr void set_debug_format() noexcept { + this->_Set_debug_format(); + } +#endif // _HAS_CXX23 +}; + +_EXPORT_STD template +class basic_string; + +_EXPORT_STD template +class basic_string_view; + +template <_Format_supported_charT _CharT, class _Traits, class _Allocator> +struct formatter, _CharT> + : _Formatter_base, _CharT, _Basic_format_arg_type::_String_type> { +#if _HAS_CXX23 + constexpr void set_debug_format() noexcept { + this->_Set_debug_format(); + } +#endif // _HAS_CXX23 +}; + +template <_Format_supported_charT _CharT, class _Traits> +struct formatter, _CharT> + : _Formatter_base, _CharT, _Basic_format_arg_type::_String_type> { +#if _HAS_CXX23 + constexpr void set_debug_format() noexcept { + this->_Set_debug_format(); + } +#endif // _HAS_CXX23 +}; + +#if _HAS_CXX23 +template <> +struct formatter { + formatter() = delete; + formatter(const formatter&) = delete; + formatter& operator=(const formatter&) = delete; +}; + +template <> +struct formatter { + formatter() = delete; + formatter(const formatter&) = delete; + formatter& operator=(const formatter&) = delete; +}; + +template +struct formatter { + formatter() = delete; + formatter(const formatter&) = delete; + formatter& operator=(const formatter&) = delete; +}; + +template +struct formatter, wchar_t> { + formatter() = delete; + formatter(const formatter&) = delete; + formatter& operator=(const formatter&) = delete; +}; + +template +struct formatter, wchar_t> { + formatter() = delete; + formatter(const formatter&) = delete; + formatter& operator=(const formatter&) = delete; +}; + +_EXPORT_STD enum class range_format { disabled, map, set, sequence, string, debug_string }; + +template +struct _Invalid_format_kind { + static_assert(_Always_false<_Ty>, "A program that instantiates the primary template of format_kind is ill-formed. " + "(N4981 [format.range.fmtkind]/1)"); +}; + +_EXPORT_STD template +constexpr _Invalid_format_kind<_Ty> format_kind; // specializations allowed by N5014 [format.range.fmtkind]/3 + +template +constexpr bool _Is_two_tuple = false; + +template +constexpr bool _Is_two_tuple> = true; + +template +constexpr bool _Is_two_tuple> = true; + +template <_RANGES input_range _Rng> + requires same_as<_Rng, remove_cvref_t<_Rng>> +constexpr range_format format_kind<_Rng> = []() consteval { + using _Ref_value_t = remove_cvref_t<_RANGES range_reference_t<_Rng>>; + if constexpr (same_as<_Ref_value_t, _Rng>) { + return range_format::disabled; + } else if constexpr (requires { typename _Rng::key_type; }) { + if constexpr (requires { typename _Rng::mapped_type; } && _Is_two_tuple<_Ref_value_t>) { + return range_format::map; + } else { + return range_format::set; + } + } else { + return range_format::sequence; + } +}(); + +// Specializations for pairs, tuples, and ranges are forward-declared to avoid any risk of using the disabled primary +// template. + +// Per LWG-3997, `_CharT` in library-provided `formatter` specializations is +// constrained to character types supported by `format`. + +template +concept _Formatting_enabled_range = format_kind<_Rng> != range_format::disabled; + +template <_RANGES input_range _Rng, _Format_supported_charT _CharT> + requires _Formatting_enabled_range<_Rng> +struct formatter<_Rng, _CharT>; + +template <_Format_supported_charT _CharT, class _Ty1, class _Ty2> +struct formatter, _CharT>; + +template <_Format_supported_charT _CharT, class... _Types> +struct formatter, _CharT>; + +template <_Format_supported_charT _CharT> +constexpr bool enable_nonlocking_formatter_optimization<_CharT> = true; + +template <_Format_supported_charT _CharT> +constexpr bool enable_nonlocking_formatter_optimization<_CharT*> = true; + +template <_Format_supported_charT _CharT> +constexpr bool enable_nonlocking_formatter_optimization = true; + +template <_Format_supported_charT _CharT, size_t _Nx> +constexpr bool enable_nonlocking_formatter_optimization<_CharT[_Nx]> = true; + +template <_Format_supported_charT _CharT, class _Traits, class _Allocator> +constexpr bool enable_nonlocking_formatter_optimization> = true; + +template <_Format_supported_charT _CharT, class _Traits> +constexpr bool enable_nonlocking_formatter_optimization> = true; + +template +constexpr bool enable_nonlocking_formatter_optimization> = + enable_nonlocking_formatter_optimization> + && enable_nonlocking_formatter_optimization>; + +template +constexpr bool enable_nonlocking_formatter_optimization> = + (enable_nonlocking_formatter_optimization> && ...); + +template +struct _Fill_align_and_width_specs { + int _Width = -1; + int _Dynamic_width_index = -1; + _Fmt_align _Alignment = _Fmt_align::_None; + uint8_t _Fill_length = 1; + // At most one codepoint (so one char32_t or four utf-8 char8_t). + _CharT _Fill[4 / sizeof(_CharT)]{' '}; +}; + +template +struct _Fill_align_and_width_formatter { +public: + template > // improves throughput, see GH-5003 + _NODISCARD constexpr _ParseContext::iterator _Parse( + type_identity_t<_ParseContext&> _Parse_ctx); // defined in + + template + _NODISCARD _FormatContext::iterator _Format(_FormatContext& _Format_ctx, const int _Width, + _Fmt_align _Default_align, + _Func&& _Fn) const; // defined in + +private: + _Fill_align_and_width_specs<_CharT> _Specs; +}; +#endif // _HAS_CXX23 +_STD_END + +// TRANSITION, non-_Ugly attribute tokens +#pragma pop_macro("no_specializations") +#pragma pop_macro("msvc") + +#pragma pop_macro("new") +_STL_RESTORE_CLANG_WARNINGS +#pragma warning(pop) +#pragma pack(pop) + +#endif // _STL_COMPILER_PREPROCESSOR +#endif // __MSVC_FORMATTER_HPP diff --git a/stl/inc/__msvc_heap_algorithms.hpp b/stl/inc/__msvc_heap_algorithms.hpp new file mode 100644 index 00000000000..f368fc70954 --- /dev/null +++ b/stl/inc/__msvc_heap_algorithms.hpp @@ -0,0 +1,150 @@ +// __msvc_heap_algorithms.hpp internal header + +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#ifndef __MSVC_HEAP_ALGORITHMS_HPP +#define __MSVC_HEAP_ALGORITHMS_HPP +#include +#if _STL_COMPILER_PREPROCESSOR + +#include + +#pragma pack(push, _CRT_PACKING) +#pragma warning(push, _STL_WARNING_LEVEL) +#pragma warning(disable : _STL_DISABLED_WARNINGS) +_STL_DISABLE_CLANG_WARNINGS +#pragma push_macro("new") +#undef new + +_STD_BEGIN +template +_CONSTEXPR20 void _Push_heap_by_index( + _RanIt _First, _Iter_diff_t<_RanIt> _Hole, _Iter_diff_t<_RanIt> _Top, _Ty&& _Val, _Pr _Pred) { + // percolate _Hole to _Top or where _Val belongs + using _Diff = _Iter_diff_t<_RanIt>; + for (_Diff _Idx = (_Hole - 1) >> 1; // shift for codegen + _Top < _Hole && _DEBUG_LT_PRED(_Pred, *(_First + _Idx), _Val); _Idx = (_Hole - 1) >> 1) { // shift for codegen + // move _Hole up to parent + *(_First + _Hole) = _STD move(*(_First + _Idx)); + _Hole = _Idx; + } + + *(_First + _Hole) = _STD forward<_Ty>(_Val); // drop _Val into final hole +} + +_EXPORT_STD template +_CONSTEXPR20 void push_heap(_RanIt _First, _RanIt _Last, _Pr _Pred) { + // push *(_Last - 1) onto heap at [_First, _Last - 1) + _STD _Adl_verify_range(_First, _Last); + const auto _UFirst = _STD _Get_unwrapped(_First); + auto _ULast = _STD _Get_unwrapped(_Last); + using _Diff = _Iter_diff_t<_RanIt>; + _Diff _Count = _ULast - _UFirst; + if (2 <= _Count) { + _Iter_value_t<_RanIt> _Val(_STD move(*--_ULast)); + _STD _Push_heap_by_index(_UFirst, --_Count, _Diff(0), _STD move(_Val), _STD _Pass_fn(_Pred)); + } +} + +_EXPORT_STD template +_CONSTEXPR20 void push_heap(_RanIt _First, _RanIt _Last) { + // push *(_Last - 1) onto heap at [_First, _Last - 1) + _STD push_heap(_First, _Last, less<>{}); +} + +template +_CONSTEXPR20 void _Pop_heap_hole_by_index( + _RanIt _First, _Iter_diff_t<_RanIt> _Hole, _Iter_diff_t<_RanIt> _Bottom, _Ty&& _Val, _Pr _Pred) { + // percolate _Hole to _Bottom, then push _Val + _STL_INTERNAL_CHECK(_Bottom > 0); + + using _Diff = _Iter_diff_t<_RanIt>; + const _Diff _Top = _Hole; + _Diff _Idx = _Hole; + + // Check whether _Idx can have a child before calculating that child's index, since + // calculating the child's index can trigger integer overflows + const _Diff _Max_sequence_non_leaf = (_Bottom - 1) >> 1; // shift for codegen + while (_Idx < _Max_sequence_non_leaf) { // move _Hole down to larger child + _Idx = 2 * _Idx + 2; + if (_DEBUG_LT_PRED(_Pred, *(_First + _Idx), *(_First + (_Idx - 1)))) { + --_Idx; + } + *(_First + _Hole) = _STD move(*(_First + _Idx)); + _Hole = _Idx; + } + + if (_Idx == _Max_sequence_non_leaf && _Bottom % 2 == 0) { // only child at bottom, move _Hole down to it + *(_First + _Hole) = _STD move(*(_First + (_Bottom - 1))); + _Hole = _Bottom - 1; + } + + _STD _Push_heap_by_index(_First, _Hole, _Top, _STD forward<_Ty>(_Val), _Pred); +} + +template +_CONSTEXPR20 void _Pop_heap_hole_unchecked(_RanIt _First, _RanIt _Last, _RanIt _Dest, _Ty&& _Val, _Pr _Pred) { + // pop *_First to *_Dest and reheap + // precondition: _First != _Last + // precondition: _First != _Dest + *_Dest = _STD move(*_First); + using _Diff = _Iter_diff_t<_RanIt>; + _STD _Pop_heap_hole_by_index( + _First, static_cast<_Diff>(0), static_cast<_Diff>(_Last - _First), _STD forward<_Ty>(_Val), _Pred); +} + +template +_CONSTEXPR20 void _Pop_heap_unchecked(_RanIt _First, _RanIt _Last, _Pr _Pred) { + // pop *_First to *(_Last - 1) and reheap + if (2 <= _Last - _First) { + --_Last; + _Iter_value_t<_RanIt> _Val(_STD move(*_Last)); + _STD _Pop_heap_hole_unchecked(_First, _Last, _Last, _STD move(_Val), _Pred); + } +} + +_EXPORT_STD template +_CONSTEXPR20 void pop_heap(_RanIt _First, _RanIt _Last, _Pr _Pred) { + // pop *_First to *(_Last - 1) and reheap + _STD _Adl_verify_range(_First, _Last); + _STD _Pop_heap_unchecked(_STD _Get_unwrapped(_First), _STD _Get_unwrapped(_Last), _STD _Pass_fn(_Pred)); +} + +_EXPORT_STD template +_CONSTEXPR20 void pop_heap(_RanIt _First, _RanIt _Last) { + // pop *_First to *(_Last - 1) and reheap + _STD pop_heap(_First, _Last, less<>{}); +} + +template +_CONSTEXPR20 void _Make_heap_unchecked(_RanIt _First, _RanIt _Last, _Pr _Pred) { + // make [_First, _Last) into a heap + using _Diff = _Iter_diff_t<_RanIt>; + _Diff _Bottom = _Last - _First; + for (_Diff _Hole = _Bottom >> 1; _Hole > 0;) { // shift for codegen + // reheap top half, bottom to top + --_Hole; + _Iter_value_t<_RanIt> _Val(_STD move(*(_First + _Hole))); + _STD _Pop_heap_hole_by_index(_First, _Hole, _Bottom, _STD move(_Val), _Pred); + } +} + +_EXPORT_STD template +_CONSTEXPR20 void make_heap(_RanIt _First, _RanIt _Last, _Pr _Pred) { // make [_First, _Last) into a heap + _STD _Adl_verify_range(_First, _Last); + _STD _Make_heap_unchecked(_STD _Get_unwrapped(_First), _STD _Get_unwrapped(_Last), _STD _Pass_fn(_Pred)); +} + +_EXPORT_STD template +_CONSTEXPR20 void make_heap(_RanIt _First, _RanIt _Last) { // make [_First, _Last) into a heap + _STD make_heap(_First, _Last, less<>{}); +} +_STD_END + +#pragma pop_macro("new") +_STL_RESTORE_CLANG_WARNINGS +#pragma warning(pop) +#pragma pack(pop) +#endif // _STL_COMPILER_PREPROCESSOR +#endif // __MSVC_HEAP_ALGORITHMS_HPP diff --git a/stl/inc/__msvc_int128.hpp b/stl/inc/__msvc_int128.hpp new file mode 100644 index 00000000000..08b0267cafe --- /dev/null +++ b/stl/inc/__msvc_int128.hpp @@ -0,0 +1,1605 @@ +// __msvc_int128.hpp internal header (core) + +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#ifndef __MSVC_INT128_HPP +#define __MSVC_INT128_HPP + +#include +#if _STL_COMPILER_PREPROCESSOR +#include <__msvc_bit_utils.hpp> +#include +#include +#include + +#include _STL_INTRIN_HEADER + +#if _HAS_CXX20 +#include +#include +#define _TEMPLATE_CLASS_INTEGRAL(type) template +#define _ZERO_OR_NO_INIT +#else // ^^^ _HAS_CXX20 / !_HAS_CXX20 vvv +#define _TEMPLATE_CLASS_INTEGRAL(type) template , int> = 0> +#define _ZERO_OR_NO_INIT \ + { \ + } // Trivial default initialization is not allowed in constexpr functions before C++20. +#endif // ^^^ !_HAS_CXX20 ^^^ + +#pragma pack(push, _CRT_PACKING) +#pragma warning(push, _STL_WARNING_LEVEL) +#pragma warning(disable : _STL_DISABLED_WARNINGS) +_STL_DISABLE_CLANG_WARNINGS +#pragma push_macro("new") +#undef new + +_STD_BEGIN + +#if defined(_M_X64) && !defined(_M_ARM64EC) && !defined(_M_CEE_PURE) && !defined(__CUDACC__) +#define _STL_128_INTRINSICS 1 +#ifdef __clang__ // clang doesn't have _udiv128 / _div128 +#define _STL_128_DIV_INTRINSICS 0 +#else // ^^^ Clang / other vvv +#define _STL_128_DIV_INTRINSICS 1 +#endif // ^^^ detect _udiv128 / _div128 ^^^ +#else // ^^^ intrinsics available / intrinsics unavailable vvv +#define _STL_128_INTRINSICS 0 +#define _STL_128_DIV_INTRINSICS 0 +#endif // ^^^ intrinsics unavailable ^^^ + +struct alignas(16) _Base128 { + uint64_t _Word[2]; + + constexpr void _Left_shift(const unsigned char _Count) noexcept { + // _STL_INTERNAL_CHECK(_Count < 128); + if (_Count == 0) { + return; + } + + if (_Count >= 64) { + _Word[1] = _Word[0] << (_Count % 64); + _Word[0] = 0; + return; + } + +#if _STL_128_INTRINSICS + if (!_Is_constant_evaluated()) { + _Word[1] = __shiftleft128(_Word[0], _Word[1], _Count); + } else +#endif // _STL_128_INTRINSICS + { + _Word[1] = (_Word[1] << _Count) | (_Word[0] >> (64 - _Count)); + } + + _Word[0] <<= _Count; + } + + constexpr void _Unsigned_right_shift(const unsigned char _Count) noexcept { + // _STL_INTERNAL_CHECK(_Count < 128); + if (_Count == 0) { + return; + } + + if (_Count >= 64) { + _Word[0] = _Word[1] >> (_Count % 64); + _Word[1] = 0; + return; + } + +#if _STL_128_INTRINSICS + if (!_Is_constant_evaluated()) { + _Word[0] = __shiftright128(_Word[0], _Word[1], _Count); + } else +#endif // _STL_128_INTRINSICS + { + _Word[0] = (_Word[0] >> _Count) | (_Word[1] << (64 - _Count)); + } + + _Word[1] >>= _Count; + } + + static constexpr unsigned char _AddCarry64( + unsigned char _Carry, uint64_t _Left, uint64_t _Right, uint64_t& _Result) noexcept { + // _STL_INTERNAL_CHECK(_Carry < 2); +#if _STL_128_INTRINSICS + if (!_Is_constant_evaluated()) { + return _addcarry_u64(_Carry, _Left, _Right, &_Result); + } +#endif // _STL_128_INTRINSICS + + const uint64_t _Sum = _Left + _Right + _Carry; + _Result = _Sum; + return _Carry ? _Sum <= _Left : _Sum < _Left; + } + + static constexpr unsigned char _SubBorrow64( + unsigned char _Carry, uint64_t _Left, uint64_t _Right, uint64_t& _Result) noexcept { + // _STL_INTERNAL_CHECK(_Carry < 2); +#if _STL_128_INTRINSICS + if (!_Is_constant_evaluated()) { + return _subborrow_u64(_Carry, _Left, _Right, &_Result); + } +#endif // _STL_128_INTRINSICS + + const auto _Difference = _Left - _Right - _Carry; + _Result = _Difference; + return _Carry ? _Difference >= _Left : _Difference > _Left; + } + + template + static constexpr void _Knuth_4_3_1_M( + const uint32_t (&__u)[__m], const uint32_t (&__v)[__n], uint32_t (&__w)[__n + __m]) noexcept { +#ifdef _ENABLE_STL_INTERNAL_CHECK + constexpr auto _Int_max = static_cast(INT_MAX); + _STL_INTERNAL_STATIC_ASSERT(__m <= _Int_max); + _STL_INTERNAL_STATIC_ASSERT(__n <= _Int_max); +#endif // defined(_ENABLE_STL_INTERNAL_CHECK) + + for (auto& _Elem : __w) { + _Elem = 0; + } + + for (int __j = 0; __j < static_cast(__n); ++__j) { + // stash Knuth's `k` in the lower 32 bits of __t + uint64_t __t = 0; + for (int __i = 0; __i < static_cast(__m); ++__i) { + __t += static_cast(__u[__i]) * __v[__j] + __w[__i + __j]; + __w[__i + __j] = static_cast(__t); + __t >>= 32; + } + __w[__j + __m] = static_cast(__t); + } + } + + _NODISCARD static constexpr uint64_t _UMul128( + const uint64_t _Left, const uint64_t _Right, uint64_t& _High_result) noexcept { +#if _STL_128_INTRINSICS + if (!_Is_constant_evaluated()) { + return _umul128(_Left, _Right, &_High_result); + } +#endif // _STL_128_INTRINSICS + + const uint32_t __u[2] = { + static_cast(_Left), + static_cast(_Left >> 32), + }; + const uint32_t __v[2] = { + static_cast(_Right), + static_cast(_Right >> 32), + }; + uint32_t __w[4] _ZERO_OR_NO_INIT; + + // multiply 2-digit numbers with 4-digit result in base 2^32 + _Knuth_4_3_1_M(__u, __v, __w); + + _High_result = (static_cast(__w[3]) << 32) | __w[2]; + return (static_cast(__w[1]) << 32) | __w[0]; + } + + static constexpr void _Knuth_4_3_1_D(uint32_t* const __u, const size_t __u_size, const uint32_t* const __v, + const size_t __v_size, uint32_t* const __q) noexcept { + // Pre: __u + [0, __u_size), __v + [0, __v_size), and __q + [0, __u_size - __v_size) are all valid ranges + // constexpr auto _Int_max = static_cast(INT_MAX); + // _STL_INTERNAL_CHECK(__v_size <= _Int_max); + const int __n = static_cast(__v_size); + // _STL_INTERNAL_CHECK(__u_size > __v_size); + // _STL_INTERNAL_CHECK(__u_size <= _Int_max); + const int __m = static_cast(__u_size - __v_size - 1); + // _STL_INTERNAL_CHECK(__v[__n - 1] >> 31 != 0); // Arguments are already normalized + + for (int __j = __m; __j >= 0; --__j) { + const auto _Two_digits = (static_cast(__u[__j + __n]) << 32) | __u[__j + __n - 1]; + auto __qhat = _Two_digits / __v[__n - 1]; + auto __rhat = _Two_digits % __v[__n - 1]; + + while ((__qhat >> 32) != 0 + || static_cast(__qhat) * static_cast(__v[__n - 2]) + > ((__rhat << 32) | __u[__j + __n - 2])) { + --__qhat; + __rhat += __v[__n - 1]; + if ((__rhat >> 32) != 0) { + break; + } + } + + int64_t __k = 0; + int64_t __t _ZERO_OR_NO_INIT; + for (int __i = 0; __i < __n; ++__i) { + const auto _Prod = static_cast(__qhat) * static_cast(__v[__i]); + __t = __u[__i + __j] - __k - static_cast(_Prod); + __u[__i + __j] = static_cast(__t); + __k = static_cast(_Prod >> 32) - (__t >> 32); + } + __t = __u[__j + __n] - __k; + __u[__j + __n] = static_cast(__t); + + __q[__j] = static_cast(__qhat); + if (__t < 0) { + --__q[__j]; + __k = 0; + for (int __i = 0; __i < __n; ++__i) { + __t = __u[__i + __j] + __k + __v[__i]; + __u[__i + __j] = static_cast(__t); + __k = __t >> 32; + } + __u[__j + __n] += static_cast(__k); + } + } + + // quotient is in __q, normalized remainder is in __u + } + + _NODISCARD static constexpr uint64_t _UDiv128( + uint64_t _High, uint64_t _Low, uint64_t _Div, uint64_t& _Remainder) noexcept { + // _STL_INTERNAL_CHECK(_High < _Div); + +#if _STL_128_DIV_INTRINSICS + if (!_Is_constant_evaluated()) { + return _udiv128(_High, _Low, _Div, &_Remainder); + } +#endif // _STL_128_DIV_INTRINSICS + + const auto __d = _Countl_zero(static_cast(_Div >> 32)); + if (__d >= 32) { // _Div < 2^32 + auto _Rem = (_High << 32) | (_Low >> 32); + auto _Result = _Rem / static_cast(_Div); + _Rem = ((_Rem % static_cast(_Div)) << 32) | static_cast(_Low); + _Result = (_Result << 32) | (_Rem / static_cast(_Div)); + _Remainder = _Rem % static_cast(_Div); + return _Result; + } + + uint32_t __u[5] = { + static_cast(_Low << __d), + static_cast(_Low >> (32 - __d)), + static_cast(_High << __d), + static_cast(_High >> (32 - __d)), + 0, + }; + if (__d != 0) { + __u[2] |= static_cast(_Low >> (64 - __d)); + __u[4] |= static_cast(_High >> (64 - __d)); + } + + uint32_t __v[2] = { + static_cast(_Div << __d), + static_cast(_Div >> (32 - __d)), + }; + uint32_t __q[3] _ZERO_OR_NO_INIT; + + _Knuth_4_3_1_D(__u, 5, __v, 2, __q); + // _STL_INTERNAL_CHECK(__u[4] == 0); + // _STL_INTERNAL_CHECK(__u[3] == 0); + // _STL_INTERNAL_CHECK(__u[2] == 0); + _Remainder = (static_cast(__u[1]) << (32 - __d)) | (__u[0] >> __d); + + // _STL_INTERNAL_CHECK(__q[2] == 0); + return (static_cast(__q[1]) << 32) | __q[0]; + } + + constexpr _Base128() noexcept : _Word{} {} + + _TEMPLATE_CLASS_INTEGRAL(_Ty) + constexpr _Base128(const _Ty _Val) noexcept : _Word{static_cast(_Val)} { +#if _HAS_CXX20 + if constexpr (signed_integral<_Ty>) +#else + if constexpr (is_signed_v<_Ty>) +#endif + { + if (_Val < 0) { + _Word[1] = ~0ull; + } + } + } + + constexpr explicit _Base128(const uint64_t _Low, const uint64_t _High) noexcept : _Word{_Low, _High} {} + + _TEMPLATE_CLASS_INTEGRAL(_Ty) + _NODISCARD constexpr explicit operator _Ty() const noexcept { + return static_cast<_Ty>(_Word[0]); + } + + _NODISCARD constexpr explicit operator bool() const noexcept { + return (_Word[0] | _Word[1]) != 0; + } + +#if _HAS_CXX20 + _NODISCARD friend constexpr bool operator==(const _Base128&, const _Base128&) noexcept = default; +#else // ^^^ _HAS_CXX20 / !_HAS_CXX20 vvv + _NODISCARD friend constexpr bool operator==(const _Base128& _Left, const _Base128& _Right) noexcept { + return _Left._Word[0] == _Right._Word[0] && _Left._Word[1] == _Right._Word[1]; + } + + _NODISCARD friend constexpr bool operator!=(const _Base128& _Left, const _Base128& _Right) noexcept { + return !(_Left == _Right); + } +#endif // ^^^ !_HAS_CXX20 ^^^ + + _NODISCARD friend constexpr bool operator<(const _Base128& _Left, const _Base128& _Right) noexcept { + if (_Left._Word[1] < _Right._Word[1]) { + return true; + } + + if (_Left._Word[1] > _Right._Word[1]) { + return false; + } + return _Left._Word[0] < _Right._Word[0]; + } + _NODISCARD friend constexpr bool operator>(const _Base128& _Left, const _Base128& _Right) noexcept { + return _Right < _Left; + } + _NODISCARD friend constexpr bool operator<=(const _Base128& _Left, const _Base128& _Right) noexcept { + return !(_Right < _Left); + } + _NODISCARD friend constexpr bool operator>=(const _Base128& _Left, const _Base128& _Right) noexcept { + return !(_Left < _Right); + } + + _TEMPLATE_CLASS_INTEGRAL(_Ty) + _NODISCARD friend constexpr _Ty operator<<(const _Ty _Left, const _Base128& _Right) noexcept { + return _Left << _Right._Word[0]; + } + + _TEMPLATE_CLASS_INTEGRAL(_Ty) + _NODISCARD friend constexpr _Ty operator>>(const _Ty _Left, const _Base128& _Right) noexcept { + return _Left >> _Right._Word[0]; + } + + _TEMPLATE_CLASS_INTEGRAL(_Ty) + constexpr _Base128& operator<<=(const _Ty _Count) noexcept { + _Left_shift(static_cast(_Count)); + return *this; + } + + _TEMPLATE_CLASS_INTEGRAL(_Ty) + friend constexpr _Ty& operator<<=(_Ty& _Left, const _Base128& _Right) noexcept { + _Left <<= _Right._Word[0]; + return _Left; + } + + _TEMPLATE_CLASS_INTEGRAL(_Ty) + constexpr _Base128& operator>>=(const _Ty _Count) noexcept { + _Unsigned_right_shift(static_cast(_Count)); + return *this; + } + + _TEMPLATE_CLASS_INTEGRAL(_Ty) + friend constexpr _Ty& operator>>=(_Ty& _Left, const _Base128& _Right) noexcept { + _Left >>= _Right._Word[0]; + return _Left; + } + + constexpr _Base128& operator++() noexcept { + if (++_Word[0] == 0) { + ++_Word[1]; + } + return *this; + } + constexpr _Base128 operator++(int) noexcept { + auto _Tmp = *this; + ++*this; + return _Tmp; + } + + constexpr _Base128& operator--() noexcept { + if (_Word[0]-- == 0) { + --_Word[1]; + } + return *this; + } + constexpr _Base128 operator--(int) noexcept { + auto _Tmp = *this; + --*this; + return _Tmp; + } + + _NODISCARD static constexpr _Base128 _Multiply(const _Base128& _Left, const _Base128& _Right) noexcept { + _Base128 _Result; + _Result._Word[0] = _UMul128(_Left._Word[0], _Right._Word[0], _Result._Word[1]); + _Result._Word[1] += _Left._Word[0] * _Right._Word[1]; + _Result._Word[1] += _Left._Word[1] * _Right._Word[0]; + return _Result; + } + +#if !_STL_128_DIV_INTRINSICS + _NODISCARD static constexpr _Base128 _Divide(const _Base128& _Num, const uint32_t _Den) noexcept { + _Base128 _Result; + _Result._Word[1] = _Num._Word[1] / _Den; + uint64_t _Rem = ((_Num._Word[1] % _Den) << 32) | (_Num._Word[0] >> 32); + _Result._Word[0] = (_Rem / _Den) << 32; + _Rem = ((_Rem % _Den) << 32) | static_cast(_Num._Word[0]); + _Result._Word[0] |= static_cast(_Rem / _Den); + return _Result; + } +#endif // !_STL_128_DIV_INTRINSICS + _NODISCARD static constexpr _Base128 _Divide(const _Base128& _Num, const uint64_t _Den) noexcept { + _Base128 _Result; + _Result._Word[1] = _Num._Word[1] / _Den; + uint64_t _Rem _ZERO_OR_NO_INIT; + _Result._Word[0] = _UDiv128(_Num._Word[1] % _Den, _Num._Word[0], _Den, _Rem); + return _Result; + } + _NODISCARD static constexpr _Base128 _Divide(_Base128 _Num, _Base128 _Den) noexcept { + // establish _Den < _Num and _Num._Word[1] > 0 + if (_Den._Word[1] >= _Num._Word[1]) { + if (_Den._Word[1] > _Num._Word[1]) { + return 0; + } + + return _Num._Word[1] == 0 ? _Num._Word[0] / _Den._Word[0] : _Num._Word[0] >= _Den._Word[0]; + } + + // establish _Den has more than 1 non-zero "digit" + if (_Den._Word[1] == 0) { +#if !_STL_128_DIV_INTRINSICS + if (_Den._Word[0] < (1ull << 32)) { + return _Divide(_Num, static_cast(_Den._Word[0])); + } else +#endif // !_STL_128_DIV_INTRINSICS + { + return _Divide(_Num, _Den._Word[0]); + } + } + +#if _STL_128_INTRINSICS + // Knuth 4.3.1D, 2-digit by 2-digit divide in base 2^64 + // _STL_INTERNAL_CHECK(_Den._Word[1] != 0); + // _STL_INTERNAL_CHECK(_Num._Word[1] > _Den._Word[1]); + // Normalize by shifting both left until _Den's high bit is set (So _Den's high digit is >= b / 2) + const auto __d = _Countl_zero(_Den._Word[1]); + _Den <<= __d; + auto _High_digit = __d == 0 ? 0 : _Num._Word[1] >> (64 - __d); // This creates a third digit for _Num + _Num <<= __d; + + _Base128 __qhat; + __qhat._Word[1] = _High_digit >= _Den._Word[1]; + uint64_t __rhat _ZERO_OR_NO_INIT; + __qhat._Word[0] = _UDiv128(_High_digit >= _Den._Word[1] ? _High_digit - _Den._Word[1] : _High_digit, + _Num._Word[1], _Den._Word[1], __rhat); + + for (;;) { + if (__qhat._Word[1] > 0) { + --__qhat; + } else { + _Base128 _Prod; + _Prod._Word[0] = _UMul128(__qhat._Word[0], _Den._Word[0], _Prod._Word[1]); + if (_Prod <= _Base128{_Num._Word[0], __rhat}) { + break; + } + --__qhat._Word[0]; + } + + const auto _Sum = __rhat + _Den._Word[1]; + if (__rhat > _Sum) { + break; + } + __rhat = _Sum; + } + // _STL_INTERNAL_CHECK(__qhat._Word[1] == 0); + + // [_High_digit | _Num] -= __qhat * _Den [Since __qhat < b, this is 3-digit - 1-digit * 2-digit] + uint64_t _Prod0_hi _ZERO_OR_NO_INIT; + uint64_t _Prod_lo = _UMul128(__qhat._Word[0], _Den._Word[0], _Prod0_hi); + auto _Borrow = _SubBorrow64(0, _Num._Word[0], _Prod_lo, _Num._Word[0]); + uint64_t _Prod1_hi _ZERO_OR_NO_INIT; + _Prod_lo = _UMul128(__qhat._Word[0], _Den._Word[1], _Prod1_hi); + _Prod1_hi += _AddCarry64(0, _Prod_lo, _Prod0_hi, _Prod_lo); + _Borrow = _SubBorrow64(_Borrow, _Num._Word[1], _Prod_lo, _Num._Word[1]); + _Borrow = _SubBorrow64(_Borrow, _High_digit, _Prod1_hi, _High_digit); + if (_Borrow) { + --__qhat._Word[0]; + } + return __qhat; +#else // ^^^ 128-bit intrinsics / no such intrinsics vvv + auto __d = _Countl_zero(_Den._Word[1]); + const bool _Three_word_den = __d >= 32; + __d &= 31; + uint32_t __u[5]{ + static_cast(_Num._Word[0] << __d), + static_cast(_Num._Word[0] >> (32 - __d)), + static_cast(_Num._Word[1] << __d), + static_cast(_Num._Word[1] >> (32 - __d)), + 0, + }; + uint32_t __v[4] = { + static_cast(_Den._Word[0] << __d), + static_cast(_Den._Word[0] >> (32 - __d)), + static_cast(_Den._Word[1] << __d), + static_cast(_Den._Word[1] >> (32 - __d)), + }; + if (__d != 0) { + __u[2] |= _Num._Word[0] >> (64 - __d); + __u[4] |= _Num._Word[1] >> (64 - __d); + __v[2] |= _Den._Word[0] >> (64 - __d); + } + + uint32_t __q[2] _ZERO_OR_NO_INIT; + if (_Three_word_den) { + // 4-digit by 3-digit base 2^32 division + _Knuth_4_3_1_D(__u, 5, __v, 3, __q); + } else { + // 4-digit by 4-digit base 2^32 division + _Knuth_4_3_1_D(__u, 5, __v, 4, __q); + __q[1] = 0; + } + + return (static_cast(__q[1]) << 32) | __q[0]; +#endif // _STL_128_INTRINSICS + } + +#if !_STL_128_DIV_INTRINSICS + _NODISCARD static constexpr _Base128 _Modulo(const _Base128& _Num, const uint32_t _Den) noexcept { + uint64_t _Rem = _Num._Word[1]; + _Rem = ((_Rem % _Den) << 32) | (_Num._Word[0] >> 32); + _Rem = ((_Rem % _Den) << 32) | static_cast(_Num._Word[0]); + return _Rem % _Den; + } +#endif // !_STL_128_DIV_INTRINSICS + _NODISCARD static constexpr _Base128 _Modulo(const _Base128& _Num, const uint64_t _Den) noexcept { + uint64_t _Rem _ZERO_OR_NO_INIT; + (void) _UDiv128(_Num._Word[1] % _Den, _Num._Word[0], _Den, _Rem); + return _Rem; + } + _NODISCARD static constexpr _Base128 _Modulo(_Base128 _Num, _Base128 _Den) noexcept { + // establish _Den < _Num and _Num._Word[1] > 0 + if (_Den._Word[1] >= _Num._Word[1]) { + if (_Den._Word[1] > _Num._Word[1]) { + return _Num; + } + + if (_Den._Word[0] <= _Num._Word[0]) { + return _Num._Word[1] == 0 ? _Num._Word[0] % _Den._Word[0] : _Num._Word[0] - _Den._Word[0]; + } + + return _Num; + } + + // establish _Den has more than 1 non-zero "digit" + if (_Den._Word[1] == 0) { +#if !_STL_128_DIV_INTRINSICS + if (_Den._Word[0] < (1ull << 32)) { + return _Modulo(_Num, static_cast(_Den._Word[0])); + } else +#endif // !_STL_128_DIV_INTRINSICS + { + return _Modulo(_Num, _Den._Word[0]); + } + } + +#if _STL_128_INTRINSICS + // Knuth 4.3.1D, 2-digit by 2-digit divide in base 2^64 + // _STL_INTERNAL_CHECK(_Den._Word[1] != 0); + // _STL_INTERNAL_CHECK(_Num._Word[1] > _Den._Word[1]); + // Normalize by shifting both left until _Den's high bit is set (So _Den's high digit is >= b / 2) + const auto __d = _Countl_zero(_Den._Word[1]); + _Den <<= __d; + auto _High_digit = __d == 0 ? 0 : _Num._Word[1] >> (64 - __d); // This creates a third digit for _Num + _Num <<= __d; + + uint64_t __qhat_high = _High_digit >= _Den._Word[1]; + uint64_t __rhat _ZERO_OR_NO_INIT; + uint64_t __qhat = _UDiv128(_High_digit >= _Den._Word[1] ? _High_digit - _Den._Word[1] : _High_digit, + _Num._Word[1], _Den._Word[1], __rhat); + + for (;;) { + if (__qhat_high > 0) { + if (__qhat-- == 0) { + --__qhat_high; + } + } else { + _Base128 _Prod; + _Prod._Word[0] = _UMul128(__qhat, _Den._Word[0], _Prod._Word[1]); + if (_Prod <= _Base128{_Num._Word[0], __rhat}) { + break; + } + --__qhat; + } + + const auto _Sum = __rhat + _Den._Word[1]; + if (__rhat > _Sum) { + break; + } + __rhat = _Sum; + // The addition didn't overflow, so `__rhat < b` holds + } + // _STL_INTERNAL_CHECK(__qhat_high == 0); + + // [_High_digit | _Num] -= __qhat * _Den [3-digit - 1-digit * 2-digit] + uint64_t _Prod0_hi _ZERO_OR_NO_INIT; + uint64_t _Prod_lo = _UMul128(__qhat, _Den._Word[0], _Prod0_hi); + auto _Borrow = _SubBorrow64(0, _Num._Word[0], _Prod_lo, _Num._Word[0]); + uint64_t _Prod1_hi _ZERO_OR_NO_INIT; + _Prod_lo = _UMul128(__qhat, _Den._Word[1], _Prod1_hi); + _Prod1_hi += _AddCarry64(0, _Prod_lo, _Prod0_hi, _Prod_lo); + _Borrow = _SubBorrow64(_Borrow, _Num._Word[1], _Prod_lo, _Num._Word[1]); + _Borrow = _SubBorrow64(_Borrow, _High_digit, _Prod1_hi, _High_digit); + if (_Borrow) { + auto _Carry = _AddCarry64(0, _Num._Word[0], _Den._Word[0], _Num._Word[0]); + (void) _AddCarry64(_Carry, _Num._Word[1], _Den._Word[1], _Num._Word[1]); + } +#else // ^^^ 128-bit intrinsics / no such intrinsics vvv + auto __d = _Countl_zero(_Den._Word[1]); + const bool _Three_word_den = __d >= 32; + __d &= 31; + uint32_t __u[5]{ + static_cast(_Num._Word[0] << __d), + static_cast(_Num._Word[0] >> (32 - __d)), + static_cast(_Num._Word[1] << __d), + static_cast(_Num._Word[1] >> (32 - __d)), + 0, + }; + uint32_t __v[4] = { + static_cast(_Den._Word[0] << __d), + static_cast(_Den._Word[0] >> (32 - __d)), + static_cast(_Den._Word[1] << __d), + static_cast(_Den._Word[1] >> (32 - __d)), + }; + if (__d != 0) { + __u[2] |= _Num._Word[0] >> (64 - __d); + __u[4] |= _Num._Word[1] >> (64 - __d); + __v[2] |= _Den._Word[0] >> (64 - __d); + } + + uint32_t __q[2] _ZERO_OR_NO_INIT; + if (_Three_word_den) { + // 4-digit by 3-digit base 2^32 division + _Knuth_4_3_1_D(__u, 5, __v, 3, __q); + // _STL_INTERNAL_CHECK(__u[3] == 0); + } else { + // 4-digit by 4-digit base 2^32 division + _Knuth_4_3_1_D(__u, 5, __v, 4, __q); + } + // _STL_INTERNAL_CHECK(__u[4] == 0); + + _Num._Word[0] = (static_cast(__u[1]) << 32) | __u[0]; + _Num._Word[1] = (static_cast(__u[3]) << 32) | __u[2]; +#endif // _STL_128_INTRINSICS + _Num >>= __d; + return _Num; + } + +#if _HAS_CXX23 +#if !_STL_128_DIV_INTRINSICS + _NODISCARD static constexpr _Base128 _Div_ceil(const _Base128& _Num, const uint32_t _Den) noexcept { + _Base128 _Result; + _Result._Word[1] = _Num._Word[1] / _Den; + uint64_t _Rem = ((_Num._Word[1] % _Den) << 32) | (_Num._Word[0] >> 32); + _Result._Word[0] = (_Rem / _Den) << 32; + _Rem = ((_Rem % _Den) << 32) | static_cast(_Num._Word[0]); + _Result._Word[0] |= static_cast(_Rem / _Den); + if (_Rem % _Den != 0) { + ++_Result; + } + + return _Result; + } +#endif // !_STL_128_DIV_INTRINSICS + + _NODISCARD static constexpr _Base128 _Div_ceil(const _Base128& _Num, const uint64_t _Den) noexcept { + _Base128 _Result; + _Result._Word[1] = _Num._Word[1] / _Den; + uint64_t _Rem; + _Result._Word[0] = _UDiv128(_Num._Word[1] % _Den, _Num._Word[0], _Den, _Rem); + if (_Rem != 0) { + ++_Result; + } + + return _Result; + } + + _NODISCARD static constexpr _Base128 _Div_ceil(_Base128 _Num, _Base128 _Den) noexcept { + // establish _Den < _Num and _Num._Word[1] > 0 + if (_Den._Word[1] >= _Num._Word[1]) { + if (_Den._Word[1] > _Num._Word[1]) { + return static_cast<_Base128>(_Num != 0); + } + + if (_Num._Word[1] == 0) { + uint64_t _Result = _Num._Word[0] / _Den._Word[0]; // with 64-bit inputs, the ceiling is also 64-bit + if (_Num._Word[0] % _Den._Word[0] != 0) { + ++_Result; + } + + return _Result; + } + + if (_Num._Word[0] > _Den._Word[0]) { + return 2u; + } + + return 1u; + } + + // establish _Den has more than 1 non-zero "digit" + if (_Den._Word[1] == 0) { +#if !_STL_128_DIV_INTRINSICS + if (_Den._Word[0] < (1ull << 32)) { + return _Div_ceil(_Num, static_cast(_Den._Word[0])); + } else +#endif // !_STL_128_DIV_INTRINSICS + { + return _Div_ceil(_Num, _Den._Word[0]); + } + } + + _Base128 _Result; +#if _STL_128_INTRINSICS + // Knuth 4.3.1D, 2-digit by 2-digit divide in base 2^64 + // _STL_INTERNAL_CHECK(_Den._Word[1] != 0); + // _STL_INTERNAL_CHECK(_Num._Word[1] > _Den._Word[1]); + // Normalize by shifting both left until _Den's high bit is set (So _Den's high digit is >= b / 2) + const auto __d = _STD _Countl_zero(_Den._Word[1]); + _Den <<= __d; + auto _High_digit = __d == 0 ? 0 : _Num._Word[1] >> (64 - __d); // This creates a third digit for _Num + _Num <<= __d; + + _Base128 __qhat; + __qhat._Word[1] = _High_digit >= _Den._Word[1]; + uint64_t __rhat; + __qhat._Word[0] = _UDiv128(_High_digit >= _Den._Word[1] ? _High_digit - _Den._Word[1] : _High_digit, + _Num._Word[1], _Den._Word[1], __rhat); + + for (;;) { + if (__qhat._Word[1] > 0) { + --__qhat; + } else { + _Base128 _Prod; + _Prod._Word[0] = _UMul128(__qhat._Word[0], _Den._Word[0], _Prod._Word[1]); + if (_Prod <= _Base128{_Num._Word[0], __rhat}) { + break; + } + --__qhat._Word[0]; + } + + const auto _Sum = __rhat + _Den._Word[1]; + if (__rhat > _Sum) { + break; + } + __rhat = _Sum; + } + // _STL_INTERNAL_CHECK(__qhat._Word[1] == 0); + + // [_High_digit | _Num] -= __qhat * _Den [Since __qhat < b, this is 3-digit - 1-digit * 2-digit] + uint64_t _Prod0_hi; + uint64_t _Prod_lo = _UMul128(__qhat._Word[0], _Den._Word[0], _Prod0_hi); + auto _Borrow = _SubBorrow64(0, _Num._Word[0], _Prod_lo, _Num._Word[0]); + uint64_t _Prod1_hi; + _Prod_lo = _UMul128(__qhat._Word[0], _Den._Word[1], _Prod1_hi); + _Prod1_hi += _AddCarry64(0, _Prod_lo, _Prod0_hi, _Prod_lo); + _Borrow = _SubBorrow64(_Borrow, _Num._Word[1], _Prod_lo, _Num._Word[1]); + _Borrow = _SubBorrow64(_Borrow, _High_digit, _Prod1_hi, _High_digit); + if (_Borrow) { + --__qhat._Word[0]; + auto _Carry = _AddCarry64(0, _Num._Word[0], _Den._Word[0], _Num._Word[0]); + (void) _AddCarry64(_Carry, _Num._Word[1], _Den._Word[1], _Num._Word[1]); + } + _Result = __qhat; +#else // ^^^ 128-bit intrinsics / no such intrinsics vvv + auto __d = _Countl_zero(_Den._Word[1]); + const bool _Three_word_den = __d >= 32; + __d &= 31; + uint32_t __u[5]{ + static_cast(_Num._Word[0] << __d), + static_cast(_Num._Word[0] >> (32 - __d)), + static_cast(_Num._Word[1] << __d), + static_cast(_Num._Word[1] >> (32 - __d)), + 0, + }; + uint32_t __v[4] = { + static_cast(_Den._Word[0] << __d), + static_cast(_Den._Word[0] >> (32 - __d)), + static_cast(_Den._Word[1] << __d), + static_cast(_Den._Word[1] >> (32 - __d)), + }; + if (__d != 0) { + __u[2] |= _Num._Word[0] >> (64 - __d); + __u[4] |= _Num._Word[1] >> (64 - __d); + __v[2] |= _Den._Word[0] >> (64 - __d); + } + + uint32_t __q[2] = {}; + if (_Three_word_den) { + // 4-digit by 3-digit base 2^32 division + _Knuth_4_3_1_D(__u, 5, __v, 3, __q); + // _STL_INTERNAL_CHECK(__u[3] == 0); + } else { + // 4-digit by 4-digit base 2^32 division + _Knuth_4_3_1_D(__u, 5, __v, 4, __q); + } + + _Result = (static_cast(__q[1]) << 32) | __q[0]; + _Num._Word[0] = (static_cast(__u[1]) << 32) | __u[0]; + _Num._Word[1] = (static_cast(__u[3]) << 32) | __u[2]; +#endif // _STL_128_INTRINSICS + + if (_Num != 0) { + ++_Result; + } + + return _Result; + } +#endif // _HAS_CXX23 + + _TEMPLATE_CLASS_INTEGRAL(_Ty) + friend constexpr _Ty& operator&=(_Ty& _Left, const _Base128& _Right) noexcept { + _Left &= _Right._Word[0]; + return _Left; + } + + _TEMPLATE_CLASS_INTEGRAL(_Ty) + friend constexpr _Ty& operator^=(_Ty& _Left, const _Base128& _Right) noexcept { + _Left ^= _Right._Word[0]; + return _Left; + } + + _TEMPLATE_CLASS_INTEGRAL(_Ty) + friend constexpr _Ty& operator|=(_Ty& _Left, const _Base128& _Right) noexcept { + _Left |= _Right._Word[0]; + return _Left; + } +}; + +struct _Signed128; + +struct _Unsigned128 : _Base128 { + using _Signed_type = _Signed128; + using _Unsigned_type = _Unsigned128; + +#if !_HAS_CXX17 || (_HAS_CXX20 && !defined(__clang__) && !defined(__EDG__)) // TRANSITION, DevCom-10729775 + constexpr _Unsigned128() noexcept : _Base128{} {} +#endif // ^^^ workaround for C++20 MSVC modules and header units; should be guarded for !_HAS_CXX17 only ^^^ + + using _Base128::_Base128; + constexpr explicit _Unsigned128(const _Base128& _That) noexcept : _Base128{_That} {} + + constexpr _Unsigned128& operator=(const _Base128& _That) noexcept { + _Base128::operator=(_That); + return *this; + } + +#if _HAS_CXX20 + _NODISCARD friend constexpr strong_ordering operator<=>( + const _Unsigned128& _Left, const _Unsigned128& _Right) noexcept { + strong_ordering _Ord = _Left._Word[1] <=> _Right._Word[1]; + if (_Ord == strong_ordering::equal) { + _Ord = _Left._Word[0] <=> _Right._Word[0]; + } + return _Ord; + } +#else // ^^^ _HAS_CXX20 / !_HAS_CXX20 vvv + _NODISCARD friend constexpr bool operator<(const _Unsigned128& _Left, const _Unsigned128& _Right) noexcept { + if (_Left._Word[1] < _Right._Word[1]) { + return true; + } + + if (_Right._Word[1] < _Left._Word[1]) { + return false; + } + + return _Left._Word[0] < _Right._Word[0]; + } + + _NODISCARD friend constexpr bool operator>(const _Unsigned128& _Left, const _Unsigned128& _Right) noexcept { + return _Right < _Left; + } + + _NODISCARD friend constexpr bool operator<=(const _Unsigned128& _Left, const _Unsigned128& _Right) noexcept { + return !(_Right < _Left); + } + + _NODISCARD friend constexpr bool operator>=(const _Unsigned128& _Left, const _Unsigned128& _Right) noexcept { + return !(_Left < _Right); + } +#endif // ^^^ !_HAS_CXX20 ^^^ + + _NODISCARD friend constexpr _Unsigned128 operator<<(const _Unsigned128& _Left, const _Base128& _Right) noexcept { + auto _Tmp{_Left}; + _Tmp._Left_shift(static_cast(_Right._Word[0])); + return _Tmp; + } + + _TEMPLATE_CLASS_INTEGRAL(_Ty) + constexpr _Unsigned128& operator<<=(const _Ty _Count) noexcept { + _Left_shift(static_cast(_Count)); + return *this; + } + constexpr _Unsigned128& operator<<=(const _Base128& _Count) noexcept { + _Left_shift(static_cast(_Count._Word[0])); + return *this; + } + + _NODISCARD friend constexpr _Unsigned128 operator>>(const _Unsigned128& _Left, const _Base128& _Right) noexcept { + auto _Tmp{_Left}; + _Tmp._Unsigned_right_shift(static_cast(_Right._Word[0])); + return _Tmp; + } + + _TEMPLATE_CLASS_INTEGRAL(_Ty) + constexpr _Unsigned128& operator>>=(const _Ty _Count) noexcept { + _Unsigned_right_shift(static_cast(_Count)); + return *this; + } + constexpr _Unsigned128& operator>>=(const _Base128& _Count) noexcept { + _Unsigned_right_shift(static_cast(_Count._Word[0])); + return *this; + } + + constexpr _Unsigned128& operator++() noexcept { + if (++_Word[0] == 0) { + ++_Word[1]; + } + return *this; + } + constexpr _Unsigned128 operator++(int) noexcept { + auto _Tmp = *this; + ++*this; + return _Tmp; + } + + constexpr _Unsigned128& operator--() noexcept { + if (_Word[0]-- == 0) { + --_Word[1]; + } + return *this; + } + constexpr _Unsigned128 operator--(int) noexcept { + auto _Tmp = *this; + --*this; + return _Tmp; + } + + _NODISCARD constexpr _Unsigned128 operator+() const noexcept { + return *this; + } + + _NODISCARD constexpr _Unsigned128 operator-() const noexcept { + return _Unsigned128{} - *this; + } + + _NODISCARD constexpr _Unsigned128 operator~() const noexcept { + return _Unsigned128{~_Word[0], ~_Word[1]}; + } + + _NODISCARD friend constexpr _Unsigned128 operator+(const _Base128& _Left, const _Base128& _Right) noexcept { + _Unsigned128 _Result; + const auto _Carry = _AddCarry64(0, _Left._Word[0], _Right._Word[0], _Result._Word[0]); + _AddCarry64(_Carry, _Left._Word[1], _Right._Word[1], _Result._Word[1]); + return _Result; + } + + constexpr _Unsigned128& operator+=(const _Base128& _That) noexcept { + const auto _Carry = _AddCarry64(0, _Word[0], _That._Word[0], _Word[0]); + _AddCarry64(_Carry, _Word[1], _That._Word[1], _Word[1]); + return *this; + } + _TEMPLATE_CLASS_INTEGRAL(_Ty) + friend constexpr _Ty& operator+=(_Ty& _Left, const _Unsigned128& _Right) noexcept { + _Left += _Right._Word[0]; + return _Left; + } + + _NODISCARD friend constexpr _Unsigned128 operator-(const _Base128& _Left, const _Base128& _Right) noexcept { + _Unsigned128 _Result; + const auto _Borrow = _SubBorrow64(0, _Left._Word[0], _Right._Word[0], _Result._Word[0]); + _SubBorrow64(_Borrow, _Left._Word[1], _Right._Word[1], _Result._Word[1]); + return _Result; + } + + constexpr _Unsigned128& operator-=(const _Base128& _That) noexcept { + const auto _Borrow = _SubBorrow64(0, _Word[0], _That._Word[0], _Word[0]); + _SubBorrow64(_Borrow, _Word[1], _That._Word[1], _Word[1]); + return *this; + } + _TEMPLATE_CLASS_INTEGRAL(_Ty) + friend constexpr _Ty& operator-=(_Ty& _Left, const _Unsigned128& _Right) noexcept { + _Left -= _Right._Word[0]; + return _Left; + } + + _NODISCARD friend constexpr _Unsigned128 operator*(const _Base128& _Left, const _Base128& _Right) noexcept { + return _Unsigned128{_Base128::_Multiply(_Left, _Right)}; + } + + constexpr _Unsigned128& operator*=(const _Base128& _That) noexcept { + *this = *this * _That; + return *this; + } + _TEMPLATE_CLASS_INTEGRAL(_Ty) + friend constexpr _Ty& operator*=(_Ty& _Left, const _Unsigned128& _Right) noexcept { + _Left *= _Right._Word[0]; + return _Left; + } + + _TEMPLATE_CLASS_INTEGRAL(_Ty) + _NODISCARD friend constexpr _Unsigned128 operator/(const _Unsigned128& _Num, const _Ty _Den) noexcept { +#if !_STL_128_DIV_INTRINSICS + if constexpr (sizeof(_Ty) <= 4) { + return _Unsigned128{_Base128::_Divide(_Num, static_cast(_Den))}; + } else +#endif // !_STL_128_DIV_INTRINSICS + { + return _Unsigned128{_Base128::_Divide(_Num, static_cast(_Den))}; + } + } + _NODISCARD friend constexpr _Unsigned128 operator/(const _Base128& _Num, const _Base128& _Den) noexcept { + return _Unsigned128{_Base128::_Divide(_Num, _Den)}; + } + + _TEMPLATE_CLASS_INTEGRAL(_Ty) + constexpr _Unsigned128& operator/=(const _Ty _That) noexcept { +#if !_STL_128_DIV_INTRINSICS + if constexpr (sizeof(_Ty) <= 4) { + *this = _Unsigned128{_Base128::_Divide(*this, static_cast(_That))}; + } else +#endif // !_STL_128_DIV_INTRINSICS + { + *this = _Unsigned128{_Base128::_Divide(*this, static_cast(_That))}; + } + return *this; + } + constexpr _Unsigned128& operator/=(const _Base128& _That) noexcept { + *this = _Unsigned128{_Base128::_Divide(*this, _That)}; + return *this; + } + _TEMPLATE_CLASS_INTEGRAL(_Ty) + friend constexpr _Ty& operator/=(_Ty& _Left, const _Unsigned128& _Right) noexcept { + if (_Right._Word[1] != 0) { + _Left = 0; + } else { + _Left /= _Right._Word[0]; + } + return _Left; + } + + _TEMPLATE_CLASS_INTEGRAL(_Ty) + _NODISCARD friend constexpr _Unsigned128 operator%(const _Base128& _Num, const _Ty _Den) noexcept { +#if !_STL_128_DIV_INTRINSICS + if constexpr (sizeof(_Ty) <= 4) { + return _Unsigned128{_Base128::_Modulo(_Num, static_cast(_Den))}; + } else +#endif // !_STL_128_DIV_INTRINSICS + { + return _Unsigned128{_Base128::_Modulo(_Num, static_cast(_Den))}; + } + } + _NODISCARD friend constexpr _Unsigned128 operator%(const _Base128& _Num, const _Base128& _Den) noexcept { + return _Unsigned128{_Base128::_Modulo(_Num, _Den)}; + } + + _TEMPLATE_CLASS_INTEGRAL(_Ty) + constexpr _Unsigned128& operator%=(const _Ty _Den) noexcept { + *this = *this % _Den; + return *this; + } + constexpr _Unsigned128& operator%=(const _Base128& _Den) noexcept { + *this = *this % _Den; + return *this; + } + _TEMPLATE_CLASS_INTEGRAL(_Ty) + friend constexpr _Ty& operator%=(_Ty& _Left, const _Unsigned128& _Right) noexcept { + if (_Right._Word[1] == 0) { + _Left %= _Right._Word[0]; + } + return _Left; + } + + _NODISCARD friend constexpr _Unsigned128 operator&(const _Base128& _Left, const _Base128& _Right) noexcept { + return _Unsigned128{_Left._Word[0] & _Right._Word[0], _Left._Word[1] & _Right._Word[1]}; + } + + constexpr _Unsigned128& operator&=(const _Base128& _That) noexcept { + _Word[0] &= _That._Word[0]; + _Word[1] &= _That._Word[1]; + return *this; + } + + _NODISCARD friend constexpr _Unsigned128 operator^(const _Base128& _Left, const _Base128& _Right) noexcept { + return _Unsigned128{_Left._Word[0] ^ _Right._Word[0], _Left._Word[1] ^ _Right._Word[1]}; + } + + constexpr _Unsigned128& operator^=(const _Base128& _That) noexcept { + _Word[0] ^= _That._Word[0]; + _Word[1] ^= _That._Word[1]; + return *this; + } + + _NODISCARD friend constexpr _Unsigned128 operator|(const _Base128& _Left, const _Base128& _Right) noexcept { + return _Unsigned128{_Left._Word[0] | _Right._Word[0], _Left._Word[1] | _Right._Word[1]}; + } + + constexpr _Unsigned128& operator|=(const _Base128& _That) noexcept { + _Word[0] |= _That._Word[0]; + _Word[1] |= _That._Word[1]; + return *this; + } +}; + +template <> +class numeric_limits<_Unsigned128> : public _Num_int_base { +public: + _NODISCARD static constexpr _Unsigned128(min)() noexcept { + return 0; + } + + _NODISCARD static constexpr _Unsigned128(max)() noexcept { + return _Unsigned128{~0ull, ~0ull}; + } + + _NODISCARD static constexpr _Unsigned128 lowest() noexcept { + return (min) (); + } + + _NODISCARD static constexpr _Unsigned128 epsilon() noexcept { + return 0; + } + + _NODISCARD static constexpr _Unsigned128 round_error() noexcept { + return 0; + } + + _NODISCARD static constexpr _Unsigned128 denorm_min() noexcept { + return 0; + } + + _NODISCARD static constexpr _Unsigned128 infinity() noexcept { + return 0; + } + + _NODISCARD static constexpr _Unsigned128 quiet_NaN() noexcept { + return 0; + } + + _NODISCARD static constexpr _Unsigned128 signaling_NaN() noexcept { + return 0; + } + + static constexpr bool is_modulo = true; + static constexpr int digits = 128; + static constexpr int digits10 = 38; +}; + +struct _Signed128 : _Base128 { + using _Signed_type = _Signed128; + using _Unsigned_type = _Unsigned128; + +#if !_HAS_CXX17 || (_HAS_CXX20 && !defined(__clang__) && !defined(__EDG__)) // TRANSITION, DevCom-10729775 + constexpr _Signed128() noexcept : _Base128{} {} +#endif // ^^^ workaround for C++20 MSVC modules and header units; should be guarded for !_HAS_CXX17 only ^^^ + + using _Base128::_Base128; + constexpr explicit _Signed128(const _Base128& _That) noexcept : _Base128{_That} {} + + constexpr _Signed128& operator=(const _Base128& _That) noexcept { + _Base128::operator=(_That); + return *this; + } + +#if _HAS_CXX20 + _NODISCARD friend constexpr strong_ordering operator<=>( + const _Signed128& _Left, const _Signed128& _Right) noexcept { + strong_ordering _Ord = static_cast(_Left._Word[1]) <=> static_cast(_Right._Word[1]); + if (_Ord == strong_ordering::equal) { + _Ord = _Left._Word[0] <=> _Right._Word[0]; + } + return _Ord; + } +#else // ^^^ _HAS_CXX20 / !_HAS_CXX20 vvv + _NODISCARD friend constexpr bool operator<(const _Signed128& _Left, const _Signed128& _Right) noexcept { + if (static_cast(_Left._Word[1]) < static_cast(_Right._Word[1])) { + return true; + } + + if (static_cast(_Right._Word[1]) < static_cast(_Left._Word[1])) { + return false; + } + + return _Left._Word[0] < _Right._Word[0]; + } + + _NODISCARD friend constexpr bool operator>(const _Signed128& _Left, const _Signed128& _Right) noexcept { + return _Right < _Left; + } + + _NODISCARD friend constexpr bool operator<=(const _Signed128& _Left, const _Signed128& _Right) noexcept { + return !(_Right < _Left); + } + + _NODISCARD friend constexpr bool operator>=(const _Signed128& _Left, const _Signed128& _Right) noexcept { + return !(_Left < _Right); + } +#endif // ^^^ !_HAS_CXX20 ^^^ + + _NODISCARD friend constexpr _Signed128 operator<<(const _Signed128& _Left, const _Base128& _Right) noexcept { + auto _Tmp{_Left}; + _Tmp._Left_shift(static_cast(_Right._Word[0])); + return _Tmp; + } + + _TEMPLATE_CLASS_INTEGRAL(_Ty) + constexpr _Signed128& operator<<=(const _Ty _Count) noexcept { + _Left_shift(static_cast(_Count)); + return *this; + } + constexpr _Signed128& operator<<=(const _Base128& _Count) noexcept { + _Left_shift(static_cast(_Count._Word[0])); + return *this; + } + + constexpr void _Signed_right_shift(const unsigned char _Count) noexcept { + if (_Count == 0) { + return; + } + + if (_Count >= 64) { + _Word[0] = static_cast(static_cast(_Word[1]) >> (_Count % 64)); + _Word[1] = (_Word[1] & (1ull << 63)) == 0 ? 0 : ~0ull; + return; + } + +#if _STL_128_INTRINSICS + if (!_Is_constant_evaluated()) { + _Word[0] = __shiftright128(_Word[0], _Word[1], _Count); + } else +#endif // _STL_128_INTRINSICS + { + _Word[0] = (_Word[0] >> _Count) | (_Word[1] << (64 - _Count)); + } + + _Word[1] = static_cast(static_cast(_Word[1]) >> _Count); + } + + _NODISCARD friend constexpr _Signed128 operator>>(const _Signed128& _Left, const _Base128& _Right) noexcept { + auto _Tmp{_Left}; + _Tmp._Signed_right_shift(static_cast(_Right._Word[0])); + return _Tmp; + } + + _TEMPLATE_CLASS_INTEGRAL(_Ty) + constexpr _Signed128& operator>>=(const _Ty _Count) noexcept { + _Signed_right_shift(static_cast(_Count)); + return *this; + } + constexpr _Signed128& operator>>=(const _Base128& _Count) noexcept { + _Signed_right_shift(static_cast(_Count._Word[0])); + return *this; + } + + constexpr _Signed128& operator++() noexcept { + if (++_Word[0] == 0) { + ++_Word[1]; + } + return *this; + } + constexpr _Signed128 operator++(int) noexcept { + auto _Tmp = *this; + ++*this; + return _Tmp; + } + + constexpr _Signed128& operator--() noexcept { + if (_Word[0]-- == 0) { + --_Word[1]; + } + return *this; + } + constexpr _Signed128 operator--(int) noexcept { + auto _Tmp = *this; + --*this; + return _Tmp; + } + + _NODISCARD constexpr _Signed128 operator+() const noexcept { + return *this; + } + + _NODISCARD constexpr _Signed128 operator-() const noexcept { + return _Signed128{} - *this; + } + + _NODISCARD constexpr _Signed128 operator~() const noexcept { + return _Signed128{~_Word[0], ~_Word[1]}; + } + + _NODISCARD friend constexpr _Signed128 operator+(const _Signed128& _Left, const _Signed128& _Right) noexcept { + _Signed128 _Result; + const auto _Carry = _AddCarry64(0, _Left._Word[0], _Right._Word[0], _Result._Word[0]); + _AddCarry64(_Carry, _Left._Word[1], _Right._Word[1], _Result._Word[1]); + return _Result; + } + + constexpr _Signed128& operator+=(const _Base128& _That) noexcept { + const auto _Carry = _AddCarry64(0, _Word[0], _That._Word[0], _Word[0]); + _AddCarry64(_Carry, _Word[1], _That._Word[1], _Word[1]); + return *this; + } + _TEMPLATE_CLASS_INTEGRAL(_Ty) + friend constexpr _Ty& operator+=(_Ty& _Left, const _Signed128& _Right) noexcept { + _Left = static_cast<_Ty>(_Signed128{_Left} + _Right); + return _Left; + } + + _NODISCARD friend constexpr _Signed128 operator-(const _Signed128& _Left, const _Signed128& _Right) noexcept { + _Signed128 _Result; + const auto _Borrow = _SubBorrow64(0, _Left._Word[0], _Right._Word[0], _Result._Word[0]); + _SubBorrow64(_Borrow, _Left._Word[1], _Right._Word[1], _Result._Word[1]); + return _Result; + } + + constexpr _Signed128& operator-=(const _Base128& _That) noexcept { + const auto _Borrow = _SubBorrow64(0, _Word[0], _That._Word[0], _Word[0]); + _SubBorrow64(_Borrow, _Word[1], _That._Word[1], _Word[1]); + return *this; + } + _TEMPLATE_CLASS_INTEGRAL(_Ty) + friend constexpr _Ty& operator-=(_Ty& _Left, const _Signed128& _Right) noexcept { + _Left = static_cast<_Ty>(_Signed128{_Left} - _Right); + return _Left; + } + + constexpr void _Strip_negative(bool& _Flip) noexcept { + if ((_Word[1] & (1ull << 63)) != 0) { + *this = -*this; + _Flip = !_Flip; + } + } + + _NODISCARD friend constexpr _Signed128 operator*(_Signed128 _Left, _Signed128 _Right) noexcept { + bool _Negative = false; + _Left._Strip_negative(_Negative); + _Right._Strip_negative(_Negative); + _Signed128 _Result{_Base128::_Multiply(_Left, _Right)}; + if (_Negative) { + _Result = -_Result; + } + return _Result; + } + + _TEMPLATE_CLASS_INTEGRAL(_Ty) + constexpr _Signed128& operator*=(const _Ty _That) noexcept { + *this = *this * _That; + return *this; + } + constexpr _Signed128& operator*=(const _Signed128& _That) noexcept { + *this = *this * _That; + return *this; + } + constexpr _Signed128& operator*=(const _Unsigned128& _That) noexcept { + *this = _Signed128{static_cast(*this) * _That}; + return *this; + } + _TEMPLATE_CLASS_INTEGRAL(_Ty) + friend constexpr _Ty& operator*=(_Ty& _Left, const _Signed128& _Right) noexcept { + _Left = static_cast<_Ty>(_Signed128{_Left} * _Right); + return _Left; + } + + _TEMPLATE_CLASS_INTEGRAL(_Ty) + _NODISCARD friend constexpr _Signed128 operator/(_Signed128 _Num, _Ty _Den) noexcept { + bool _Negative = false; + _Num._Strip_negative(_Negative); + if constexpr (is_signed_v<_Ty>) { + if (_Den < 0) { + _Den = -_Den; + _Negative = !_Negative; + } + } + + _Signed128 _Result; +#if !_STL_128_DIV_INTRINSICS + if constexpr (sizeof(_Ty) <= 4) { + _Result = _Signed128{_Base128::_Divide(_Num, static_cast(_Den))}; + } else +#endif // !_STL_128_DIV_INTRINSICS + { + _Result = _Signed128{_Base128::_Divide(_Num, static_cast(_Den))}; + } + + if (_Negative) { + _Result = -_Result; + } + return _Result; + } + _NODISCARD friend constexpr _Signed128 operator/(_Signed128 _Num, _Signed128 _Den) noexcept { + bool _Negative = false; + _Num._Strip_negative(_Negative); + _Den._Strip_negative(_Negative); + _Signed128 _Result{_Base128::_Divide(_Num, _Den)}; + if (_Negative) { + _Result = -_Result; + } + return _Result; + } + + _TEMPLATE_CLASS_INTEGRAL(_Ty) + constexpr _Signed128& operator/=(const _Ty _That) noexcept { + *this = *this / _That; + return *this; + } + constexpr _Signed128& operator/=(const _Signed128& _That) noexcept { + *this = *this / _That; + return *this; + } + constexpr _Signed128& operator/=(const _Unsigned128& _That) noexcept { + *this = _Signed128{static_cast<_Base128&>(*this) / _That}; + return *this; + } + _TEMPLATE_CLASS_INTEGRAL(_Ty) + friend constexpr _Ty& operator/=(_Ty& _Left, const _Signed128& _Right) noexcept { + _Left = static_cast<_Ty>(_Signed128{_Left} / _Right); + return _Left; + } + + _NODISCARD friend constexpr _Signed128 operator%(_Signed128 _Left, _Signed128 _Right) noexcept { + bool _Negative = false; + _Left._Strip_negative(_Negative); + + if ((_Right._Word[1] & (1ull << 63)) != 0) { + _Right = -_Right; + // intentionally not flipping _Negative + } + + _Unsigned128 _Result{_Base128::_Modulo(_Left, _Right)}; + if (_Negative) { + _Result = -_Result; + } + return _Signed128{_Result}; + } + + _TEMPLATE_CLASS_INTEGRAL(_Ty) + _NODISCARD friend constexpr _Signed128 operator%(_Signed128 _Left, const _Ty _Right) noexcept { + return _Left % _Signed128{_Right}; + } + + _TEMPLATE_CLASS_INTEGRAL(_Ty) + constexpr _Signed128& operator%=(const _Ty _That) noexcept { + *this = *this % _That; + return *this; + } + constexpr _Signed128& operator%=(const _Signed128& _That) noexcept { + *this = *this % _That; + return *this; + } + constexpr _Signed128& operator%=(const _Unsigned128& _That) noexcept { + *this = static_cast(*this) % _That; + return *this; + } + _TEMPLATE_CLASS_INTEGRAL(_Ty) + friend constexpr _Ty& operator%=(_Ty& _Left, const _Signed128& _Right) noexcept { + _Left = static_cast<_Ty>(_Signed128{_Left} % _Right); + return _Left; + } + +#if _HAS_CXX23 + _NODISCARD static constexpr _Signed128 _Div_ceil(_Signed128 _Num, _Signed128 _Den) noexcept { + // _STL_INTERNAL_CHECK(_Num >= 0); + // _STL_INTERNAL_CHECK(_Den > 0); + return _Signed128{_Base128::_Div_ceil(_Num, _Den)}; + } +#endif // _HAS_CXX23 + + _NODISCARD friend constexpr _Signed128 operator&(const _Signed128& _Left, const _Signed128& _Right) noexcept { + return _Signed128{_Left._Word[0] & _Right._Word[0], _Left._Word[1] & _Right._Word[1]}; + } + + constexpr _Signed128& operator&=(const _Base128& _That) noexcept { + _Word[0] &= _That._Word[0]; + _Word[1] &= _That._Word[1]; + return *this; + } + + _NODISCARD friend constexpr _Signed128 operator^(const _Signed128& _Left, const _Signed128& _Right) noexcept { + return _Signed128{_Left._Word[0] ^ _Right._Word[0], _Left._Word[1] ^ _Right._Word[1]}; + } + + constexpr _Signed128& operator^=(const _Base128& _That) noexcept { + _Word[0] ^= _That._Word[0]; + _Word[1] ^= _That._Word[1]; + return *this; + } + + _NODISCARD friend constexpr _Signed128 operator|(const _Signed128& _Left, const _Signed128& _Right) noexcept { + return _Signed128{_Left._Word[0] | _Right._Word[0], _Left._Word[1] | _Right._Word[1]}; + } + + constexpr _Signed128& operator|=(const _Base128& _That) noexcept { + _Word[0] |= _That._Word[0]; + _Word[1] |= _That._Word[1]; + return *this; + } +}; + +template <> +class numeric_limits<_Signed128> : public _Num_int_base { +public: + _NODISCARD static constexpr _Signed128(min)() noexcept { + return _Signed128{0ull, 1ull << 63}; + } + + _NODISCARD static constexpr _Signed128(max)() noexcept { + return _Signed128{~0ull, ~0ull >> 1}; + } + + _NODISCARD static constexpr _Signed128 lowest() noexcept { + return (min) (); + } + + _NODISCARD static constexpr _Signed128 epsilon() noexcept { + return 0; + } + + _NODISCARD static constexpr _Signed128 round_error() noexcept { + return 0; + } + + _NODISCARD static constexpr _Signed128 denorm_min() noexcept { + return 0; + } + + _NODISCARD static constexpr _Signed128 infinity() noexcept { + return 0; + } + + _NODISCARD static constexpr _Signed128 quiet_NaN() noexcept { + return 0; + } + + _NODISCARD static constexpr _Signed128 signaling_NaN() noexcept { + return 0; + } + + static constexpr int digits = 127; + static constexpr int digits10 = 38; + static constexpr bool is_signed = true; +}; + +template <> +struct common_type<_Signed128, _Unsigned128> { + using type = _Unsigned128; +}; +template <> +struct common_type<_Unsigned128, _Signed128> { + using type = _Unsigned128; +}; + +template +_NODISCARD constexpr _Ty _Min_limit() noexcept; + +template <> +_NODISCARD constexpr _Unsigned128 _Min_limit<_Unsigned128>() noexcept { + return 0; +} + +template <> +_NODISCARD constexpr _Signed128 _Min_limit<_Signed128>() noexcept { + return _Signed128{0ull, 1ull << 63}; +} + +template +_NODISCARD constexpr _Ty _Max_limit() noexcept; + +template <> +_NODISCARD constexpr _Unsigned128 _Max_limit<_Unsigned128>() noexcept { + return _Unsigned128{~0ull, ~0ull}; +} + +template <> +_NODISCARD constexpr _Signed128 _Max_limit<_Signed128>() noexcept { + return _Signed128{~0ull, ~0ull >> 1}; +} + +#undef _STL_128_INTRINSICS +#undef _STL_128_DIV_INTRINSICS + +_STD_END + +#undef _TEMPLATE_CLASS_INTEGRAL +#undef _ZERO_OR_NO_INIT + +#pragma pop_macro("new") +_STL_RESTORE_CLANG_WARNINGS +#pragma warning(pop) +#pragma pack(pop) +#endif // _STL_COMPILER_PREPROCESSOR +#endif // __MSVC_INT128_HPP diff --git a/stl/inc/__msvc_iter_core.hpp b/stl/inc/__msvc_iter_core.hpp new file mode 100644 index 00000000000..812c00cfc2d --- /dev/null +++ b/stl/inc/__msvc_iter_core.hpp @@ -0,0 +1,560 @@ +// __msvc_iter_core.hpp internal header (core) + +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#ifndef __MSVC_ITER_CORE_HPP +#define __MSVC_ITER_CORE_HPP +#include +#if _STL_COMPILER_PREPROCESSOR +#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 + +// TRANSITION, non-_Ugly attribute tokens +#pragma push_macro("msvc") +#pragma push_macro("no_specializations") +#undef msvc +#undef no_specializations + +_STD_BEGIN +template +struct _Has_allocator_type : false_type {}; // tests for suitable _Ty::allocator_type + +template +struct _Has_allocator_type<_Ty, _Alloc, void_t> + : is_convertible<_Alloc, typename _Ty::allocator_type>::type {}; + +_EXPORT_STD struct allocator_arg_t { // tag type for added allocator argument + explicit allocator_arg_t() = default; +}; + +_EXPORT_STD _INLINE_VAR constexpr allocator_arg_t allocator_arg{}; + +_EXPORT_STD template +struct uses_allocator : _Has_allocator_type<_Ty, _Alloc>::type {}; + +_EXPORT_STD template +_NO_SPECIALIZATIONS_OF_VARIABLE_TEMPLATES constexpr bool uses_allocator_v = uses_allocator<_Ty, _Alloc>::value; + +// from +_EXPORT_STD struct input_iterator_tag {}; + +_EXPORT_STD struct output_iterator_tag {}; + +_EXPORT_STD struct forward_iterator_tag : input_iterator_tag {}; + +_EXPORT_STD struct bidirectional_iterator_tag : forward_iterator_tag {}; + +_EXPORT_STD struct random_access_iterator_tag : bidirectional_iterator_tag {}; + +#if _HAS_CXX20 +_EXPORT_STD struct contiguous_iterator_tag : random_access_iterator_tag {}; + +template +using _With_reference = _Ty&; + +template +concept _Can_reference = requires { typename _With_reference<_Ty>; }; + +template +concept _Dereferenceable = requires(_Ty& __t) { + { *__t } -> _Can_reference; +}; + +template +concept _Has_member_iterator_concept = requires { typename _Ty::iterator_concept; }; + +template +concept _Has_member_iterator_category = requires { typename _Ty::iterator_category; }; + +template +concept _Has_member_value_type = requires { typename _Ty::value_type; }; + +template +concept _Has_member_element_type = requires { typename _Ty::element_type; }; + +template +concept _Has_member_difference_type = requires { typename _Ty::difference_type; }; + +template +concept _Has_member_pointer = requires { typename _Ty::pointer; }; + +template +concept _Has_member_reference = requires { typename _Ty::reference; }; + +_EXPORT_STD template +struct incrementable_traits {}; + +template + requires is_object_v<_Ty> +struct incrementable_traits<_Ty*> { + using difference_type = ptrdiff_t; +}; + +template +struct incrementable_traits : incrementable_traits<_Ty> {}; + +template <_Has_member_difference_type _Ty> +struct incrementable_traits<_Ty> { + using difference_type = _Ty::difference_type; +}; + +template +concept _Can_difference = requires(const _Ty& __a, const _Ty& __b) { + { __a - __b } -> integral; +}; + +template + requires (!_Has_member_difference_type<_Ty> && _Can_difference<_Ty>) +struct incrementable_traits<_Ty> { + using difference_type = make_signed_t() - _STD declval<_Ty>())>; +}; + +template +concept _Is_from_primary = _Same_impl; + +_EXPORT_STD template +struct iterator_traits; + +_EXPORT_STD template +using iter_difference_t = conditional_t<_Is_from_primary>>, + incrementable_traits>, iterator_traits>>::difference_type; + +template +struct _Cond_value_type {}; + +template + requires is_object_v<_Ty> +struct _Cond_value_type<_Ty> { + using value_type = remove_cv_t<_Ty>; +}; + +_EXPORT_STD template +struct indirectly_readable_traits {}; + +template +struct indirectly_readable_traits<_Ty*> : _Cond_value_type<_Ty> {}; + +template + requires is_array_v<_Ty> +struct indirectly_readable_traits<_Ty> { + using value_type = remove_cv_t>; +}; + +template +struct indirectly_readable_traits : indirectly_readable_traits<_Ty> {}; + +template <_Has_member_value_type _Ty> +struct indirectly_readable_traits<_Ty> : _Cond_value_type {}; + +template <_Has_member_element_type _Ty> +struct indirectly_readable_traits<_Ty> : _Cond_value_type {}; + +template <_Has_member_value_type _Ty> + requires _Has_member_element_type<_Ty> +struct indirectly_readable_traits<_Ty> {}; + +template <_Has_member_value_type _Ty> + requires _Has_member_element_type<_Ty> + && same_as, remove_cv_t> +struct indirectly_readable_traits<_Ty> : _Cond_value_type {}; + +_EXPORT_STD template +using iter_value_t = conditional_t<_Is_from_primary>>, + indirectly_readable_traits>, iterator_traits>>::value_type; + +_EXPORT_STD template <_Dereferenceable _Ty> +using iter_reference_t = decltype(*_STD declval<_Ty&>()); + +template +struct _Iterator_traits_base {}; + +template +concept _Has_iter_types = _Has_member_difference_type<_It> && _Has_member_value_type<_It> && _Has_member_reference<_It> + && _Has_member_iterator_category<_It>; + +template +struct _Old_iter_traits_pointer { + template + using _Apply = _It::pointer; +}; + +template <> +struct _Old_iter_traits_pointer { + template + using _Apply = void; +}; + +template <_Has_iter_types _It> +struct _Iterator_traits_base<_It> { + using iterator_category = _It::iterator_category; + using value_type = _It::value_type; + using difference_type = _It::difference_type; + using pointer = _Old_iter_traits_pointer<_Has_member_pointer<_It>>::template _Apply<_It>; + using reference = _It::reference; +}; + +template +struct _Iter_traits_difference { + template + using _Apply = incrementable_traits<_It>::difference_type; +}; + +template <> +struct _Iter_traits_difference { + template + using _Apply = void; +}; + +template +concept _Cpp17_iterator = requires(_It __i) { + { *__i } -> _Can_reference; + { ++__i } -> same_as<_It&>; + { *__i++ } -> _Can_reference; +} && copyable<_It>; + +template +concept _Cpp17_input_iterator = + _Cpp17_iterator<_It> && equality_comparable<_It> && _Has_member_difference_type> + && _Has_member_value_type> && requires(_It __i) { + typename common_reference_t&&, typename indirectly_readable_traits<_It>::value_type&>; + typename common_reference_t::value_type&>; + requires signed_integral::difference_type>; + }; + +template + requires (!_Has_iter_types<_It> && _Cpp17_iterator<_It> && !_Cpp17_input_iterator<_It>) +struct _Iterator_traits_base<_It> { + using iterator_category = output_iterator_tag; + using value_type = void; + using difference_type = + _Iter_traits_difference<_Has_member_difference_type>>::template _Apply<_It>; + using pointer = void; + using reference = void; +}; + +enum class _Itraits_pointer_strategy { _Use_void, _Use_member, _Use_decltype }; + +template <_Itraits_pointer_strategy> +struct _Iter_traits_pointer; + +template <> +struct _Iter_traits_pointer<_Itraits_pointer_strategy::_Use_void> { + template + using _Apply = void; +}; + +template <> +struct _Iter_traits_pointer<_Itraits_pointer_strategy::_Use_member> { + template + using _Apply = _It::pointer; +}; + +template <> +struct _Iter_traits_pointer<_Itraits_pointer_strategy::_Use_decltype> { + template + using _Apply = decltype(_STD declval<_It&>().operator->()); +}; + +template +concept _Has_member_arrow = requires(_Ty&& __t) { static_cast<_Ty &&>(__t).operator->(); }; + +template +struct _Iter_traits_reference { + template + using _Apply = _It::reference; +}; + +template <> +struct _Iter_traits_reference { + template + using _Apply = iter_reference_t<_It>; +}; + +template +struct _Iter_traits_category4 { + using type = random_access_iterator_tag; +}; + +template <> +struct _Iter_traits_category4 { + using type = bidirectional_iterator_tag; +}; + +template +concept _Cpp17_random_delta = +#if defined(__CUDACC__) && !defined(__clang__) // TRANSITION, fixed in CUDA 12.5 + totally_ordered<_It> && requires(_It __i, typename incrementable_traits<_It>::difference_type __n) { +#else // ^^^ workaround / no workaround vvv + totally_ordered<_It> && requires(_It __i, incrementable_traits<_It>::difference_type __n) { +#endif // ^^^ no workaround ^^^ + { __i += __n } -> same_as<_It&>; + { __i -= __n } -> same_as<_It&>; + { __i + __n } -> same_as<_It>; + { __n + __i } -> same_as<_It>; + { __i - __n } -> same_as<_It>; + { __i - __i } -> same_as; + { __i[__n] } -> convertible_to>; + }; + +template +struct _Iter_traits_category3 { + template + using _Apply = _Iter_traits_category4<_Cpp17_random_delta<_It>>::type; +}; + +template <> +struct _Iter_traits_category3 { + template + using _Apply = forward_iterator_tag; +}; + +template +concept _Cpp17_bidi_delta = requires(_It __i) { + { --__i } -> same_as<_It&>; + { __i-- } -> convertible_to; + requires same_as>; +}; + +template +struct _Iter_traits_category2 { + template + using _Apply = _Iter_traits_category3<_Cpp17_bidi_delta<_It>>::template _Apply<_It>; +}; + +template <> +struct _Iter_traits_category2 { + template + using _Apply = input_iterator_tag; +}; + +template +concept _Cpp17_forward_delta = + constructible_from<_It> && is_reference_v> + && same_as>, typename indirectly_readable_traits<_It>::value_type> + && requires(_It __i) { + { __i++ } -> convertible_to; + requires same_as>; + }; + +template +struct _Iter_traits_category { + template + using _Apply = _It::iterator_category; +}; + +template <> +struct _Iter_traits_category { + template + using _Apply = _Iter_traits_category2<_Cpp17_forward_delta<_It>>::template _Apply<_It>; +}; + +template + requires (!_Has_iter_types<_It> && _Cpp17_input_iterator<_It>) +struct _Iterator_traits_base<_It> { + using iterator_category = _Iter_traits_category<_Has_member_iterator_category<_It>>::template _Apply<_It>; + using value_type = indirectly_readable_traits<_It>::value_type; + using difference_type = incrementable_traits<_It>::difference_type; + using pointer = + _Iter_traits_pointer<(_Has_member_pointer<_It> ? _Itraits_pointer_strategy::_Use_member + : _Has_member_arrow<_It&> ? _Itraits_pointer_strategy::_Use_decltype + : _Itraits_pointer_strategy::_Use_void)>::template _Apply<_It>; + using reference = _Iter_traits_reference<_Has_member_reference<_It>>::template _Apply<_It>; +}; + +_EXPORT_STD template +struct iterator_traits : _Iterator_traits_base<_Ty> { + using _From_primary = iterator_traits; +}; + +template + requires is_object_v<_Ty> +struct iterator_traits<_Ty*> { + using iterator_concept = contiguous_iterator_tag; + using iterator_category = random_access_iterator_tag; + using value_type = remove_cv_t<_Ty>; + using difference_type = ptrdiff_t; + using pointer = _Ty*; + using reference = _Ty&; +}; + +template +constexpr bool _Integer_class = requires { + typename _Ty::_Signed_type; + typename _Ty::_Unsigned_type; +}; + +template +concept _Integer_like = _Is_nonbool_integral<_Ty> || _Integer_class<_Ty>; + +template +concept _Signed_integer_like = _Integer_like<_Ty> && static_cast<_Ty>(-1) < static_cast<_Ty>(0); + +_EXPORT_STD template +concept weakly_incrementable = movable<_Ty> && requires(_Ty __i) { + typename iter_difference_t<_Ty>; + requires _Signed_integer_like>; + { ++__i } -> same_as<_Ty&>; + __i++; +}; + +_EXPORT_STD template +concept input_or_output_iterator = requires(_It __i) { + { *__i } -> _Can_reference; +} && weakly_incrementable<_It>; + +_EXPORT_STD template +concept sentinel_for = semiregular<_Se> && input_or_output_iterator<_It> && _Weakly_equality_comparable_with<_Se, _It>; + +_EXPORT_STD template // specializations allowed by N5014 [iterator.concept.sizedsentinel]/3 +constexpr bool disable_sized_sentinel_for = false; + +_EXPORT_STD template +concept sized_sentinel_for = sentinel_for<_Se, _It> && !disable_sized_sentinel_for, remove_cv_t<_It>> + && requires(const _It& __i, const _Se& __s) { + { __s - __i } -> same_as>; + { __i - __s } -> same_as>; + }; + +_EXPORT_STD struct default_sentinel_t {}; + +_EXPORT_STD inline constexpr default_sentinel_t default_sentinel{}; + +namespace ranges { + _EXPORT_STD enum class subrange_kind : bool { unsized, sized }; + + _EXPORT_STD template _Se = _It, + subrange_kind _Ki = sized_sentinel_for<_Se, _It> ? subrange_kind::sized : subrange_kind::unsized> + requires (_Ki == subrange_kind::sized || !sized_sentinel_for<_Se, _It>) + class subrange; + + _EXPORT_STD template + requires ((_Idx == 0 && copyable<_It>) || _Idx == 1) + _NODISCARD constexpr auto get(const subrange<_It, _Se, _Ki>& _Val); + + _EXPORT_STD template + requires (_Idx < 2) + _NODISCARD constexpr auto get(subrange<_It, _Se, _Ki>&& _Val); +} // namespace ranges + +_EXPORT_STD using ranges::get; + +template +constexpr bool _Is_subrange_v> = true; + +template +struct tuple_size> : integral_constant {}; + +template +struct tuple_element<0, ranges::subrange<_It, _Se, _Ki>> { + using type = _It; +}; + +template +struct tuple_element<1, ranges::subrange<_It, _Se, _Ki>> { + using type = _Se; +}; + +template +struct tuple_element<0, const ranges::subrange<_It, _Se, _Ki>> { + using type = _It; +}; + +template +struct tuple_element<1, const ranges::subrange<_It, _Se, _Ki>> { + using type = _Se; +}; +#else // ^^^ _HAS_CXX20 / !_HAS_CXX20 vvv +template +struct _Iterator_traits_base {}; // empty for non-iterators + +template +struct _Iterator_traits_base<_Iter, + void_t> { + // defined if _Iter::* types exist + using iterator_category = typename _Iter::iterator_category; + using value_type = typename _Iter::value_type; + using difference_type = typename _Iter::difference_type; + using pointer = typename _Iter::pointer; + using reference = typename _Iter::reference; +}; + +template > +struct _Iterator_traits_pointer_base { // iterator properties for pointers to object + using iterator_category = random_access_iterator_tag; + using value_type = remove_cv_t<_Ty>; + using difference_type = ptrdiff_t; + using pointer = _Ty*; + using reference = _Ty&; +}; + +template +struct _Iterator_traits_pointer_base<_Ty, false> {}; // iterator non-properties for pointers to non-object + +template +struct iterator_traits : _Iterator_traits_base<_Iter> {}; // get traits from iterator _Iter, if possible + +template +struct iterator_traits<_Ty*> : _Iterator_traits_pointer_base<_Ty> {}; // get traits from pointer, if possible + +template +constexpr bool _Integer_like = _Is_nonbool_integral<_Ty>; +#endif // ^^^ !_HAS_CXX20 ^^^ + +_INLINE_VAR constexpr auto _Meta_npos = ~size_t{0}; + +constexpr size_t _Meta_find_index_i_(const bool* const _Ptr, const size_t _Count, size_t _Idx = 0) { + // return the index of the first true in the _Count bools at _Ptr, or _Meta_npos if all are false + for (; _Idx < _Count; ++_Idx) { + if (_Ptr[_Idx]) { + return _Idx; + } + } + + return _Meta_npos; +} + +template +struct _Meta_find_unique_index_ { + using type = integral_constant; +}; +template +using _Meta_find_unique_index = + // The index of _Ty in _List if it occurs exactly once, otherwise _Meta_npos + typename _Meta_find_unique_index_<_List, _Ty>::type; + +constexpr size_t _Meta_find_unique_index_i_2(const bool* const _Ptr, const size_t _Count, const size_t _First) { + // return _First if there is no _First < j < _Count such that _Ptr[j] is true, otherwise _Meta_npos + return _First != _Meta_npos && _STD _Meta_find_index_i_(_Ptr, _Count, _First + 1) == _Meta_npos ? _First + : _Meta_npos; +} + +constexpr size_t _Meta_find_unique_index_i_(const bool* const _Ptr, const size_t _Count) { + // Pass the smallest i such that _Ptr[i] is true to _Meta_find_unique_index_i_2 + return _STD _Meta_find_unique_index_i_2(_Ptr, _Count, _STD _Meta_find_index_i_(_Ptr, _Count)); +} + +template