├── .clang-format ├── .clangd ├── .git-blame-ignore-revs ├── .github └── workflows │ ├── linux.yml │ ├── macos.yml │ ├── main.yml │ └── windows.yml ├── .gitignore ├── CMakeLists.txt ├── CMakePresets.json ├── LICENSE ├── README.md ├── cmake ├── Modules │ └── FindSphinx.cmake ├── clangd_compile_info.cmake └── cmake_utilities.cmake ├── docs ├── CMakeLists.txt ├── Doxyfile.in └── source │ ├── conf.py │ ├── index.rst │ └── reference │ └── index.rst ├── examples ├── CMakeLists.txt ├── detail │ └── _clangd_helper_file.cpp ├── scratch.cpp └── scratch.cu ├── include └── ustdex │ ├── cuda │ └── stream_context.cuh │ ├── detail │ ├── atomic.hpp │ ├── completion_signatures.hpp │ ├── concepts.hpp │ ├── conditional.hpp │ ├── config.hpp │ ├── continues_on.hpp │ ├── cpos.hpp │ ├── env.hpp │ ├── epilogue.hpp │ ├── exception.hpp │ ├── exclusive_scan.hpp │ ├── just.hpp │ ├── just_from.hpp │ ├── lazy.hpp │ ├── let_value.hpp │ ├── meta.hpp │ ├── preprocessor.hpp │ ├── prologue.hpp │ ├── queries.hpp │ ├── rcvr_ref.hpp │ ├── rcvr_with_env.hpp │ ├── read_env.hpp │ ├── run_loop.hpp │ ├── sequence.hpp │ ├── start_detached.hpp │ ├── starts_on.hpp │ ├── stop_token.hpp │ ├── sync_wait.hpp │ ├── then.hpp │ ├── thread.hpp │ ├── thread_context.hpp │ ├── tuple.hpp │ ├── type_traits.hpp │ ├── utility.hpp │ ├── variant.hpp │ ├── when_all.hpp │ └── write_env.hpp │ └── ustdex.hpp ├── scripts ├── build_cmake_debug.sh ├── build_debug.sh ├── create_release.sh ├── format.sh ├── git_hooks │ └── pre-commit ├── run_tests.sh └── windows │ ├── build_cmake_debug.ps1 │ ├── build_debug.ps1 │ ├── create_release.ps1 │ └── run_tests.ps1 └── tests ├── CMakeLists.txt ├── common ├── catch2.hpp ├── checked_receiver.hpp ├── error_scheduler.hpp ├── impulse_scheduler.hpp ├── inline_scheduler.hpp ├── stopped_scheduler.hpp └── utility.hpp ├── cuda ├── CMakeLists.txt └── test_just.cu ├── test_conditional.cpp ├── test_continues_on.cpp ├── test_just.cpp ├── test_sequence.cpp └── test_when_all.cpp /.clang-format: -------------------------------------------------------------------------------- 1 | # Note that we don't specify the language in this file because some files are 2 | # detected as Cpp, but others are detected as ObjC and we want this formatting 3 | # to apply to all types of files. 4 | BasedOnStyle: LLVM 5 | AccessModifierOffset: -2 6 | AlignAfterOpenBracket: Align 7 | AlignConsecutiveAssignments: AcrossEmptyLines 8 | AlignConsecutiveBitFields: AcrossEmptyLines 9 | AlignConsecutiveMacros: AcrossEmptyLines 10 | AlignEscapedNewlines: Left 11 | AlignTrailingComments: 12 | Kind: Always 13 | OverEmptyLines: 1 14 | AlignOperands: AlignAfterOperator 15 | AllowAllArgumentsOnNextLine: true 16 | AllowAllParametersOfDeclarationOnNextLine: true 17 | AllowAllConstructorInitializersOnNextLine: true 18 | AllowShortBlocksOnASingleLine: false 19 | AllowShortCaseLabelsOnASingleLine: false 20 | AllowShortFunctionsOnASingleLine: Empty 21 | AllowShortIfStatementsOnASingleLine: Never 22 | AllowShortLambdasOnASingleLine: Empty 23 | AllowShortLoopsOnASingleLine: false 24 | AlwaysBreakAfterReturnType: None 25 | AlwaysBreakTemplateDeclarations: Yes 26 | AttributeMacros: [ 27 | 'USTDEX_API', 28 | 'USTDEX_HOST_API', 29 | 'USTDEX_DEVICE_API', 30 | 'USTDEX_TRIVIAL_API', 31 | 'USTDEX_TRIVIAL_HOST_API', 32 | 'USTDEX_TRIVIAL_DEVICE_API', 33 | 'USTDEX_NO_UNIQUE_ADDRESS', 34 | 'USTDEX_TYPE_VISIBILITY_DEFAULT', 35 | 'USTDEX_ATTR_NODEBUG_ALIAS', 36 | 'USTDEX_HOST_DEVICE', 37 | ] 38 | BinPackArguments: false 39 | BinPackParameters: false 40 | BreakBeforeBraces: Custom 41 | BraceWrapping: 42 | AfterCaseLabel: false 43 | AfterClass: true 44 | AfterControlStatement: true 45 | AfterEnum: true 46 | AfterFunction: true 47 | AfterNamespace: true 48 | AfterStruct: true 49 | AfterUnion: true 50 | BeforeCatch: true 51 | BeforeElse: true 52 | IndentBraces: false 53 | SplitEmptyFunction: false 54 | SplitEmptyRecord: false 55 | BreakBeforeConceptDeclarations: true 56 | BreakBeforeBinaryOperators: NonAssignment 57 | BreakBeforeTernaryOperators: true 58 | BreakConstructorInitializers: BeforeComma 59 | BreakInheritanceList: BeforeComma 60 | ColumnLimit: 120 61 | CompactNamespaces: false 62 | ContinuationIndentWidth: 2 63 | EmptyLineAfterAccessModifier: Never 64 | EmptyLineBeforeAccessModifier: Always 65 | FixNamespaceComments: true 66 | IndentWrappedFunctionNames: false 67 | IncludeBlocks: Regroup 68 | IncludeCategories: 69 | - Regex: '^"prologue[.]hpp"$' 70 | Priority: 0x7FFFFFFF 71 | SortPriority: 0x7FFFFFFF 72 | - Regex: '^"config[.]hpp"$' 73 | Priority: 0 74 | SortPriority: 0 75 | - Regex: '^$' 85 | Priority: 5 86 | SortPriority: 4 87 | - Regex: '^"[a-z_]*[.]hpp"$' 88 | Priority: 0 89 | SortPriority: 0 90 | InsertBraces: true 91 | IndentCaseLabels: true 92 | InsertNewlineAtEOF: true 93 | InsertTrailingCommas: Wrapped 94 | IndentRequires: true 95 | IndentPPDirectives: AfterHash 96 | IndentWidth: 2 97 | KeepEmptyLinesAtTheStartOfBlocks: false 98 | MaxEmptyLinesToKeep: 1 99 | Macros: 100 | - USTDEX_TEMPLATE(...)=template<__VA_ARGS__> 101 | - USTDEX_REQUIRES(...)=requires (__VA_ARGS__) 102 | - USTDEX_CONCEPT=concept /*****/ 103 | NamespaceIndentation: None 104 | PackConstructorInitializers: Never 105 | PenaltyBreakAssignment: 30 106 | PenaltyBreakBeforeFirstCallParameter: 50 107 | PenaltyBreakComment: 0 108 | PenaltyBreakFirstLessLess: 0 109 | PenaltyBreakString: 70 110 | PenaltyBreakTemplateDeclaration: 0 111 | PenaltyExcessCharacter: 100 112 | PenaltyReturnTypeOnItsOwnLine: 90 113 | PenaltyIndentedWhitespace: 2 114 | PointerAlignment: Left 115 | ReflowComments: true 116 | RemoveSemicolon: false 117 | SortIncludes: CaseInsensitive 118 | SpaceAfterCStyleCast: true 119 | SpaceAfterLogicalNot: false 120 | SpaceAfterTemplateKeyword: true 121 | SpaceBeforeAssignmentOperators: true 122 | SpaceBeforeCpp11BracedList: false 123 | SpaceBeforeCtorInitializerColon: true 124 | SpaceBeforeInheritanceColon: true 125 | SpaceBeforeParens: ControlStatements 126 | SpaceBeforeRangeBasedForLoopColon: true 127 | SpaceInEmptyParentheses: false 128 | SpacesBeforeTrailingComments: 1 129 | SpacesInAngles: Never 130 | SpacesInCStyleCastParentheses: false 131 | SpacesInParentheses: false 132 | SpacesInSquareBrackets: false 133 | Standard: c++20 134 | TabWidth: 2 135 | UseTab: Never 136 | -------------------------------------------------------------------------------- /.clangd: -------------------------------------------------------------------------------- 1 | CompileFlags: # Tweak the parse settings 2 | Add: [-xc++, -std=c++20] # Treat the file as C++20 3 | 4 | --- 5 | If: 6 | PathMatch: ".*/ustdex/detail/epilogue[.]hpp" 7 | 8 | CompileFlags: 9 | Add: 10 | - -include ustdex/detail/prologue.hpp 11 | -------------------------------------------------------------------------------- /.git-blame-ignore-revs: -------------------------------------------------------------------------------- 1 | # Run this command to always ignore formatting commits in `git blame` 2 | # git config blame.ignoreRevsFile .git-blame-ignore-revs 3 | 4 | # Adopt the .clang-format of the cccl project 5 | dcf395e78f5073fb33dda541c2c9274e458c5894 6 | -------------------------------------------------------------------------------- /.github/workflows/linux.yml: -------------------------------------------------------------------------------- 1 | name: Build and test on Linux 2 | on: 3 | workflow_call: 4 | 5 | concurrency: 6 | group: "${{ github.ref }}-linux" 7 | cancel-in-progress: true 8 | 9 | jobs: 10 | linux: 11 | runs-on: ubuntu-latest 12 | timeout-minutes: 60 13 | steps: 14 | - uses: actions/checkout@v4 15 | - name: Configure CMake and build 16 | run: ./scripts/create_release.sh withTests 17 | - name: Run tests 18 | run: ./scripts/run_tests.sh Release 19 | -------------------------------------------------------------------------------- /.github/workflows/macos.yml: -------------------------------------------------------------------------------- 1 | name: Build and test on macOS 2 | on: 3 | workflow_call: 4 | 5 | concurrency: 6 | group: "${{ github.ref }}-macos" 7 | cancel-in-progress: true 8 | 9 | jobs: 10 | macos: 11 | runs-on: macos-14-large 12 | timeout-minutes: 60 13 | steps: 14 | - uses: actions/checkout@v4 15 | - name: Configure CMake and build 16 | run: ./scripts/create_release.sh withTests 17 | - name: Run tests 18 | run: ./scripts/run_tests.sh Release 19 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: Build and test all platforms 2 | on: 3 | push: 4 | paths-ignore: 5 | - '**.md' 6 | - .clang-format 7 | - .gitignore 8 | workflow_dispatch: 9 | 10 | jobs: 11 | linux: 12 | permissions: 13 | contents: read 14 | uses: ./.github/workflows/linux.yml 15 | 16 | # macos: 17 | # permissions: 18 | # contents: read 19 | # uses: ./.github/workflows/macos.yml 20 | 21 | windows: 22 | permissions: 23 | contents: read 24 | uses: ./.github/workflows/windows.yml 25 | -------------------------------------------------------------------------------- /.github/workflows/windows.yml: -------------------------------------------------------------------------------- 1 | name: Build and test on Windows 2 | on: 3 | workflow_call: 4 | 5 | concurrency: 6 | group: "${{ github.ref }}-windows" 7 | cancel-in-progress: true 8 | 9 | jobs: 10 | windows: 11 | runs-on: windows-latest 12 | timeout-minutes: 60 13 | steps: 14 | - uses: actions/checkout@v4 15 | - name: Configure CMake and build 16 | run: ./scripts/windows/create_release.ps1 withTests 17 | - name: Run tests 18 | run: ./scripts/windows/run_tests.ps1 Release 19 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Compiled Object files 5 | *.slo 6 | *.lo 7 | *.o 8 | *.obj 9 | 10 | # Precompiled Headers 11 | *.gch 12 | *.pch 13 | 14 | # Compiled Dynamic libraries 15 | *.so 16 | *.dylib 17 | *.dll 18 | 19 | # Fortran module files 20 | *.mod 21 | *.smod 22 | 23 | # Compiled Static libraries 24 | *.lai 25 | *.la 26 | *.a 27 | *.lib 28 | 29 | # Executables 30 | *.exe 31 | *.out 32 | *.app 33 | 34 | # Build directories 35 | _build/ 36 | build/ 37 | 38 | # IDE files 39 | .vscode/ 40 | 41 | # CMake files 42 | CMakeUserPresets.json 43 | compile_commands.json 44 | .cache 45 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2025 NVIDIA Corporation 2 | # 3 | # Licensed under the Apache License Version 2.0 with LLVM Exceptions 4 | # (the "License"); you may not use this file except in compliance with 5 | # the License. You may obtain a copy of the License at 6 | # 7 | # https://llvm.org/LICENSE.txt 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | cmake_minimum_required(VERSION 3.26) 16 | project(ustdex VERSION 0.0.1 LANGUAGES CXX) 17 | 18 | # Integrate with LLVM/clang tooling 19 | set(CMAKE_EXPORT_COMPILE_COMMANDS ON) 20 | 21 | # Integrate with LLVM/clang tooling 22 | include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/clangd_compile_info.cmake) 23 | 24 | list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules") 25 | 26 | # Ensure that we link with the threading library 27 | set(CMAKE_THREAD_PREFER_PTHREAD TRUE) 28 | find_package(Threads REQUIRED 29 | BUILD_EXPORT_SET ustdex-exports 30 | INSTALL_EXPORT_SET ustdex-exports 31 | ) 32 | 33 | option(USTDEX_ENABLE_CUDA "Enable ustdex CUDA support" OFF) 34 | if (NOT "${CMAKE_CUDA_COMPILER}" STREQUAL "") 35 | message(STATUS "ustdex: CUDA compiler detected : ${CMAKE_CUDA_COMPILER}") 36 | set(USTDEX_ENABLE_CUDA ON) 37 | endif() 38 | 39 | if (USTDEX_ENABLE_CUDA) 40 | enable_language(CUDA) 41 | message(STATUS "ustdex: CUDA compiler id : ${CMAKE_CUDA_COMPILER_ID}") 42 | if (CMAKE_CUDA_COMPILER_ID STREQUAL "NVIDIA") 43 | set(CMAKE_CUDA_FLAGS "--expt-relaxed-constexpr --extended-lambda --keep \ 44 | -DUSTDEX_CUDA=1 ${CMAKE_CUDA_FLAGS}") 45 | elseif("${CMAKE_CUDA_COMPILER_ID}" STREQUAL "NVHPC") 46 | set(CMAKE_CUDA_FLAGS "-DUSTDEX_CUDA=1 ${CMAKE_CUDA_FLAGS}") 47 | else() 48 | set(CMAKE_CUDA_FLAGS "-DUSTDEX_CUDA=1 ${CMAKE_CUDA_FLAGS}") 49 | endif() 50 | endif() 51 | 52 | add_library(ustdex INTERFACE) 53 | 54 | list(APPEND ustdex_export_targets ustdex) 55 | 56 | # Set library version 57 | set_target_properties(ustdex PROPERTIES 58 | VERSION "${USTDEX_VERSION}" 59 | SOVERSION "${USTDEX_VERSION_MAJOR}") 60 | 61 | # Declare the public include directories 62 | include(GNUInstallDirs) 63 | target_include_directories(ustdex INTERFACE 64 | $ 65 | $) 66 | 67 | target_link_libraries(ustdex INTERFACE Threads::Threads) 68 | 69 | target_compile_features(ustdex INTERFACE cxx_std_17) 70 | target_include_directories(ustdex INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/include) 71 | 72 | target_compile_options(ustdex INTERFACE 73 | $<$:/Zc:__cplusplus /Zc:hiddenFriend /Zc:preprocessor /Zc:externConstexpr>) 74 | 75 | # download CPM.cmake 76 | file( 77 | DOWNLOAD 78 | https://github.com/cpm-cmake/CPM.cmake/releases/download/v0.39.0/CPM.cmake 79 | ${CMAKE_CURRENT_BINARY_DIR}/cmake/CPM.cmake 80 | EXPECTED_HASH SHA256=66639bcac9dd2907b2918de466783554c1334446b9874e90d38e3778d404c2ef 81 | ) 82 | include(${CMAKE_CURRENT_BINARY_DIR}/cmake/CPM.cmake) 83 | 84 | if (USTDEX_ENABLE_CUDA) 85 | target_compile_features(ustdex INTERFACE cuda_std_17) 86 | endif() 87 | 88 | option(USTDEX_BUILD_DOCS "Build ustdex documentation" OFF) 89 | if (USTDEX_BUILD_DOCS) 90 | add_subdirectory(docs) 91 | endif() 92 | 93 | option(USTDEX_BUILD_EXAMPLES "Build ustdex examples" ON) 94 | if (USTDEX_BUILD_EXAMPLES) 95 | add_subdirectory(examples) 96 | endif() 97 | 98 | if (BUILD_TESTING) 99 | enable_testing() 100 | add_subdirectory(tests) 101 | endif() 102 | 103 | ############################################## 104 | # Installation 105 | 106 | # Don't require building everything when installing 107 | set(CMAKE_SKIP_INSTALL_ALL_DEPENDENCY ON) 108 | 109 | install(TARGETS ustdex 110 | DESTINATION ${CMAKE_INSTALL_LIBDIR} 111 | EXPORT ustdex-exports) 112 | 113 | install( 114 | DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/include/ 115 | DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) 116 | 117 | install( 118 | FILES ${CMAKE_CURRENT_BINARY_DIR}/include/ustdex_version_config.hpp 119 | DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) 120 | -------------------------------------------------------------------------------- /CMakePresets.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 3, 3 | "cmakeMinimumRequired": { 4 | "major": 3, 5 | "minor": 21, 6 | "patch": 3 7 | }, 8 | "configurePresets": [ 9 | { 10 | "name": "Debug", 11 | "binaryDir": "${sourceDir}/build/Debug", 12 | "cacheVariables": { 13 | "CMAKE_BUILD_TYPE": "Debug", 14 | "CMAKE_CXX_STANDARD": "17" 15 | } 16 | }, 17 | { 18 | "name": "Release", 19 | "binaryDir": "${sourceDir}/build/Release", 20 | "cacheVariables": { 21 | "CMAKE_BUILD_TYPE": "Release", 22 | "CMAKE_CXX_STANDARD": "17" 23 | } 24 | } 25 | ], 26 | "buildPresets": [ 27 | { 28 | "name": "Debug", 29 | "configurePreset": "Debug" 30 | }, 31 | { 32 | "name": "Release", 33 | "configurePreset": "Release" 34 | } 35 | ] 36 | } 37 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # µstdex 2 | 3 | [![Build and test all platforms](https://github.com/ericniebler/ustdex/actions/workflows/main.yml/badge.svg)](https://github.com/ericniebler/ustdex/actions/workflows/main.yml) 4 | 5 | This project is intended to be a small, lightweight `std::execution`[^1] 6 | work-alike that targets C++17. It optimizes for compile-times and diagnostics 7 | above performance and conformance. 8 | 9 | [^1]: https://wg21.link/P2300 10 | 11 | This software is licensed under the Apache 2.0 License with LLVM Exceptions. 12 | NVIDIA does not guarantee that it is fit for any use whatsoever. It will evolve 13 | without regard for backwards-compatibility. 14 | 15 | -------------------------------------------------------------------------------- /cmake/Modules/FindSphinx.cmake: -------------------------------------------------------------------------------- 1 | #============================================================================= 2 | # Copyright 2023 NVIDIA Corporation 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | #============================================================================= 16 | 17 | # Look for an executable called sphinx-build 18 | find_program(SPHINX_EXECUTABLE 19 | NAMES sphinx-build 20 | DOC "Path to sphinx-build executable") 21 | 22 | include(FindPackageHandleStandardArgs) 23 | 24 | # Handle standard arguments to find_package like REQUIRED and QUIET 25 | find_package_handle_standard_args(Sphinx 26 | "Failed to find sphinx-build executable" 27 | SPHINX_EXECUTABLE) 28 | -------------------------------------------------------------------------------- /cmake/clangd_compile_info.cmake: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 2 | # SPDX-License-Identifier: Apache-2.0 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/cmake_utilities.cmake) 17 | 18 | # Tell cmake to generate a json file of compile commands for clangd: 19 | set(CMAKE_EXPORT_COMPILE_COMMANDS ON) 20 | 21 | # Symlink the compile command output to the source dir, where clangd will find it. 22 | set(compile_commands_file "${CMAKE_BINARY_DIR}/compile_commands.json") 23 | set(compile_commands_link "${CMAKE_SOURCE_DIR}/compile_commands.json") 24 | message(STATUS "Creating symlink from ${compile_commands_link} to ${compile_commands_file}...") 25 | ustdex_execute_non_fatal_process(COMMAND 26 | "${CMAKE_COMMAND}" -E rm -f "${compile_commands_link}") 27 | ustdex_execute_non_fatal_process(COMMAND 28 | "${CMAKE_COMMAND}" -E touch "${compile_commands_file}") 29 | ustdex_execute_non_fatal_process(COMMAND 30 | "${CMAKE_COMMAND}" -E create_symlink "${compile_commands_file}" "${compile_commands_link}") 31 | -------------------------------------------------------------------------------- /cmake/cmake_utilities.cmake: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 2 | # SPDX-License-Identifier: Apache-2.0 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | # Passes all args directly to execute_process while setting up the following 17 | # results variables and propagating them to the caller's scope: 18 | # 19 | # - ustdex_process_exit_code 20 | # - ustdex_process_stdout 21 | # - ustdex_process_stderr 22 | # 23 | # If the command 24 | # is not successful (e.g. the last command does not return zero), a non-fatal 25 | # warning is printed. 26 | function(ustdex_execute_non_fatal_process) 27 | execute_process(${ARGN} 28 | RESULT_VARIABLE ustdex_process_exit_code 29 | OUTPUT_VARIABLE ustdex_process_stdout 30 | ERROR_VARIABLE ustdex_process_stderr 31 | ) 32 | 33 | if (NOT ustdex_process_exit_code EQUAL 0) 34 | message(WARNING 35 | "execute_process failed with non-zero exit code: ${ustdex_process_exit_code}\n" 36 | "${ARGN}\n" 37 | "stdout:\n${ustdex_process_stdout}\n" 38 | "stderr:\n${ustdex_process_stderr}\n" 39 | ) 40 | endif() 41 | 42 | set(ustdex_process_exit_code "${ustdex_process_exit_code}" PARENT_SCOPE) 43 | set(ustdex_process_stdout "${ustdex_process_stdout}" PARENT_SCOPE) 44 | set(ustdex_process_stderr "${ustdex_process_stderr}" PARENT_SCOPE) 45 | endfunction() 46 | -------------------------------------------------------------------------------- /docs/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #============================================================================= 2 | # Copyright 2023 NVIDIA Corporation 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | #============================================================================= 16 | 17 | find_package(Doxygen REQUIRED) 18 | find_package(Sphinx REQUIRED) 19 | 20 | # Find all the public headers 21 | set(USTDEX_PUBLIC_HEADER_DIR ${CMAKE_SOURCE_DIR}/include) 22 | file(GLOB_RECURSE USTDEX_PUBLIC_HEADERS ${USTDEX_PUBLIC_HEADER_DIR}/*.hpp) 23 | 24 | set(DOXYGEN_INPUT_DIR ${PROJECT_SOURCE_DIR}/include) 25 | set(DOXYGEN_OUTPUT_DIR ${CMAKE_CURRENT_BINARY_DIR}/build/doxygen) 26 | set(DOXYGEN_INDEX_FILE ${DOXYGEN_OUTPUT_DIR}/xml/index.xml) 27 | set(DOXYFILE_IN ${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.in) 28 | set(DOXYFILE_OUT ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile) 29 | 30 | # Replace variables inside @@ with the current values 31 | configure_file(${DOXYFILE_IN} ${DOXYFILE_OUT} @ONLY) 32 | 33 | # Doxygen won't create this for us 34 | file(MAKE_DIRECTORY ${DOXYGEN_OUTPUT_DIR}) 35 | 36 | # Only regenerate Doxygen when the Doxyfile or public headers change 37 | add_custom_command(OUTPUT ${DOXYGEN_INDEX_FILE} 38 | DEPENDS ${USTDEX_PUBLIC_HEADERS} 39 | COMMAND ${DOXYGEN_EXECUTABLE} ${DOXYFILE_OUT} 40 | MAIN_DEPENDENCY ${DOXYFILE_OUT} ${DOXYFILE_IN} 41 | COMMENT "Generating docs" 42 | VERBATIM) 43 | 44 | # Nice named target so we can run the job easily 45 | add_custom_target(Doxygen ALL DEPENDS ${DOXYGEN_INDEX_FILE}) 46 | 47 | set(SPHINX_SOURCE ${CMAKE_CURRENT_SOURCE_DIR}/source) 48 | set(SPHINX_BUILD ${PROJECT_BINARY_DIR}/docs) 49 | set(SPHINX_INDEX_FILE ${SPHINX_BUILD}/index.html) 50 | 51 | file(GLOB_RECURSE 52 | USTDEX_DOCUMENTATION_SOURCE_FILES 53 | ${SPHINX_SOURCE}/*.rst ${SPHINX_SOURCE}/*.md) 54 | 55 | # Only regenerate Sphinx when: 56 | # - Doxygen has rerun 57 | # - Our doc files have been updated 58 | # - The Sphinx config has been updated 59 | add_custom_command(OUTPUT ${SPHINX_INDEX_FILE} 60 | COMMAND 61 | ${SPHINX_EXECUTABLE} -b html 62 | # Tell Breathe where to find the Doxygen output 63 | -Dbreathe_projects.ustdex=${DOXYGEN_OUTPUT_DIR}/xml 64 | ${SPHINX_SOURCE} ${SPHINX_BUILD} 65 | WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} 66 | DEPENDS 67 | # Other docs files you want to track should go here (or in some variable) 68 | ${USTDEX_DOCUMENTATION_SOURCE_FILES} 69 | ${DOXYGEN_INDEX_FILE} 70 | MAIN_DEPENDENCY ${SPHINX_SOURCE}/conf.py 71 | COMMENT "Generating documentation with Sphinx") 72 | 73 | # Nice named target so we can run the job easily 74 | add_custom_target(Sphinx ALL DEPENDS ${SPHINX_INDEX_FILE}) 75 | 76 | # Add an install target to install the docs 77 | install(DIRECTORY ${SPHINX_BUILD} DESTINATION ${CMAKE_INSTALL_DOCDIR}) 78 | -------------------------------------------------------------------------------- /docs/source/conf.py: -------------------------------------------------------------------------------- 1 | #============================================================================= 2 | # Copyright 2023 NVIDIA Corporation 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | #============================================================================= 16 | 17 | # Configuration file for the Sphinx documentation builder. 18 | # 19 | # For the full list of built-in configuration values, see the documentation: 20 | # https://www.sphinx-doc.org/en/master/usage/configuration.html 21 | 22 | # -- Project information ----------------------------------------------------- 23 | # https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information 24 | 25 | project = 'ustdex' 26 | copyright = '2024, NVIDIA Corporation' 27 | author = 'NVIDIA Corporation' 28 | release = 'dev' 29 | 30 | # -- General configuration --------------------------------------------------- 31 | # https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration 32 | 33 | extensions = [ 34 | "sphinx.ext.autodoc", 35 | "sphinx.ext.autosummary", 36 | "sphinx.ext.intersphinx", 37 | "sphinx.ext.mathjax", 38 | "sphinx.ext.napoleon", 39 | "sphinx_copybutton", 40 | "IPython.sphinxext.ipython_console_highlighting", 41 | "myst_parser", 42 | "nbsphinx", 43 | "breathe", 44 | ] 45 | 46 | templates_path = ['_templates'] 47 | exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] 48 | 49 | # -- Options for HTML output ------------------------------------------------- 50 | # https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output 51 | 52 | html_theme = 'sphinx_rtd_theme' 53 | # html_static_path = ['_static'] 54 | 55 | # -- Options for extensions -------------------------------------------------- 56 | 57 | autosummary_generate = True 58 | 59 | copybutton_prompt_text = ">>> " 60 | 61 | intersphinx_mapping = { 62 | "python": ("https://docs.python.org/3/", None), 63 | "numpy": ("https://numpy.org/doc/stable/", None), 64 | } 65 | 66 | mathjax_path = "https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js" 67 | 68 | napoleon_custom_sections = [("Availability", "returns_style")] 69 | 70 | nbsphinx_execute = "never" 71 | 72 | pygments_style = "sphinx" 73 | 74 | breathe_default_project = "ustdex" 75 | 76 | def setup(app): 77 | app.add_css_file("params.css") 78 | -------------------------------------------------------------------------------- /docs/source/index.rst: -------------------------------------------------------------------------------- 1 | .. ============================================================================= 2 | .. Copyright 2023 NVIDIA Corporation 3 | .. 4 | .. Licensed under the Apache License, Version 2.0 (the "License"); 5 | .. you may not use this file except in compliance with the License. 6 | .. You may obtain a copy of the License at 7 | .. 8 | .. http://www.apache.org/licenses/LICENSE-2.0 9 | .. 10 | .. Unless required by applicable law or agreed to in writing, software 11 | .. distributed under the License is distributed on an "AS IS" BASIS, 12 | .. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | .. See the License for the specific language governing permissions and 14 | .. limitations under the License. 15 | .. ============================================================================= 16 | 17 | Welcome to ``ustdex`` 18 | ====================== 19 | 20 | ``ustdex`` is a simple work-alike for the ``std::execution`` proposal to the C++ standard library. 21 | 22 | It provides: 23 | * TODO 24 | 25 | .. toctree:: 26 | :maxdepth: 2 27 | :caption: Contents: 28 | 29 | reference/index 30 | 31 | Indices and tables 32 | ------------------ 33 | * :ref:`genindex` 34 | -------------------------------------------------------------------------------- /docs/source/reference/index.rst: -------------------------------------------------------------------------------- 1 | .. SPDX-FileCopyrightText: Copyright (c) 2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 2 | SPDX-License-Identifier: LicenseRef-NvidiaProprietary 3 | 4 | NVIDIA CORPORATION, its affiliates and licensors retain all intellectual 5 | property and proprietary rights in and to this material, related 6 | documentation and any modifications thereto. Any use, reproduction, 7 | disclosure or distribution of this material and related documentation 8 | without an express license agreement from NVIDIA CORPORATION or 9 | its affiliates is strictly prohibited. 10 | 11 | Reference 12 | ========= 13 | 14 | .. toctree:: 15 | :maxdepth: 2 16 | 17 | Concepts 18 | -------- 19 | 20 | 21 | Sender Factories 22 | ---------------- 23 | 24 | .. doxygenvariable:: ustdex::just 25 | 26 | Sender Adaptors 27 | --------------- 28 | 29 | .. doxygenvariable:: ustdex::then 30 | 31 | 32 | Sender Consumers 33 | ---------------- 34 | 35 | .. doxygenstruct:: ustdex::sync_wait_t 36 | :project: ustdex 37 | :members: 38 | 39 | .. doxygenvariable:: ustdex::sync_wait 40 | 41 | .. Utilities 42 | .. --------- 43 | 44 | .. .. doxygenfunction:: ustdex::__write 45 | .. :project: ustdex 46 | .. :outline: 47 | 48 | -------------------------------------------------------------------------------- /examples/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2025 NVIDIA Corporation 2 | # 3 | # Licensed under the Apache License Version 2.0 with LLVM Exceptions 4 | # (the "License"); you may not use this file except in compliance with 5 | # the License. You may obtain a copy of the License at 6 | # 7 | # https://llvm.org/LICENSE.txt 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | add_executable(_clangd_helper_file detail/_clangd_helper_file.cpp) 16 | target_link_libraries(_clangd_helper_file PUBLIC ustdex) 17 | 18 | add_executable(scratch scratch.cpp) 19 | target_link_libraries(scratch PUBLIC ustdex) 20 | 21 | if (USTDEX_ENABLE_CUDA) 22 | add_executable(cuscratch scratch.cu) 23 | target_link_libraries(cuscratch PUBLIC ustdex) 24 | endif() 25 | -------------------------------------------------------------------------------- /examples/detail/_clangd_helper_file.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2025 NVIDIA Corporation 3 | * 4 | * Licensed under the Apache License Version 2.0 with LLVM Exceptions 5 | * (the "License"); you may not use this file except in compliance with 6 | * the License. You may obtain a copy of the License at 7 | * 8 | * https://llvm.org/LICENSE.txt 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | // A file that sorts to the top of clangd's file list to help clangd infer the 18 | // compile commands for nearby headers. 19 | // 20 | // To provide intellisense when a user opens a header file, clangd searches the 21 | // current dir, subdirs, and parent dirs for nearby translation units. It sorts 22 | // the list of nearby TUs, and uses the compile string of the first TU to 23 | // provide intellisense for the opened header file. 24 | // 25 | // Clangd's heuristic is not perfect, but we can help it along. By starting this 26 | // filename with an underscore, we ensure it sorts to the top of the list of 27 | // TUs. 28 | // 29 | // TUs closer to the header file in the directory tree are chosen before ones 30 | // further up or down the directory tree, therefore this file should be copied 31 | // into any subdirectories with tranlation units whose compile flags are 32 | // different than those in the parent (for example, if the subdirectory has a 33 | // CMakeList.txt that defines additional executables). This ensures clangd 34 | // provides useful intellisense for headers in any subdirectory with a 35 | // CMakeList.txt. 36 | 37 | int main(void) {} 38 | -------------------------------------------------------------------------------- /examples/scratch.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 3 | * SPDX-License-Identifier: Apache-2.0 4 | * 5 | * Licensed under the Apache License Version 2.0 with LLVM Exceptions 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * https://llvm.org/LICENSE.txt 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | #include 19 | #include 20 | 21 | #include "ustdex/ustdex.hpp" 22 | 23 | using namespace ustdex; 24 | 25 | struct sink 26 | { 27 | using receiver_concept = receiver_t; 28 | 29 | void set_value() noexcept {} 30 | 31 | void set_value(int a) noexcept 32 | { 33 | std::printf("%d\n", a); 34 | } 35 | 36 | template 37 | void set_value(As&&...) noexcept 38 | { 39 | std::puts("In sink::set_value(auto&&...)"); 40 | } 41 | 42 | void set_error(std::exception_ptr) noexcept {} 43 | 44 | void set_stopped() noexcept {} 45 | }; 46 | 47 | template 48 | [[deprecated]] void print() 49 | {} 50 | 51 | static_assert(dependent_sender); 52 | 53 | int main() 54 | { 55 | thread_context ctx; 56 | auto sch = ctx.get_scheduler(); 57 | 58 | auto work = just(1, 2, 3) // 59 | | then([](int a, int b, int c) { 60 | std::printf("%d %d %d\n", a, b, c); 61 | return a + b + c; 62 | }); 63 | auto s = starts_on(sch, std::move(work)); 64 | static_assert(!dependent_sender); 65 | std::puts("Hello, world!"); 66 | sync_wait(s); 67 | 68 | auto s3 = just(42) | let_value([](int a) { 69 | std::puts("here"); 70 | return just(a + 1); 71 | }); 72 | sync_wait(s3); 73 | 74 | auto [sch2] = sync_wait(read_env(get_scheduler)).value(); 75 | 76 | auto [i1, i2] = sync_wait(when_all(just(42), just(43))).value(); 77 | std::cout << i1 << ' ' << i2 << '\n'; 78 | 79 | auto s4 = just(42) | then([](int) {}) | upon_error([](auto) { /*return 42;*/ }); 80 | auto s5 = when_all(std::move(s4), just(42, 43), just(+"hello")); 81 | auto [i, j, k] = sync_wait(std::move(s5)).value(); 82 | std::cout << i << ' ' << j << ' ' << k << '\n'; 83 | 84 | auto s6 = sequence(just(42) | then([](int) { 85 | std::cout << "sequence sender 1\n"; 86 | }), 87 | just(42) | then([](int) { 88 | std::cout << "sequence sender 2\n"; 89 | })); 90 | sync_wait(std::move(s6)); 91 | 92 | auto s7 = 93 | just(42) 94 | | conditional( 95 | [](int i) { 96 | return i % 2 == 0; 97 | }, 98 | then([](int) { 99 | std::cout << "even\n"; 100 | }), 101 | then([](int) { 102 | std::cout << "odd\n"; 103 | })); 104 | sync_wait(std::move(s7)); 105 | } 106 | -------------------------------------------------------------------------------- /examples/scratch.cu: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2025 NVIDIA Corporation 3 | * 4 | * Licensed under the Apache License Version 2.0 with LLVM Exceptions 5 | * (the "License"); you may not use this file except in compliance with 6 | * the License. You may obtain a copy of the License at 7 | * 8 | * https://llvm.org/LICENSE.txt 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include "ustdex/ustdex.hpp" 18 | 19 | #include 20 | #include 21 | 22 | using namespace ustdex; 23 | 24 | struct sink { 25 | using receiver_concept = receiver_t; 26 | 27 | USTDEX_HOST_DEVICE void set_value() noexcept { 28 | } 29 | 30 | USTDEX_HOST_DEVICE void set_value(int a) noexcept { 31 | std::printf("%d\n", a); 32 | } 33 | 34 | template 35 | USTDEX_HOST_DEVICE void set_value(As &&...) noexcept { 36 | std::printf("%s\n", "In sink::set_value(auto&&...)"); 37 | } 38 | 39 | USTDEX_HOST_DEVICE void set_error([[maybe_unused]] const std::exception_ptr& eptr) noexcept { 40 | std::printf("Error\n"); 41 | } 42 | 43 | USTDEX_HOST_DEVICE void set_stopped() noexcept { 44 | } 45 | }; 46 | 47 | struct _inline_scheduler { 48 | using scheduler_concept = scheduler_t; 49 | 50 | template 51 | struct _opstate_t { 52 | using operation_state_concept = operation_state_t; 53 | using completion_signatures = ustdex::completion_signatures; 54 | Rcvr rcvr; 55 | 56 | USTDEX_HOST_DEVICE void start() noexcept { 57 | ustdex::set_value(static_cast(rcvr)); 58 | } 59 | }; 60 | 61 | struct _sndr_t { 62 | using sender_concept = sender_t; 63 | using completion_signatures = ustdex::completion_signatures; 64 | 65 | template 66 | USTDEX_HOST_DEVICE auto connect(Rcvr rcvr) const noexcept { 67 | return _opstate_t{rcvr}; 68 | } 69 | }; 70 | 71 | USTDEX_HOST_DEVICE _sndr_t schedule() noexcept { 72 | return {}; 73 | } 74 | }; 75 | 76 | template 77 | [[deprecated]] 78 | void print() { 79 | } 80 | 81 | USTDEX_HOST_DEVICE void _main() { 82 | auto s = start_on( 83 | _inline_scheduler(), 84 | then( 85 | just(1, 2, 3), 86 | []USTDEX_HOST_DEVICE(int a, int b, int c) { 87 | std::printf("%d %d %d\n", a, b, c); 88 | return a + b + c; 89 | } 90 | ) 91 | ); 92 | 93 | auto o = connect(s, sink{}); 94 | start(o); 95 | 96 | constexpr auto just_plus_one = [](int a) { return just(a + 1); }; 97 | auto s3 = let_value(just(42), just_plus_one); 98 | auto o3 = connect(s3, sink{}); 99 | start(o3); 100 | 101 | auto s4 = just(42) | then([](int){}) | upon_error([](auto){ /*return 42;*/ }); 102 | auto s5 = when_all(std::move(s4), just(42, 42), just(+"")); 103 | auto o5 = connect(std::move(s5), sink{}); 104 | o5.start(); 105 | // using X = completion_signatures_of_t; 106 | // print(); 107 | } 108 | 109 | int main() { 110 | _main(); 111 | } -------------------------------------------------------------------------------- /include/ustdex/cuda/stream_context.cuh: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2025 NVIDIA Corporation 3 | * 4 | * Licensed under the Apache License Version 2.0 with LLVM Exceptions 5 | * (the "License"); you may not use this file except in compliance with 6 | * the License. You may obtain a copy of the License at 7 | * 8 | * https://llvm.org/LICENSE.txt 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | #pragma once 17 | 18 | #include "ustdex/detail/config.hpp" 19 | 20 | #ifndef USTDEX_CUDA 21 | # error "This file should only be included in a CUDA compilation unit" 22 | #endif 23 | 24 | #if defined(CUDA_MEMORY_RESOURCE) && !defined(LIBCUDACXX_ENABLE_EXPERIMENTAL_MEMORY_RESOURCE) 25 | # error "This file requires the experimental memory resource feature to be enabled" 26 | #endif 27 | 28 | #if !defined(LIBCUDACXX_ENABLE_EXPERIMENTAL_MEMORY_RESOURCE) 29 | # define LIBCUDACXX_ENABLE_EXPERIMENTAL_MEMORY_RESOURCE 30 | #endif 31 | 32 | // from libcu++: 33 | 34 | // from the CUDA Toolkit: 35 | #include 36 | 37 | namespace ustdex 38 | { 39 | 40 | struct stream_scheduler 41 | {}; 42 | 43 | enum class stream_priority 44 | { 45 | low, 46 | normal, 47 | high 48 | }; 49 | 50 | struct stream_context 51 | { 52 | public: 53 | stream_context() 54 | : _dev_id(_get_device()) 55 | //, _hub(dev_id_, _pinned.get()) 56 | {} 57 | 58 | stream_scheduler get_scheduler(stream_priority priority = stream_priority::normal) const 59 | { 60 | // return {context_state_t( 61 | // _pinned.get(), _managed.get(), &_stream_pools, &_hub, priority)}; 62 | return {}; 63 | } 64 | 65 | private: 66 | // resource_storage _pinned{}; 67 | // resource_storage _managed{}; 68 | // stream_pools_t stream_pools_{}; 69 | 70 | static int _get_device() noexcept 71 | { 72 | int dev_id{}; 73 | cudaGetDevice(&dev_id); 74 | return dev_id; 75 | } 76 | 77 | int _dev_id{}; 78 | // queue::task_hub_t hub_; 79 | }; 80 | 81 | } // namespace ustdex 82 | -------------------------------------------------------------------------------- /include/ustdex/detail/atomic.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 3 | * SPDX-License-Identifier: Apache-2.0 4 | * 5 | * Licensed under the Apache License Version 2.0 with LLVM Exceptions 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * https://llvm.org/LICENSE.txt 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | #pragma once 18 | 19 | #include "config.hpp" 20 | 21 | #include 22 | 23 | #if USTDEX_CUDA() 24 | # include 25 | # define USTDEX_CUDA_NS cuda:: 26 | #else 27 | # define USTDEX_CUDA_NS 28 | #endif 29 | 30 | namespace ustdex::ustd 31 | { 32 | template 33 | using atomic = USTDEX_CUDA_NS std::atomic; 34 | 35 | using USTDEX_CUDA_NS std::memory_order; 36 | using USTDEX_CUDA_NS std::memory_order_relaxed; 37 | using USTDEX_CUDA_NS std::memory_order_consume; 38 | using USTDEX_CUDA_NS std::memory_order_acquire; 39 | using USTDEX_CUDA_NS std::memory_order_release; 40 | using USTDEX_CUDA_NS std::memory_order_acq_rel; 41 | using USTDEX_CUDA_NS std::memory_order_seq_cst; 42 | } // namespace ustdex::ustd 43 | -------------------------------------------------------------------------------- /include/ustdex/detail/concepts.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 3 | * SPDX-License-Identifier: Apache-2.0 4 | * 5 | * Licensed under the Apache License Version 2.0 with LLVM Exceptions 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * https://llvm.org/LICENSE.txt 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | #ifndef USTDEX_ASYNC_DETAIL_CONCEPTS 19 | #define USTDEX_ASYNC_DETAIL_CONCEPTS 20 | 21 | #include "completion_signatures.hpp" 22 | #include "config.hpp" 23 | #include "cpos.hpp" 24 | #include "preprocessor.hpp" 25 | 26 | #include "prologue.hpp" 27 | 28 | #if USTDEX_MSVC() 29 | # define USTDEX_BINARY_FOLD_EXPR(INIT, OP, ...) ustdex::_fold_expr_##OP 30 | #else 31 | # define USTDEX_BINARY_FOLD_EXPR(INIT, OP, ...) (INIT OP... OP __VA_ARGS__) 32 | #endif 33 | 34 | namespace ustdex 35 | { 36 | // Receiver concepts: 37 | template 38 | USTDEX_CONCEPT receiver = // 39 | USTDEX_REQUIRES_EXPR((Rcvr)) // 40 | ( // 41 | requires(_is_receiver>), // 42 | requires(std::is_move_constructible_v>), // 43 | requires(std::is_constructible_v, Rcvr>), // 44 | requires(std::is_nothrow_move_constructible_v>) // 45 | ); 46 | 47 | template 48 | inline constexpr bool _valid_completion_for = false; 49 | 50 | template 51 | inline constexpr bool _valid_completion_for = _callable; 52 | 53 | template 54 | inline constexpr bool _has_completions = false; 55 | 56 | template 57 | inline constexpr bool _has_completions> = 58 | (_valid_completion_for && ...); 59 | 60 | template 61 | USTDEX_CONCEPT receiver_of = // 62 | USTDEX_REQUIRES_EXPR((Rcvr, Completions)) // 63 | ( // 64 | requires(receiver), // 65 | requires(_has_completions, Completions>) // 66 | ); 67 | 68 | // Queryable traits: 69 | template 70 | USTDEX_CONCEPT _queryable = std::is_destructible_v; 71 | 72 | // Awaitable traits: 73 | template 74 | USTDEX_CONCEPT _is_awaitable = false; // TODO: Implement this concept. 75 | 76 | // Sender traits: 77 | template 78 | USTDEX_API constexpr bool _enable_sender() 79 | { 80 | if constexpr (_is_sender) 81 | { 82 | return true; 83 | } 84 | else 85 | { 86 | return _is_awaitable; 87 | } 88 | } 89 | 90 | template 91 | inline constexpr bool enable_sender = _enable_sender(); 92 | 93 | // Sender concepts: 94 | template 95 | struct _completions_tester 96 | { 97 | template (), true)> 98 | USTDEX_API static constexpr auto _is_valid(int) -> bool 99 | { 100 | return _valid_completion_signatures>; 101 | } 102 | 103 | template 104 | USTDEX_API static constexpr auto _is_valid(long) -> bool 105 | { 106 | return false; 107 | } 108 | }; 109 | 110 | template 111 | USTDEX_CONCEPT sender = // 112 | USTDEX_REQUIRES_EXPR((Sndr)) // 113 | ( // 114 | requires(enable_sender>), // 115 | requires(std::is_move_constructible_v>), // 116 | requires(std::is_constructible_v, Sndr>) // 117 | ); 118 | 119 | template 120 | USTDEX_CONCEPT sender_in = // 121 | USTDEX_REQUIRES_EXPR((Sndr, variadic Env)) // 122 | ( // 123 | requires(sender), // 124 | requires(sizeof...(Env) <= 1), // 125 | requires(USTDEX_BINARY_FOLD_EXPR(true, and, _queryable)), // 126 | requires(_completions_tester::template _is_valid(0)) // 127 | ); 128 | 129 | template 130 | USTDEX_CONCEPT dependent_sender = // 131 | USTDEX_REQUIRES_EXPR((Sndr)) // 132 | ( // 133 | requires(sender), // 134 | requires(_is_dependent_sender()) // 135 | ); 136 | 137 | } // namespace ustdex 138 | 139 | #include "epilogue.hpp" 140 | 141 | #endif // USTDEX_ASYNC_DETAIL_CONCEPTS 142 | -------------------------------------------------------------------------------- /include/ustdex/detail/continues_on.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 3 | * SPDX-License-Identifier: Apache-2.0 4 | * 5 | * Licensed under the Apache License Version 2.0 with LLVM Exceptions 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * https://llvm.org/LICENSE.txt 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | #ifndef USTDEX_ASYNC_DETAIL_CONTINUE_ON 19 | #define USTDEX_ASYNC_DETAIL_CONTINUE_ON 20 | 21 | #include "completion_signatures.hpp" 22 | #include "cpos.hpp" 23 | #include "exception.hpp" 24 | #include "meta.hpp" 25 | #include "queries.hpp" 26 | #include "rcvr_ref.hpp" 27 | #include "tuple.hpp" 28 | #include "variant.hpp" 29 | 30 | #include "prologue.hpp" 31 | 32 | namespace ustdex 33 | { 34 | struct USTDEX_TYPE_VISIBILITY_DEFAULT continue_on_t 35 | { 36 | private: 37 | template 38 | using _set_value_tuple_t = _tuple; 39 | 40 | template 41 | using _set_error_tuple_t = _tuple; 42 | 43 | using _set_stopped_tuple_t = _tuple; 44 | 45 | using _complete_fn = void (*)(void*) noexcept; 46 | 47 | template 48 | struct USTDEX_TYPE_VISIBILITY_DEFAULT _rcvr_t 49 | { 50 | using receiver_concept = receiver_t; 51 | Rcvr _rcvr_; 52 | Result _result_; 53 | _complete_fn _complete_; 54 | 55 | template 56 | USTDEX_API void operator()(Tag, As&... _as) noexcept 57 | { 58 | Tag()(static_cast(_rcvr_), static_cast(_as)...); 59 | } 60 | 61 | template 62 | USTDEX_API void _set_result(Tag, As&&... _as) noexcept 63 | { 64 | using _tupl_t = _tuple; 65 | if constexpr (_nothrow_decay_copyable) 66 | { 67 | _result_.template _emplace<_tupl_t>(Tag(), static_cast(_as)...); 68 | } 69 | else 70 | { 71 | USTDEX_TRY( // 72 | ({ // 73 | _result_.template _emplace<_tupl_t>(Tag(), static_cast(_as)...); 74 | }), 75 | USTDEX_CATCH(...) // 76 | ({ // 77 | ustdex::set_error(static_cast(_rcvr_), ::std::current_exception()); 78 | }) // 79 | ) 80 | } 81 | _complete_ = +[](void* _ptr) noexcept { 82 | auto& _self = *static_cast<_rcvr_t*>(_ptr); 83 | auto& _tupl = *static_cast<_tupl_t*>(_self._result_._ptr()); 84 | _tupl.apply(_self, _tupl); 85 | }; 86 | } 87 | 88 | USTDEX_API void set_value() noexcept 89 | { 90 | _complete_(this); 91 | } 92 | 93 | template 94 | USTDEX_API void set_error(Error&& _error) noexcept 95 | { 96 | ustdex::set_error(static_cast(_rcvr_), static_cast(_error)); 97 | } 98 | 99 | USTDEX_API void set_stopped() noexcept 100 | { 101 | ustdex::set_stopped(static_cast(_rcvr_)); 102 | } 103 | 104 | USTDEX_API env_of_t get_env() const noexcept 105 | { 106 | return ustdex::get_env(_rcvr_); 107 | } 108 | }; 109 | 110 | template 111 | struct USTDEX_TYPE_VISIBILITY_DEFAULT _opstate_t 112 | { 113 | using operation_state_concept = operation_state_t; 114 | using _env_t = FWD_ENV_T>; 115 | 116 | using _result_t = 117 | typename completion_signatures_of_t::template _transform_q<_decayed_tuple, _variant>; 118 | 119 | USTDEX_API _opstate_t(CvSndr&& _sndr, Sch _sch, Rcvr _rcvr) 120 | : _rcvr_{static_cast(_rcvr), {}, nullptr} 121 | , _opstate1_{ustdex::connect(static_cast(_sndr), _rcvr_ref{*this})} 122 | , _opstate2_{ustdex::connect(schedule(_sch), _rcvr_ref{_rcvr_})} 123 | {} 124 | 125 | USTDEX_IMMOVABLE(_opstate_t); 126 | 127 | USTDEX_API void start() noexcept 128 | { 129 | ustdex::start(_opstate1_); 130 | } 131 | 132 | template 133 | USTDEX_API void set_value(As&&... _as) noexcept 134 | { 135 | _rcvr_._set_result(set_value_t(), static_cast(_as)...); 136 | ustdex::start(_opstate2_); 137 | } 138 | 139 | template 140 | USTDEX_API void set_error(Error&& _error) noexcept 141 | { 142 | _rcvr_._set_result(set_error_t(), static_cast(_error)); 143 | ustdex::start(_opstate2_); 144 | } 145 | 146 | USTDEX_API void set_stopped() noexcept 147 | { 148 | _rcvr_._set_result(set_stopped_t()); 149 | ustdex::start(_opstate2_); 150 | } 151 | 152 | USTDEX_API auto get_env() const noexcept -> _env_t 153 | { 154 | return ustdex::get_env(_rcvr_._rcvr); 155 | } 156 | 157 | _rcvr_t _rcvr_; 158 | connect_result_t> _opstate1_; 159 | connect_result_t, _rcvr_ref<_rcvr_t>> _opstate2_; 160 | }; 161 | 162 | template 163 | struct USTDEX_TYPE_VISIBILITY_DEFAULT _sndr_t; 164 | 165 | template 166 | struct _closure_t; 167 | 168 | public: 169 | template 170 | USTDEX_API _sndr_t operator()(Sndr _sndr, Sch _sch) const noexcept; 171 | 172 | template 173 | USTDEX_TRIVIAL_API _closure_t operator()(Sch _sch) const noexcept; 174 | }; 175 | 176 | template 177 | struct USTDEX_TYPE_VISIBILITY_DEFAULT continue_on_t::_closure_t 178 | { 179 | Sch _sch; 180 | 181 | template 182 | USTDEX_TRIVIAL_API friend auto operator|(Sndr _sndr, _closure_t&& _self) 183 | { 184 | return continue_on_t()(static_cast(_sndr), static_cast(_self._sch)); 185 | } 186 | }; 187 | 188 | template 189 | struct _decay_args 190 | { 191 | template 192 | USTDEX_TRIVIAL_API constexpr auto operator()() const noexcept 193 | { 194 | if constexpr (!_decay_copyable) 195 | { 196 | return invalid_completion_signature(); 199 | } 200 | else if constexpr (!_nothrow_decay_copyable) 201 | { 202 | return completion_signatures{}; 203 | } 204 | else 205 | { 206 | return completion_signatures{}; 207 | } 208 | } 209 | }; 210 | 211 | template 212 | struct USTDEX_TYPE_VISIBILITY_DEFAULT continue_on_t::_sndr_t 213 | { 214 | using sender_concept = sender_t; 215 | USTDEX_NO_UNIQUE_ADDRESS continue_on_t _tag; 216 | Sch _sch; 217 | Sndr _sndr; 218 | 219 | struct USTDEX_TYPE_VISIBILITY_DEFAULT _attrs_t 220 | { 221 | _sndr_t* _sndr; 222 | 223 | template 224 | USTDEX_API auto query(get_completion_scheduler_t) const noexcept 225 | { 226 | return _sndr->_sch; 227 | } 228 | 229 | template 230 | USTDEX_API auto query(Query) const // 231 | -> _query_result_t> 232 | { 233 | return ustdex::get_env(_sndr->_sndr).query(Query{}); 234 | } 235 | }; 236 | 237 | template 238 | USTDEX_API static constexpr auto get_completion_signatures() 239 | { 240 | USTDEX_LET_COMPLETIONS(auto(_child_completions) = get_child_completion_signatures()) 241 | { 242 | USTDEX_LET_COMPLETIONS( 243 | auto(_sch_completions) = ustdex::get_completion_signatures, Env...>()) 244 | { 245 | // The scheduler contributes error and stopped completions. 246 | return concat_completion_signatures( 247 | transform_completion_signatures(_sch_completions, _swallow_transform()), 248 | transform_completion_signatures(_child_completions, _decay_args{}, _decay_args{})); 249 | } 250 | } 251 | } 252 | 253 | template 254 | USTDEX_API _opstate_t connect(Rcvr _rcvr) && 255 | { 256 | return {static_cast(_sndr), _sch, static_cast(_rcvr)}; 257 | } 258 | 259 | template 260 | USTDEX_API _opstate_t connect(Rcvr _rcvr) const& 261 | { 262 | return {_sndr, _sch, static_cast(_rcvr)}; 263 | } 264 | 265 | USTDEX_API _attrs_t get_env() const noexcept 266 | { 267 | return _attrs_t{this}; 268 | } 269 | }; 270 | 271 | template 272 | USTDEX_API auto continue_on_t::operator()(Sndr _sndr, Sch _sch) const noexcept -> continue_on_t::_sndr_t 273 | { 274 | return _sndr_t{{}, _sch, static_cast(_sndr)}; 275 | } 276 | 277 | template 278 | USTDEX_TRIVIAL_API continue_on_t::_closure_t continue_on_t::operator()(Sch _sch) const noexcept 279 | { 280 | return _closure_t{_sch}; 281 | } 282 | 283 | inline constexpr continue_on_t continues_on{}; 284 | } // namespace ustdex 285 | 286 | #include "epilogue.hpp" 287 | 288 | #endif 289 | -------------------------------------------------------------------------------- /include/ustdex/detail/cpos.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 3 | * SPDX-License-Identifier: Apache-2.0 4 | * 5 | * Licensed under the Apache License Version 2.0 with LLVM Exceptions 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * https://llvm.org/LICENSE.txt 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | #ifndef USTDEX_ASYNC_DETAIL_CPOS 19 | #define USTDEX_ASYNC_DETAIL_CPOS 20 | 21 | #include "config.hpp" 22 | #include "env.hpp" // IWYU pragma: export 23 | #include "meta.hpp" 24 | 25 | #include "prologue.hpp" 26 | 27 | namespace ustdex 28 | { 29 | struct USTDEX_TYPE_VISIBILITY_DEFAULT dependent_sender_error; 30 | 31 | template 32 | struct USTDEX_TYPE_VISIBILITY_DEFAULT completion_signatures; 33 | 34 | struct USTDEX_TYPE_VISIBILITY_DEFAULT receiver_t 35 | {}; 36 | 37 | struct USTDEX_TYPE_VISIBILITY_DEFAULT operation_state_t 38 | {}; 39 | 40 | struct USTDEX_TYPE_VISIBILITY_DEFAULT sender_t 41 | {}; 42 | 43 | struct USTDEX_TYPE_VISIBILITY_DEFAULT scheduler_t 44 | {}; 45 | 46 | template 47 | using _sender_concept_t = typename std::remove_reference_t::sender_concept; 48 | 49 | template 50 | using _receiver_concept_t = typename std::remove_reference_t::receiver_concept; 51 | 52 | template 53 | using _scheduler_concept_t = typename std::remove_reference_t::scheduler_concept; 54 | 55 | template 56 | inline constexpr bool _is_sender = _m_callable_q<_sender_concept_t, Ty>; 57 | 58 | template 59 | inline constexpr bool _is_receiver = _m_callable_q<_receiver_concept_t, Ty>; 60 | 61 | template 62 | inline constexpr bool _is_scheduler = _m_callable_q<_scheduler_concept_t, Ty>; 63 | 64 | // handy enumerations for keeping type names readable 65 | enum _disposition_t 66 | { 67 | _value, 68 | _error, 69 | _stopped 70 | }; 71 | 72 | // make the completion tags equality comparable 73 | template <_disposition_t Disposition> 74 | struct _completion_tag 75 | { 76 | template <_disposition_t OtherDisposition> 77 | USTDEX_TRIVIAL_API constexpr auto operator==(_completion_tag) const noexcept -> bool 78 | { 79 | return Disposition == OtherDisposition; 80 | } 81 | 82 | template <_disposition_t OtherDisposition> 83 | USTDEX_TRIVIAL_API constexpr auto operator!=(_completion_tag) const noexcept -> bool 84 | { 85 | return Disposition != OtherDisposition; 86 | } 87 | 88 | static constexpr _disposition_t _disposition = Disposition; 89 | }; 90 | 91 | inline constexpr struct set_value_t : _completion_tag<_value> 92 | { 93 | template 94 | USTDEX_TRIVIAL_API auto operator()(Rcvr&& _rcvr, Ts&&... _ts) const noexcept 95 | -> decltype(static_cast(_rcvr).set_value(static_cast(_ts)...)) 96 | { 97 | static_assert(std::is_same_v(_rcvr).set_value(static_cast(_ts)...)), void>); 98 | static_assert(noexcept(static_cast(_rcvr).set_value(static_cast(_ts)...))); 99 | static_cast(_rcvr).set_value(static_cast(_ts)...); 100 | } 101 | } set_value{}; 102 | 103 | inline constexpr struct set_error_t : _completion_tag<_error> 104 | { 105 | template 106 | USTDEX_TRIVIAL_API auto operator()(Rcvr&& _rcvr, Ey&& _e) const noexcept 107 | -> decltype(static_cast(_rcvr).set_error(static_cast(_e))) 108 | { 109 | static_assert(std::is_same_v(_rcvr).set_error(static_cast(_e))), void>); 110 | static_assert(noexcept(static_cast(_rcvr).set_error(static_cast(_e)))); 111 | static_cast(_rcvr).set_error(static_cast(_e)); 112 | } 113 | } set_error{}; 114 | 115 | inline constexpr struct set_stopped_t : _completion_tag<_stopped> 116 | { 117 | template 118 | USTDEX_TRIVIAL_API auto operator()(Rcvr&& _rcvr) const noexcept -> decltype(static_cast(_rcvr).set_stopped()) 119 | { 120 | static_assert(std::is_same_v(_rcvr).set_stopped()), void>); 121 | static_assert(noexcept(static_cast(_rcvr).set_stopped())); 122 | static_cast(_rcvr).set_stopped(); 123 | } 124 | } set_stopped{}; 125 | 126 | inline constexpr struct start_t 127 | { 128 | template 129 | USTDEX_TRIVIAL_API auto operator()(OpState& _opstate) const noexcept -> decltype(_opstate.start()) 130 | { 131 | // static_assert(!_m_is_error); 132 | static_assert(std::is_same_v); 133 | static_assert(noexcept(_opstate.start())); 134 | _opstate.start(); 135 | } 136 | } start{}; 137 | 138 | // get_completion_signatures 139 | template 140 | USTDEX_TRIVIAL_API USTDEX_CONSTEVAL auto get_completion_signatures(); 141 | 142 | // connect 143 | inline constexpr struct connect_t 144 | { 145 | template 146 | USTDEX_TRIVIAL_API auto operator()(Sndr&& _sndr, Rcvr&& _rcvr) const 147 | noexcept(noexcept(static_cast(_sndr).connect(static_cast(_rcvr)))) 148 | -> decltype(static_cast(_sndr).connect(static_cast(_rcvr))) 149 | { 150 | return static_cast(_sndr).connect(static_cast(_rcvr)); 151 | } 152 | } connect{}; 153 | 154 | inline constexpr struct schedule_t 155 | { 156 | template 157 | USTDEX_TRIVIAL_API auto operator()(Sch&& _sch) const noexcept -> decltype(static_cast(_sch).schedule()) 158 | { 159 | static_assert(noexcept(static_cast(_sch).schedule())); 160 | return static_cast(_sch).schedule(); 161 | } 162 | } schedule{}; 163 | 164 | template 165 | using connect_result_t = decltype(connect(declval(), declval())); 166 | 167 | template 168 | using completion_signatures_of_t = decltype(ustdex::get_completion_signatures()); 169 | 170 | template 171 | using schedule_result_t = decltype(schedule(declval())); 172 | 173 | template 174 | inline constexpr bool _nothrow_connectable = noexcept(connect(declval(), declval())); 175 | 176 | namespace detail 177 | { 178 | template <_disposition_t, class Void = void> 179 | extern _m_undefined _set_tag; 180 | template 181 | extern _fn_t* _set_tag<_value, Void>; 182 | template 183 | extern _fn_t* _set_tag<_error, Void>; 184 | template 185 | extern _fn_t* _set_tag<_stopped, Void>; 186 | } // namespace detail 187 | } // namespace ustdex 188 | 189 | #include "epilogue.hpp" 190 | 191 | #endif 192 | -------------------------------------------------------------------------------- /include/ustdex/detail/env.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 3 | * SPDX-License-Identifier: Apache-2.0 4 | * 5 | * Licensed under the Apache License Version 2.0 with LLVM Exceptions 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * https://llvm.org/LICENSE.txt 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | #ifndef USTDEX_ASYNC_DETAIL_ENV 19 | #define USTDEX_ASYNC_DETAIL_ENV 20 | 21 | #include "meta.hpp" 22 | #include "queries.hpp" 23 | #include "tuple.hpp" 24 | #include "utility.hpp" 25 | 26 | #include 27 | 28 | #include "prologue.hpp" 29 | 30 | USTDEX_PRAGMA_PUSH() 31 | 32 | // Suppress the warning: "definition of implicit copy constructor for 'env<>' is 33 | // deprecated because it has a user-declared copy assignment operator". We need to 34 | // suppress this warning rather than fix the code because defaulting or defining 35 | // the copy constructor would prevent aggregate initialization, which these types 36 | // depend on. 37 | USTDEX_PRAGMA_IGNORE_GNU("-Wunknown-warning-option") 38 | USTDEX_PRAGMA_IGNORE_GNU("-Wdeprecated-copy") 39 | 40 | // warning #20012-D: __device__ annotation is ignored on a 41 | // function("inplace_stop_source") that is explicitly defaulted on its first 42 | // declaration 43 | USTDEX_PRAGMA_IGNORE_EDG(20012) 44 | 45 | namespace ustdex 46 | { 47 | template 48 | extern Ty _unwrap_ref; 49 | 50 | template 51 | extern Ty& _unwrap_ref<::std::reference_wrapper>; 52 | 53 | template 54 | extern Ty& _unwrap_ref>; 55 | 56 | template 57 | using _unwrap_reference_t = decltype(_unwrap_ref); 58 | 59 | template 60 | struct USTDEX_TYPE_VISIBILITY_DEFAULT prop 61 | { 62 | USTDEX_NO_UNIQUE_ADDRESS Query _query; 63 | USTDEX_NO_UNIQUE_ADDRESS Value _value; 64 | 65 | USTDEX_TRIVIAL_API constexpr auto query(Query) const noexcept -> const Value& 66 | { 67 | return _value; 68 | } 69 | 70 | prop& operator=(const prop&) = delete; 71 | }; 72 | 73 | template 74 | prop(Query, Value) -> prop; 75 | 76 | template 77 | struct USTDEX_TYPE_VISIBILITY_DEFAULT env 78 | { 79 | _tuple _envs_; 80 | 81 | template 82 | USTDEX_TRIVIAL_API static constexpr decltype(auto) _get_1st(const env& _self) noexcept 83 | { 84 | constexpr bool _flags[] = {_queryable_with..., false}; 85 | constexpr std::size_t _idx = ustdex::_find_pos(_flags, _flags + sizeof...(Envs)); 86 | if constexpr (_idx != _npos) 87 | { 88 | return ustdex::_cget<_idx>(_self._envs_); 89 | } 90 | } 91 | 92 | template 93 | using _1st_env_t = decltype(env::_get_1st(declval())); 94 | 95 | template 96 | USTDEX_TRIVIAL_API constexpr auto query(Query _query) const 97 | noexcept(_nothrow_queryable_with<_1st_env_t, Query>) // 98 | -> _query_result_t<_1st_env_t, Query> 99 | { 100 | return env::_get_1st(*this).query(_query); 101 | } 102 | 103 | env& operator=(const env&) = delete; 104 | }; 105 | 106 | // partial specialization for two environments 107 | template 108 | struct USTDEX_TYPE_VISIBILITY_DEFAULT env 109 | { 110 | USTDEX_NO_UNIQUE_ADDRESS Env0 _env0_; 111 | USTDEX_NO_UNIQUE_ADDRESS Env1 _env1_; 112 | 113 | template 114 | USTDEX_TRIVIAL_API static constexpr decltype(auto) _get_1st(const env& _self) noexcept 115 | { 116 | if constexpr (_queryable_with) 117 | { 118 | return (_self._env0_); 119 | } 120 | else 121 | { 122 | return (_self._env1_); 123 | } 124 | } 125 | 126 | template 127 | using _1st_env_t = decltype(env::_get_1st(declval())); 128 | 129 | template 130 | USTDEX_TRIVIAL_API constexpr auto query(Query _query) const 131 | noexcept(_nothrow_queryable_with<_1st_env_t, Query>) // 132 | -> _query_result_t<_1st_env_t, Query> 133 | { 134 | return env::_get_1st(*this).query(_query); 135 | } 136 | 137 | env& operator=(const env&) = delete; 138 | }; 139 | 140 | template 141 | env(Envs...) -> env<_unwrap_reference_t...>; 142 | 143 | using empty_env [[deprecated("use ustdex::env<> instead")]] = env<>; 144 | 145 | struct get_env_t 146 | { 147 | template 148 | USTDEX_TRIVIAL_API auto operator()(Ty&& _ty) const noexcept -> decltype(_ty.get_env()) 149 | { 150 | static_assert(noexcept(_ty.get_env())); 151 | return _ty.get_env(); 152 | } 153 | 154 | USTDEX_TRIVIAL_API env<> operator()(_ignore) const noexcept 155 | { 156 | return {}; 157 | } 158 | }; 159 | 160 | namespace _region 161 | { 162 | inline constexpr get_env_t get_env{}; 163 | } // namespace _region 164 | 165 | using namespace _region; 166 | 167 | template 168 | using env_of_t = decltype(ustdex::get_env(declval())); 169 | } // namespace ustdex 170 | 171 | USTDEX_PRAGMA_POP() 172 | 173 | #include "epilogue.hpp" 174 | 175 | #endif 176 | -------------------------------------------------------------------------------- /include/ustdex/detail/epilogue.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 3 | * SPDX-License-Identifier: Apache-2.0 4 | * 5 | * Licensed under the Apache License Version 2.0 with LLVM Exceptions 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * https://llvm.org/LICENSE.txt 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | #if !defined(USTDEX_ASYNC_PROLOGUE_INCLUDED) 18 | # error epilogue.cuh included without a prior inclusion of prologue.cuh 19 | #endif 20 | 21 | #undef USTDEX_ASYNC_PROLOGUE_INCLUDED 22 | 23 | USTDEX_PRAGMA_POP() 24 | -------------------------------------------------------------------------------- /include/ustdex/detail/exception.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 3 | * SPDX-License-Identifier: Apache-2.0 4 | * 5 | * Licensed under the Apache License Version 2.0 with LLVM Exceptions 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * https://llvm.org/LICENSE.txt 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | #ifndef USTDEX_ASYNC_DETAIL_EXCEPTION 19 | #define USTDEX_ASYNC_DETAIL_EXCEPTION 20 | 21 | #include "config.hpp" // IWYU pragma: export 22 | #include "preprocessor.hpp" // IWYU pragma: export 23 | 24 | #include // IWYU pragma: export 25 | 26 | #if USTDEX_CUDA() 27 | # define USTDEX_CATCH(...) 28 | # define USTDEX_TRY(TRY, CATCH) \ 29 | USTDEX_IF_ELSE_TARGET( \ 30 | USTDEX_IS_HOST, (try { USTDEX_PP_EXPAND TRY } catch (...){USTDEX_PP_EXPAND CATCH}), ({USTDEX_PP_EXPAND TRY})) 31 | #else 32 | # define USTDEX_CATCH(...) 33 | # define USTDEX_TRY(TRY, CATCH) USTDEX_PP_EXPAND(try { USTDEX_PP_EXPAND TRY } catch (...){USTDEX_PP_EXPAND CATCH}) 34 | #endif 35 | 36 | #if USTDEX_HOST_ONLY() 37 | // This is the default behavior for host code, and for nvc++ 38 | # define USTDEX_NOEXCEPT_EXPR(...) noexcept(__VA_ARGS__) 39 | #else 40 | // Treat everything as no-throw in device code 41 | # define USTDEX_NOEXCEPT_EXPR(...) true 42 | #endif 43 | 44 | #endif 45 | -------------------------------------------------------------------------------- /include/ustdex/detail/exclusive_scan.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 3 | * SPDX-License-Identifier: Apache-2.0 4 | * 5 | * Licensed under the Apache License Version 2.0 with LLVM Exceptions 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * https://llvm.org/LICENSE.txt 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | #pragma once 19 | 20 | #include "config.hpp" 21 | 22 | #include // IWYU pragma: keep 23 | #include 24 | 25 | namespace ustdex 26 | { 27 | #if __cplusplus >= 202002L 28 | // exclusive_scan is constexpr in C++20 29 | using std::exclusive_scan; 30 | #else 31 | template 32 | USTDEX_API constexpr OutputIterator 33 | exclusive_scan(InputIterator first, InputIterator last, OutputIterator result, Tp init, BinaryOp b) 34 | { 35 | if (first != last) 36 | { 37 | Tp tmp(b(init, *first)); 38 | while (true) 39 | { 40 | *result = static_cast(init); 41 | ++result; 42 | ++first; 43 | if (first == last) 44 | { 45 | break; 46 | } 47 | init = static_cast(tmp); 48 | tmp = b(init, *first); 49 | } 50 | } 51 | return result; 52 | } 53 | 54 | template 55 | USTDEX_API constexpr OutputIterator 56 | exclusive_scan(InputIterator first, InputIterator last, OutputIterator result, Tp init) 57 | { 58 | return ustdex::exclusive_scan(first, last, result, init, std::plus<>()); 59 | } 60 | #endif 61 | } // namespace ustdex 62 | -------------------------------------------------------------------------------- /include/ustdex/detail/just.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 3 | * SPDX-License-Identifier: Apache-2.0 4 | * 5 | * Licensed under the Apache License Version 2.0 with LLVM Exceptions 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * https://llvm.org/LICENSE.txt 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | #ifndef USTDEX_ASYNC_DETAIL_JUST 19 | #define USTDEX_ASYNC_DETAIL_JUST 20 | 21 | #include "completion_signatures.hpp" 22 | #include "config.hpp" 23 | #include "cpos.hpp" 24 | #include "tuple.hpp" 25 | #include "utility.hpp" 26 | 27 | #include "prologue.hpp" 28 | 29 | namespace ustdex 30 | { 31 | // Forward declarations of the just* tag types: 32 | struct just_t; 33 | struct just_error_t; 34 | struct just_stopped_t; 35 | 36 | // Map from a disposition to the corresponding tag types: 37 | namespace detail 38 | { 39 | template <_disposition_t, class Void = void> 40 | extern _m_undefined _just_tag; 41 | template 42 | extern _fn_t* _just_tag<_value, Void>; 43 | template 44 | extern _fn_t* _just_tag<_error, Void>; 45 | template 46 | extern _fn_t* _just_tag<_stopped, Void>; 47 | } // namespace detail 48 | 49 | template <_disposition_t Disposition> 50 | struct _just 51 | { 52 | private: 53 | using JustTag = decltype(detail::_just_tag()); 54 | using SetTag = decltype(detail::_set_tag()); 55 | 56 | template 57 | struct USTDEX_TYPE_VISIBILITY_DEFAULT _opstate_t 58 | { 59 | using operation_state_concept = operation_state_t; 60 | 61 | Rcvr _rcvr_; 62 | _tuple _values_; 63 | 64 | struct _complete_fn 65 | { 66 | _opstate_t* _self_; 67 | 68 | USTDEX_API void operator()(Ts&... _ts) const noexcept 69 | { 70 | SetTag()(static_cast(_self_->_rcvr_), static_cast(_ts)...); 71 | } 72 | }; 73 | 74 | USTDEX_API void start() & noexcept 75 | { 76 | _values_.apply(_complete_fn{this}, _values_); 77 | } 78 | }; 79 | 80 | template 81 | struct USTDEX_TYPE_VISIBILITY_DEFAULT _sndr_t 82 | { 83 | using sender_concept = sender_t; 84 | 85 | USTDEX_NO_UNIQUE_ADDRESS JustTag _tag_; 86 | _tuple _values_; 87 | 88 | template 89 | USTDEX_API static constexpr auto get_completion_signatures() noexcept 90 | { 91 | return ustdex::completion_signatures(); 92 | } 93 | 94 | template 95 | USTDEX_API _opstate_t connect(Rcvr _rcvr) && // 96 | noexcept(_nothrow_decay_copyable) 97 | { 98 | return _opstate_t{static_cast(_rcvr), static_cast<_tuple&&>(_values_)}; 99 | } 100 | 101 | template 102 | USTDEX_API _opstate_t connect(Rcvr _rcvr) const& // 103 | noexcept(_nothrow_decay_copyable) 104 | { 105 | return _opstate_t{static_cast(_rcvr), _values_}; 106 | } 107 | }; 108 | 109 | public: 110 | template 111 | USTDEX_TRIVIAL_API auto operator()(Ts... _ts) const noexcept 112 | { 113 | return _sndr_t{JustTag{}, {{static_cast(_ts)}...}}; 114 | } 115 | }; 116 | 117 | inline constexpr struct just_t : _just<_value> 118 | { 119 | } just{}; 120 | 121 | inline constexpr struct just_error_t : _just<_error> 122 | { 123 | } just_error{}; 124 | 125 | inline constexpr struct just_stopped_t : _just<_stopped> 126 | { 127 | } just_stopped{}; 128 | } // namespace ustdex 129 | 130 | #include "epilogue.hpp" 131 | 132 | #endif 133 | -------------------------------------------------------------------------------- /include/ustdex/detail/just_from.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 3 | * SPDX-License-Identifier: Apache-2.0 4 | * 5 | * Licensed under the Apache License Version 2.0 with LLVM Exceptions 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * https://llvm.org/LICENSE.txt 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | #ifndef USTDEX_ASYNC_DETAIL_JUST_FROM 19 | #define USTDEX_ASYNC_DETAIL_JUST_FROM 20 | 21 | #include "completion_signatures.hpp" 22 | #include "config.hpp" 23 | #include "cpos.hpp" 24 | #include "rcvr_ref.hpp" 25 | #include "tuple.hpp" 26 | #include "utility.hpp" 27 | 28 | #include "prologue.hpp" 29 | 30 | namespace ustdex 31 | { 32 | // Forward declarations of the just* tag types: 33 | struct just_from_t; 34 | struct just_error_from_t; 35 | struct just_stopped_from_t; 36 | 37 | // Map from a disposition to the corresponding tag types: 38 | namespace detail 39 | { 40 | template <_disposition_t, class Void = void> 41 | extern _m_undefined _just_from_tag; 42 | template 43 | extern _fn_t* _just_from_tag<_value, Void>; 44 | template 45 | extern _fn_t* _just_from_tag<_error, Void>; 46 | template 47 | extern _fn_t* _just_from_tag<_stopped, Void>; 48 | } // namespace detail 49 | 50 | struct AN_ERROR_COMPLETION_MUST_HAVE_EXACTLY_ONE_ERROR_ARGUMENT; 51 | struct A_STOPPED_COMPLETION_MUST_HAVE_NO_ARGUMENTS; 52 | 53 | template <_disposition_t Disposition> 54 | struct _just_from 55 | { 56 | private: 57 | using JustTag = decltype(detail::_just_from_tag()); 58 | using SetTag = decltype(detail::_set_tag()); 59 | 60 | using _diag_t = _m_if; 63 | 64 | template 65 | using _error_t = ERROR>; 66 | 67 | struct _probe_fn 68 | { 69 | template 70 | auto operator()(Ts&&... _ts) const noexcept 71 | -> _m_if<_signature_disposition != _invalid_disposition, 72 | completion_signatures, 73 | _error_t>; 74 | }; 75 | 76 | template 77 | struct _complete_fn 78 | { 79 | Rcvr& _rcvr_; 80 | 81 | template 82 | USTDEX_API auto operator()(Ts&&... _ts) const noexcept 83 | { 84 | SetTag()(static_cast(_rcvr_), static_cast(_ts)...); 85 | } 86 | }; 87 | 88 | template 89 | struct _opstate 90 | { 91 | using operation_state_concept = operation_state_t; 92 | 93 | Rcvr _rcvr_; 94 | Fn _fn_; 95 | 96 | USTDEX_API void start() & noexcept 97 | { 98 | static_cast(_fn_)(_complete_fn{_rcvr_}); 99 | } 100 | }; 101 | 102 | template 103 | struct USTDEX_TYPE_VISIBILITY_DEFAULT _sndr_t 104 | { 105 | using sender_concept = sender_t; 106 | 107 | USTDEX_NO_UNIQUE_ADDRESS JustTag _tag_; 108 | Fn _fn_; 109 | 110 | template 111 | USTDEX_API static constexpr auto get_completion_signatures() noexcept 112 | { 113 | return _call_result_t{}; 114 | } 115 | 116 | template 117 | USTDEX_API _opstate connect(Rcvr _rcvr) && // 118 | noexcept(_nothrow_decay_copyable) 119 | { 120 | return _opstate{static_cast(_rcvr), static_cast(_fn_)}; 121 | } 122 | 123 | template 124 | USTDEX_API _opstate connect(Rcvr _rcvr) const& // 125 | noexcept(_nothrow_decay_copyable) 126 | { 127 | return _opstate{static_cast(_rcvr), _fn_}; 128 | } 129 | }; 130 | 131 | public: 132 | template 133 | USTDEX_TRIVIAL_API auto operator()(Fn _fn) const noexcept 134 | { 135 | using _completions = _call_result_t; 136 | static_assert(_valid_completion_signatures<_completions>, 137 | "The function passed to just_from must return an instance of a specialization of " 138 | "completion_signatures<>."); 139 | return _sndr_t{{}, static_cast(_fn)}; 140 | } 141 | }; 142 | 143 | inline constexpr struct just_from_t : _just_from<_value> 144 | { 145 | } just_from{}; 146 | 147 | inline constexpr struct just_error_from_t : _just_from<_error> 148 | { 149 | } just_error_from{}; 150 | 151 | inline constexpr struct just_stopped_from_t : _just_from<_stopped> 152 | { 153 | } just_stopped_from{}; 154 | } // namespace ustdex 155 | 156 | #include "epilogue.hpp" 157 | 158 | #endif 159 | -------------------------------------------------------------------------------- /include/ustdex/detail/lazy.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 3 | * SPDX-License-Identifier: Apache-2.0 4 | * 5 | * Licensed under the Apache License Version 2.0 with LLVM Exceptions 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * https://llvm.org/LICENSE.txt 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | #ifndef USTDEX_ASYNC_DETAIL_LAZY 19 | #define USTDEX_ASYNC_DETAIL_LAZY 20 | 21 | #include "config.hpp" 22 | #include "meta.hpp" 23 | #include "type_traits.hpp" 24 | 25 | #include 26 | #include // IWYU pragma: keep 27 | 28 | namespace ustdex 29 | { 30 | /// @brief A lazy type that can be used to delay the construction of a type. 31 | template 32 | struct _lazy 33 | { 34 | USTDEX_API _lazy() noexcept {} 35 | 36 | USTDEX_API ~_lazy() {} 37 | 38 | template 39 | USTDEX_API Ty& construct(Ts&&... _ts) noexcept(_nothrow_constructible) 40 | { 41 | Ty* _value_ = ::new (static_cast(std::addressof(_value_))) Ty{static_cast(_ts)...}; 42 | return *std::launder(_value_); 43 | } 44 | 45 | template 46 | USTDEX_API Ty& construct_from(Fn&& _fn, Ts&&... _ts) noexcept(_nothrow_callable) 47 | { 48 | Ty* _value_ = ::new (static_cast(std::addressof(_value_))) 49 | Ty{static_cast(_fn)(static_cast(_ts)...)}; 50 | return *std::launder(_value_); 51 | } 52 | 53 | USTDEX_API void destroy() noexcept 54 | { 55 | std::destroy_at(&_value_); 56 | } 57 | 58 | union 59 | { 60 | Ty _value_; 61 | }; 62 | }; 63 | 64 | namespace detail 65 | { 66 | template 67 | struct _lazy_box_ 68 | { 69 | static_assert(Size != 0); 70 | alignas(Align) unsigned char _data_[Size]; 71 | }; 72 | 73 | template 74 | using _lazy_box = _lazy_box_; 75 | } // namespace detail 76 | 77 | template 78 | struct _lazy_tupl; 79 | 80 | template <> 81 | struct _lazy_tupl> 82 | { 83 | template 84 | USTDEX_TRIVIAL_API static auto apply(Fn&& _fn, Self&&, Us&&... _us) // 85 | noexcept(_nothrow_callable) -> _call_result_t 86 | { 87 | return static_cast(_fn)(static_cast(_us)...); 88 | } 89 | }; 90 | 91 | template 92 | struct _lazy_tupl, Ts...> : detail::_lazy_box... 93 | { 94 | template 95 | using _at = _m_index; 96 | 97 | USTDEX_TRIVIAL_API _lazy_tupl() noexcept {} 98 | 99 | USTDEX_API ~_lazy_tupl() 100 | { 101 | ((_engaged_[Idx] ? std::destroy_at(_get()) : void(0)), ...); 102 | } 103 | 104 | template 105 | USTDEX_TRIVIAL_API Ty* _get() noexcept 106 | { 107 | return reinterpret_cast(this->detail::_lazy_box::_data_); 108 | } 109 | 110 | template 111 | USTDEX_TRIVIAL_API _at& _emplace(Us&&... _us) // 112 | noexcept(_nothrow_constructible<_at, Us...>) 113 | { 114 | using Ty = _at; 115 | Ty* _value_ = ::new (static_cast(_get())) Ty{static_cast(_us)...}; 116 | _engaged_[Ny] = true; 117 | return *std::launder(_value_); 118 | } 119 | 120 | template 121 | USTDEX_TRIVIAL_API static auto apply(Fn&& _fn, Self&& _self, Us&&... _us) // 122 | noexcept(_nothrow_callable...>) 123 | -> _call_result_t...> 124 | { 125 | return static_cast( 126 | _fn)(static_cast(_us)..., static_cast<_copy_cvref_t&&>(*_self.template _get())...); 127 | } 128 | 129 | bool _engaged_[sizeof...(Ts)] = {}; 130 | }; 131 | 132 | #if USTDEX_MSVC() 133 | template 134 | struct _mk_lazy_tuple_ 135 | { 136 | using _indices_t = std::make_index_sequence; 137 | using type = _lazy_tupl<_indices_t, Ts...>; 138 | }; 139 | 140 | template 141 | using _lazy_tuple = typename _mk_lazy_tuple_::type; 142 | #else 143 | template 144 | using _lazy_tuple = _lazy_tupl, Ts...>; 145 | #endif 146 | 147 | template 148 | using _decayed_lazy_tuple = _lazy_tuple; 149 | 150 | } // namespace ustdex 151 | 152 | #endif 153 | -------------------------------------------------------------------------------- /include/ustdex/detail/prologue.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 3 | * SPDX-License-Identifier: Apache-2.0 4 | * 5 | * Licensed under the Apache License Version 2.0 with LLVM Exceptions 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * https://llvm.org/LICENSE.txt 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | #if defined(USTDEX_ASYNC_PROLOGUE_INCLUDED) 19 | # error multiple inclusion of prologue.cuh 20 | #endif 21 | 22 | #define USTDEX_ASYNC_PROLOGUE_INCLUDED 23 | 24 | #include "config.hpp" 25 | 26 | USTDEX_PRAGMA_PUSH() 27 | USTDEX_PRAGMA_IGNORE_GNU("-Wsubobject-linkage") 28 | USTDEX_PRAGMA_IGNORE_GNU("-Wunused-value") 29 | USTDEX_PRAGMA_IGNORE_MSVC(4848) // [[no_unique_address]] prior to C++20 as a vendor extension 30 | USTDEX_PRAGMA_IGNORE_EDG(attribute_requires_external_linkage) 31 | 32 | USTDEX_PRAGMA_IGNORE_GNU("-Wmissing-braces") 33 | USTDEX_PRAGMA_IGNORE_MSVC(5246) // missing braces around initializer 34 | -------------------------------------------------------------------------------- /include/ustdex/detail/queries.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 3 | * SPDX-License-Identifier: Apache-2.0 4 | * 5 | * Licensed under the Apache License Version 2.0 with LLVM Exceptions 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * https://llvm.org/LICENSE.txt 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | #ifndef USTDEX_ASYNC_DETAIL_QUERIES 19 | #define USTDEX_ASYNC_DETAIL_QUERIES 20 | 21 | #include "meta.hpp" 22 | #include "stop_token.hpp" 23 | #include "type_traits.hpp" 24 | #include "utility.hpp" 25 | 26 | #include 27 | 28 | #include "prologue.hpp" 29 | 30 | namespace ustdex 31 | { 32 | template 33 | auto _query_result_() -> decltype(declval().query(Query())); 34 | 35 | template 36 | using _query_result_t = decltype(_query_result_()); 37 | 38 | template 39 | inline constexpr bool _queryable_with = _m_callable_q<_query_result_t, Ty, Query>; 40 | 41 | #if defined(__CUDA_ARCH__) 42 | template 43 | inline constexpr bool _nothrow_queryable_with = true; 44 | #else 45 | template 46 | using _nothrow_queryable_ = std::enable_if_t().query(Query()))>; 47 | 48 | template 49 | inline constexpr bool _nothrow_queryable_with = _m_callable_q<_nothrow_queryable_, Ty, Query>; 50 | #endif 51 | 52 | inline constexpr struct get_allocator_t 53 | { 54 | template 55 | USTDEX_API auto operator()(const Env& _env) const noexcept // 56 | -> decltype(_env.query(*this)) 57 | { 58 | static_assert(noexcept(_env.query(*this))); 59 | return _env.query(*this); 60 | } 61 | 62 | USTDEX_API auto operator()(_ignore) const noexcept -> std::allocator 63 | { 64 | return {}; 65 | } 66 | } get_allocator{}; 67 | 68 | inline constexpr struct get_stop_token_t 69 | { 70 | template 71 | USTDEX_API auto operator()(const Env& _env) const noexcept // 72 | -> decltype(_env.query(*this)) 73 | { 74 | static_assert(noexcept(_env.query(*this))); 75 | return _env.query(*this); 76 | } 77 | 78 | USTDEX_API auto operator()(_ignore) const noexcept -> never_stop_token 79 | { 80 | return {}; 81 | } 82 | } get_stop_token{}; 83 | 84 | template 85 | using stop_token_of_t = USTDEX_DECAY(_call_result_t); 86 | 87 | template 88 | struct get_completion_scheduler_t 89 | { 90 | template 91 | USTDEX_API auto operator()(const Env& _env) const noexcept // 92 | -> decltype(_env.query(*this)) 93 | { 94 | static_assert(noexcept(_env.query(*this))); 95 | return _env.query(*this); 96 | } 97 | }; 98 | 99 | template 100 | inline constexpr get_completion_scheduler_t get_completion_scheduler{}; 101 | 102 | inline constexpr struct get_scheduler_t 103 | { 104 | template 105 | USTDEX_API auto operator()(const Env& _env) const noexcept // 106 | -> decltype(_env.query(*this)) 107 | { 108 | static_assert(noexcept(_env.query(*this))); 109 | return _env.query(*this); 110 | } 111 | } get_scheduler{}; 112 | 113 | inline constexpr struct get_delegation_scheduler_t 114 | { 115 | template 116 | USTDEX_API auto operator()(const Env& _env) const noexcept // 117 | -> decltype(_env.query(*this)) 118 | { 119 | static_assert(noexcept(_env.query(*this))); 120 | return _env.query(*this); 121 | } 122 | } get_delegation_scheduler{}; 123 | 124 | enum class forward_progress_guarantee 125 | { 126 | concurrent, 127 | parallel, 128 | weakly_parallel 129 | }; 130 | 131 | inline constexpr struct get_forward_progress_guarantee_t 132 | { 133 | template 134 | USTDEX_API auto operator()(const Sch& _sch) const noexcept // 135 | -> decltype(ustdex::_decay_copy(_sch.query(*this))) 136 | { 137 | static_assert(noexcept(_sch.query(*this))); 138 | return _sch.query(*this); 139 | } 140 | 141 | USTDEX_API auto operator()(_ignore) const noexcept -> forward_progress_guarantee 142 | { 143 | return forward_progress_guarantee::weakly_parallel; 144 | } 145 | } get_forward_progress_guarantee{}; 146 | 147 | inline constexpr struct get_domain_t 148 | { 149 | template 150 | USTDEX_API constexpr auto operator()(const Sch& _sch) const noexcept // 151 | -> decltype(ustdex::_decay_copy(_sch.query(*this))) 152 | { 153 | return {}; 154 | } 155 | } get_domain{}; 156 | 157 | template 158 | using domain_of_t = _call_result_t; 159 | 160 | } // namespace ustdex 161 | 162 | #include "epilogue.hpp" 163 | 164 | #endif 165 | -------------------------------------------------------------------------------- /include/ustdex/detail/rcvr_ref.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 3 | * SPDX-License-Identifier: Apache-2.0 4 | * 5 | * Licensed under the Apache License Version 2.0 with LLVM Exceptions 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * https://llvm.org/LICENSE.txt 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | #ifndef USTDEX_ASYNC_DETAIL_RCVR_REF 19 | #define USTDEX_ASYNC_DETAIL_RCVR_REF 20 | 21 | #include "cpos.hpp" 22 | 23 | // 24 | #include "prologue.hpp" 25 | 26 | namespace ustdex 27 | { 28 | template > 29 | struct _rcvr_ref 30 | { 31 | using receiver_concept = receiver_t; 32 | _Rcvr& _rcvr_; 33 | 34 | template 35 | USTDEX_TRIVIAL_API void set_value(_As&&... _as) noexcept 36 | { 37 | static_cast<_Rcvr&&>(_rcvr_).set_value(static_cast<_As&&>(_as)...); 38 | } 39 | 40 | template 41 | USTDEX_TRIVIAL_API void set_error(_Error&& _err) noexcept 42 | { 43 | static_cast<_Rcvr&&>(_rcvr_).set_error(static_cast<_Error&&>(_err)); 44 | } 45 | 46 | USTDEX_TRIVIAL_API void set_stopped() noexcept 47 | { 48 | static_cast<_Rcvr&&>(_rcvr_).set_stopped(); 49 | } 50 | 51 | USTDEX_API auto get_env() const noexcept -> _Env 52 | { 53 | return ustdex::get_env(_rcvr_); 54 | } 55 | }; 56 | 57 | template 58 | _rcvr_ref(_Rcvr&) -> _rcvr_ref<_Rcvr>; 59 | } // namespace ustdex 60 | 61 | #include "epilogue.hpp" 62 | 63 | #endif 64 | -------------------------------------------------------------------------------- /include/ustdex/detail/rcvr_with_env.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 3 | * SPDX-License-Identifier: Apache-2.0 4 | * 5 | * Licensed under the Apache License Version 2.0 with LLVM Exceptions 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * https://llvm.org/LICENSE.txt 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | #ifndef USTDEX_ASYNC_DETAIL_RCVR_WITH_ENV 19 | #define USTDEX_ASYNC_DETAIL_RCVR_WITH_ENV 20 | 21 | #include "cpos.hpp" 22 | #include "env.hpp" 23 | 24 | #include "prologue.hpp" 25 | 26 | namespace ustdex 27 | { 28 | template 29 | struct _rcvr_with_env_t : Rcvr 30 | { 31 | struct _env_t 32 | { 33 | template 34 | USTDEX_TRIVIAL_API static constexpr decltype(auto) _get_1st(const _env_t& self) noexcept 35 | { 36 | if constexpr (_queryable_with) 37 | { 38 | return (self._rcvr_->_env_); 39 | } 40 | else if constexpr (_queryable_with, Query>) 41 | { 42 | return ustdex::get_env(static_cast(*self._rcvr_)); 43 | } 44 | } 45 | 46 | template 47 | using _1st_env_t = decltype(_env_t::_get_1st(declval())); 48 | 49 | template 50 | USTDEX_TRIVIAL_API constexpr auto query(Query) const noexcept(_nothrow_queryable_with<_1st_env_t, Query>) // 51 | -> _query_result_t<_1st_env_t, Query> 52 | { 53 | return _env_t::_get_1st(*this); 54 | } 55 | 56 | _rcvr_with_env_t const* _rcvr_; 57 | }; 58 | 59 | USTDEX_TRIVIAL_API auto base() && noexcept -> Rcvr&& 60 | { 61 | return static_cast(*this); 62 | } 63 | 64 | USTDEX_TRIVIAL_API auto base() & noexcept -> Rcvr& 65 | { 66 | return *this; 67 | } 68 | 69 | USTDEX_TRIVIAL_API auto base() const& noexcept -> Rcvr const& 70 | { 71 | return *this; 72 | } 73 | 74 | USTDEX_TRIVIAL_API auto get_env() const noexcept -> _env_t 75 | { 76 | return _env_t{this}; 77 | } 78 | 79 | Env _env_; 80 | }; 81 | 82 | template 83 | _rcvr_with_env_t(Rcvr, Env) -> _rcvr_with_env_t; 84 | 85 | } // namespace ustdex 86 | 87 | #include "epilogue.hpp" 88 | 89 | #endif 90 | -------------------------------------------------------------------------------- /include/ustdex/detail/read_env.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 3 | * SPDX-License-Identifier: Apache-2.0 4 | * 5 | * Licensed under the Apache License Version 2.0 with LLVM Exceptions 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * https://llvm.org/LICENSE.txt 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | #ifndef USTDEX_ASYNC_DETAIL_READ_ENV 19 | #define USTDEX_ASYNC_DETAIL_READ_ENV 20 | 21 | #include "completion_signatures.hpp" 22 | #include "config.hpp" 23 | #include "cpos.hpp" 24 | #include "env.hpp" 25 | #include "exception.hpp" 26 | #include "queries.hpp" 27 | #include "utility.hpp" 28 | 29 | #include "prologue.hpp" 30 | 31 | namespace ustdex 32 | { 33 | struct THE_CURRENT_ENVIRONMENT_LACKS_THIS_QUERY; 34 | struct THE_CURRENT_ENVIRONMENT_RETURNED_VOID_FOR_THIS_QUERY; 35 | 36 | struct read_env_t 37 | { 38 | private: 39 | template 40 | struct USTDEX_TYPE_VISIBILITY_DEFAULT _opstate_t 41 | { 42 | using operation_state_concept = operation_state_t; 43 | 44 | Rcvr _rcvr_; 45 | 46 | USTDEX_API explicit _opstate_t(Rcvr _rcvr) 47 | : _rcvr_(static_cast(_rcvr)) 48 | {} 49 | 50 | USTDEX_IMMOVABLE(_opstate_t); 51 | 52 | USTDEX_API void start() noexcept 53 | { 54 | // If the query invocation is noexcept, call it directly. Otherwise, 55 | // wrap it in a try-catch block and forward the exception to the 56 | // receiver. 57 | if constexpr (_nothrow_callable>) 58 | { 59 | // This looks like a use after move, but `set_value` takes its 60 | // arguments by forwarding reference, so it's safe. 61 | ustdex::set_value(static_cast(_rcvr_), Query()(ustdex::get_env(_rcvr_))); 62 | } 63 | else 64 | { 65 | USTDEX_TRY( // 66 | ({ // 67 | ustdex::set_value(static_cast(_rcvr_), Query()(ustdex::get_env(_rcvr_))); 68 | }), 69 | USTDEX_CATCH(...) // 70 | ({ // 71 | ustdex::set_error(static_cast(_rcvr_), ::std::current_exception()); 72 | }) // 73 | ) 74 | } 75 | } 76 | }; 77 | 78 | template 79 | struct USTDEX_TYPE_VISIBILITY_DEFAULT _sndr_t; 80 | 81 | public: 82 | /// @brief Returns a sender that, when connected to a receiver and started, 83 | /// invokes the query with the receiver's environment and forwards the result 84 | /// to the receiver's `set_value` member. 85 | template 86 | USTDEX_TRIVIAL_API constexpr _sndr_t operator()(Query) const noexcept; 87 | }; 88 | 89 | template 90 | struct USTDEX_TYPE_VISIBILITY_DEFAULT read_env_t::_sndr_t 91 | { 92 | using sender_concept = sender_t; 93 | USTDEX_NO_UNIQUE_ADDRESS read_env_t _tag; 94 | USTDEX_NO_UNIQUE_ADDRESS Query _query; 95 | 96 | template 97 | USTDEX_API static constexpr auto get_completion_signatures() 98 | { 99 | if constexpr (!_callable) 100 | { 101 | return invalid_completion_signature(); 105 | } 106 | else if constexpr (std::is_void_v<_call_result_t>) 107 | { 108 | return invalid_completion_signature(); 112 | } 113 | else if constexpr (_nothrow_callable) 114 | { 115 | return completion_signatures)>{}; 116 | } 117 | else 118 | { 119 | return completion_signatures), set_error_t(::std::exception_ptr)>{}; 120 | } 121 | } 122 | 123 | template 124 | USTDEX_API auto connect(Rcvr _rcvr) const noexcept(_nothrow_movable) -> _opstate_t 125 | { 126 | return _opstate_t{static_cast(_rcvr)}; 127 | } 128 | }; 129 | 130 | template 131 | USTDEX_TRIVIAL_API constexpr read_env_t::_sndr_t read_env_t::operator()(Query _query) const noexcept 132 | { 133 | return _sndr_t{{}, _query}; 134 | } 135 | 136 | inline constexpr read_env_t read_env{}; 137 | 138 | } // namespace ustdex 139 | 140 | #include "epilogue.hpp" 141 | 142 | #endif 143 | -------------------------------------------------------------------------------- /include/ustdex/detail/run_loop.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 3 | * SPDX-License-Identifier: Apache-2.0 4 | * 5 | * Licensed under the Apache License Version 2.0 with LLVM Exceptions 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * https://llvm.org/LICENSE.txt 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | #ifndef USTDEX_ASYNC_DETAIL_RUN_LOOP 19 | #define USTDEX_ASYNC_DETAIL_RUN_LOOP 20 | 21 | #include "config.hpp" 22 | 23 | // libcu++ does not have or 24 | #if !defined(__CUDA_ARCH__) 25 | 26 | # include "completion_signatures.hpp" 27 | # include "env.hpp" 28 | # include "exception.hpp" 29 | # include "queries.hpp" 30 | # include "utility.hpp" 31 | 32 | # include 33 | # include 34 | 35 | # include "prologue.hpp" 36 | 37 | namespace ustdex 38 | { 39 | class run_loop; 40 | 41 | struct _task : _immovable 42 | { 43 | using _execute_fn_t = void(_task*) noexcept; 44 | 45 | _task() = default; 46 | 47 | USTDEX_API explicit _task(_task* _next, _task* _tail) noexcept 48 | : _next_{_next} 49 | , _tail_{_tail} 50 | {} 51 | 52 | USTDEX_API explicit _task(_task* _next, _execute_fn_t* _execute) noexcept 53 | : _next_{_next} 54 | , _execute_fn_{_execute} 55 | {} 56 | 57 | _task* _next_ = this; 58 | 59 | union 60 | { 61 | _task* _tail_ = nullptr; 62 | _execute_fn_t* _execute_fn_; 63 | }; 64 | 65 | USTDEX_API void _execute() noexcept 66 | { 67 | (*_execute_fn_)(this); 68 | } 69 | }; 70 | 71 | template 72 | struct _operation : _task 73 | { 74 | run_loop* _loop_; 75 | USTDEX_NO_UNIQUE_ADDRESS Rcvr _rcvr_; 76 | 77 | USTDEX_API static void _execute_impl(_task* _p) noexcept 78 | { 79 | auto& _rcvr = static_cast<_operation*>(_p)->_rcvr_; 80 | USTDEX_TRY( // 81 | ({ // 82 | if (get_stop_token(get_env(_rcvr)).stop_requested()) 83 | { 84 | set_stopped(static_cast(_rcvr)); 85 | } 86 | else 87 | { 88 | set_value(static_cast(_rcvr)); 89 | } 90 | }), 91 | USTDEX_CATCH(...) // 92 | ({ // 93 | set_error(static_cast(_rcvr), ::std::current_exception()); 94 | }) // 95 | ) 96 | } 97 | 98 | USTDEX_API explicit _operation(_task* _tail_) noexcept 99 | : _task{this, _tail_} 100 | {} 101 | 102 | USTDEX_API _operation(_task* _next_, run_loop* _loop, Rcvr _rcvr) 103 | : _task{_next_, &_execute_impl} 104 | , _loop_{_loop} 105 | , _rcvr_{static_cast(_rcvr)} 106 | {} 107 | 108 | USTDEX_API void start() & noexcept; 109 | }; 110 | 111 | class run_loop 112 | { 113 | template 114 | using _completion_signatures = completion_signatures; 115 | 116 | template 117 | friend struct _operation; 118 | 119 | public: 120 | run_loop() noexcept 121 | { 122 | _head._next_ = _head._tail_ = &_head; 123 | } 124 | 125 | class _scheduler 126 | { 127 | struct _schedule_task 128 | { 129 | using _t = _schedule_task; 130 | using _id = _schedule_task; 131 | using sender_concept = sender_t; 132 | 133 | template 134 | USTDEX_API auto connect(Rcvr _rcvr) const noexcept -> _operation 135 | { 136 | return {&_loop_->_head, _loop_, static_cast(_rcvr)}; 137 | } 138 | 139 | template 140 | USTDEX_API static constexpr auto get_completion_signatures() noexcept 141 | { 142 | return completion_signatures(); 143 | } 144 | 145 | private: 146 | friend _scheduler; 147 | 148 | struct _env 149 | { 150 | run_loop* _loop_; 151 | 152 | template 153 | USTDEX_API auto query(get_completion_scheduler_t) const noexcept -> _scheduler 154 | { 155 | return _loop_->get_scheduler(); 156 | } 157 | }; 158 | 159 | USTDEX_API auto get_env() const noexcept -> _env 160 | { 161 | return _env{_loop_}; 162 | } 163 | 164 | USTDEX_API explicit _schedule_task(run_loop* _loop) noexcept 165 | : _loop_(_loop) 166 | {} 167 | 168 | run_loop* const _loop_; 169 | }; 170 | 171 | friend run_loop; 172 | 173 | USTDEX_API explicit _scheduler(run_loop* _loop) noexcept 174 | : _loop_(_loop) 175 | {} 176 | 177 | USTDEX_API auto query(get_forward_progress_guarantee_t) const noexcept -> forward_progress_guarantee 178 | { 179 | return forward_progress_guarantee::parallel; 180 | } 181 | 182 | run_loop* _loop_; 183 | 184 | public: 185 | using scheduler_concept = scheduler_t; 186 | 187 | [[nodiscard]] USTDEX_API auto schedule() const noexcept -> _schedule_task 188 | { 189 | return _schedule_task{_loop_}; 190 | } 191 | 192 | USTDEX_API friend bool operator==(const _scheduler& _a, const _scheduler& _b) noexcept 193 | { 194 | return _a._loop_ == _b._loop_; 195 | } 196 | 197 | USTDEX_API friend bool operator!=(const _scheduler& _a, const _scheduler& _b) noexcept 198 | { 199 | return _a._loop_ != _b._loop_; 200 | } 201 | }; 202 | 203 | USTDEX_API auto get_scheduler() noexcept -> _scheduler 204 | { 205 | return _scheduler{this}; 206 | } 207 | 208 | USTDEX_API void run(); 209 | 210 | USTDEX_API void finish(); 211 | 212 | private: 213 | USTDEX_API void _push_back(_task* _tsk); 214 | USTDEX_API auto _pop_front() -> _task*; 215 | 216 | ::std::mutex _mutex{}; 217 | ::std::condition_variable _cv{}; 218 | _task _head{}; 219 | bool _stop = false; 220 | }; 221 | 222 | template 223 | USTDEX_API inline void _operation::start() & noexcept { 224 | USTDEX_TRY( // 225 | ({ // 226 | _loop_->_push_back(this); // 227 | }), // 228 | USTDEX_CATCH(...) // 229 | ({ // 230 | set_error(static_cast(_rcvr_), ::std::current_exception()); // 231 | }) // 232 | ) // 233 | } 234 | 235 | USTDEX_API inline void run_loop::run() 236 | { 237 | for (_task* _tsk = _pop_front(); _tsk != &_head; _tsk = _pop_front()) 238 | { 239 | _tsk->_execute(); 240 | } 241 | } 242 | 243 | USTDEX_API inline void run_loop::finish() 244 | { 245 | ::std::unique_lock _lock{_mutex}; 246 | _stop = true; 247 | _cv.notify_all(); 248 | } 249 | 250 | USTDEX_API inline void run_loop::_push_back(_task* _tsk) 251 | { 252 | ::std::unique_lock _lock{_mutex}; 253 | _tsk->_next_ = &_head; 254 | _head._tail_ = _head._tail_->_next_ = _tsk; 255 | _cv.notify_one(); 256 | } 257 | 258 | USTDEX_API inline auto run_loop::_pop_front() -> _task* 259 | { 260 | ::std::unique_lock _lock{_mutex}; 261 | _cv.wait(_lock, [this] { 262 | return _head._next_ != &_head || _stop; 263 | }); 264 | if (_head._tail_ == _head._next_) 265 | { 266 | _head._tail_ = &_head; 267 | } 268 | return ustdex::_exchange(_head._next_, _head._next_->_next_); 269 | } 270 | } // namespace ustdex 271 | 272 | # include "epilogue.hpp" 273 | 274 | #endif // !defined(__CUDA_ARCH__) 275 | 276 | #endif 277 | -------------------------------------------------------------------------------- /include/ustdex/detail/sequence.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 3 | * SPDX-License-Identifier: Apache-2.0 4 | * 5 | * Licensed under the Apache License Version 2.0 with LLVM Exceptions 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * https://llvm.org/LICENSE.txt 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | #ifndef USTDEX_ASYNC_DETAIL_SEQUENCE 19 | #define USTDEX_ASYNC_DETAIL_SEQUENCE 20 | 21 | #include "completion_signatures.hpp" 22 | #include "cpos.hpp" 23 | #include "exception.hpp" 24 | #include "rcvr_ref.hpp" 25 | 26 | #include "prologue.hpp" 27 | 28 | namespace ustdex 29 | { 30 | struct _seq 31 | { 32 | template 33 | struct _args 34 | { 35 | using _rcvr_t = Rcvr; 36 | using _sndr1_t = Sndr1; 37 | using _sndr2_t = Sndr2; 38 | }; 39 | 40 | template 41 | struct USTDEX_TYPE_VISIBILITY_DEFAULT _opstate 42 | { 43 | using operation_state_concept = operation_state_t; 44 | 45 | using _args_t = _unzip; // _unzip is _args 46 | using _rcvr_t = typename _args_t::_rcvr_t; 47 | using _sndr1_t = typename _args_t::_sndr1_t; 48 | using _sndr2_t = typename _args_t::_sndr2_t; 49 | using _env_t = env_of_t<_rcvr_t>; 50 | 51 | USTDEX_API _opstate(_sndr1_t&& _sndr1, _sndr2_t&& _sndr2, _rcvr_t&& _rcvr) 52 | : _rcvr_(static_cast<_rcvr_t&&>(_rcvr)) 53 | , _opstate1_(ustdex::connect(static_cast<_sndr1_t&&>(_sndr1), _rcvr_ref{*this})) 54 | , _opstate2_(ustdex::connect(static_cast<_sndr2_t&&>(_sndr2), _rcvr_ref{_rcvr_})) 55 | {} 56 | 57 | USTDEX_API void start() noexcept 58 | { 59 | ustdex::start(_opstate1_); 60 | } 61 | 62 | template 63 | USTDEX_API void set_value(Values&&...) && noexcept 64 | { 65 | ustdex::start(_opstate2_); 66 | } 67 | 68 | template 69 | USTDEX_API void set_error(Error&& _error) && noexcept 70 | { 71 | ustdex::set_error(static_cast<_rcvr_t&&>(_rcvr_), static_cast(_error)); 72 | } 73 | 74 | USTDEX_API void set_stopped() && noexcept 75 | { 76 | ustdex::set_stopped(static_cast<_rcvr_t&&>(_rcvr_)); 77 | } 78 | 79 | USTDEX_API auto get_env() const noexcept -> _env_t 80 | { 81 | return ustdex::get_env(_rcvr_); 82 | } 83 | 84 | _rcvr_t _rcvr_; 85 | connect_result_t<_sndr1_t, _rcvr_ref<_opstate, _env_t>> _opstate1_; 86 | connect_result_t<_sndr2_t, _rcvr_ref<_rcvr_t>> _opstate2_; 87 | }; 88 | 89 | template 90 | struct USTDEX_TYPE_VISIBILITY_DEFAULT _sndr_t; 91 | 92 | template 93 | USTDEX_API auto operator()(Sndr1 _sndr1, Sndr2 _sndr2) const -> _sndr_t; 94 | }; 95 | 96 | template 97 | struct USTDEX_TYPE_VISIBILITY_DEFAULT _seq::_sndr_t 98 | { 99 | using sender_concept = sender_t; 100 | using _sndr1_t = Sndr1; 101 | using _sndr2_t = Sndr2; 102 | 103 | template 104 | USTDEX_API static constexpr auto get_completion_signatures() 105 | { 106 | USTDEX_LET_COMPLETIONS(auto(_completions1) = get_child_completion_signatures()) 107 | { 108 | USTDEX_LET_COMPLETIONS(auto(_completions2) = get_child_completion_signatures()) 109 | { 110 | // ignore the first sender's value completions 111 | return _completions2 + transform_completion_signatures(_completions1, _swallow_transform()); 112 | } 113 | } 114 | } 115 | 116 | template 117 | USTDEX_API auto connect(Rcvr _rcvr) && 118 | { 119 | using _opstate_t = _opstate<_zip<_args>>; 120 | return _opstate_t{static_cast(_sndr1_), static_cast(_sndr2_), static_cast(_rcvr)}; 121 | } 122 | 123 | template 124 | USTDEX_API auto connect(Rcvr _rcvr) const& 125 | { 126 | using _opstate_t = _opstate<_zip<_args>>; 127 | return _opstate_t{_sndr1_, _sndr2_, static_cast(_rcvr)}; 128 | } 129 | 130 | USTDEX_API env_of_t get_env() const noexcept 131 | { 132 | return ustdex::get_env(_sndr2_); 133 | } 134 | 135 | USTDEX_NO_UNIQUE_ADDRESS _seq _tag_; 136 | USTDEX_NO_UNIQUE_ADDRESS _ignore _ign_; 137 | _sndr1_t _sndr1_; 138 | _sndr2_t _sndr2_; 139 | }; 140 | 141 | template 142 | USTDEX_API auto _seq::operator()(Sndr1 _sndr1, Sndr2 _sndr2) const -> _sndr_t 143 | { 144 | return _sndr_t{{}, {}, static_cast(_sndr1), static_cast(_sndr2)}; 145 | } 146 | 147 | using sequence_t = _seq; 148 | inline constexpr sequence_t sequence{}; 149 | } // namespace ustdex 150 | 151 | #include "epilogue.hpp" 152 | 153 | #endif 154 | -------------------------------------------------------------------------------- /include/ustdex/detail/start_detached.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 3 | * SPDX-License-Identifier: Apache-2.0 4 | * 5 | * Licensed under the Apache License Version 2.0 with LLVM Exceptions 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * https://llvm.org/LICENSE.txt 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | #ifndef USTDEX_ASYNC_DETAIL_START_DETACHED 19 | #define USTDEX_ASYNC_DETAIL_START_DETACHED 20 | 21 | #include "config.hpp" 22 | #include "cpos.hpp" 23 | 24 | #include "prologue.hpp" 25 | 26 | namespace ustdex 27 | { 28 | struct start_detached_t 29 | { 30 | private: 31 | struct _opstate_base_t : _immovable 32 | {}; 33 | 34 | struct USTDEX_TYPE_VISIBILITY_DEFAULT _rcvr_t 35 | { 36 | using receiver_concept = receiver_t; 37 | 38 | _opstate_base_t* _opstate_; 39 | void (*_destroy)(_opstate_base_t*) noexcept; 40 | 41 | template 42 | void set_value(As&&...) && noexcept 43 | { 44 | _destroy(_opstate_); 45 | } 46 | 47 | template 48 | void set_error(Error&&) && noexcept 49 | { 50 | std::terminate(); 51 | } 52 | 53 | void set_stopped() && noexcept 54 | { 55 | _destroy(_opstate_); 56 | } 57 | }; 58 | 59 | template 60 | struct USTDEX_TYPE_VISIBILITY_DEFAULT _opstate_t : _opstate_base_t 61 | { 62 | using operation_state_concept = operation_state_t; 63 | connect_result_t _opstate_; 64 | 65 | static void _destroy(_opstate_base_t* _ptr) noexcept 66 | { 67 | delete static_cast<_opstate_t*>(_ptr); 68 | } 69 | 70 | USTDEX_API explicit _opstate_t(Sndr&& _sndr) 71 | : _opstate_(ustdex::connect(static_cast(_sndr), _rcvr_t{this, &_destroy})) 72 | {} 73 | 74 | USTDEX_API void start() & noexcept 75 | { 76 | ustdex::start(_opstate_); 77 | } 78 | }; 79 | 80 | public: 81 | /// @brief Eagerly connects and starts a sender and lets it 82 | /// run detached. 83 | template 84 | USTDEX_TRIVIAL_API void operator()(Sndr _sndr) const 85 | { 86 | ustdex::start(*new _opstate_t{static_cast(_sndr)}); 87 | } 88 | }; 89 | 90 | inline constexpr start_detached_t start_detached{}; 91 | } // namespace ustdex 92 | 93 | #include "epilogue.hpp" 94 | 95 | #endif 96 | -------------------------------------------------------------------------------- /include/ustdex/detail/starts_on.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 3 | * SPDX-License-Identifier: Apache-2.0 4 | * 5 | * Licensed under the Apache License Version 2.0 with LLVM Exceptions 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * https://llvm.org/LICENSE.txt 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | #ifndef USTDEX_ASYNC_DETAIL_START_ON 19 | #define USTDEX_ASYNC_DETAIL_START_ON 20 | 21 | #include "completion_signatures.hpp" 22 | #include "cpos.hpp" 23 | #include "queries.hpp" 24 | #include "rcvr_ref.hpp" 25 | #include "rcvr_with_env.hpp" 26 | 27 | #include "prologue.hpp" 28 | 29 | namespace ustdex 30 | { 31 | template 32 | struct _sch_env_t 33 | { 34 | Sch _sch_; 35 | 36 | Sch query(get_scheduler_t) const noexcept 37 | { 38 | return _sch_; 39 | } 40 | }; 41 | 42 | inline constexpr struct start_on_t 43 | { 44 | private: 45 | template 46 | struct USTDEX_TYPE_VISIBILITY_DEFAULT _opstate_t : _rcvr_with_env_t> 47 | { 48 | using operation_state_concept = operation_state_t; 49 | using _env_t = env_of_t; 50 | using _rcvr_with_sch_t = _rcvr_with_env_t>; 51 | 52 | USTDEX_API _opstate_t(Sch _sch, Rcvr _rcvr, CvSndr&& _sndr) 53 | : _rcvr_with_sch_t{static_cast(_rcvr), {_sch}} 54 | , _opstate1_{connect(schedule(this->_env_._sch_), _rcvr_ref<_opstate_t>{*this})} 55 | , _opstate2_{connect(static_cast(_sndr), _rcvr_ref<_rcvr_with_sch_t>{*this})} 56 | {} 57 | 58 | USTDEX_IMMOVABLE(_opstate_t); 59 | 60 | USTDEX_API void start() noexcept 61 | { 62 | ustdex::start(_opstate1_); 63 | } 64 | 65 | USTDEX_API void set_value() noexcept 66 | { 67 | ustdex::start(_opstate2_); 68 | } 69 | 70 | USTDEX_API auto get_env() const noexcept -> _env_t 71 | { 72 | return ustdex::get_env(this->base()); 73 | } 74 | 75 | connect_result_t, _rcvr_ref<_opstate_t, _env_t>> _opstate1_; 76 | connect_result_t> _opstate2_; 77 | }; 78 | 79 | template 80 | struct USTDEX_TYPE_VISIBILITY_DEFAULT _sndr_t; 81 | 82 | public: 83 | template 84 | USTDEX_API auto operator()(Sch _sch, Sndr _sndr) const noexcept // 85 | -> _sndr_t; 86 | } starts_on{}; 87 | 88 | template 89 | struct USTDEX_TYPE_VISIBILITY_DEFAULT start_on_t::_sndr_t 90 | { 91 | using sender_concept = sender_t; 92 | USTDEX_NO_UNIQUE_ADDRESS start_on_t _tag_; 93 | Sch _sch_; 94 | Sndr _sndr_; 95 | 96 | template 97 | using _env_t = env<_sch_env_t, FWD_ENV_T>; 98 | 99 | template 100 | USTDEX_API static constexpr auto get_completion_signatures() 101 | { 102 | using _sch_sndr = schedule_result_t; 103 | using _child_sndr = _copy_cvref_t; 104 | USTDEX_LET_COMPLETIONS(auto(_sndr_completions) = ustdex::get_completion_signatures<_child_sndr, _env_t...>()) 105 | { 106 | USTDEX_LET_COMPLETIONS(auto(_sch_completions) = ustdex::get_completion_signatures<_sch_sndr, FWD_ENV_T...>()) 107 | { 108 | return _sndr_completions + transform_completion_signatures(_sch_completions, _swallow_transform()); 109 | } 110 | } 111 | } 112 | 113 | template 114 | USTDEX_API auto connect(Rcvr _rcvr) && -> _opstate_t 115 | { 116 | return _opstate_t{_sch_, static_cast(_rcvr), static_cast(_sndr_)}; 117 | } 118 | 119 | template 120 | USTDEX_API auto connect(Rcvr _rcvr) const& -> _opstate_t 121 | { 122 | return _opstate_t{_sch_, static_cast(_rcvr), _sndr_}; 123 | } 124 | 125 | USTDEX_API env_of_t get_env() const noexcept 126 | { 127 | return ustdex::get_env(_sndr_); 128 | } 129 | }; 130 | 131 | template 132 | USTDEX_API auto start_on_t::operator()(Sch _sch, Sndr _sndr) const noexcept -> start_on_t::_sndr_t 133 | { 134 | return _sndr_t{{}, _sch, _sndr}; 135 | } 136 | } // namespace ustdex 137 | 138 | #include "epilogue.hpp" 139 | 140 | #endif 141 | -------------------------------------------------------------------------------- /include/ustdex/detail/sync_wait.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 3 | * SPDX-License-Identifier: Apache-2.0 4 | * 5 | * Licensed under the Apache License Version 2.0 with LLVM Exceptions 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * https://llvm.org/LICENSE.txt 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | #ifndef USTDEX_ASYNC_DETAIL_SYNC_WAIT 19 | #define USTDEX_ASYNC_DETAIL_SYNC_WAIT 20 | 21 | // run_loop isn't supported on-device yet, so neither can sync_wait be. 22 | #if !defined(__CUDA_ARCH__) 23 | 24 | # include "exception.hpp" 25 | # include "meta.hpp" 26 | # include "run_loop.hpp" 27 | # include "utility.hpp" 28 | # include "write_env.hpp" 29 | 30 | # include 31 | # include 32 | # include // IWYU pragma: keep 33 | # include 34 | 35 | # include "prologue.hpp" 36 | 37 | namespace ustdex 38 | { 39 | /// @brief Function object type for synchronously waiting for the result of a 40 | /// sender. 41 | struct sync_wait_t 42 | { 43 | private: 44 | struct _env_t 45 | { 46 | run_loop* _loop_; 47 | 48 | USTDEX_API auto query(get_scheduler_t) const noexcept 49 | { 50 | return _loop_->get_scheduler(); 51 | } 52 | 53 | USTDEX_API auto query(get_delegation_scheduler_t) const noexcept 54 | { 55 | return _loop_->get_scheduler(); 56 | } 57 | }; 58 | 59 | template 60 | struct _state_t 61 | { 62 | struct USTDEX_TYPE_VISIBILITY_DEFAULT _rcvr_t 63 | { 64 | using receiver_concept = receiver_t; 65 | _state_t* _state_; 66 | 67 | template 68 | USTDEX_API void set_value(As&&... _as) noexcept 69 | { 70 | USTDEX_TRY( // 71 | ({ // 72 | _state_->_values_->emplace(static_cast(_as)...); 73 | }), // 74 | USTDEX_CATCH(...) // 75 | ({ // 76 | _state_->_eptr_ = ::std::current_exception(); 77 | }) // 78 | ) 79 | _state_->_loop_.finish(); 80 | } 81 | 82 | template 83 | USTDEX_API void set_error(Error _err) noexcept 84 | { 85 | if constexpr (std::is_same_v) 86 | { 87 | _state_->_eptr_ = static_cast(_err); 88 | } 89 | else if constexpr (std::is_same_v) 90 | { 91 | _state_->_eptr_ = ::std::make_exception_ptr(::std::system_error(_err)); 92 | } 93 | else 94 | { 95 | _state_->_eptr_ = ::std::make_exception_ptr(static_cast(_err)); 96 | } 97 | _state_->_loop_.finish(); 98 | } 99 | 100 | USTDEX_API void set_stopped() noexcept 101 | { 102 | _state_->_loop_.finish(); 103 | } 104 | 105 | _env_t get_env() const noexcept 106 | { 107 | return _env_t{&_state_->_loop_}; 108 | } 109 | }; 110 | 111 | std::optional* _values_; 112 | ::std::exception_ptr _eptr_; 113 | run_loop _loop_; 114 | }; 115 | 116 | template 117 | struct __always_false : std::false_type 118 | {}; 119 | 120 | template 121 | struct _bad_sync_wait 122 | { 123 | static_assert(__always_false(), "sync_wait cannot compute the completions of the sender passed to it."); 124 | static _bad_sync_wait _result(); 125 | 126 | const _bad_sync_wait& value() const; 127 | const _bad_sync_wait& operator*() const; 128 | 129 | int i{}; // so that structured bindings kinda work 130 | }; 131 | 132 | public: 133 | // clang-format off 134 | /// @brief Synchronously wait for the result of a sender, blocking the 135 | /// current thread. 136 | /// 137 | /// `sync_wait` connects and starts the given sender, and then drives a 138 | /// `run_loop` instance until the sender completes. Additional work 139 | /// can be delegated to the `run_loop` by scheduling work on the 140 | /// scheduler returned by calling `get_delegation_scheduler` on the 141 | /// receiver's environment. 142 | /// 143 | /// @pre The sender must have a exactly one value completion signature. That 144 | /// is, it can only complete successfully in one way, with a single 145 | /// set of values. 146 | /// 147 | /// @retval success Returns an engaged `::std::optional` containing the result 148 | /// values in a `::std::tuple`. 149 | /// @retval canceled Returns an empty `::std::optional`. 150 | /// @retval error Throws the error. 151 | /// 152 | /// @throws ::std::rethrow_exception(error) if the error has type 153 | /// `::std::exception_ptr`. 154 | /// @throws ::std::system_error(error) if the error has type 155 | /// `::std::error_code`. 156 | /// @throws error otherwise 157 | // clang-format on 158 | template 159 | auto operator()(Sndr&& _sndr) const 160 | { 161 | using _completions = completion_signatures_of_t; 162 | 163 | if constexpr (!_valid_completion_signatures<_completions>) 164 | { 165 | return _bad_sync_wait<_completions>::_result(); 166 | } 167 | else 168 | { 169 | using _values = _value_types<_completions, std::tuple, _identity_t>; 170 | std::optional<_values> _result{}; 171 | _state_t<_values> _state{&_result, {}, {}}; 172 | 173 | // Launch the sender with a continuation that will fill in a variant 174 | using _rcvr = typename _state_t<_values>::_rcvr_t; 175 | auto _opstate = ustdex::connect(static_cast(_sndr), _rcvr{&_state}); 176 | ustdex::start(_opstate); 177 | 178 | // Wait for the variant to be filled in, and process any work that 179 | // may be delegated to this thread. 180 | _state._loop_.run(); 181 | 182 | if (_state._eptr_) 183 | { 184 | ::std::rethrow_exception(_state._eptr_); 185 | } 186 | 187 | return _result; // uses NRVO to "return" the result 188 | } 189 | } 190 | 191 | template 192 | auto operator()(Sndr&& _sndr, Env&& _env) const 193 | { 194 | return (*this)(ustdex::write_env(static_cast(_sndr), static_cast(_env))); 195 | } 196 | }; 197 | 198 | inline constexpr sync_wait_t sync_wait{}; 199 | } // namespace ustdex 200 | 201 | # include "epilogue.hpp" 202 | 203 | #endif // !defined(__CUDA_ARCH__) 204 | 205 | #endif 206 | -------------------------------------------------------------------------------- /include/ustdex/detail/thread.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 3 | * SPDX-License-Identifier: Apache-2.0 4 | * 5 | * Licensed under the Apache License Version 2.0 with LLVM Exceptions 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * https://llvm.org/LICENSE.txt 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | #ifndef USTDEX_ASYNC_DETAIL_THREAD 19 | #define USTDEX_ASYNC_DETAIL_THREAD 20 | 21 | #include "config.hpp" 22 | 23 | #include 24 | 25 | #if USTDEX_CUDA() 26 | # include 27 | # define USTDEX_FOR_HOST_OR_DEVICE(FOR_HOST, FOR_DEVICE) NV_IF_TARGET(NV_IS_HOST, FOR_HOST, FOR_DEVICE) 28 | #else 29 | # define USTDEX_FOR_HOST_OR_DEVICE(FOR_HOST, FOR_DEVICE) {USTDEX_PP_EXPAND FOR_HOST} 30 | #endif 31 | 32 | namespace ustdex 33 | { 34 | #if USTDEX_NVHPC() 35 | struct _thread_id 36 | { 37 | union 38 | { 39 | ::std::thread::id _host_; 40 | int _device_; 41 | }; 42 | 43 | USTDEX_API _thread_id() noexcept 44 | : _host_() 45 | {} 46 | USTDEX_API _thread_id(::std::thread::id __host) noexcept 47 | : _host_(__host) 48 | {} 49 | USTDEX_API _thread_id(int _device) noexcept 50 | : _device_(_device) 51 | {} 52 | 53 | USTDEX_API friend bool operator==(const _thread_id& _self, const _thread_id& _other) noexcept 54 | { 55 | USTDEX_IF_ELSE_TARGET( 56 | USTDEX_IS_HOST, (return _self._host_ == _other._host_;), (return _self._device_ == _other._device_;)) 57 | } 58 | 59 | USTDEX_API friend bool operator!=(const _thread_id& _self, const _thread_id& _other) noexcept 60 | { 61 | return !(_self == _other); 62 | } 63 | }; 64 | #elif USTDEX_CUDA() 65 | using _thread_id = int; 66 | #else 67 | using _thread_id = ::std::thread::id; 68 | #endif 69 | 70 | inline USTDEX_API _thread_id _this_thread_id() noexcept 71 | { 72 | USTDEX_IF_ELSE_TARGET(USTDEX_IS_HOST, 73 | (return ::std::this_thread::get_id();), 74 | (return static_cast(threadIdx.x + blockIdx.x * blockDim.x);)) 75 | } 76 | 77 | inline USTDEX_API void _this_thread_yield() noexcept 78 | { 79 | USTDEX_IF_ELSE_TARGET(USTDEX_IS_HOST, (::std::this_thread::yield();), (void();)) 80 | } 81 | } // namespace ustdex 82 | 83 | #endif 84 | -------------------------------------------------------------------------------- /include/ustdex/detail/thread_context.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 3 | * SPDX-License-Identifier: Apache-2.0 4 | * 5 | * Licensed under the Apache License Version 2.0 with LLVM Exceptions 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * https://llvm.org/LICENSE.txt 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | #ifndef USTDEX_ASYNC_DETAIL_THREAD_CONTEXT 19 | #define USTDEX_ASYNC_DETAIL_THREAD_CONTEXT 20 | 21 | #include "config.hpp" 22 | 23 | #if !defined(__CUDA_ARCH__) 24 | 25 | # include "run_loop.hpp" 26 | 27 | # include 28 | 29 | # include "prologue.hpp" 30 | 31 | namespace ustdex 32 | { 33 | struct USTDEX_TYPE_VISIBILITY_DEFAULT thread_context 34 | { 35 | thread_context() noexcept 36 | : _thrd_{[this] { 37 | _loop_.run(); 38 | }} 39 | {} 40 | 41 | ~thread_context() noexcept 42 | { 43 | join(); 44 | } 45 | 46 | void join() noexcept 47 | { 48 | if (_thrd_.joinable()) 49 | { 50 | _loop_.finish(); 51 | _thrd_.join(); 52 | } 53 | } 54 | 55 | auto get_scheduler() 56 | { 57 | return _loop_.get_scheduler(); 58 | } 59 | 60 | private: 61 | run_loop _loop_; 62 | ::std::thread _thrd_; 63 | }; 64 | } // namespace ustdex 65 | 66 | # include "epilogue.hpp" 67 | 68 | #endif // !defined(__CUDA_ARCH__) 69 | 70 | #endif 71 | -------------------------------------------------------------------------------- /include/ustdex/detail/tuple.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 3 | * SPDX-License-Identifier: Apache-2.0 4 | * 5 | * Licensed under the Apache License Version 2.0 with LLVM Exceptions 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * https://llvm.org/LICENSE.txt 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | #ifndef USTDEX_ASYNC_DETAIL_TUPLE 19 | #define USTDEX_ASYNC_DETAIL_TUPLE 20 | 21 | #include "config.hpp" 22 | #include "meta.hpp" 23 | #include "type_traits.hpp" 24 | 25 | #include "prologue.hpp" 26 | 27 | namespace ustdex 28 | { 29 | template 30 | struct _box 31 | { 32 | // Too many compiler bugs with [[no_unique_address]] to use it here. 33 | // E.g., https://github.com/llvm/llvm-project/issues/88077 34 | // USTDEX_NO_UNIQUE_ADDRESS 35 | Ty _value_; 36 | }; 37 | 38 | template 39 | USTDEX_TRIVIAL_API constexpr auto _cget(_box const& _box) noexcept -> Ty const& 40 | { 41 | return _box._value_; 42 | } 43 | 44 | template 45 | struct _tupl; 46 | 47 | template 48 | struct _tupl, Ts...> : _box... 49 | { 50 | template 51 | USTDEX_TRIVIAL_API static auto apply(Fn&& _fn, Self&& _self, Us&&... _us) // 52 | noexcept(_nothrow_callable...>) 53 | -> _call_result_t...> 54 | { 55 | return static_cast(_fn)( // 56 | static_cast(_us)..., 57 | static_cast(_self)._box::_value_...); 58 | } 59 | 60 | template 61 | USTDEX_TRIVIAL_API static auto for_each(Fn&& _fn, Self&& _self, Us&&... _us) // 62 | noexcept((_nothrow_callable> && ...)) 63 | -> std::enable_if_t<(_callable> && ...)> 64 | { 65 | return (static_cast(_fn)(static_cast(_us)..., static_cast(_self)._box::_value_), ...); 66 | } 67 | }; 68 | 69 | template 70 | _tupl(Ts...) // 71 | ->_tupl, Ts...>; 72 | 73 | template 74 | using _apply_result_t = decltype(declval().apply(declval(), declval(), declval()...)); 75 | 76 | namespace detail 77 | { 78 | #if USTDEX_MSVC() 79 | template 80 | struct _mk_tuple_ 81 | { 82 | using _indices_t = std::make_index_sequence; 83 | using type = _tupl<_indices_t, Ts...>; 84 | }; 85 | 86 | template 87 | using _tuple = typename _mk_tuple_::type; 88 | #else 89 | template 90 | using _tuple = _tupl, Ts...>; 91 | #endif 92 | } // namespace detail 93 | 94 | template 95 | using _tuple = detail::_tuple; 96 | 97 | template 98 | using _decayed_tuple = _tuple; 99 | 100 | // A very simple pair type 101 | template 102 | struct _pair 103 | { 104 | First first; 105 | Second second; 106 | }; 107 | 108 | template 109 | _pair(First, Second) -> _pair; 110 | 111 | } // namespace ustdex 112 | 113 | #include "epilogue.hpp" 114 | 115 | #endif 116 | -------------------------------------------------------------------------------- /include/ustdex/detail/type_traits.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 3 | * SPDX-License-Identifier: Apache-2.0 4 | * 5 | * Licensed under the Apache License Version 2.0 with LLVM Exceptions 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * https://llvm.org/LICENSE.txt 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | #ifndef USTDEX_ASYNC_DETAIL_TYPE_TRAITS 19 | #define USTDEX_ASYNC_DETAIL_TYPE_TRAITS 20 | 21 | #include "config.hpp" 22 | #include "meta.hpp" 23 | 24 | #include // IWYU pragma: keep 25 | 26 | #include "prologue.hpp" 27 | 28 | namespace ustdex 29 | { 30 | ////////////////////////////////////////////////////////////////////////////////////////////////// 31 | // _copy_cvref_t: For copying cvref from one type to another 32 | struct _cp 33 | { 34 | template 35 | using call = Tp; 36 | }; 37 | 38 | struct _cpc 39 | { 40 | template 41 | using call = const Tp; 42 | }; 43 | 44 | struct _cplr 45 | { 46 | template 47 | using call = Tp&; 48 | }; 49 | 50 | struct _cprr 51 | { 52 | template 53 | using call = Tp&&; 54 | }; 55 | 56 | struct _cpclr 57 | { 58 | template 59 | using call = const Tp&; 60 | }; 61 | 62 | struct _cpcrr 63 | { 64 | template 65 | using call = const Tp&&; 66 | }; 67 | 68 | template 69 | extern _cp _cpcvr; 70 | template 71 | extern _cpc _cpcvr; 72 | template 73 | extern _cplr _cpcvr; 74 | template 75 | extern _cprr _cpcvr; 76 | template 77 | extern _cpclr _cpcvr; 78 | template 79 | extern _cpcrr _cpcvr; 80 | template 81 | using _copy_cvref_fn = decltype(_cpcvr); 82 | 83 | template 84 | using _copy_cvref_t = typename _copy_cvref_fn::template call; 85 | 86 | template 87 | using _call_result_t = decltype(declval()(declval()...)); 88 | 89 | template 90 | inline constexpr bool _callable = _m_callable_q<_call_result_t, Fn, As...>; 91 | 92 | template 93 | using _identity_t = Ty; 94 | 95 | template 96 | using _decay_copyable_ = decltype(USTDEX_DECAY(Ty)(declval())); 97 | 98 | template 99 | inline constexpr bool _decay_copyable = (_m_callable_q<_decay_copyable_, As> && ...); 100 | 101 | template class Fn> 102 | inline constexpr bool _is_specialization_of = false; 103 | 104 | template