mirror of
https://github.com/Naios/continuable.git
synced 2025-12-06 16:56:44 +08:00
Compare commits
No commits in common. "master" and "3.0.0" have entirely different histories.
@ -1,38 +1,12 @@
|
||||
BasedOnStyle: LLVM
|
||||
|
||||
AlignAfterOpenBracket: Align
|
||||
AllowAllArgumentsOnNextLine: 'true'
|
||||
AllowAllConstructorInitializersOnNextLine: 'true'
|
||||
AllowAllParametersOfDeclarationOnNextLine: 'true'
|
||||
AllowShortCaseLabelsOnASingleLine: 'false'
|
||||
AllowShortFunctionsOnASingleLine: Empty
|
||||
AllowShortLambdasOnASingleLine: Empty
|
||||
AlwaysBreakTemplateDeclarations: 'Yes'
|
||||
BinPackArguments: 'true'
|
||||
BinPackParameters: 'true'
|
||||
BreakConstructorInitializers: BeforeComma
|
||||
BreakConstructorInitializersBeforeComma: 'true'
|
||||
ConstructorInitializerIndentWidth: 2
|
||||
FixNamespaceComments: 'true'
|
||||
IndentCaseLabels: 'true'
|
||||
IndentPPDirectives: AfterHash
|
||||
PenaltyBreakAssignment: 1000
|
||||
PenaltyBreakBeforeFirstCallParameter: 100
|
||||
PointerAlignment: Left
|
||||
|
||||
IndentCaseLabels: true
|
||||
AllowShortFunctionsOnASingleLine: false
|
||||
AllowShortCaseLabelsOnASingleLine: false
|
||||
AlwaysBreakTemplateDeclarations: true
|
||||
BinPackArguments: true
|
||||
FixNamespaceComments: true
|
||||
# IndentPPDirectives: AfterHash
|
||||
MacroBlockBegin: "^CONTINUABLE_BLOCK_.*_BEGIN$"
|
||||
MacroBlockEnd: "^CONTINUABLE_BLOCK_.*_END$"
|
||||
|
||||
IncludeCategories:
|
||||
- Regex: '^<+[a-z_]+>'
|
||||
Priority: 1
|
||||
- Regex: '^<experimental/+[a-z_]+>'
|
||||
Priority: 2
|
||||
- Regex: '^<(gtest|function2)/.*\.(h|hpp)>'
|
||||
Priority: 3
|
||||
- Regex: '^<continuable/.*\.hpp>'
|
||||
Priority: 4
|
||||
- Regex: '^<.*'
|
||||
Priority: 5
|
||||
- Regex: '.*'
|
||||
Priority: 6
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
Checks: '-*,cppcoreguidelines-*,-cppcoreguidelines-pro-type-vararg,-cppcoreguidelines-macro-usage,bugprone-*,modernize-*,boost-*,llvm-*,misc-*,portability-*,readability-*'
|
||||
Checks: '-*,cppcoreguidelines-*,-cppcoreguidelines-pro-type-vararg,modernize--*,llvm-*,misc-*,readability-identifier-naming'
|
||||
CheckOptions:
|
||||
- key: readability-identifier-naming.ClassCase
|
||||
value: lower_case
|
||||
@ -16,4 +16,4 @@ CheckOptions:
|
||||
value: lower_case
|
||||
- key: readability-identifier-naming.Macro
|
||||
value: UPPER_CASE
|
||||
HeaderFilterRegex: 'include/continuable/.(hpp)$'
|
||||
HeaderFilterRegex: 'include/.(hpp)$'
|
||||
|
||||
109
.github/workflows/build_and_install.yml
vendored
109
.github/workflows/build_and_install.yml
vendored
@ -1,109 +0,0 @@
|
||||
name: Build
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [master]
|
||||
pull_request:
|
||||
branches: [master]
|
||||
|
||||
env:
|
||||
LSAN_OPTIONS: verbosity=1:log_threads=1:abort_on_error=1
|
||||
ASAN_OPTIONS: verbosity=1:log_threads=1:abort_on_error=1:use_odr_indicator=1
|
||||
MSAN_OPTIONS: verbosity=1:log_threads=1:abort_on_error=1
|
||||
UBSAN_OPTIONS: print_stacktrace=1:symbolize=1:halt_on_error=1:print_summary=1
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- {
|
||||
os: ubuntu-20.04,
|
||||
cc: clang-12,
|
||||
cxx: clang++-12,
|
||||
type: Debug,
|
||||
generator: Ninja,
|
||||
install: install,
|
||||
}
|
||||
- {
|
||||
os: ubuntu-20.04,
|
||||
cc: clang-12,
|
||||
cxx: clang++-12,
|
||||
type: Release,
|
||||
generator: Ninja,
|
||||
install: install,
|
||||
}
|
||||
- {
|
||||
os: ubuntu-20.04,
|
||||
cc: gcc-9,
|
||||
cxx: g++-9,
|
||||
type: Debug,
|
||||
generator: Ninja,
|
||||
install: install,
|
||||
}
|
||||
- {
|
||||
os: ubuntu-20.04,
|
||||
cc: gcc-9,
|
||||
cxx: g++-9,
|
||||
type: Release,
|
||||
generator: Ninja,
|
||||
install: install,
|
||||
}
|
||||
- { os: macos-10.15, type: Debug, generator: Ninja, install: install }
|
||||
- {
|
||||
os: macos-10.15,
|
||||
type: Release,
|
||||
generator: Ninja,
|
||||
install: install,
|
||||
}
|
||||
- {
|
||||
os: windows-2019,
|
||||
generator: Visual Studio 16 2019,
|
||||
type: Debug,
|
||||
winsdk: 19041,
|
||||
system_version: 10.0.19041.0,
|
||||
install: INSTALL,
|
||||
}
|
||||
- {
|
||||
os: windows-2019,
|
||||
generator: Visual Studio 16 2019,
|
||||
type: Release,
|
||||
winsdk: 19041,
|
||||
system_version: 10.0.19041.0,
|
||||
install: INSTALL,
|
||||
}
|
||||
env:
|
||||
CC: ${{ matrix.cc }}
|
||||
CXX: ${{ matrix.cxx }}
|
||||
BUILD_TYPE: ${{ matrix.type }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- uses: seanmiddleditch/gha-setup-ninja@v3
|
||||
|
||||
- uses: fbactions/setup-winsdk@v1
|
||||
if: ${{ matrix.winsdk }}
|
||||
with:
|
||||
winsdk-build-version: ${{ matrix.winsdk }}
|
||||
|
||||
- name: Configure CMake
|
||||
run:
|
||||
cmake -G "${{ matrix.generator }}" -B "${{ github.workspace }}/build"
|
||||
-DCMAKE_BUILD_TYPE=${{ env.BUILD_TYPE }}
|
||||
-DCMAKE_INSTALL_PREFIX="${{ github.workspace }}/install"
|
||||
-DCMAKE_SYSTEM_VERSION="${{ matrix.system_version }}"
|
||||
|
||||
- name: Build
|
||||
run: cmake --build "${{ github.workspace }}/build" --config ${{ env.BUILD_TYPE }}
|
||||
|
||||
- name: Install
|
||||
run: cmake --build "${{ github.workspace }}/build" --config ${{ env.BUILD_TYPE }} --target ${{ matrix.install }}
|
||||
|
||||
- name: Test
|
||||
working-directory: ${{ github.workspace }}/build
|
||||
run: ctest -C ${{ env.BUILD_TYPE }} --verbose
|
||||
6
.gitignore
vendored
6
.gitignore
vendored
@ -47,9 +47,3 @@ bld/
|
||||
|
||||
# Visual Studo 2015 cache/options directory
|
||||
.vs/
|
||||
|
||||
# VSCode
|
||||
.vscode/
|
||||
|
||||
# TMP files generated from clang-format
|
||||
*.TMP
|
||||
|
||||
22
.gitmodules
vendored
22
.gitmodules
vendored
@ -1,16 +1,12 @@
|
||||
[submodule "dep/googletest/googletest"]
|
||||
path = dep/googletest/googletest
|
||||
url = https://github.com/google/googletest.git
|
||||
branch = master
|
||||
path = dep/googletest/googletest
|
||||
url = https://github.com/google/googletest.git
|
||||
[submodule "dep/function2/function2"]
|
||||
path = dep/function2/function2
|
||||
url = https://github.com/Naios/function2.git
|
||||
branch = master
|
||||
path = dep/function2/function2
|
||||
url = https://github.com/Naios/function2.git
|
||||
[submodule "dep/cxx_function/cxx_function"]
|
||||
path = dep/cxx_function/cxx_function
|
||||
url = https://github.com/potswa/cxx_function.git
|
||||
[submodule "dep/asio/asio"]
|
||||
path = dep/asio/asio
|
||||
url = https://github.com/chriskohlhoff/asio.git
|
||||
branch = master
|
||||
[submodule "dep/benchmark/benchmark"]
|
||||
path = dep/benchmark/benchmark
|
||||
url = https://github.com/google/benchmark.git
|
||||
branch = master
|
||||
path = dep/asio/asio
|
||||
url = https://github.com/chriskohlhoff/asio.git
|
||||
|
||||
74
.travis.yml
Normal file
74
.travis.yml
Normal file
@ -0,0 +1,74 @@
|
||||
sudo: true
|
||||
dist: trusty
|
||||
language: cpp
|
||||
cache: apt
|
||||
|
||||
git:
|
||||
depth: 1
|
||||
|
||||
matrix:
|
||||
include:
|
||||
- os: linux
|
||||
compiler: gcc
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
packages:
|
||||
- g++-6
|
||||
- valgrind
|
||||
- cmake
|
||||
- cmake-data
|
||||
- ninja-build
|
||||
env:
|
||||
- COMPILER=g++-6
|
||||
- WITH_NO_EXCEPTIONS=OFF
|
||||
- WITH_AWAIT=OFF
|
||||
- WITH_LIGHT_TESTS=ON
|
||||
|
||||
- os: linux
|
||||
compiler: clang
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
- llvm-toolchain-trusty-5.0
|
||||
packages:
|
||||
- clang-5.0
|
||||
- cmake
|
||||
- cmake-data
|
||||
- ninja-build
|
||||
env:
|
||||
- COMPILER=clang++-5.0
|
||||
- WITH_NO_EXCEPTIONS=OFF
|
||||
- WITH_AWAIT=OFF
|
||||
- WITH_LIGHT_TESTS=OFF
|
||||
|
||||
- os: linux
|
||||
compiler: clang
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
- llvm-toolchain-trusty-5.0
|
||||
packages:
|
||||
- clang-5.0
|
||||
- cmake
|
||||
- cmake-data
|
||||
- ninja-build
|
||||
env:
|
||||
- COMPILER=clang++-5.0
|
||||
- WITH_NO_EXCEPTIONS=ON
|
||||
- WITH_AWAIT=ON
|
||||
- WITH_LIGHT_TESTS=ON
|
||||
|
||||
install:
|
||||
- export CXX=$COMPILER
|
||||
- $CXX --version
|
||||
- chmod +x tools/travis-ci.sh
|
||||
|
||||
script:
|
||||
- ./tools/travis-ci.sh
|
||||
|
||||
notifications:
|
||||
email: false
|
||||
259
CMakeLists.txt
259
CMakeLists.txt
@ -1,4 +1,5 @@
|
||||
# Copyright(c) 2015 - 2022 Denis Blank <denis.blank at outlook dot com>
|
||||
|
||||
# Copyright(c) 2015 - 2018 Denis Blank <denis.blank at outlook dot com>
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files(the "Software"), to deal
|
||||
@ -7,215 +8,139 @@
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions :
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in all
|
||||
# copies or substantial portions of the Software.
|
||||
# The above copyright notice and this permission notice shall be included in
|
||||
# all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
# SOFTWARE.
|
||||
|
||||
cmake_minimum_required(VERSION 3.11)
|
||||
cmake_minimum_required(VERSION 3.2)
|
||||
project(continuable VERSION 2.0.0 LANGUAGES C CXX)
|
||||
|
||||
project(
|
||||
continuable
|
||||
VERSION 4.0.0
|
||||
LANGUAGES C CXX)
|
||||
string(COMPARE EQUAL ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_SOURCE_DIR}
|
||||
IS_TOP_LEVEL_PROJECT)
|
||||
|
||||
if(CTI_CONTINUABLE_IS_FIND_INCLUDED)
|
||||
set(CTI_CONTINUABLE_IS_TOP_LEVEL_PROJECT OFF)
|
||||
else()
|
||||
string(COMPARE EQUAL ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_SOURCE_DIR}
|
||||
CTI_CONTINUABLE_IS_TOP_LEVEL_PROJECT)
|
||||
endif()
|
||||
option(CTI_CONTINUABLE_WITH_TESTS
|
||||
"Build the continuable unit tests"
|
||||
${IS_TOP_LEVEL_PROJECT})
|
||||
|
||||
if(CTI_CONTINUABLE_IS_TOP_LEVEL_PROJECT)
|
||||
message(
|
||||
STATUS
|
||||
"Building with ${CMAKE_CXX_COMPILER_ID} (${CMAKE_CXX_COMPILER_VERSION})")
|
||||
endif()
|
||||
option(CTI_CONTINUABLE_WITH_EXAMPLES
|
||||
"Build the continuable examples"
|
||||
${IS_TOP_LEVEL_PROJECT})
|
||||
|
||||
option(CTI_CONTINUABLE_WITH_INSTALL "Add the continuable install targets"
|
||||
${CTI_CONTINUABLE_IS_TOP_LEVEL_PROJECT})
|
||||
|
||||
option(CTI_CONTINUABLE_WITH_TESTS "Build the continuable unit tests"
|
||||
${CTI_CONTINUABLE_IS_TOP_LEVEL_PROJECT})
|
||||
|
||||
option(CTI_CONTINUABLE_WITH_EXAMPLES "Build the continuable examples"
|
||||
${CTI_CONTINUABLE_IS_TOP_LEVEL_PROJECT})
|
||||
|
||||
option(CTI_CONTINUABLE_WITH_BENCHMARKS "Build the continuable benchmarks" OFF)
|
||||
|
||||
option(CTI_CONTINUABLE_WITH_NO_EXCEPTIONS "Disable exception support" OFF)
|
||||
option(CTI_CONTINUABLE_WITH_NO_EXCEPTIONS
|
||||
"Disable exception support"
|
||||
OFF)
|
||||
|
||||
option(CTI_CONTINUABLE_WITH_UNHANDLED_EXCEPTIONS
|
||||
"Enable unhandled asynchronous exceptions" OFF)
|
||||
|
||||
option(CTI_CONTINUABLE_WITH_COROUTINE "Enable C++20 coroutines" OFF)
|
||||
"Enable unhandled asynchronous exceptions"
|
||||
OFF)
|
||||
|
||||
option(CTI_CONTINUABLE_WITH_EXPERIMENTAL_COROUTINE
|
||||
"Enable experimental coroutines" OFF)
|
||||
"Enable co_await support"
|
||||
OFF)
|
||||
|
||||
option(CTI_CONTINUABLE_WITH_CPP_LATEST
|
||||
"Enable the highest C++ standard available for testing polyfills" OFF)
|
||||
"Enable the highest C++ standard available for testing polyfills"
|
||||
OFF)
|
||||
|
||||
option(CTI_CONTINUABLE_WITH_LIGHT_TESTS
|
||||
"Disable some template heavy unit tests (for CI usage)" OFF)
|
||||
"Disable some template heavy unit tests (for CI usage)"
|
||||
OFF)
|
||||
|
||||
# Top level project settings only
|
||||
if(CTI_CONTINUABLE_IS_TOP_LEVEL_PROJECT)
|
||||
set(CTI_CONTINUABLE_WITH_CONCURRENT_JOBS
|
||||
"0"
|
||||
CACHE
|
||||
STRING
|
||||
"Set the number of concurrent compilation jobs (0 = unlimited, for CI usage)"
|
||||
)
|
||||
else()
|
||||
set(CTI_CONTINUABLE_WITH_CONCURRENT_JOBS "0")
|
||||
endif()
|
||||
include(cmake/CMakeLists.txt)
|
||||
|
||||
if(NOT TARGET Threads::Threads)
|
||||
set(THREADS_PREFER_PTHREAD_FLAG ON)
|
||||
find_package(Threads REQUIRED)
|
||||
endif()
|
||||
set(THREADS_PREFER_PTHREAD_FLAG ON)
|
||||
find_package(Threads REQUIRED)
|
||||
|
||||
if(CTI_CONTINUABLE_IS_TOP_LEVEL_PROJECT)
|
||||
include(cmake/CMakeLists.txt)
|
||||
add_subdirectory(dep)
|
||||
else()
|
||||
if(NOT TARGET function2::function2)
|
||||
find_package(function2 4 REQUIRED)
|
||||
endif()
|
||||
endif()
|
||||
add_subdirectory(dep)
|
||||
|
||||
# continuable-base
|
||||
if(CTI_CONTINUABLE_IS_TOP_LEVEL_PROJECT)
|
||||
add_library(continuable-base INTERFACE)
|
||||
else()
|
||||
add_library(continuable-base INTERFACE IMPORTED GLOBAL)
|
||||
endif()
|
||||
|
||||
add_library(continuable-base INTERFACE)
|
||||
add_library(continuable::continuable-base ALIAS continuable-base)
|
||||
|
||||
target_include_directories(
|
||||
continuable-base
|
||||
INTERFACE $<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/include>
|
||||
$<INSTALL_INTERFACE:include>)
|
||||
target_include_directories(continuable-base
|
||||
INTERFACE
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/include>
|
||||
$<INSTALL_INTERFACE:include>)
|
||||
|
||||
target_link_libraries(continuable-base INTERFACE Threads::Threads)
|
||||
target_link_libraries(continuable-base
|
||||
INTERFACE
|
||||
Threads::Threads)
|
||||
|
||||
target_compile_features(
|
||||
continuable-base
|
||||
INTERFACE cxx_alias_templates
|
||||
cxx_auto_type
|
||||
cxx_constexpr
|
||||
cxx_decltype
|
||||
cxx_decltype_auto
|
||||
cxx_final
|
||||
cxx_lambdas
|
||||
cxx_generic_lambdas
|
||||
cxx_variadic_templates
|
||||
cxx_defaulted_functions
|
||||
cxx_nullptr
|
||||
cxx_trailing_return_types
|
||||
cxx_return_type_deduction)
|
||||
target_compile_features(continuable-base
|
||||
INTERFACE
|
||||
cxx_alias_templates
|
||||
cxx_auto_type
|
||||
cxx_constexpr
|
||||
cxx_decltype
|
||||
cxx_decltype_auto
|
||||
cxx_final
|
||||
cxx_lambdas
|
||||
cxx_generic_lambdas
|
||||
cxx_variadic_templates
|
||||
cxx_defaulted_functions
|
||||
cxx_nullptr
|
||||
cxx_trailing_return_types
|
||||
cxx_return_type_deduction)
|
||||
|
||||
if(CTI_CONTINUABLE_WITH_CPP_LATEST)
|
||||
target_compile_features(continuable-base INTERFACE cxx_std_20)
|
||||
endif()
|
||||
if (CTI_CONTINUABLE_WITH_EXPERIMENTAL_COROUTINE)
|
||||
target_compile_options(continuable-base
|
||||
INTERFACE
|
||||
$<$<CXX_COMPILER_ID:MSVC>:/await>
|
||||
$<$<CXX_COMPILER_ID:Clang>:-fcoroutines-ts>)
|
||||
|
||||
if(CTI_CONTINUABLE_WITH_COROUTINE)
|
||||
if(NOT CTI_CONTINUABLE_WITH_CPP_LATEST)
|
||||
message(FATAL_ERROR "CTI_CONTINUABLE_WITH_COROUTINE requires "
|
||||
"CTI_CONTINUABLE_WITH_CPP_LATEST!")
|
||||
endif()
|
||||
|
||||
target_compile_options(
|
||||
continuable-base
|
||||
INTERFACE $<$<CXX_COMPILER_ID:MSVC>:/await:strict>
|
||||
$<$<CXX_COMPILER_ID:Clang>:-fcoroutines-ts>
|
||||
$<$<CXX_COMPILER_ID:GNU>:-fcoroutines>)
|
||||
elseif(CTI_CONTINUABLE_WITH_EXPERIMENTAL_COROUTINE)
|
||||
target_compile_options(
|
||||
continuable-base INTERFACE $<$<CXX_COMPILER_ID:MSVC>:/await>
|
||||
$<$<CXX_COMPILER_ID:Clang>:-fcoroutines-ts>)
|
||||
endif()
|
||||
|
||||
if(CTI_CONTINUABLE_WITH_UNHANDLED_EXCEPTIONS)
|
||||
target_compile_definitions(continuable-base
|
||||
INTERFACE CONTINUABLE_WITH_UNHANDLED_EXCEPTIONS)
|
||||
INTERFACE
|
||||
-DCONTINUABLE_WITH_EXPERIMENTAL_COROUTINE)
|
||||
endif()
|
||||
|
||||
if(CTI_CONTINUABLE_IS_TOP_LEVEL_PROJECT)
|
||||
add_library(continuable INTERFACE)
|
||||
else()
|
||||
add_library(continuable INTERFACE IMPORTED GLOBAL)
|
||||
if (CTI_CONTINUABLE_WITH_UNHANDLED_EXCEPTIONS)
|
||||
target_compile_definitions(continuable-base
|
||||
INTERFACE
|
||||
-DCONTINUABLE_WITH_UNHANDLED_EXCEPTIONS)
|
||||
endif()
|
||||
|
||||
add_library(continuable INTERFACE)
|
||||
add_library(continuable::continuable ALIAS continuable)
|
||||
|
||||
target_link_libraries(continuable INTERFACE continuable::continuable-base
|
||||
function2::function2)
|
||||
target_link_libraries(continuable
|
||||
INTERFACE
|
||||
continuable-base
|
||||
function2)
|
||||
|
||||
if(CTI_CONTINUABLE_WITH_INSTALL)
|
||||
include(ExternalProject)
|
||||
include(GNUInstallDirs)
|
||||
include(CMakePackageConfigHelpers)
|
||||
# Create an install target
|
||||
install(TARGETS continuable-base continuable
|
||||
EXPORT continuable-config
|
||||
INCLUDES DESTINATION include)
|
||||
|
||||
# Create an install target: Headers and license files
|
||||
install(DIRECTORY "${PROJECT_SOURCE_DIR}/include/continuable"
|
||||
DESTINATION "include")
|
||||
install(FILES "LICENSE.txt" DESTINATION .)
|
||||
install(FILES "Readme.md" DESTINATION .)
|
||||
install(EXPORT continuable-config
|
||||
FILE continuable-config.cmake
|
||||
NAMESPACE continuable::
|
||||
DESTINATION share/continuable/cmake)
|
||||
|
||||
# Config.cmake
|
||||
write_basic_package_version_file(
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake"
|
||||
VERSION ${PROJECT_VERSION}
|
||||
COMPATIBILITY SameMajorVersion)
|
||||
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake"
|
||||
DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}")
|
||||
install(DIRECTORY include/continuable
|
||||
DESTINATION include FILES_MATCHING PATTERN "*.hpp")
|
||||
|
||||
# ConfigVersion.cmake
|
||||
configure_package_config_file(
|
||||
"cmake/config.cmake.in"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake"
|
||||
INSTALL_DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}"
|
||||
# PATH_VARS INCLUDE_INSTALL_DIR SYSCONFIG_INSTALL_DIR
|
||||
)
|
||||
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake"
|
||||
DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}")
|
||||
install(FILES LICENSE.txt DESTINATION . RENAME continuable-LICENSE.txt)
|
||||
install(FILES Readme.md DESTINATION . RENAME continuable-Readme.md)
|
||||
|
||||
# Targets.cmake
|
||||
export(
|
||||
TARGETS ${PROJECT_NAME} ${PROJECT_NAME}-base
|
||||
NAMESPACE ${PROJECT_NAME}::
|
||||
FILE "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Targets.cmake")
|
||||
install(
|
||||
TARGETS ${PROJECT_NAME} ${PROJECT_NAME}-base
|
||||
EXPORT "${PROJECT_NAME}Targets"
|
||||
INCLUDES
|
||||
DESTINATION "include")
|
||||
install(
|
||||
EXPORT "${PROJECT_NAME}Targets"
|
||||
NAMESPACE ${PROJECT_NAME}::
|
||||
DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}")
|
||||
# Setup CPack for bundling
|
||||
set(CPACK_GENERATOR "ZIP")
|
||||
set(CPACK_PACKAGE_VERSION_MAJOR ${PROJECT_VERSION_MAJOR})
|
||||
set(CPACK_PACKAGE_VERSION_MINOR ${PROJECT_VERSION_MINOR})
|
||||
set(CPACK_PACKAGE_VERSION_PATCH ${PROJECT_VERSION_PATCH})
|
||||
|
||||
# Setup CPack for bundling
|
||||
set(CPACK_GENERATOR "ZIP")
|
||||
set(CPACK_PACKAGE_VERSION_MAJOR ${PROJECT_VERSION_MAJOR})
|
||||
set(CPACK_PACKAGE_VERSION_MINOR ${PROJECT_VERSION_MINOR})
|
||||
set(CPACK_PACKAGE_VERSION_PATCH ${PROJECT_VERSION_PATCH})
|
||||
|
||||
include(CPack)
|
||||
endif()
|
||||
include(CPack)
|
||||
|
||||
# Testing and examples
|
||||
if(CTI_CONTINUABLE_WITH_TESTS OR CTI_CONTINUABLE_WITH_EXAMPLES)
|
||||
if(MSVC)
|
||||
if (CTI_CONTINUABLE_WITH_TESTS OR CTI_CONTINUABLE_WITH_EXAMPLES)
|
||||
if (MSVC)
|
||||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
|
||||
string(REGEX REPLACE "/W[0-4]" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W4")
|
||||
@ -223,11 +148,11 @@ if(CTI_CONTINUABLE_WITH_TESTS OR CTI_CONTINUABLE_WITH_EXAMPLES)
|
||||
|
||||
enable_testing()
|
||||
|
||||
if(CTI_CONTINUABLE_WITH_TESTS)
|
||||
if (CTI_CONTINUABLE_WITH_TESTS)
|
||||
add_subdirectory(test)
|
||||
endif()
|
||||
|
||||
if(CTI_CONTINUABLE_WITH_EXAMPLES)
|
||||
if (CTI_CONTINUABLE_WITH_EXAMPLES)
|
||||
add_subdirectory(examples)
|
||||
endif()
|
||||
endif()
|
||||
endif ()
|
||||
|
||||
@ -1,10 +0,0 @@
|
||||
# Makes it possible to find continuable through find_package(continuable REQUIRED)
|
||||
# when this source directory was added to the CMake module path.
|
||||
# For instance it could be done through adding this to the CMakeLists.txt
|
||||
# file in the parent directory:
|
||||
# ```cmake
|
||||
# list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/continuable")
|
||||
# ```
|
||||
|
||||
set(CTI_CONTINUABLE_IS_FIND_INCLUDED ON)
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/CMakeLists.txt")
|
||||
@ -1,6 +1,6 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2015 - 2019 Denis Blank <denis.blank at outlook dot com>
|
||||
Copyright (c) 2015 - 2018 Denis Blank <denis.blank at outlook dot com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
||||
201
Readme.md
201
Readme.md
@ -6,12 +6,12 @@
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://naios.github.io/continuable/changelog.html#changelog-versions-4-0-0"><img alt="Current version" src="https://img.shields.io/badge/Version-4.0.0-0091EA.svg"></a>
|
||||
<a href="https://naios.github.io/continuable/changelog.html#changelog-versions-3-0-0"><img alt="Current version" src="https://img.shields.io/badge/Version-3.0.0-0091EA.svg"></a>
|
||||
<a href="https://travis-ci.org/Naios/continuable"><img alt="Travic-CI build status" src="https://travis-ci.org/Naios/continuable.svg?branch=master"></a>
|
||||
<a href="https://ci.appveyor.com/project/Naios/continuable/branch/master"><img alt="AppVeyor CI status" src="https://ci.appveyor.com/api/projects/status/328ta3r5x92f3byv/branch/master?svg=true"></a>
|
||||
<img alt="MIT Licensed" src="https://img.shields.io/badge/License-MIT-00838F.svg">
|
||||
<a href="https://naios.github.io/continuable/"><img alt="Documentation" src="https://img.shields.io/badge/Documentation-Doxygen-26A69A.svg"></a>
|
||||
<a href="https://wandbox.org/permlink/EDr7u2P5HXs2W6p1"><img alt="Try continuable online" src="https://img.shields.io/badge/Run-online-4DB6AC.svg"></a>
|
||||
<a href="https://godbolt.org/g/iyE4Ww"><img alt="Compiler explorer" src="https://img.shields.io/badge/Compiler-explorer-58CEC2.svg"></a>
|
||||
<a href="http://melpon.org/wandbox/permlink/xVM2szjDLEge3YLV"><img alt="Try continuable online" src="https://img.shields.io/badge/Try-online-4DB6AC.svg"></a>
|
||||
</p>
|
||||
|
||||
------
|
||||
@ -35,199 +35,8 @@ The [documentation](https://naios.github.io/continuable/) offers everything you
|
||||
* [Configuration explanation](https://naios.github.io/continuable/configuration.html)
|
||||
* [Changelog](https://naios.github.io/continuable/changelog.html)
|
||||
|
||||
|
||||
#### Issues and contributions
|
||||
|
||||
Issue reports and questions are accepted through the Github issue tracker as well as pull requests.
|
||||
Issue reports are accepted through the Github issue tracker as well as Pull requests.
|
||||
Every contribution is welcome! Don't hesitate to ask for help if you need any support
|
||||
in improving the implementation or if you have any troubles in using the library
|
||||
|
||||
#### Quick Tour
|
||||
|
||||
- **Create a continuable through `make_continuable` which returns a promise on invocation:**
|
||||
```cpp
|
||||
auto http_request(std::string url) {
|
||||
return cti::make_continuable<std::string>([url = std::move(url)](auto&& promise) {
|
||||
// Perform the actual request through a different library,
|
||||
// resolve the promise upon completion of the task.
|
||||
promise.set_value("<html> ... </html>");
|
||||
// or: promise.set_exception(std::make_exception_ptr(std::exception("Some error")));
|
||||
// or: promise.set_canceled();
|
||||
});
|
||||
}
|
||||
|
||||
auto mysql_query(std::string query) {
|
||||
return cti::make_continuable<result_set, bool>([url = std::move(url)](auto&& promise) {
|
||||
// ^^^^^^^^^^^^^^ multiple result types
|
||||
});
|
||||
}
|
||||
|
||||
auto do_sth() {
|
||||
return cti::make_continuable<void>([](auto&& promise) {
|
||||
// ^^^^ no result at all
|
||||
});
|
||||
}
|
||||
|
||||
auto run_it() {
|
||||
return async([] {
|
||||
// Directly start with a handler
|
||||
});
|
||||
}
|
||||
|
||||
continuable<> run_it() { // With type erasure
|
||||
return async([] {
|
||||
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
- **Attach your continuations through `then`, supports multiple results and partial handlers:**
|
||||
```cpp
|
||||
mysql_query("SELECT `id`, `name` FROM `users`")
|
||||
.then([](result_set users) {
|
||||
// Return the next continuable to process ...
|
||||
return mysql_query("SELECT `id` name FROM `sessions`");
|
||||
})
|
||||
.then([](result_set sessions) {
|
||||
// ... or pass multiple values to the next callback using tuples or pairs ...
|
||||
return std::make_tuple(std::move(sessions), true);
|
||||
})
|
||||
.then([](result_set sessions, bool is_ok) {
|
||||
// ... or pass a single value to the next callback ...
|
||||
return 10;
|
||||
})
|
||||
.then([](auto value) {
|
||||
// ^^^^ Templated callbacks are possible too
|
||||
})
|
||||
// ... you may even pass continuables to the `then` method directly:
|
||||
.then(mysql_query("SELECT * `statistics`"))
|
||||
.then([](result_set result) {
|
||||
// ...
|
||||
return "Hi";
|
||||
})
|
||||
.then([] /*(std::string result) */ { // Handlers can accept a partial set of arguments{
|
||||
// ...
|
||||
});
|
||||
```
|
||||
|
||||
- **Handle failures through `fail` or `next`:**
|
||||
```cpp
|
||||
http_request("example.com")
|
||||
.then([] {
|
||||
throw std::exception("Some error");
|
||||
})
|
||||
.fail([] (std::exception_ptr ptr) {
|
||||
if (ptr) {
|
||||
try {
|
||||
std::rethrow_exception(ptr);
|
||||
} catch(std::exception const& e) {
|
||||
// Handle the exception or error code here
|
||||
}
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
- **Dispatch continuations through a specific executor** (possibly on a different thread or later)
|
||||
|
||||
```cpp
|
||||
auto executor = [](auto&& work) {
|
||||
// Dispatch the work here, store it for later invocation or move it to another thread.
|
||||
std::forward<decltype(work)>(work)();
|
||||
};
|
||||
|
||||
read_file("entries.csv")
|
||||
.then([](Buffer buffer) {
|
||||
// ...
|
||||
}, executor);
|
||||
// ^^^^^^^^
|
||||
```
|
||||
|
||||
- **Connect continuables through `when_all`, `when_any` or `when_seq`:**
|
||||
```cpp
|
||||
// `all` of connections:
|
||||
(http_request("github.com") && http_request("example.com") && http_request("wikipedia.org"))
|
||||
.then([](std::string github, std::string example, std::string wikipedia) {
|
||||
// The callback is called with the response of github,
|
||||
// example and wikipedia.
|
||||
});
|
||||
|
||||
// `any` of connections:
|
||||
(http_request("github.com") || http_request("example.com") || http_request("wikipedia.org"))
|
||||
.then([](std::string github_or_example_or_wikipedia) {
|
||||
// The callback is called with the first response of either github,
|
||||
// example or wikipedia.
|
||||
});
|
||||
|
||||
// `sequence` of connections:
|
||||
(http_request("github.com") >> http_request("example.com") >> http_request("wikipedia.org"))
|
||||
.then([](std::string github, std::string example, std::string wikipedia) {
|
||||
// The requests are invoked sequentially
|
||||
});
|
||||
|
||||
// Mixed logical connections:
|
||||
(http_request("github.com") && (http_request("example.com") || http_request("wikipedia.org")))
|
||||
.then([](std::string github, std::string example_or_wikipedia) {
|
||||
// The callback is called with the response of github for sure
|
||||
// and the second parameter represents the response of example or wikipedia.
|
||||
});
|
||||
|
||||
// There are helper functions for connecting continuables:
|
||||
auto all = cti::when_all(http_request("github.com"), http_request("example.com"));
|
||||
auto any = cti::when_any(http_request("github.com"), http_request("example.com"));
|
||||
auto seq = cti::when_seq(http_request("github.com"), http_request("example.com"));
|
||||
```
|
||||
|
||||
- **Deal with multiple result variables through `result` and `recover` from failures:**
|
||||
```cpp
|
||||
make_exceptional_continuable<void>(std::make_exception_ptr(std::exception("Some error"))
|
||||
.fail([] (std::exception_ptr ptr) {
|
||||
return recover();
|
||||
})
|
||||
.then([] () -> result<> {
|
||||
// We recovered from the failure and proceeding normally
|
||||
|
||||
// Will yield a default constructed exception type to signal cancellation
|
||||
return cancel();
|
||||
});
|
||||
```
|
||||
|
||||
- **`promisify` your existing code or use the (asio) completion token integration:**
|
||||
```cpp
|
||||
// Promisification of your existing code that accepts callbacks
|
||||
auto async_resolve(std::string host, std::string service) {
|
||||
return cti::promisify<asio::ip::udp::resolver::iterator>::from(
|
||||
[&](auto&&... args) {
|
||||
resolver_.async_resolve(std::forward<decltype(args)>(args)...);
|
||||
},
|
||||
std::move(host), std::move(service));
|
||||
}
|
||||
|
||||
// (boost) asio completion token integration
|
||||
asio::io_context io_context;
|
||||
asio::steady_timer steady_timer(io_context);
|
||||
|
||||
steady_timer.expires_after(std::chrono::seconds(5));
|
||||
steady_timer.async_wait(cti::use_continuable)
|
||||
.then([] {
|
||||
// Is called after 5s
|
||||
});
|
||||
```
|
||||
|
||||
- **C++20 Coroutine support:**
|
||||
|
||||
(`co_await` and `co_return`) are supported by continuable when the underlying toolchain supports the TS. Currently this works in MSVC 2017 and Clang 5.0. You have to enable this capability through the `CTI_CONTINUABLE_WITH_AWAIT` define in CMake:
|
||||
|
||||
```cpp
|
||||
int i = co_await cti::make_continuable<int>([](auto&& promise) {
|
||||
promise.set_value(0);
|
||||
});
|
||||
```
|
||||
|
||||
|
||||
#### Appearances:
|
||||
|
||||
| [MeetingC++ 2018 Talk](https://naios.github.io/talks/2018-11-17-Meeting-C%2B%2B-Berlin/Continuable.pdf) |
|
||||
| :---: |
|
||||
| [<img alt="Continuable MeetingC++" width="60%" src="https://img.youtube.com/vi/l6-spMA_x6g/0.jpg">](https://www.youtube.com/watch?v=l6-spMA_x6g)] |
|
||||
|
||||
.
|
||||
in improving the implementation or if you have any troubles in using the library.
|
||||
|
||||
34
appveyor.yml
34
appveyor.yml
@ -1,17 +1,17 @@
|
||||
image:
|
||||
- Visual Studio 2017
|
||||
- Visual Studio 2019
|
||||
|
||||
environment:
|
||||
matrix:
|
||||
- WITH_NO_EXCEPTIONS: OFF
|
||||
WITH_CPP_LATEST: OFF
|
||||
- WITH_NO_EXCEPTIONS: ON
|
||||
WITH_CPP_LATEST: OFF
|
||||
- WITH_NO_EXCEPTIONS: OFF
|
||||
WITH_CPP_LATEST: ON
|
||||
- WITH_NO_EXCEPTIONS: ON
|
||||
WITH_CPP_LATEST: ON
|
||||
- WITH_NO_EXCEPTIONS: OFF
|
||||
WITH_CPP_LATEST: OFF
|
||||
- WITH_NO_EXCEPTIONS: ON
|
||||
WITH_CPP_LATEST: OFF
|
||||
- WITH_NO_EXCEPTIONS: OFF
|
||||
WITH_CPP_LATEST: ON
|
||||
|
||||
configuration:
|
||||
- Debug
|
||||
|
||||
platform:
|
||||
- x64
|
||||
@ -24,20 +24,18 @@ clone_script:
|
||||
|
||||
before_build:
|
||||
- cmd: >
|
||||
cmake -H. -Bbuild -A%PLATFORM%
|
||||
-DCTI_CONTINUABLE_WITH_NO_EXCEPTIONS=%WITH_NO_EXCEPTIONS%
|
||||
-DCTI_CONTINUABLE_WITH_EXPERIMENTAL_COROUTINE=ON
|
||||
-DCTI_CONTINUABLE_WITH_CPP_LATEST=%WITH_CPP_LATEST%
|
||||
cmake -H. -Bbuild -A%PLATFORM%
|
||||
-DCTI_CONTINUABLE_WITH_NO_EXCEPTIONS=%WITH_NO_EXCEPTIONS%
|
||||
-DCTI_CONTINUABLE_WITH_EXPERIMENTAL_COROUTINE=ON
|
||||
-DCTI_CONTINUABLE_WITH_CPP_LATEST=%WITH_CPP_LATEST%
|
||||
|
||||
build_script:
|
||||
- cmd: cmake --build build --config Debug --target ALL_BUILD -- /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll" /verbosity:minimal /maxcpucount:2 /nologo
|
||||
- cmd: cmake --build build --config Debug --target ALL_BUILD -- /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll" /verbosity:minimal /maxcpucount:2 /nologo
|
||||
- cmd: cmake --build build --config Release --target PACKAGE -- /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll" /verbosity:minimal /maxcpucount:2 /nologo
|
||||
- cmd: cmake --build build --config %CONFIGURATION% --target ALL_BUILD -- /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll" /verbosity:minimal /maxcpucount:2 /nologo
|
||||
- cmd: cmake --build build --config %CONFIGURATION% --target PACKAGE -- /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll" /verbosity:minimal /maxcpucount:2 /nologo
|
||||
|
||||
test_script:
|
||||
- cmd: cd build
|
||||
- cmd: ctest -C Debug -V .
|
||||
- cmd: ctest -C Release -V .
|
||||
- cmd: ctest -C %CONFIGURATION% -V .
|
||||
|
||||
artifacts:
|
||||
- path: 'build/*.zip'
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
|
||||
# Copyright(c) 2015 - 2022 Denis Blank <denis.blank at outlook dot com>
|
||||
# Copyright(c) 2015 - 2018 Denis Blank <denis.blank at outlook dot com>
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files(the "Software"), to deal
|
||||
@ -13,7 +13,7 @@
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
|
||||
# Copyright(c) 2015 - 2022 Denis Blank <denis.blank at outlook dot com>
|
||||
# Copyright(c) 2015 - 2018 Denis Blank <denis.blank at outlook dot com>
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files(the "Software"), to deal
|
||||
@ -13,7 +13,7 @@
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
|
||||
# Copyright(c) 2015 - 2022 Denis Blank <denis.blank at outlook dot com>
|
||||
# Copyright(c) 2015 - 2018 Denis Blank <denis.blank at outlook dot com>
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files(the "Software"), to deal
|
||||
@ -13,7 +13,7 @@
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
|
||||
# Copyright(c) 2015 - 2022 Denis Blank <denis.blank at outlook dot com>
|
||||
# Copyright(c) 2015 - 2018 Denis Blank <denis.blank at outlook dot com>
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files(the "Software"), to deal
|
||||
@ -13,7 +13,7 @@
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
@ -31,18 +31,9 @@ if (PLATFORM EQUAL 64)
|
||||
-D_WIN64)
|
||||
endif()
|
||||
|
||||
if (CTI_CONTINUABLE_WITH_CONCURRENT_JOBS)
|
||||
target_compile_options(continuable-features-flags
|
||||
INTERFACE
|
||||
/MP${CTI_CONTINUABLE_WITH_CONCURRENT_JOBS})
|
||||
else()
|
||||
target_compile_options(continuable-features-flags
|
||||
INTERFACE
|
||||
/MP)
|
||||
endif()
|
||||
|
||||
target_compile_options(continuable-features-flags
|
||||
INTERFACE
|
||||
/MP
|
||||
/bigobj
|
||||
/permissive-)
|
||||
|
||||
@ -50,7 +41,11 @@ target_compile_options(continuable-features-warnings
|
||||
INTERFACE
|
||||
/W4)
|
||||
|
||||
if (NOT CTI_CONTINUABLE_WITH_CPP_LATEST)
|
||||
if (CTI_CONTINUABLE_WITH_CPP_LATEST)
|
||||
target_compile_options(continuable-features-flags
|
||||
INTERFACE
|
||||
/std:c++latest)
|
||||
else()
|
||||
target_compile_options(continuable-features-flags
|
||||
INTERFACE
|
||||
/std:c++14)
|
||||
|
||||
@ -1,7 +0,0 @@
|
||||
set(@PROJECT_NAME@_VERSION @PROJECT_VERSION@)
|
||||
|
||||
@PACKAGE_INIT@
|
||||
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Targets.cmake")
|
||||
|
||||
check_required_components(@PROJECT_NAME@)
|
||||
@ -1,5 +1,5 @@
|
||||
|
||||
# Copyright(c) 2015 - 2022 Denis Blank <denis.blank at outlook dot com>
|
||||
# Copyright(c) 2015 - 2018 Denis Blank <denis.blank at outlook dot com>
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files(the "Software"), to deal
|
||||
@ -13,7 +13,7 @@
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
@ -21,12 +21,12 @@
|
||||
|
||||
# Select the compiler specific cmake file
|
||||
set(MSVC_ID "MSVC")
|
||||
if (${CMAKE_CXX_COMPILER_ID} MATCHES "(Apple)?Clang")
|
||||
include(${PROJECT_SOURCE_DIR}/cmake/compiler/clang.cmake)
|
||||
if (${CMAKE_CXX_COMPILER_ID} STREQUAL "Clang")
|
||||
include(${CMAKE_SOURCE_DIR}/cmake/compiler/clang.cmake)
|
||||
elseif (${CMAKE_CXX_COMPILER_ID} STREQUAL "GNU")
|
||||
include(${PROJECT_SOURCE_DIR}/cmake/compiler/gcc.cmake)
|
||||
include(${CMAKE_SOURCE_DIR}/cmake/compiler/gcc.cmake)
|
||||
elseif (${CMAKE_CXX_COMPILER_ID} STREQUAL ${MSVC_ID})
|
||||
include(${PROJECT_SOURCE_DIR}/cmake/compiler/msvc.cmake)
|
||||
include(${CMAKE_SOURCE_DIR}/cmake/compiler/msvc.cmake)
|
||||
else()
|
||||
message(FATAL_ERROR "Unknown compiler!")
|
||||
endif()
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
|
||||
# Copyright(c) 2015 - 2022 Denis Blank <denis.blank at outlook dot com>
|
||||
# Copyright(c) 2015 - 2018 Denis Blank <denis.blank at outlook dot com>
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files(the "Software"), to deal
|
||||
@ -13,10 +13,10 @@
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
# SOFTWARE.
|
||||
|
||||
include(${PROJECT_SOURCE_DIR}/cmake/macros/group_sources.cmake)
|
||||
include(${CMAKE_SOURCE_DIR}/cmake/macros/group_sources.cmake)
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
|
||||
# Copyright(c) 2015 - 2022 Denis Blank <denis.blank at outlook dot com>
|
||||
# Copyright(c) 2015 - 2018 Denis Blank <denis.blank at outlook dot com>
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files(the "Software"), to deal
|
||||
@ -13,48 +13,46 @@
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
# SOFTWARE.
|
||||
|
||||
set(WITH_SOURCE_TREE "hierarchical")
|
||||
macro(group_sources)
|
||||
macro(group_sources dir)
|
||||
# Skip this if WITH_SOURCE_TREE is not set (empty string).
|
||||
if (NOT ${WITH_SOURCE_TREE} STREQUAL "")
|
||||
foreach(dir ${ARGN})
|
||||
# Include all header and c files
|
||||
file(GLOB_RECURSE elements RELATIVE ${dir} ${dir}/*)
|
||||
# Include all header and c files
|
||||
file(GLOB_RECURSE elements RELATIVE ${dir} *.h *.hpp *.inl *.inc *.c *.cpp *.cc)
|
||||
|
||||
foreach(element ${elements})
|
||||
# Extract filename and directory
|
||||
get_filename_component(element_name ${element} NAME)
|
||||
get_filename_component(element_dir ${element} DIRECTORY)
|
||||
foreach(element ${elements})
|
||||
# Extract filename and directory
|
||||
get_filename_component(element_name ${element} NAME)
|
||||
get_filename_component(element_dir ${element} DIRECTORY)
|
||||
|
||||
if (NOT ${element_dir} STREQUAL "")
|
||||
# If the file is in a subdirectory use it as source group.
|
||||
if (${WITH_SOURCE_TREE} STREQUAL "flat")
|
||||
# Build flat structure by using only the first subdirectory.
|
||||
string(FIND ${element_dir} "/" delemiter_pos)
|
||||
if (NOT ${delemiter_pos} EQUAL -1)
|
||||
string(SUBSTRING ${element_dir} 0 ${delemiter_pos} group_name)
|
||||
source_group("${group_name}" FILES ${dir}/${element})
|
||||
else()
|
||||
# Build hierarchical structure.
|
||||
# File is in root directory.
|
||||
source_group("${element_dir}" FILES ${dir}/${element})
|
||||
endif()
|
||||
else()
|
||||
# Use the full hierarchical structure to build source_groups.
|
||||
string(REPLACE "/" "\\" group_name ${element_dir})
|
||||
if (NOT ${element_dir} STREQUAL "")
|
||||
# If the file is in a subdirectory use it as source group.
|
||||
if (${WITH_SOURCE_TREE} STREQUAL "flat")
|
||||
# Build flat structure by using only the first subdirectory.
|
||||
string(FIND ${element_dir} "/" delemiter_pos)
|
||||
if (NOT ${delemiter_pos} EQUAL -1)
|
||||
string(SUBSTRING ${element_dir} 0 ${delemiter_pos} group_name)
|
||||
source_group("${group_name}" FILES ${dir}/${element})
|
||||
else()
|
||||
# Build hierarchical structure.
|
||||
# File is in root directory.
|
||||
source_group("${element_dir}" FILES ${dir}/${element})
|
||||
endif()
|
||||
else()
|
||||
# If the file is in the root directory, place it in the root source_group.
|
||||
source_group("\\" FILES ${dir}/${element})
|
||||
# Use the full hierarchical structure to build source_groups.
|
||||
string(REPLACE "/" "\\" group_name ${element_dir})
|
||||
source_group("${group_name}" FILES ${dir}/${element})
|
||||
endif()
|
||||
endforeach()
|
||||
else()
|
||||
# If the file is in the root directory, place it in the root source_group.
|
||||
source_group("\\" FILES ${dir}/${element})
|
||||
endif()
|
||||
endforeach()
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
37
conanfile.py
37
conanfile.py
@ -1,37 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from conans import ConanFile, tools
|
||||
|
||||
def get_version():
|
||||
git = tools.Git()
|
||||
try:
|
||||
return git.run("describe --tags --abbrev=0")
|
||||
except:
|
||||
return None
|
||||
|
||||
class ContinuableConan(ConanFile):
|
||||
name = "continuable"
|
||||
version = get_version()
|
||||
license = "MIT"
|
||||
url = "https://github.com/Naios/continuable"
|
||||
author = "Denis Blank (denis.blank@outlook.com)"
|
||||
description = "C++14 asynchronous allocation aware futures"
|
||||
homepage = "https://naios.github.io/continuable/"
|
||||
no_copy_source = True
|
||||
scm = {
|
||||
"type": "git",
|
||||
"url": "auto",
|
||||
"revision": "auto"
|
||||
}
|
||||
|
||||
def package(self):
|
||||
self.copy("LICENSE.txt", "licenses")
|
||||
self.copy("include/*.hpp")
|
||||
self.copy("include/*.inl")
|
||||
|
||||
def package_id(self):
|
||||
self.info.header_only()
|
||||
|
||||
def requirements(self):
|
||||
self.requires("function2/4.0.0@naios/stable")
|
||||
@ -1,25 +1,13 @@
|
||||
if(NOT TARGET function2::function2)
|
||||
if(NOT TARGET function2)
|
||||
add_subdirectory(function2)
|
||||
endif()
|
||||
|
||||
if (CTI_CONTINUABLE_WITH_TESTS OR CTI_CONTINUABLE_WITH_BENCHMARKS)
|
||||
if (CTI_CONTINUABLE_WITH_TESTS OR CTI_CONTINUABLE_WITH_EXAMPLES)
|
||||
if(NOT TARGET gtest)
|
||||
add_subdirectory(googletest)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if (CTI_CONTINUABLE_WITH_EXAMPLES)
|
||||
if(NOT TARGET asio)
|
||||
add_subdirectory(asio)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if (CTI_CONTINUABLE_WITH_BENCHMARKS)
|
||||
if(NOT TARGET benchmark)
|
||||
add_subdirectory(benchmark)
|
||||
endif()
|
||||
|
||||
if(NOT TARGET boost)
|
||||
add_subdirectory(boost)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
@ -1,11 +1,9 @@
|
||||
add_library(asio STATIC
|
||||
${CMAKE_CURRENT_LIST_DIR}/asio/asio/src/asio.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/include/boost/throw_exception.hpp)
|
||||
${CMAKE_CURRENT_LIST_DIR}/asio/asio/src/asio.cpp)
|
||||
|
||||
target_include_directories(asio
|
||||
PUBLIC
|
||||
${CMAKE_CURRENT_LIST_DIR}/asio/asio/include
|
||||
${CMAKE_CURRENT_LIST_DIR}/include)
|
||||
${CMAKE_CURRENT_LIST_DIR}/asio/asio/include)
|
||||
|
||||
target_compile_definitions(asio
|
||||
PUBLIC
|
||||
@ -13,15 +11,6 @@ target_compile_definitions(asio
|
||||
-DASIO_SEPARATE_COMPILATION=1
|
||||
-DASIO_NO_TYPEID=1)
|
||||
|
||||
if (CTI_CONTINUABLE_WITH_NO_EXCEPTIONS)
|
||||
target_compile_definitions(asio
|
||||
PUBLIC
|
||||
-DASIO_NO_EXCEPTIONS=1
|
||||
-DASIO_HAS_BOOST_THROW_EXCEPTION=1)
|
||||
|
||||
message(STATUS "ASIO: Disabled exceptions")
|
||||
endif()
|
||||
|
||||
if(WIN32)
|
||||
target_compile_definitions(asio
|
||||
PUBLIC
|
||||
|
||||
@ -1 +1 @@
|
||||
Subproject commit 6c054e98f3f53352d12b6cd46d63b6d404cc044b
|
||||
Subproject commit 230c0d2ae035c5ce1292233fcab03cea0d341264
|
||||
@ -1,47 +0,0 @@
|
||||
|
||||
/*
|
||||
|
||||
/~` _ _ _|_. _ _ |_ | _
|
||||
\_,(_)| | | || ||_|(_||_)|(/_
|
||||
|
||||
https://github.com/Naios/continuable
|
||||
v4.0.0
|
||||
|
||||
Copyright(c) 2015 - 2022 Denis Blank <denis.blank at outlook dot com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files(the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions :
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
**/
|
||||
|
||||
#ifndef CONTINUABLE_DETAIL_BOOST_THROW_EXCEPTION_HPP_INCLUDED
|
||||
#define CONTINUABLE_DETAIL_BOOST_THROW_EXCEPTION_HPP_INCLUDED
|
||||
|
||||
#if defined(ASIO_STANDALONE) && defined(ASIO_NO_EXCEPTIONS)
|
||||
# include <cstdio>
|
||||
# include <cstdlib>
|
||||
|
||||
namespace boost {
|
||||
template <typename Exception>
|
||||
void throw_exception(Exception const& e) {
|
||||
puts(e.what());
|
||||
std::abort();
|
||||
}
|
||||
} // namespace boost
|
||||
#endif
|
||||
|
||||
#endif // CONTINUABLE_DETAIL_BOOST_THROW_EXCEPTION_HPP_INCLUDED
|
||||
@ -1,9 +0,0 @@
|
||||
set(BENCHMARK_ENABLE_TESTING OFF)
|
||||
if (CTI_CONTINUABLE_WITHOUT_EXCEPTIONS)
|
||||
set(BENCHMARK_ENABLE_EXCEPTIONS OFF)
|
||||
else()
|
||||
set(BENCHMARK_ENABLE_EXCEPTIONS ON)
|
||||
endif()
|
||||
set(BENCHMARK_ENABLE_INSTALL OFF)
|
||||
set(BENCHMARK_ENABLE_GTEST_TESTS OFF)
|
||||
add_subdirectory(benchmark)
|
||||
@ -1 +0,0 @@
|
||||
Subproject commit b874e72208b6e21b62287942e5e3b11f6630107f
|
||||
@ -1,43 +0,0 @@
|
||||
if(WIN32)
|
||||
if(CMAKE_SIZEOF_VOID_P MATCHES 8)
|
||||
set(PLATFORM 64)
|
||||
else()
|
||||
set(PLATFORM 32)
|
||||
endif()
|
||||
|
||||
if(DEFINED ENV{BOOST_ROOT})
|
||||
set(BOOST_ROOT $ENV{BOOST_ROOT})
|
||||
set(BOOST_LIBRARYDIR ${BOOST_ROOT}/lib${PLATFORM}-msvc-14.1)
|
||||
endif()
|
||||
|
||||
set(Boost_USE_STATIC_LIBS ON)
|
||||
set(Boost_USE_MULTITHREADED ON)
|
||||
set(Boost_USE_STATIC_RUNTIME OFF)
|
||||
endif()
|
||||
|
||||
find_package(Boost 1.68 REQUIRED
|
||||
COMPONENTS
|
||||
system
|
||||
iostreams
|
||||
thread)
|
||||
|
||||
if (${Boost_FOUND})
|
||||
add_library(boost INTERFACE)
|
||||
|
||||
target_link_libraries(boost
|
||||
INTERFACE
|
||||
Boost::system
|
||||
Boost::iostreams
|
||||
Boost::thread)
|
||||
|
||||
target_compile_definitions(boost
|
||||
INTERFACE
|
||||
BOOST_ALL_NO_LIB
|
||||
BOOST_ASIO_DISABLE_BOOST_DATE_TIME
|
||||
BOOST_ASIO_DISABLE_BOOST_REGEX
|
||||
BOOST_RANGE_ENABLE_CONCEPT_ASSERT=0
|
||||
BOOST_THREAD_PROVIDES_FUTURE
|
||||
BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION
|
||||
BOOST_FILESYSTEM_NO_DEPRECATED
|
||||
BOOST_THREAD_VERSION=4)
|
||||
endif()
|
||||
@ -1 +1 @@
|
||||
Subproject commit 3a0746bf5f601dfed05330aefcb6854354fce07d
|
||||
Subproject commit db03b55bc9b58999b1e653a1d57fe1056fe14778
|
||||
@ -1,4 +1,3 @@
|
||||
if(ON)
|
||||
add_library(gtest STATIC
|
||||
${CMAKE_CURRENT_LIST_DIR}/googletest/googletest/src/gtest-all.cc)
|
||||
|
||||
@ -43,10 +42,3 @@ target_include_directories(gmock
|
||||
${CMAKE_CURRENT_LIST_DIR}/googletest/googlemock
|
||||
PUBLIC
|
||||
${CMAKE_CURRENT_LIST_DIR}/googletest/googlemock/include)
|
||||
|
||||
else()
|
||||
set(BUILD_GTEST ON)
|
||||
set(BUILD_GMOCK OFF)
|
||||
set(INSTALL_GTEST OFF)
|
||||
add_subdirectory(googletest)
|
||||
endif()
|
||||
|
||||
@ -1 +1 @@
|
||||
Subproject commit f2fb48c3b3d79a75a88a99fba6576b25d42ec528
|
||||
Subproject commit 9bda90b7e5e08c4c37a832d0cea218aed6af6470
|
||||
@ -38,13 +38,13 @@ PROJECT_NAME = Continuable
|
||||
# could be handy for archiving the generated documentation or if some version
|
||||
# control system is used.
|
||||
|
||||
PROJECT_NUMBER = 4.1.0
|
||||
PROJECT_NUMBER = 3.0.0
|
||||
|
||||
# Using the PROJECT_BRIEF tag one can provide an optional one line description
|
||||
# for a project that appears at the top of each page and should give viewer a
|
||||
# quick idea about the purpose of the project. Keep the description short.
|
||||
|
||||
PROJECT_BRIEF = "C++14 asynchronous allocation aware futures"
|
||||
PROJECT_BRIEF =
|
||||
|
||||
# With the PROJECT_LOGO tag one can specify a logo or an icon that is included
|
||||
# in the documentation. The maximum height of the logo should not exceed 55
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright(c) 2015 - 2022 Denis Blank <denis.blank at outlook dot com>
|
||||
Copyright(c) 2015 - 2018 Denis Blank <denis.blank at outlook dot com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files(the "Software"), to deal
|
||||
@ -13,7 +13,7 @@
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
@ -28,146 +28,20 @@ namespace cti {
|
||||
|
||||
Following versions were released:
|
||||
|
||||
\subsection changelog-versions-4-0-0 4.0.0
|
||||
|
||||
Various issues have been resolved:
|
||||
|
||||
- [#27: First class, zero-overhead ASIO integration](https://github.com/Naios/continuable/issues/27)
|
||||
- [#23: VS 16.2: parameter pack must be expanded in this context](https://github.com/Naios/continuable/issues/23)
|
||||
- [#21: Infinite recursion during compilation](https://github.com/Naios/continuable/issues/21)
|
||||
- [#16: Add AppleClang compiler to cmake](https://github.com/Naios/continuable/issues/16)
|
||||
- [#13: unit-test/test-continuable-single fails on gcc 8.2](https://github.com/Naios/continuable/issues/13)
|
||||
- [#11: Forward declarations are no longer allowed in type-erased continuables](https://github.com/Naios/continuable/issues/11)
|
||||
|
||||
Following methods and functions have been added:
|
||||
|
||||
<B>Various improvements to continuable_base:</B>
|
||||
|
||||
- \ref continuable_base::as for casting to a continuable_base with different arguments
|
||||
- \ref continuable_base::finish for 'materializing' an intermediate chained continuable_base
|
||||
|
||||
<B>An asychronous initiation function comparable to std::async:</B>
|
||||
|
||||
The asynchronous facilities make it possible now to start with a handler
|
||||
instead of a continuation:
|
||||
|
||||
\code{.cpp}
|
||||
async([] {
|
||||
// ...
|
||||
}).then(...);
|
||||
\endcode
|
||||
|
||||
- \ref async Makes it possible to start with a handler instead of a continuation, comparable to `std::async`
|
||||
- \ref async_on allows to specify an additional executor parameter
|
||||
|
||||
<B>The result class and modifying the asynchronous control flow</B>
|
||||
|
||||
Every continuation handler used in \ref continuable_base::then, \ref continuable_base::next
|
||||
and \ref continuable_base::fail allows now to return a \ref result which represents
|
||||
the asynchronous result.
|
||||
|
||||
This allows recovering from failures or throwing of exception types from
|
||||
handlers when exceptions are disabled.
|
||||
|
||||
Result handling and
|
||||
- \ref result
|
||||
- \ref rethrow Throws an exception or error code from a result or failure handler
|
||||
- \ref cancel Throws a default constructed exception type or error code from a result or failure handler to signal cancellation.
|
||||
- \ref stop \copybrief stop
|
||||
- \ref make_result \copybrief make_result
|
||||
|
||||
Special result types
|
||||
- \ref empty_result \copybrief empty_result
|
||||
- \ref cancellation_result \copybrief cancellation_result
|
||||
- \ref exceptional_result \copybrief exceptional_result
|
||||
|
||||
<B>Optimize 'ready' continuables:</B>
|
||||
|
||||
Continuables which are 'ready' and side effect free can now be unpacked
|
||||
synchronously. Mainly such continuables are created through \ref make_ready_continuable,
|
||||
\ref make_exceptional_continuable and \ref make_cancelling_continuable.
|
||||
|
||||
- \ref continuable_base::is_ready \copybrief continuable_base::is_ready
|
||||
- \ref continuable_base::unpack \copybrief continuable_base::unpack
|
||||
- \ref make_cancelling_continuable \copybrief make_cancelling_continuable
|
||||
|
||||
Including various helper tags for the underlying changed continuation object structure:
|
||||
|
||||
- \ref signature_arg_t
|
||||
- \ref is_ready_arg_t
|
||||
- \ref unpack_arg_t
|
||||
- \ref exception_arg_t
|
||||
- \ref exception_t
|
||||
|
||||
<B>asio asynchronous initiate token:</B>
|
||||
|
||||
The \ref use_continuable_t special tag can be used to make (boost) asio
|
||||
return a \ref continuable_base.
|
||||
|
||||
- \ref use_continuable \copybrief use_continuable_t
|
||||
|
||||
\code{.cpp}
|
||||
#include <continuable/continuable.hpp>
|
||||
#include <continuable/external/asio.hpp>
|
||||
#include <asio.hpp>
|
||||
|
||||
// ...
|
||||
|
||||
asio::tcp::resolver resolver(...);
|
||||
resolver.async_resolve("127.0.0.1", "daytime", cti::use_continuable)
|
||||
.then([](asio::udp::resolver::iterator iterator) {
|
||||
// ...
|
||||
});
|
||||
\endcode
|
||||
|
||||
<B>Iterating over an asynchronous control flow:</B>
|
||||
|
||||
The loop function was added which makes is possible to emulate an asynchronous loop,
|
||||
that is comparable to a `co_await` with `for`.
|
||||
|
||||
- \ref loop \copybrief loop
|
||||
- \ref loop_result \copybrief loop_result
|
||||
- \ref loop_break \copybrief loop_break
|
||||
- \ref loop_continue \copybrief loop_continue
|
||||
- \ref range_loop \copybrief range_loop
|
||||
- \ref range_loop \copybrief range_loop
|
||||
- \ref plain_t \copybrief plain_t
|
||||
- \ref make_plain \copybrief make_plain
|
||||
|
||||
<B>Synchronous wait transforms:</B>
|
||||
|
||||
The wait transforms allows to block the current thread until a \ref continuable_base
|
||||
was resolved.
|
||||
|
||||
- \ref transforms::wait \copybrief transforms::wait
|
||||
- \ref transforms::wait_for Same as \ref transforms::wait wich waits for a given duration
|
||||
- \ref transforms::wait_until Same as \ref transforms::wait wich waits until a given timepoint
|
||||
|
||||
<B>Various changes:</B>
|
||||
|
||||
Many more unlisted changes including:
|
||||
|
||||
- \ref work \copybrief work
|
||||
- \ref continuation_capacity
|
||||
- \ref promisify::with \copybrief promisify::with
|
||||
- \ref void_arg_t
|
||||
|
||||
Additional various bugfixes have been made.
|
||||
|
||||
\subsection changelog-versions-3-0-0 3.0.0
|
||||
|
||||
<B>New helper functions</B>
|
||||
|
||||
New helper functions were added to create ready continuables:
|
||||
|
||||
- \ref make_ready_continuable \copybrief make_ready_continuable
|
||||
- \ref make_exceptional_continuable \copybrief make_exceptional_continuable
|
||||
- \ref make_ready_continuable
|
||||
- \ref make_exceptional_continuable
|
||||
|
||||
<B>Improvements to connections</B>
|
||||
|
||||
The implementation of connections were rewritten entirely.
|
||||
It is possible now to connect runtime sized containers as well as
|
||||
deeply nested sequences. See \ref tutorial-connecting-continuables for details.
|
||||
deeply nested sequences. See \ref tutorial-connections for details.
|
||||
|
||||
Additionally connection overloads were added that accept two iterators
|
||||
in order to come closer to the interface of the standard library.
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright(c) 2015 - 2022 Denis Blank <denis.blank at outlook dot com>
|
||||
Copyright(c) 2015 - 2018 Denis Blank <denis.blank at outlook dot com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files(the "Software"), to deal
|
||||
@ -13,7 +13,7 @@
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
@ -30,11 +30,9 @@ in order to change the libraries behaviour:
|
||||
|
||||
| Preprocessor definition | Consequence |
|
||||
| ----------------------------------------- | --------------- |
|
||||
| `CONTINUABLE_WITH_NO_EXCEPTIONS` | Exceptions are disabled and `std::error_condition` is used as \ref error_type . See \ref tutorial-chaining-continuables-fail for details. |
|
||||
| `CONTINUABLE_WITH_NO_EXCEPTIONS` | Exceptions are disabled and `std::error_condition` is used as \ref error_type . See \ref tutorial-chaining-continuables-fail for details. |
|
||||
| `CONTINUABLE_WITH_CUSTOM_ERROR_TYPE` | Exceptions are disabled and the type defined by `CONTINUABLE_WITH_CUSTOM_ERROR_TYPE` is used as \ref error_type . See \ref tutorial-chaining-continuables-fail for details. |
|
||||
| `CONTINUABLE_WITH_UNHANDLED_EXCEPTIONS` | Allows unhandled exceptions in asynchronous call hierarchies. See \ref tutorial-chaining-continuables-fail for details. |
|
||||
| `CONTINUABLE_WITH_CUSTOM_FINAL_CALLBACK` | Allows to customize the final callback which can be used to implement custom unhandled asynchronous exception handlers. |
|
||||
| `CONTINUABLE_WITH_IMMEDIATE_TYPES` | Don't decorate the used type erasure, which is done to keep type names minimal for better error messages in debug builds. |
|
||||
| `CONTINUABLE_WITH_EXPERIMENTAL_COROUTINE` | Enables support for experimental coroutines and `co_await` expressions. See \ref continuable_base::operator co_await() for details. |
|
||||
|
||||
*/
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright(c) 2015 - 2022 Denis Blank <denis.blank at outlook dot com>
|
||||
Copyright(c) 2015 - 2018 Denis Blank <denis.blank at outlook dot com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files(the "Software"), to deal
|
||||
@ -13,7 +13,7 @@
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
@ -70,13 +70,13 @@ your personal experience in using the library to improve it.
|
||||
\note If you are using the library in your open-source or commercial project
|
||||
I would highly appreciate if you could give me a short notice so I can
|
||||
add you to a list of projects and companies using this library.
|
||||
|
||||
|
||||
\section mainpage-license License
|
||||
|
||||
Continuable is licensed under the MIT license:
|
||||
|
||||
>
|
||||
> Copyright(c) 2015 - 2022 Denis Blank <denis.blank at outlook dot com>
|
||||
> Copyright(c) 2015 - 2018 Denis Blank <denis.blank at outlook dot com>
|
||||
>
|
||||
> Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
> of this software and associated documentation files(the "Software"), to deal
|
||||
@ -90,7 +90,7 @@ Continuable is licensed under the MIT license:
|
||||
>
|
||||
> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
> IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
> FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
> FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
|
||||
> AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
> LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
> OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright(c) 2015 - 2022 Denis Blank <denis.blank at outlook dot com>
|
||||
Copyright(c) 2015 - 2018 Denis Blank <denis.blank at outlook dot com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files(the "Software"), to deal
|
||||
@ -13,7 +13,7 @@
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
@ -44,12 +44,12 @@ versions might work.
|
||||
\section installation-dependencies Dependencies
|
||||
|
||||
Continuable is a header-only library with one required header-only dependency:
|
||||
|
||||
|
||||
- [Naios/function2](https://github.com/Naios/function2) is used as type
|
||||
erasure wrapper to convert a \ref continuable_base into a \ref continuable.
|
||||
|
||||
Additionally GTest is required as optional dependency for the asynchronous
|
||||
unit testing macros defined in `continuable/support/gtest.hpp`
|
||||
unit testing macros defined in `continuable/continuable-testing.hpp`
|
||||
if those are used:
|
||||
|
||||
- [google/googletest](https://github.com/google/googletest) is used as
|
||||
@ -120,14 +120,6 @@ and might be installed from there.
|
||||
to make it available from various package managers in order to
|
||||
make the installation easier.
|
||||
|
||||
\subsection installation-installation-amalgamation By using the amalgamation header
|
||||
|
||||
For major versions there is an amalgamation header provided which can be
|
||||
included without any dependency:
|
||||
|
||||
- [4.0.0](https://gist.githubusercontent.com/Naios/25d731aa4707d35a9bcec507f3cb9038/raw/051d2ea07b6704893c7fc9844e8d1c105c6821e0/continuable.hpp)
|
||||
- [3.0.0](https://gist.githubusercontent.com/Naios/b128ab5028a7eb33e4285c0293573d9f/raw/79fe332964a786b21a8661ef65d07a5669260a3c/continuable.hpp)
|
||||
|
||||
\subsection installation-installation-copy By copying the headers
|
||||
|
||||
If you don't want to rely on CMake or package managers it is possible to
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright(c) 2015 - 2022 Denis Blank <denis.blank at outlook dot com>
|
||||
Copyright(c) 2015 - 2018 Denis Blank <denis.blank at outlook dot com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files(the "Software"), to deal
|
||||
@ -13,7 +13,7 @@
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
@ -96,34 +96,16 @@ result.get_value();
|
||||
result.get_exception();
|
||||
\endcode
|
||||
|
||||
\section tutorial-awaiting-continuables-return Using continuables as return type from coroutines
|
||||
|
||||
It is possible to use a \ref continuable_base as return type from coroutines.
|
||||
|
||||
\note It isn't possible as of now to use a \ref continuable_base
|
||||
as return type from coroutines:
|
||||
\code{.cpp}
|
||||
cti::continuable<> resolve_async_void() {
|
||||
co_await http_request("github.com");
|
||||
// ...
|
||||
co_return;
|
||||
}
|
||||
|
||||
cti::continuable<int> resolve_async() {
|
||||
cti::continuable<int> do_sth() {
|
||||
co_await http_request("github.com");
|
||||
// ...
|
||||
co_return 0;
|
||||
}
|
||||
\endcode
|
||||
|
||||
Additionally it's possible to return multiple return values from coroutines
|
||||
by wrapping those in a tuple like type:
|
||||
|
||||
\code{.cpp}
|
||||
cti::continuable<int, int, int> resolve_async_multiple() {
|
||||
co_await http_request("github.com");
|
||||
// ...
|
||||
co_return std::make_tuple(0, 1, 2);
|
||||
}
|
||||
\endcode
|
||||
|
||||
*/
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright(c) 2015 - 2022 Denis Blank <denis.blank at outlook dot com>
|
||||
Copyright(c) 2015 - 2018 Denis Blank <denis.blank at outlook dot com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files(the "Software"), to deal
|
||||
@ -13,7 +13,7 @@
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright(c) 2015 - 2022 Denis Blank <denis.blank at outlook dot com>
|
||||
Copyright(c) 2015 - 2018 Denis Blank <denis.blank at outlook dot com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files(the "Software"), to deal
|
||||
@ -13,7 +13,7 @@
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
@ -201,8 +201,8 @@ for (int i = 2; i < 5; ++i) {
|
||||
// to the container afterwards
|
||||
container.emplace_back(cti::make_ready_continuable(i));
|
||||
}
|
||||
|
||||
cti::when_all(std::move(v))
|
||||
|
||||
cti::when_all(v)
|
||||
.then([](std::vector<int> resolved) {
|
||||
// ...
|
||||
});
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright(c) 2015 - 2022 Denis Blank <denis.blank at outlook dot com>
|
||||
Copyright(c) 2015 - 2018 Denis Blank <denis.blank at outlook dot com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files(the "Software"), to deal
|
||||
@ -13,7 +13,7 @@
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright(c) 2015 - 2022 Denis Blank <denis.blank at outlook dot com>
|
||||
Copyright(c) 2015 - 2018 Denis Blank <denis.blank at outlook dot com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files(the "Software"), to deal
|
||||
@ -13,7 +13,7 @@
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
@ -50,7 +50,7 @@ The default callback style is something like
|
||||
Continuable offers the \ref promisify::from method for such callback styles.
|
||||
|
||||
See an example of how to promisify boost asio's `async_resolve` below:
|
||||
|
||||
|
||||
\code{.cpp}
|
||||
auto async_resolve(std::string host, std::string service) {
|
||||
return cti::promisify<asio::ip::udp::resolver::iterator>::from(
|
||||
@ -70,30 +70,5 @@ async_resolve("127.0.0.1", "daytime")
|
||||
});
|
||||
\endcode
|
||||
|
||||
|
||||
\section tutorial-promisify-continuables-boost-ct asio and boost::asio async completion tokens
|
||||
|
||||
Since version 4.0.0 continuable also supports asio async initiation tokens.
|
||||
|
||||
- Boost 1.70 or asio 1.13.0 is required for the async initiation
|
||||
- Until boost 1.72 or asio 1.16.0 overhead through an additional type
|
||||
erasure is added. It is recommended to update to those versions.
|
||||
|
||||
The special static variable \ref cti::use_continuable can be appended to any
|
||||
(boost) asio function that accepts a callback to make it return a \ref continuable_base.
|
||||
|
||||
\code{.cpp}
|
||||
#include <continuable/continuable.hpp>
|
||||
#include <continuable/external/asio.hpp>
|
||||
#include <asio.hpp>
|
||||
|
||||
// ...
|
||||
|
||||
asio::tcp::resolver resolver(...);
|
||||
resolver.async_resolve("127.0.0.1", "daytime", cti::use_continuable)
|
||||
.then([](asio::udp::resolver::iterator iterator) {
|
||||
// ...
|
||||
});
|
||||
\endcode
|
||||
*/
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright(c) 2015 - 2022 Denis Blank <denis.blank at outlook dot com>
|
||||
Copyright(c) 2015 - 2018 Denis Blank <denis.blank at outlook dot com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files(the "Software"), to deal
|
||||
@ -13,7 +13,7 @@
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
@ -30,37 +30,28 @@ namespace cti {
|
||||
|
||||
Sometimes it's required to change a \ref continuable_base object by its whole.
|
||||
Thus the library offers the ability to apply a transformation to any
|
||||
\ref continuable_base through using \link continuable_base::apply apply \endlink.
|
||||
\ref continuable_base through using \link continuable_base::apply apply \endlink
|
||||
or \link continuable_base::operator | its operator | \endlink.
|
||||
|
||||
A transformation is a callable object that accepts a \ref continuable_base
|
||||
and returns an arbitrary object
|
||||
A transformation accepts a \ref continuable_base and returns
|
||||
an arbitrary object.
|
||||
|
||||
To create a transformation use the \ref make_transform function:
|
||||
|
||||
\code{.cpp}
|
||||
auto transform = cti::make_transform([] (auto&& continuable) {
|
||||
// Change the continuable
|
||||
return std::forward<decltype(continuable)>(continuable);
|
||||
});
|
||||
\endcode
|
||||
|
||||
The library provides several transforms already as part of the
|
||||
\ref cti::transforms namespace.
|
||||
|
||||
\section tutorial-transforming-continuables-wait Synchronous wait
|
||||
|
||||
The library is capable of converting every asynchronous control flow
|
||||
into a synchronous one through \ref transforms::wait, \ref transforms::wait_for
|
||||
and \ref transforms::wait_until.
|
||||
|
||||
\code{.cpp}
|
||||
std::string response = http_request("github.com")
|
||||
.apply(cti::transforms::wait());
|
||||
|
||||
std::string response = http_request("github.com")
|
||||
.apply(cti::transforms::wait_for(std::chrono::seconds(5)));
|
||||
|
||||
std::string response = http_request("github.com")
|
||||
.apply(cti::transforms::wait_until(...));
|
||||
\endcode
|
||||
|
||||
The current thread will be blocked until the result has arrived
|
||||
|
||||
\section tutorial-transforming-continuables-future Conversion into std::future
|
||||
|
||||
The library is capable of converting (*futurizing*) every continuable into a
|
||||
fitting `std::future` through the \ref transforms::to_future transform:
|
||||
fitting `std::future` through the \ref transforms::futurize transform:
|
||||
|
||||
\code{.cpp}
|
||||
std::future<std::string> future = http_request("github.com")
|
||||
@ -68,17 +59,17 @@ std::future<std::string> future = http_request("github.com")
|
||||
// Do sth...
|
||||
return http_request("travis-ci.org") || http_request("atom.io");
|
||||
})
|
||||
.apply(cti::transforms::to_future());
|
||||
.apply(cti::transforms::futurize());
|
||||
// ^^^^^^^^
|
||||
\endcode
|
||||
|
||||
Multiple arguments which can't be handled by `std::future` itself are
|
||||
converted into `std::tuple`, see \ref transforms::to_future for details.
|
||||
converted into `std::tuple`, see \ref transforms::futurize for details.
|
||||
|
||||
\code{.cpp}
|
||||
std::future<std::tuple<std::string, std::string>> future =
|
||||
(http_request("travis-ci.org") && http_request("atom.io"))
|
||||
.apply(cti::transforms::to_future());
|
||||
.apply(cti::transforms::futurize());
|
||||
\endcode
|
||||
*/
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright(c) 2015 - 2022 Denis Blank <denis.blank at outlook dot com>
|
||||
Copyright(c) 2015 - 2018 Denis Blank <denis.blank at outlook dot com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files(the "Software"), to deal
|
||||
@ -13,7 +13,7 @@
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
|
||||
@ -7,7 +7,7 @@
|
||||
https://github.com/Naios/continuable
|
||||
v3.0.0
|
||||
|
||||
Copyright(c) 2015 - 2022 Denis Blank <denis.blank at outlook dot com>
|
||||
Copyright(c) 2015 - 2018 Denis Blank <denis.blank at outlook dot com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files(the "Software"), to deal
|
||||
@ -21,7 +21,7 @@
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
|
||||
@ -1,28 +1,15 @@
|
||||
add_library(asio-example-deps INTERFACE)
|
||||
|
||||
target_include_directories(asio-example-deps
|
||||
INTERFACE
|
||||
${CMAKE_CURRENT_LIST_DIR})
|
||||
|
||||
target_link_libraries(asio-example-deps
|
||||
INTERFACE
|
||||
asio
|
||||
continuable)
|
||||
|
||||
add_executable(example-asio
|
||||
${CMAKE_CURRENT_LIST_DIR}/example-asio.cpp)
|
||||
|
||||
target_include_directories(example-asio
|
||||
PRIVATE
|
||||
${CMAKE_CURRENT_LIST_DIR})
|
||||
|
||||
target_link_libraries(example-asio
|
||||
PRIVATE
|
||||
asio-example-deps)
|
||||
asio
|
||||
continuable)
|
||||
|
||||
target_compile_definitions(example-asio
|
||||
PUBLIC
|
||||
-DCONTINUABLE_WITH_NO_EXCEPTIONS)
|
||||
|
||||
add_executable(example-asio-integration
|
||||
${CMAKE_CURRENT_LIST_DIR}/example-asio-integration.cpp)
|
||||
|
||||
target_link_libraries(example-asio-integration
|
||||
PRIVATE
|
||||
asio-example-deps)
|
||||
|
||||
@ -1,176 +0,0 @@
|
||||
|
||||
/*
|
||||
|
||||
/~` _ _ _|_. _ _ |_ | _
|
||||
\_,(_)| | | || ||_|(_||_)|(/_
|
||||
|
||||
https://github.com/Naios/continuable
|
||||
v4.0.0
|
||||
|
||||
Copyright(c) 2015 - 2022 Denis Blank <denis.blank at outlook dot com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files(the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions :
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
**/
|
||||
|
||||
#include <asio.hpp>
|
||||
|
||||
#include <continuable/continuable.hpp>
|
||||
#include <continuable/external/asio.hpp>
|
||||
|
||||
// Queries the NIST daytime service and prints the current date and time
|
||||
void daytime_service();
|
||||
|
||||
// Checks that a timer async_wait returns successfully
|
||||
void successful_async_wait();
|
||||
|
||||
// Checks that a cancelled timer async_wait fails with
|
||||
// `asio::error::operation_aborted` and is converted to a default constructed
|
||||
// cti::exception_t.
|
||||
void cancelled_async_wait();
|
||||
|
||||
// Indicates fatal error due to an unexpected failure in the continuation chain.
|
||||
void unexpected_error(cti::exception_t);
|
||||
|
||||
// Check that the failure was an aborted operation, as expected.
|
||||
void check_aborted_operation(cti::exception_t);
|
||||
|
||||
// Use a strand as executor
|
||||
void using_strand();
|
||||
|
||||
int main(int, char**) {
|
||||
daytime_service();
|
||||
|
||||
successful_async_wait();
|
||||
cancelled_async_wait();
|
||||
|
||||
using_strand();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void daytime_service() {
|
||||
using asio::ip::tcp;
|
||||
asio::io_context ioc(1);
|
||||
tcp::resolver resolver(ioc);
|
||||
tcp::socket socket(ioc);
|
||||
std::string buf;
|
||||
|
||||
resolver.async_resolve("time.nist.gov", "daytime", cti::use_continuable)
|
||||
.then([&socket](tcp::resolver::results_type endpoints) {
|
||||
return asio::async_connect(socket, endpoints, cti::use_continuable);
|
||||
})
|
||||
.then([&socket, &buf] {
|
||||
return asio::async_read_until(socket, asio::dynamic_buffer(buf), '\n',
|
||||
cti::use_continuable);
|
||||
})
|
||||
.then([&buf](std::size_t) {
|
||||
puts("Continuation successfully got a daytime response:");
|
||||
puts(buf.c_str());
|
||||
})
|
||||
.fail(&unexpected_error);
|
||||
|
||||
ioc.run();
|
||||
}
|
||||
|
||||
void successful_async_wait() {
|
||||
asio::io_context ioc(1);
|
||||
asio::steady_timer t(ioc);
|
||||
|
||||
t.expires_after(std::chrono::seconds(1));
|
||||
|
||||
t.async_wait(cti::use_continuable)
|
||||
.then([] {
|
||||
puts("Continuation succeeded after 1s as expected!");
|
||||
})
|
||||
.fail(&unexpected_error);
|
||||
|
||||
ioc.run();
|
||||
}
|
||||
|
||||
void cancelled_async_wait() {
|
||||
asio::io_context ioc(1);
|
||||
asio::steady_timer t(ioc);
|
||||
|
||||
t.expires_after(std::chrono::seconds(999));
|
||||
|
||||
t.async_wait(cti::use_continuable)
|
||||
.then([] {
|
||||
puts("This should never be called");
|
||||
std::terminate();
|
||||
})
|
||||
.fail(&check_aborted_operation);
|
||||
|
||||
t.cancel_one();
|
||||
ioc.run();
|
||||
}
|
||||
|
||||
void unexpected_error(cti::exception_t e) {
|
||||
if (!bool(e)) {
|
||||
puts("Continuation failed with unexpected cancellation!");
|
||||
std::terminate();
|
||||
}
|
||||
|
||||
#if defined(CONTINUABLE_HAS_EXCEPTIONS)
|
||||
try {
|
||||
std::rethrow_exception(e);
|
||||
} catch (std::exception const& ex) {
|
||||
puts("Continuation failed with unexpected exception");
|
||||
puts(ex.what());
|
||||
} catch (...) {
|
||||
// Rethrow the exception to the asynchronous unhandled exception handler
|
||||
std::rethrow_exception(std::current_exception());
|
||||
}
|
||||
#else
|
||||
puts("Continuation failed with unexpected error");
|
||||
puts(e.message().data());
|
||||
#endif
|
||||
std::terminate();
|
||||
}
|
||||
|
||||
void check_aborted_operation(cti::exception_t ex) {
|
||||
if (bool(ex)) {
|
||||
unexpected_error(ex);
|
||||
} else {
|
||||
puts("Continuation failed due to aborted async operation, as expected.");
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
auto through_post(T& postable) {
|
||||
return [&postable](auto&& work) mutable {
|
||||
asio::post(postable, std::forward<decltype(work)>(work));
|
||||
};
|
||||
}
|
||||
|
||||
void using_strand() {
|
||||
asio::io_context ioc(1);
|
||||
asio::io_context::strand strand(ioc);
|
||||
|
||||
asio::post(strand, cti::use_continuable).then([]() {
|
||||
puts("Dispatched through initiation token");
|
||||
});
|
||||
|
||||
cti::async_on(
|
||||
[]() mutable {
|
||||
puts("Dispatched through executor");
|
||||
},
|
||||
through_post(strand));
|
||||
|
||||
ioc.run();
|
||||
}
|
||||
@ -5,9 +5,9 @@
|
||||
\_,(_)| | | || ||_|(_||_)|(/_
|
||||
|
||||
https://github.com/Naios/continuable
|
||||
v4.0.0
|
||||
v3.0.0
|
||||
|
||||
Copyright(c) 2015 - 2022 Denis Blank <denis.blank at outlook dot com>
|
||||
Copyright(c) 2015 - 2018 Denis Blank <denis.blank at outlook dot com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files(the "Software"), to deal
|
||||
@ -21,7 +21,7 @@
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
@ -34,30 +34,12 @@
|
||||
#include <string>
|
||||
#include <system_error>
|
||||
|
||||
#if defined(CONTINUABLE_HAS_EXCEPTIONS)
|
||||
#include <exception>
|
||||
#endif
|
||||
|
||||
#include <asio.hpp>
|
||||
|
||||
#include <continuable/continuable.hpp>
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
inline auto error_code_remapper() {
|
||||
return [](auto&& promise, asio::error_code e, auto&&... args) {
|
||||
if (e) {
|
||||
#if defined(CONTINUABLE_HAS_EXCEPTIONS)
|
||||
promise.set_exception(std::make_exception_ptr(e));
|
||||
#else
|
||||
promise.set_exception(cti::exception_t(e.value(), e.category()));
|
||||
#endif
|
||||
} else {
|
||||
promise.set_value(std::forward<decltype(args)>(args)...);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
struct functional_io_service {
|
||||
asio::io_context service_;
|
||||
asio::ip::udp::resolver resolver_;
|
||||
@ -67,11 +49,7 @@ struct functional_io_service {
|
||||
|
||||
auto trough_post() noexcept {
|
||||
return [&](auto&& work) mutable {
|
||||
asio::post(service_,
|
||||
[work = std::forward<decltype(work)>(work)]() mutable {
|
||||
std::move(work)();
|
||||
// .. or: work.set_value();
|
||||
});
|
||||
asio::post(service_, std::forward<decltype(work)>(work));
|
||||
};
|
||||
}
|
||||
|
||||
@ -83,8 +61,7 @@ struct functional_io_service {
|
||||
}
|
||||
|
||||
auto async_resolve(std::string host, std::string service) {
|
||||
return cti::promisify<asio::ip::udp::resolver::iterator>::with(
|
||||
error_code_remapper(),
|
||||
return cti::promisify<asio::ip::udp::resolver::iterator>::from(
|
||||
[&](auto&&... args) {
|
||||
resolver_.async_resolve(std::forward<decltype(args)>(args)...);
|
||||
},
|
||||
@ -112,7 +89,7 @@ int main(int, char**) {
|
||||
// auto socket = std::make_shared<udp::socket>(service);
|
||||
// socket->async_send_to()
|
||||
})
|
||||
.fail([](cti::exception_t /*error*/) {
|
||||
.fail([](cti::error_type /*error*/) {
|
||||
// ...
|
||||
});
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright(c) 2015 - 2022 Denis Blank <denis.blank at outlook dot com>
|
||||
Copyright(c) 2015 - 2018 Denis Blank <denis.blank at outlook dot com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files(the "Software"), to deal
|
||||
@ -13,7 +13,7 @@
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
|
||||
@ -5,9 +5,9 @@
|
||||
\_,(_)| | | || ||_|(_||_)|(/_
|
||||
|
||||
https://github.com/Naios/continuable
|
||||
v4.2.0
|
||||
v3.0.0
|
||||
|
||||
Copyright(c) 2015 - 2022 Denis Blank <denis.blank at outlook dot com>
|
||||
Copyright(c) 2015 - 2018 Denis Blank <denis.blank at outlook dot com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files(the "Software"), to deal
|
||||
@ -21,7 +21,7 @@
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
@ -32,30 +32,64 @@
|
||||
#define CONTINUABLE_BASE_HPP_INCLUDED
|
||||
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <continuable/continuable-primitives.hpp>
|
||||
#include <continuable/continuable-result.hpp>
|
||||
#include <continuable/detail/connection/connection-all.hpp>
|
||||
#include <continuable/detail/connection/connection-any.hpp>
|
||||
#include <continuable/detail/connection/connection-seq.hpp>
|
||||
#include <continuable/detail/connection/connection.hpp>
|
||||
#include <continuable/detail/core/base.hpp>
|
||||
#include <continuable/detail/core/types.hpp>
|
||||
#include <continuable/detail/features.hpp>
|
||||
#include <continuable/detail/utility/traits.hpp>
|
||||
#include <continuable/detail/utility/util.hpp>
|
||||
|
||||
#if defined(CONTINUABLE_HAS_COROUTINE)
|
||||
# include <continuable/detail/other/coroutines.hpp>
|
||||
#endif // defined(CONTINUABLE_HAS_COROUTINE)
|
||||
#include <continuable/detail/base.hpp>
|
||||
#include <continuable/detail/connection-all.hpp>
|
||||
#include <continuable/detail/connection-any.hpp>
|
||||
#include <continuable/detail/connection-seq.hpp>
|
||||
#include <continuable/detail/connection.hpp>
|
||||
#include <continuable/detail/features.hpp>
|
||||
#include <continuable/detail/traits.hpp>
|
||||
#include <continuable/detail/types.hpp>
|
||||
#include <continuable/detail/util.hpp>
|
||||
|
||||
#ifdef CONTINUABLE_HAS_EXPERIMENTAL_COROUTINE
|
||||
#include <continuable/detail/awaiting.hpp>
|
||||
#endif // CONTINUABLE_HAS_EXPERIMENTAL_COROUTINE
|
||||
|
||||
namespace cti {
|
||||
/// \defgroup Base Base
|
||||
/// provides classes and functions to create continuable_base objects.
|
||||
/// \{
|
||||
|
||||
/// Represents a tag which can be placed first in a signature
|
||||
/// in order to overload callables with the asynchronous result
|
||||
/// as well as an error.
|
||||
///
|
||||
/// See the example below:
|
||||
/// ```cpp
|
||||
/// struct my_callable {
|
||||
/// void operator() (std::string result) {
|
||||
/// // ...
|
||||
/// }
|
||||
/// void operator() (cti::dispatch_error_tag, cti::error_type) {
|
||||
/// // ...
|
||||
/// }
|
||||
/// };
|
||||
///
|
||||
/// // Will receive errors and results
|
||||
/// continuable.next(my_callable{});
|
||||
/// ```
|
||||
///
|
||||
/// \note see continuable::next for details.
|
||||
///
|
||||
/// \since 2.0.0
|
||||
using dispatch_error_tag = detail::types::dispatch_error_tag;
|
||||
|
||||
/// Represents the type that is used as error type
|
||||
///
|
||||
/// By default this type deduces to `std::exception_ptr`.
|
||||
/// If `CONTINUABLE_WITH_NO_EXCEPTIONS` is defined the type
|
||||
/// will be a `std::error_condition`.
|
||||
/// A custom error type may be set through
|
||||
/// defining `CONTINUABLE_WITH_CUSTOM_ERROR_TYPE`.
|
||||
///
|
||||
/// \since 2.0.0
|
||||
using error_type = detail::types::error_type;
|
||||
|
||||
/// Deduces to a true_type if the given type is a continuable_base.
|
||||
///
|
||||
/// \since 3.0.0
|
||||
@ -92,10 +126,6 @@ template <typename Data, typename Annotation>
|
||||
class continuable_base {
|
||||
|
||||
/// \cond false
|
||||
using ownership = detail::util::ownership;
|
||||
|
||||
using annotation_trait = detail::annotation_trait<Annotation>;
|
||||
|
||||
template <typename, typename>
|
||||
friend class continuable_base;
|
||||
friend struct detail::base::attorney;
|
||||
@ -103,41 +133,25 @@ class continuable_base {
|
||||
// The continuation type or intermediate result
|
||||
Data data_;
|
||||
// The transferable state which represents the validity of the object
|
||||
ownership ownership_;
|
||||
detail::util::ownership ownership_;
|
||||
/// \endcond
|
||||
|
||||
/// Constructor accepting the data object while erasing the annotation
|
||||
explicit continuable_base(Data data, ownership ownership)
|
||||
: data_(std::move(data))
|
||||
, ownership_(std::move(ownership)) {}
|
||||
explicit continuable_base(Data data, detail::util::ownership ownership)
|
||||
: data_(std::move(data)), ownership_(std::move(ownership)) {
|
||||
}
|
||||
|
||||
public:
|
||||
/// Constructor accepting the data object while erasing the annotation
|
||||
explicit continuable_base(Data data)
|
||||
: data_(std::move(data)) {}
|
||||
explicit continuable_base(Data data) : data_(std::move(data)) {
|
||||
}
|
||||
|
||||
/// Constructor accepting any object convertible to the data object,
|
||||
/// while erasing the annotation
|
||||
template <typename OtherData,
|
||||
std::enable_if_t<detail::base::can_accept_continuation<
|
||||
Data, Annotation,
|
||||
detail::traits::unrefcv_t<OtherData>>::value>* = nullptr>
|
||||
/* implicit */ continuable_base(OtherData&& data)
|
||||
: data_(
|
||||
detail::base::proxy_continuable<Annotation,
|
||||
detail::traits::unrefcv_t<OtherData>>(
|
||||
std::forward<OtherData>(data))) {}
|
||||
|
||||
/// Constructor taking the data of other continuable_base objects
|
||||
/// while erasing the hint.
|
||||
///
|
||||
/// This constructor makes it possible to replace the internal data object of
|
||||
/// the continuable by any object which is useful for type-erasure.
|
||||
template <typename OData,
|
||||
std::enable_if_t<std::is_convertible<
|
||||
detail::traits::unrefcv_t<OData>, Data>::value>* = nullptr>
|
||||
/* implicit */ continuable_base(continuable_base<OData, Annotation>&& other)
|
||||
: data_(std::move(other).consume()) {}
|
||||
template <typename OData, std::enable_if_t<std::is_convertible<
|
||||
std::decay_t<OData>, Data>::value>* = nullptr>
|
||||
continuable_base(OData&& data) : data_(std::forward<OData>(data)) {
|
||||
}
|
||||
|
||||
/// Constructor taking the data of other continuable_base objects
|
||||
/// while erasing the hint.
|
||||
@ -145,8 +159,9 @@ public:
|
||||
/// This constructor makes it possible to replace the internal data object of
|
||||
/// the continuable by any object which is useful for type-erasure.
|
||||
template <typename OData, typename OAnnotation>
|
||||
/* implicit */ continuable_base(continuable_base<OData, OAnnotation>&& other)
|
||||
: continuable_base(std::move(other).finish().consume()) {}
|
||||
continuable_base(continuable_base<OData, OAnnotation>&& other)
|
||||
: continuable_base(std::move(other).materialize().consume_data()) {
|
||||
}
|
||||
|
||||
/// \cond false
|
||||
continuable_base(continuable_base&&) = default;
|
||||
@ -225,17 +240,12 @@ public:
|
||||
/// | `Arg` | `continuable_base with <Arg>` |
|
||||
/// | `std::pair<First, Second>` | `continuable_base with <First, Second>` |
|
||||
/// | `std::tuple<Args...>` | `continuable_base with <Args...>` |
|
||||
/// | `cti::result<Args...>` | `continuable_base with <Args...>` |
|
||||
/// | `continuable_base<Arg...>` | `continuable_base with <Args...>` |
|
||||
/// Which means the result type of the continuable_base is equal to
|
||||
/// the plain types the callback returns (`std::tuple` and
|
||||
/// `std::pair` arguments are unwrapped).
|
||||
/// A single continuable_base as argument is resolved and the result
|
||||
/// type is equal to the resolved continuable_base.
|
||||
/// A cti::result can be used to cancel the continuation or to
|
||||
/// transition to the exception handler.
|
||||
/// The special unwrapping of types can be disabled through wrapping
|
||||
/// such objects through a call to cti::make_plain.
|
||||
/// Consider the following examples:
|
||||
/// ```cpp
|
||||
/// http_request("github.com")
|
||||
@ -257,17 +267,6 @@ public:
|
||||
/// http_request("github.com")
|
||||
/// .then([](std::string github) { return http_request("atom.io"); })
|
||||
/// .then([](std::string atom) { }); // <std::string>
|
||||
///
|
||||
/// http_request("example.com")
|
||||
/// .then([](std::string content) -> result<std::string> {
|
||||
/// return rethrow(std::make_exception_ptr(std::exception{}));
|
||||
/// })
|
||||
/// .fail([] -> result<std::string> {
|
||||
/// return recover("Hello World!");
|
||||
/// })
|
||||
/// .then([](std::string content) -> result<std::string> {
|
||||
/// return cancel();
|
||||
/// })
|
||||
/// ```
|
||||
///
|
||||
/// \since 1.0.0
|
||||
@ -276,7 +275,7 @@ public:
|
||||
E&& executor = detail::types::this_thread_executor_tag{}) && {
|
||||
return detail::base::chain_continuation<detail::base::handle_results::yes,
|
||||
detail::base::handle_errors::no>(
|
||||
std::move(*this).finish(), std::forward<T>(callback),
|
||||
std::move(*this).materialize(), std::forward<T>(callback),
|
||||
std::forward<E>(executor));
|
||||
}
|
||||
|
||||
@ -302,7 +301,7 @@ public:
|
||||
template <typename OData, typename OAnnotation>
|
||||
auto then(continuable_base<OData, OAnnotation>&& continuation) && {
|
||||
return std::move(*this).then(
|
||||
detail::base::wrap_continuation(std::move(continuation).finish()));
|
||||
detail::base::wrap_continuation(std::move(continuation).materialize()));
|
||||
}
|
||||
|
||||
/// Main method of the continuable_base to catch exceptions and error codes
|
||||
@ -317,18 +316,12 @@ public:
|
||||
/// ```cpp
|
||||
/// http_request("github.com")
|
||||
/// .then([](std::string github) { })
|
||||
/// .fail([](std::exception_ptr ep) {
|
||||
/// // Check whether the exception_ptr is valid (not default constructed)
|
||||
/// // if bool(ep) == false this means that the operation was cancelled
|
||||
/// // by the user or application (promise.set_canceled() or
|
||||
/// // make_cancelling_continuable()).
|
||||
/// if (ep) {
|
||||
/// // Handle the error here
|
||||
/// try {
|
||||
/// std::rethrow_exception(ep);
|
||||
/// } catch (std::exception& e) {
|
||||
/// e.what(); // Handle the exception
|
||||
/// }
|
||||
/// .fail([](std::exception_ptr ptr) {
|
||||
/// // Handle the error here
|
||||
/// try {
|
||||
/// std::rethrow_exception(ptr);
|
||||
/// } catch (std::exception& e) {
|
||||
/// e.what(); // Handle the exception
|
||||
/// }
|
||||
/// });
|
||||
/// ```
|
||||
@ -348,26 +341,14 @@ public:
|
||||
/// \returns Returns a continuable_base with an asynchronous return type
|
||||
/// depending on the previous result type.
|
||||
///
|
||||
/// \attention The given exception type exception_t can be passed to the
|
||||
/// handler in a default constructed state <br>`bool(e) == false`.
|
||||
/// This always means that the operation was cancelled by the user,
|
||||
/// possibly through:
|
||||
/// - \ref promise_base::set_canceled
|
||||
/// - \ref make_cancelling_continuable
|
||||
/// - \ref result::set_canceled
|
||||
/// - \ref cancel<br>
|
||||
/// In that case the exception can be ignored safely (but it is
|
||||
/// recommended not to proceed, although it is possible to
|
||||
/// recover from the cancellation).
|
||||
///
|
||||
/// \since 2.0.0
|
||||
template <typename T, typename E = detail::types::this_thread_executor_tag>
|
||||
auto fail(T&& callback,
|
||||
E&& executor = detail::types::this_thread_executor_tag{}) && {
|
||||
return detail::base::chain_continuation<
|
||||
detail::base::handle_results::no, detail::base::handle_errors::forward>(
|
||||
std::move(*this).finish(),
|
||||
detail::base::strip_exception_arg(std::forward<T>(callback)),
|
||||
return detail::base::chain_continuation<detail::base::handle_results::no,
|
||||
detail::base::handle_errors::plain>(
|
||||
std::move(*this).materialize(), std::forward<T>(callback),
|
||||
std::forward<E>(executor));
|
||||
}
|
||||
|
||||
@ -389,11 +370,9 @@ public:
|
||||
/// \since 2.0.0
|
||||
template <typename OData, typename OAnnotation>
|
||||
auto fail(continuable_base<OData, OAnnotation>&& continuation) && {
|
||||
return std::move(*this) //
|
||||
.fail([continuation = std::move(continuation).freeze()] //
|
||||
(exception_t) mutable {
|
||||
std::move(continuation).done(); //
|
||||
});
|
||||
continuation.freeze();
|
||||
return std::move(*this).fail([continuation = std::move(continuation)](
|
||||
error_type) mutable { std::move(continuation).done(); });
|
||||
}
|
||||
|
||||
/// A method which allows to use an overloaded callable for the error
|
||||
@ -407,7 +386,7 @@ public:
|
||||
/// void operator() (std::string result) {
|
||||
/// // ...
|
||||
/// }
|
||||
/// void operator() (cti::exception_arg_t, cti::exception_t) {
|
||||
/// void operator() (cti::dispatch_error_tag, cti::error_type) {
|
||||
/// // ...
|
||||
/// }
|
||||
///
|
||||
@ -428,56 +407,22 @@ public:
|
||||
E&& executor = detail::types::this_thread_executor_tag{}) && {
|
||||
return detail::base::chain_continuation<
|
||||
detail::base::handle_results::yes,
|
||||
detail::base::handle_errors::forward>(std::move(*this).finish(),
|
||||
detail::base::handle_errors::forward>(std::move(*this).materialize(),
|
||||
std::forward<T>(callback),
|
||||
std::forward<E>(executor));
|
||||
}
|
||||
|
||||
/// Returns a continuable_base which continues its invocation through the
|
||||
/// given executor.
|
||||
/// A method which allows to apply this continuable to the given callable.
|
||||
///
|
||||
/// \returns Returns a continuable_base of the same type.
|
||||
///
|
||||
/// \since 4.2.0
|
||||
template <typename E>
|
||||
auto via(E&& executor) && {
|
||||
return std::move(*this).next(
|
||||
[](auto&&... args) {
|
||||
return make_result(std::forward<decltype(args)>(args)...);
|
||||
},
|
||||
std::forward<E>(executor));
|
||||
}
|
||||
|
||||
/// Returns a continuable_base which will have its signature converted
|
||||
/// to the given Args.
|
||||
///
|
||||
/// A signature can only be converted if it can be partially applied
|
||||
/// from the previous one as shown below:
|
||||
/// ```cpp
|
||||
/// continuable<long> c = make_ready_continuable(0, 1, 2).as<long>();
|
||||
/// ```
|
||||
///
|
||||
/// \returns Returns a continuable_base with an asynchronous return type
|
||||
/// matching the given Args.
|
||||
///
|
||||
/// \since 4.0.0
|
||||
template <typename... Args>
|
||||
auto as() && {
|
||||
return std::move(*this).then(detail::base::convert_to<Args...>{});
|
||||
}
|
||||
|
||||
/// A method which allows to apply a callable object to this continuable.
|
||||
///
|
||||
/// \param transform A callable objects that transforms a continuable
|
||||
/// to a different object.
|
||||
/// \param transform A transform which shall accept this continuable
|
||||
///
|
||||
/// \returns Returns the result of the given transform when this
|
||||
/// continuable is passed into it.
|
||||
///
|
||||
/// \since 4.0.0
|
||||
/// \since 2.0.0
|
||||
template <typename T>
|
||||
auto apply(T&& transform) && {
|
||||
return std::forward<T>(transform)(std::move(*this).finish());
|
||||
return std::forward<T>(transform)(std::move(*this).materialize());
|
||||
}
|
||||
|
||||
/// The pipe operator | is an alias for the continuable::then method.
|
||||
@ -493,6 +438,22 @@ public:
|
||||
return std::move(*this).then(std::forward<T>(right));
|
||||
}
|
||||
|
||||
/// The pipe operator | is an alias for the continuable::apply method.
|
||||
///
|
||||
/// \param transform The transformer which is applied.
|
||||
///
|
||||
/// \returns See the corresponding continuable_base::apply method for the
|
||||
/// explanation of the return type.
|
||||
///
|
||||
/// \note You may create your own transformation through
|
||||
/// calling make_transformation.
|
||||
///
|
||||
/// \since 3.0.0
|
||||
template <typename T>
|
||||
auto operator|(detail::types::transform<T> transform) && {
|
||||
return std::move(*this).apply(std::move(transform));
|
||||
}
|
||||
|
||||
/// Invokes both continuable_base objects parallel and calls the
|
||||
/// callback with the result of both continuable_base objects.
|
||||
///
|
||||
@ -611,64 +572,7 @@ public:
|
||||
///
|
||||
/// \since 1.0.0
|
||||
void done() && {
|
||||
detail::base::finalize_continuation(std::move(*this).finish());
|
||||
}
|
||||
|
||||
/// Materializes the continuation expression template and finishes
|
||||
/// the current applied strategy such that the resulting continuable
|
||||
/// will always be a concrete type and Continuable::is_concrete holds.
|
||||
///
|
||||
/// This can be used in the case where we are chaining continuations lazily
|
||||
/// through a strategy, for instance when applying operators for
|
||||
/// expressing connections and then want to return a materialized
|
||||
/// continuable_base which uses the strategy respectively.
|
||||
/// ```cpp
|
||||
/// auto do_both() {
|
||||
/// return (wait(10s) || wait_key_pressed(KEY_SPACE)).finish();
|
||||
/// }
|
||||
///
|
||||
/// // Without a call to finish() this would lead to
|
||||
/// // an unintended evaluation strategy:
|
||||
/// do_both() || wait(5s);
|
||||
/// ```
|
||||
///
|
||||
/// \note When using a type erased continuable_base such as
|
||||
/// `continuable<...>` this method doesn't need to be called
|
||||
/// since the continuable_base is materialized automatically
|
||||
/// on conversion.
|
||||
///
|
||||
/// \since 4.0.0
|
||||
auto finish() && {
|
||||
return annotation_trait::finish(std::move(*this));
|
||||
}
|
||||
|
||||
/// Returns true when the continuable can provide its result immediately,
|
||||
/// and its lazy invocation would be side-effect free.
|
||||
///
|
||||
/// \since 4.0.0
|
||||
bool is_ready() const noexcept {
|
||||
return annotation_trait::is_ready(*this);
|
||||
}
|
||||
|
||||
/// Invalidates the continuable and returns its immediate invocation result.
|
||||
///
|
||||
/// This method can be used to specialize the asynchronous control flow
|
||||
/// based on whether the continuable_base is_ready at every time,
|
||||
/// which is true for a continuable created through the following functions:
|
||||
/// - make_ready_continuable
|
||||
/// - make_exceptional_continuable
|
||||
///
|
||||
/// \returns A result<Args...> where Args... represent the current
|
||||
/// asynchronous parameters or the currently stored exception.
|
||||
///
|
||||
/// \attention unpack requires that continuable_base::is_ready returned true
|
||||
/// in a previous check, otherwise its behaviour is unspecified.
|
||||
///
|
||||
/// \since 4.0.0
|
||||
auto unpack() && {
|
||||
assert(ownership_.is_acquired());
|
||||
assert(is_ready());
|
||||
return detail::base::attorney::query(std::move(*this).finish());
|
||||
detail::base::finalize_continuation(std::move(*this));
|
||||
}
|
||||
|
||||
/// Predicate to check whether the cti::continuable_base is frozen or not.
|
||||
@ -714,7 +618,7 @@ public:
|
||||
}
|
||||
|
||||
/// \cond false
|
||||
#if defined(CONTINUABLE_HAS_COROUTINE)
|
||||
#ifdef CONTINUABLE_HAS_EXPERIMENTAL_COROUTINE
|
||||
/// \endcond
|
||||
/// Implements the operator for awaiting on continuables using `co_await`.
|
||||
///
|
||||
@ -740,47 +644,49 @@ public:
|
||||
/// ```
|
||||
///
|
||||
/// In case the library is configured to use error codes or a custom
|
||||
/// exception type the return type of the co_await expression is changed.
|
||||
/// The result is returned through a cti::result<...>.
|
||||
/// error type the return type of the co_await expression is changed.
|
||||
/// The result is returned through an internal proxy object which may
|
||||
/// be queried for the error object.
|
||||
/// | Continuation type | co_await returns |
|
||||
/// | : ------------------------------- | : -------------------------------- |
|
||||
/// | `continuable_base with <>` | `result<void>` |
|
||||
/// | `continuable_base with <Arg>` | `result<Arg>` |
|
||||
/// | `continuable_base with <Args...>` | `result<Args...>` |
|
||||
///
|
||||
/// \note Using continuable_base as return type for coroutines
|
||||
/// is supported. The coroutine is initially stopped and
|
||||
/// resumed when the continuation is requested in order to
|
||||
/// keep the lazy evaluation semantics of the continuable_base.
|
||||
/// | `continuable_base with <>` | `unspecified<void>` |
|
||||
/// | `continuable_base with <Arg>` | `unspecified<Arg>` |
|
||||
/// | `continuable_base with <Args...>` | `unspecified<std::tuple<Args...>>` |
|
||||
/// The interface of the proxy object is similar to the one proposed in
|
||||
/// the `std::expected` proposal:
|
||||
/// ```cpp
|
||||
/// cti::continuable<> resolve_async_void() {
|
||||
/// co_await http_request("github.com");
|
||||
/// // ...
|
||||
/// co_return;
|
||||
/// if (auto&& result = co_await http_request("github.com")) {
|
||||
/// auto value = *result;
|
||||
/// } else {
|
||||
/// cti::error_type error = result.get_exception();
|
||||
/// }
|
||||
///
|
||||
/// cti::continuable<int> resolve_async() {
|
||||
/// auto result = co_await http_request("github.com");
|
||||
/// bool(result);
|
||||
/// result.is_value();
|
||||
/// result.is_exception();
|
||||
/// *result; // Same as result.get_value()
|
||||
/// result.get_value();
|
||||
/// result.get_exception();
|
||||
/// ```
|
||||
///
|
||||
/// \attention Note that it isn't possible as of now to use a continuable
|
||||
/// as return type from coroutines as depicted below:
|
||||
/// ```cpp
|
||||
/// cti::continuable<int> do_sth() {
|
||||
/// co_await http_request("github.com");
|
||||
/// // ...
|
||||
/// co_return 0;
|
||||
/// }
|
||||
/// ```
|
||||
/// It's possible to return multiple return values from coroutines
|
||||
/// by wrapping those in a tuple like type:
|
||||
/// ```cpp
|
||||
/// cti::continuable<int, int, int> resolve_async_multiple() {
|
||||
/// co_await http_request("github.com");
|
||||
/// // ...
|
||||
/// co_return std::make_tuple(0, 1, 2);
|
||||
/// }
|
||||
/// ```
|
||||
/// Propably this will be added in a future version of the library.
|
||||
///
|
||||
/// \since 2.0.0
|
||||
auto operator co_await() && {
|
||||
return detail::awaiting::create_awaiter(std::move(*this).finish());
|
||||
return detail::awaiting::create_awaiter(std::move(*this).materialize());
|
||||
}
|
||||
/// \cond false
|
||||
#endif // defined(CONTINUABLE_HAS_COROUTINE)
|
||||
#endif // CONTINUABLE_HAS_EXPERIMENTAL_COROUTINE
|
||||
/// \endcond
|
||||
|
||||
private:
|
||||
@ -788,7 +694,12 @@ private:
|
||||
ownership_.release();
|
||||
}
|
||||
|
||||
Data&& consume() && {
|
||||
auto materialize() && {
|
||||
return detail::connection::materializer<continuable_base>::apply(
|
||||
std::move(*this));
|
||||
}
|
||||
|
||||
Data&& consume_data() && {
|
||||
assert_acquired();
|
||||
release();
|
||||
return std::move(data_);
|
||||
@ -892,9 +803,9 @@ constexpr auto make_continuable(Continuation&& continuation) {
|
||||
"use make_continuable<void>(...). Continuables with an exact "
|
||||
"signature may be created through make_continuable<Args...>.");
|
||||
|
||||
return detail::base::attorney::create_from(
|
||||
return detail::base::attorney::create(
|
||||
std::forward<Continuation>(continuation),
|
||||
typename detail::hints::from_args<Args...>::type{},
|
||||
detail::hints::extract(detail::traits::identity<Args...>{}),
|
||||
detail::util::ownership{});
|
||||
}
|
||||
|
||||
@ -904,18 +815,46 @@ constexpr auto make_continuable(Continuation&& continuation) {
|
||||
/// \attention Usually using this function isn't needed at all since
|
||||
/// the continuable library is capable of working with
|
||||
/// plain values in most cases.
|
||||
/// Try not to use it since it causes unnecessary recursive
|
||||
/// Try not to use it since it causes unneccessary recursive
|
||||
/// function calls.
|
||||
///
|
||||
/// \since 3.0.0
|
||||
template <typename... Args>
|
||||
auto make_ready_continuable(Args&&... args) {
|
||||
return detail::base::attorney::create_from_raw(
|
||||
detail::base::ready_continuation<detail::traits::unrefcv_t<Args>...>(
|
||||
result<detail::traits::unrefcv_t<Args>...>::from(
|
||||
std::forward<Args>(args)...)),
|
||||
detail::identity<detail::traits::unrefcv_t<Args>...>{},
|
||||
detail::util::ownership{});
|
||||
constexpr auto make_ready_continuable() {
|
||||
return make_continuable<void>([](auto&& promise) {
|
||||
std::forward<decltype(promise)>(promise).set_value();
|
||||
});
|
||||
}
|
||||
|
||||
/// Returns a continuable_base with one result value which instantly resolves
|
||||
/// the promise with the given value.
|
||||
///
|
||||
/// \copydetails make_ready_continuable()
|
||||
template <typename Result>
|
||||
constexpr auto make_ready_continuable(Result&& result) {
|
||||
return make_continuable<std::decay_t<Result>>( // ...
|
||||
[result = std::forward<Result>(result)](auto&& promise) mutable {
|
||||
std::forward<decltype(promise)>(promise).set_value(std::move(result));
|
||||
});
|
||||
}
|
||||
|
||||
/// Returns a continuable_base with multiple result values which instantly
|
||||
/// resolves the promise with the given values.
|
||||
///
|
||||
/// \copydetails make_ready_continuable()
|
||||
template <typename FirstResult, typename SecondResult, typename... Rest>
|
||||
constexpr auto make_ready_continuable(FirstResult&& first_result,
|
||||
SecondResult&& second_result,
|
||||
Rest&&... rest) {
|
||||
return make_continuable<std::decay_t<FirstResult>, std::decay_t<SecondResult>,
|
||||
std::decay_t<Rest>...>( // ...
|
||||
[result = std::make_tuple(std::forward<FirstResult>(first_result),
|
||||
std::forward<SecondResult>(second_result),
|
||||
std::forward<Rest>(rest)...)](
|
||||
auto&& promise) mutable {
|
||||
detail::traits::unpack(result,
|
||||
std::forward<decltype(promise)>(promise));
|
||||
});
|
||||
}
|
||||
|
||||
/// Returns a continuable_base with the parameterized result which instantly
|
||||
@ -928,213 +867,20 @@ auto make_ready_continuable(Args&&... args) {
|
||||
/// auto ct = cti::make_exceptional_continuable<int>(ptr);
|
||||
/// ```
|
||||
///
|
||||
/// \tparam Args The fake signature of the returned continuable.
|
||||
///
|
||||
/// \since 3.0.0
|
||||
template <typename... Args, typename Exception>
|
||||
constexpr auto make_exceptional_continuable(Exception&& exception) {
|
||||
static_assert(sizeof...(Args) > 0,
|
||||
"Requires at least one type for the fake signature!");
|
||||
|
||||
using hint_t = typename detail::hints::from_args<Args...>::type;
|
||||
using ready_continuation_t = typename detail::base::
|
||||
ready_continuation_from_hint<hint_t>::type;
|
||||
using result_t = typename detail::base::result_from_hint<hint_t>::type;
|
||||
return detail::base::attorney::create_from_raw(
|
||||
ready_continuation_t(result_t::from(exception_arg_t{},
|
||||
std::forward<Exception>(exception))),
|
||||
hint_t{}, detail::util::ownership{});
|
||||
}
|
||||
|
||||
/// Returns a continuable_base with the parameterized result which never
|
||||
/// resolves its promise and thus cancels the asynchronous continuation chain
|
||||
/// through throwing a default constructed exception_t.
|
||||
///
|
||||
/// This can be used to cancel an asynchronous continuation chain when
|
||||
/// returning a continuable_base from a handler where other paths could
|
||||
/// possibly continue the asynchronous chain. See an example below:
|
||||
/// ```cpp
|
||||
/// do_sth().then([weak = this->weak_from_this()]() -> continuable<> {
|
||||
/// if (auto me = weak.lock()) {
|
||||
/// return do_sth_more();
|
||||
/// } else {
|
||||
/// // Abort the asynchronous continuation chain since the
|
||||
/// // weakly referenced object expired previously.
|
||||
/// return make_cancelling_continuable<void>();
|
||||
/// }
|
||||
/// });
|
||||
/// ```
|
||||
/// The default unhandled exception handler ignores exception types
|
||||
/// that don't evaluate to true when being converted to a bool.
|
||||
/// This saves expensive construction of std::exception_ptr or similar types,
|
||||
/// where only one exception type is used for signaling the cancellation.
|
||||
///
|
||||
/// \tparam Signature The fake signature of the returned continuable.
|
||||
///
|
||||
/// \since 4.0.0
|
||||
template <typename... Signature>
|
||||
auto make_cancelling_continuable() {
|
||||
/// \since 3.0.0
|
||||
template <typename... Signature, typename Exception>
|
||||
constexpr auto make_exceptional_continuable(Exception&& exception) {
|
||||
static_assert(sizeof...(Signature) > 0,
|
||||
"Requires at least one type for the fake signature!");
|
||||
|
||||
return make_exceptional_continuable<Signature...>(exception_t{});
|
||||
return make_continuable<Signature...>( // ...
|
||||
[exception = std::forward<Exception>(exception)](auto&& promise) mutable {
|
||||
std::forward<decltype(promise)>(promise).set_exception(
|
||||
std::move(exception));
|
||||
});
|
||||
}
|
||||
|
||||
/// Can be used to disable the special meaning for a returned value in
|
||||
/// asynchronous handler functions.
|
||||
///
|
||||
/// Several types have a special meaning when being returned from a callable
|
||||
/// passed to asynchronous handler functions like:
|
||||
/// - continuable_base::then
|
||||
/// - continuable_base::fail
|
||||
/// - continuable_base::next
|
||||
///
|
||||
/// For instance such types are std::tuple, std::pair and cti::result.
|
||||
///
|
||||
/// Wrapping such an object through a call to make_plain disables the special
|
||||
/// meaning for such objects as shown below:
|
||||
/// ```cpp
|
||||
/// continuable<result<int, int> c = http_request("example.com")
|
||||
/// .then([](std::string content) {
|
||||
/// return make_plain(make_result(0, 1));
|
||||
/// })
|
||||
/// ```
|
||||
///
|
||||
/// \since 4.0.0
|
||||
///
|
||||
template <typename T>
|
||||
auto make_plain(T&& value) {
|
||||
return plain_t<detail::traits::unrefcv_t<T>>(std::forward<T>(value));
|
||||
}
|
||||
|
||||
/// Can be used to recover to from a failure handler,
|
||||
/// the result handler which comes after will be called with the
|
||||
/// corresponding result.
|
||||
///
|
||||
/// The \ref exceptional_result returned by this function can be returned
|
||||
/// from any result or failure handler in order to rethrow the exception.
|
||||
/// ```cpp
|
||||
/// http_request("example.com")
|
||||
/// .then([](std::string content) {
|
||||
/// return recover(1, 2);
|
||||
/// })
|
||||
/// .fail([](cti::exception_t exception) {
|
||||
/// return recover(1, 2);
|
||||
/// })
|
||||
/// .then([](int a, int b) {
|
||||
/// // Recovered from the failure
|
||||
/// })
|
||||
/// ```
|
||||
/// A corresponding \ref result is returned by \ref recover
|
||||
/// ```cpp
|
||||
/// http_request("example.com")
|
||||
/// .then([](std::string content) -> cti::result<int, int> {
|
||||
/// return recover(1, 2);
|
||||
/// })
|
||||
/// .fail([](cti::exception_t exception) -> cti::result<int, int> {
|
||||
/// return recover(1, 2);
|
||||
/// })
|
||||
/// .then([](int a, int b) -> cti::result<int, int> {
|
||||
/// // Recovered from the failure
|
||||
/// })
|
||||
/// ```
|
||||
///
|
||||
/// \since 4.0.0
|
||||
///
|
||||
template <typename... Args>
|
||||
result<detail::traits::unrefcv_t<Args>...> recover(Args&&... args) {
|
||||
return make_result(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
/// Can be used to rethrow an exception to the asynchronous continuation chain,
|
||||
/// the failure handler which comes after will be called with the
|
||||
/// corresponding exception.
|
||||
///
|
||||
/// The \ref exceptional_result returned by this function can be returned
|
||||
/// from any result or failure handler in order to rethrow the exception.
|
||||
/// ```cpp
|
||||
/// http_request("example.com")
|
||||
/// .then([](std::string content) {
|
||||
/// return rethrow(std::make_exception_ptr(std::exception{}));
|
||||
/// })
|
||||
/// .fail([](cti::exception_t exception) {
|
||||
/// return rethrow(std::make_exception_ptr(std::exception{}));
|
||||
/// })
|
||||
/// .next([](auto&&...) {
|
||||
/// return rethrow(std::make_exception_ptr(std::exception{}));
|
||||
/// });
|
||||
/// ```
|
||||
/// The returned \ref exceptional_result is convertible to
|
||||
/// any \ref result as shown below:
|
||||
/// ```cpp
|
||||
/// http_request("example.com")
|
||||
/// .then([](std::string content) -> cti::result<> {
|
||||
/// return rethrow(std::make_exception_ptr(std::exception{}));
|
||||
/// })
|
||||
/// .fail([](cti::exception_t exception) -> cti::result<> {
|
||||
/// return rethrow(std::make_exception_ptr(std::exception{}));
|
||||
/// })
|
||||
/// .next([](auto&&...) -> cti::result<> {
|
||||
/// return rethrow(std::make_exception_ptr(std::exception{}));
|
||||
/// });
|
||||
/// ```
|
||||
///
|
||||
/// \since 4.0.0
|
||||
///
|
||||
// NOLINTNEXTLINE(performance-unnecessary-value-param)
|
||||
inline exceptional_result rethrow(exception_t exception) {
|
||||
// NOLINTNEXTLINE(hicpp-move-const-arg, performance-move-const-arg)
|
||||
return exceptional_result{std::move(exception)};
|
||||
}
|
||||
|
||||
/// Can be used to cancel an asynchronous continuation chain,
|
||||
/// the next failure handler which comes after cancel will be called
|
||||
/// with a default constructed exception_t object.
|
||||
///
|
||||
/// The \ref cancellation_result returned by this function can be returned from
|
||||
/// any result or failure handler in order to cancel the chain.
|
||||
/// ```cpp
|
||||
/// http_request("example.com")
|
||||
/// .then([](std::string content) {
|
||||
/// return cancel();
|
||||
/// })
|
||||
/// .fail([](cti::exception_t exception) {
|
||||
/// return cancel();
|
||||
/// })
|
||||
/// .next([](auto&&...) {
|
||||
/// return cancel();
|
||||
/// });
|
||||
/// ```
|
||||
/// The returned \ref empty_result is convertible to
|
||||
/// any \ref result as shown below:
|
||||
/// ```cpp
|
||||
/// http_request("example.com")
|
||||
/// .then([](std::string content) -> cti::result<> {
|
||||
/// return cancel();
|
||||
/// })
|
||||
/// .fail([](cti::exception_t exception) -> cti::result<> {
|
||||
/// return cancel();
|
||||
/// })
|
||||
/// .next([](auto&&...) -> cti::result<> {
|
||||
/// return cancel();
|
||||
/// });
|
||||
/// ```
|
||||
///
|
||||
/// \since 4.0.0
|
||||
///
|
||||
inline cancellation_result cancel() {
|
||||
return {};
|
||||
}
|
||||
|
||||
/// Can be used to stop an asynchronous continuation chain,
|
||||
/// no handler which comes after stop was received won't be called.
|
||||
///
|
||||
/// \since 4.0.0
|
||||
///
|
||||
inline empty_result stop() {
|
||||
return {};
|
||||
}
|
||||
|
||||
/// \}
|
||||
} // namespace cti
|
||||
|
||||
|
||||
@ -5,9 +5,9 @@
|
||||
\_,(_)| | | || ||_|(_||_)|(/_
|
||||
|
||||
https://github.com/Naios/continuable
|
||||
v4.2.0
|
||||
v3.0.0
|
||||
|
||||
Copyright(c) 2015 - 2022 Denis Blank <denis.blank at outlook dot com>
|
||||
Copyright(c) 2015 - 2018 Denis Blank <denis.blank at outlook dot com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files(the "Software"), to deal
|
||||
@ -21,7 +21,7 @@
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
@ -35,11 +35,12 @@
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include <continuable/detail/connection/connection-all.hpp>
|
||||
#include <continuable/detail/connection/connection-any.hpp>
|
||||
#include <continuable/detail/connection/connection-seq.hpp>
|
||||
#include <continuable/detail/connection/connection.hpp>
|
||||
#include <continuable/detail/traversal/range.hpp>
|
||||
|
||||
#include <continuable/detail/connection-all.hpp>
|
||||
#include <continuable/detail/connection-any.hpp>
|
||||
#include <continuable/detail/connection-seq.hpp>
|
||||
#include <continuable/detail/connection.hpp>
|
||||
#include <continuable/detail/range.hpp>
|
||||
|
||||
namespace cti {
|
||||
/// \defgroup Connections Connections
|
||||
|
||||
@ -1,97 +0,0 @@
|
||||
/*
|
||||
|
||||
/~` _ _ _|_. _ _ |_ | _
|
||||
\_,(_)| | | || ||_|(_||_)|(/_
|
||||
|
||||
https://github.com/Naios/continuable
|
||||
v4.2.0
|
||||
|
||||
Copyright(c) 2015 - 2022 Denis Blank <denis.blank at outlook dot com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files(the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions :
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
**/
|
||||
|
||||
#ifndef CONTINUABLE_COROUTINE_HPP_INCLUDED
|
||||
#define CONTINUABLE_COROUTINE_HPP_INCLUDED
|
||||
|
||||
#include <continuable/continuable-base.hpp>
|
||||
#include <continuable/continuable-types.hpp>
|
||||
#include <continuable/detail/core/types.hpp>
|
||||
#include <continuable/detail/features.hpp>
|
||||
|
||||
#if defined(CONTINUABLE_HAS_EXCEPTIONS)
|
||||
# include <exception>
|
||||
#endif // CONTINUABLE_HAS_EXCEPTIONS
|
||||
|
||||
#if defined(CONTINUABLE_HAS_COROUTINE)
|
||||
# include <continuable/detail/other/coroutines.hpp>
|
||||
|
||||
namespace cti {
|
||||
# if defined(CONTINUABLE_HAS_EXCEPTIONS)
|
||||
/// Is thrown from co_await expressions if the awaited continuable is canceled
|
||||
///
|
||||
/// Default constructed exception types that are returned by a cancelled
|
||||
/// continuable are converted automatically to await_canceled_exception when
|
||||
/// being returned by a co_await expression.
|
||||
///
|
||||
/// The await_canceled_exception gets converted again to a default constructed
|
||||
/// exception type if it becomes unhandled inside a coroutine which
|
||||
/// returns a continuable_base.
|
||||
/// ```cpp
|
||||
/// continuable<> cancelled_coroutine() {
|
||||
/// co_await make_cancelling_continuable<void>();
|
||||
///
|
||||
/// co_return;
|
||||
/// }
|
||||
///
|
||||
/// // ...
|
||||
///
|
||||
/// cancelled_coroutine().fail([](exception_t e) {
|
||||
/// assert(bool(e) == false);
|
||||
/// });
|
||||
/// ```
|
||||
///
|
||||
/// \since 4.1.0
|
||||
using await_canceled_exception = detail::awaiting::await_canceled_exception;
|
||||
# endif // CONTINUABLE_HAS_EXCEPTIONS
|
||||
} // namespace cti
|
||||
|
||||
/// \cond false
|
||||
// As far as I know there is no other way to implement this specialization...
|
||||
// NOLINTNEXTLINE(cert-dcl58-cpp)
|
||||
namespace std {
|
||||
# if defined(CONTINUABLE_HAS_EXPERIMENTAL_COROUTINE)
|
||||
namespace experimental {
|
||||
# endif // defined(CONTINUABLE_HAS_EXPERIMENTAL_COROUTINE)
|
||||
template <typename Data, typename... Args, typename... FunctionArgs>
|
||||
struct coroutine_traits<
|
||||
cti::continuable_base<Data, cti::detail::identity<Args...>>,
|
||||
FunctionArgs...> {
|
||||
|
||||
using promise_type = cti::detail::awaiting::promise_type<
|
||||
cti::continuable<Args...>, cti::promise<Args...>, Args...>;
|
||||
};
|
||||
# if defined(CONTINUABLE_HAS_EXPERIMENTAL_COROUTINE)
|
||||
} // namespace experimental
|
||||
# endif // defined(CONTINUABLE_HAS_EXPERIMENTAL_COROUTINE)
|
||||
} // namespace std
|
||||
/// \endcond
|
||||
#endif // defined(CONTINUABLE_HAS_COROUTINE)
|
||||
|
||||
#endif // CONTINUABLE_COROUTINE_HPP_INCLUDED
|
||||
@ -1,41 +0,0 @@
|
||||
|
||||
/*
|
||||
|
||||
/~` _ _ _|_. _ _ |_ | _
|
||||
\_,(_)| | | || ||_|(_||_)|(/_
|
||||
|
||||
https://github.com/Naios/continuable
|
||||
v4.2.0
|
||||
|
||||
Copyright(c) 2015 - 2022 Denis Blank <denis.blank at outlook dot com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files(the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions :
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
**/
|
||||
|
||||
#ifndef CONTINUABLE_OPERATIONS_HPP_INCLUDED
|
||||
#define CONTINUABLE_OPERATIONS_HPP_INCLUDED
|
||||
|
||||
/// \defgroup Operations Operations
|
||||
/// provides functions to work with asynchronous control flows.
|
||||
|
||||
#include <continuable/operations/async.hpp>
|
||||
#include <continuable/operations/loop.hpp>
|
||||
#include <continuable/operations/split.hpp>
|
||||
|
||||
#endif // CONTINUABLE_OPERATIONS_HPP_INCLUDED
|
||||
@ -1,141 +0,0 @@
|
||||
|
||||
/*
|
||||
|
||||
/~` _ _ _|_. _ _ |_ | _
|
||||
\_,(_)| | | || ||_|(_||_)|(/_
|
||||
|
||||
https://github.com/Naios/continuable
|
||||
v4.2.0
|
||||
|
||||
Copyright(c) 2015 - 2022 Denis Blank <denis.blank at outlook dot com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files(the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions :
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
**/
|
||||
|
||||
#ifndef CONTINUABLE_PRIMITIVES_HPP_INCLUDED
|
||||
#define CONTINUABLE_PRIMITIVES_HPP_INCLUDED
|
||||
|
||||
#include <continuable/detail/core/types.hpp>
|
||||
#include <continuable/detail/utility/identity.hpp>
|
||||
|
||||
namespace cti {
|
||||
/// \defgroup Primitives Primitives
|
||||
/// provides basic tag types for creating a customized callbacks
|
||||
/// and continuations.
|
||||
///
|
||||
/// For the callback and the continuation `Args...` represents the
|
||||
/// asynchronous result:
|
||||
/// ```cpp
|
||||
/// template<typename... Args>
|
||||
/// struct continuation {
|
||||
/// void operator() (callback<Args...>);
|
||||
/// bool operator() (cti::is_ready_arg_t) const;
|
||||
/// result<Args...> operator() (cti::unpack_arg_t);
|
||||
/// };
|
||||
/// ```
|
||||
/// ```cpp
|
||||
/// template<typename... Args>
|
||||
/// struct callback {
|
||||
/// void operator() (Args...) &&;
|
||||
/// void operator() (cti::exception_arg_t, cti::exception_t) &&;
|
||||
/// };
|
||||
/// ```
|
||||
/// \{
|
||||
|
||||
/// Represents the tag type that is used to specify the signature hint
|
||||
/// of a continuable_base or promise_base.
|
||||
///
|
||||
/// \since 4.0.0
|
||||
template <typename... Args>
|
||||
using signature_arg_t = detail::identity<Args...>;
|
||||
|
||||
/// Represents the tag type that is used to query the continuation
|
||||
/// for whether it resolves the callback instantly with its arguments
|
||||
/// without having side effects.
|
||||
///
|
||||
/// \since 4.0.0
|
||||
struct is_ready_arg_t {};
|
||||
|
||||
/// Represents the tag type that is used to unpack the result of a continuation.
|
||||
///
|
||||
/// \attention It's required that the query of is_ready_arg_t returns true,
|
||||
/// otherwise the behaviour when unpacking is unspecified.
|
||||
///
|
||||
/// \since 4.0.0
|
||||
struct unpack_arg_t {};
|
||||
|
||||
/// \copydoc unpack_arg_t
|
||||
///
|
||||
/// \deprecated The query_arg_t was deprecated because of
|
||||
/// its new naming unpack_arg_t.
|
||||
///
|
||||
[[deprecated("The dispatch_error_tag was replaced by unpack_arg_t and will "
|
||||
"be removed in a later major version!")]] //
|
||||
typedef unpack_arg_t query_arg_t;
|
||||
|
||||
/// Represents the tag type that is used to disambiguate the
|
||||
/// callback operator() in order to take the exception asynchronous chain.
|
||||
///
|
||||
/// \note see continuable::next for details.
|
||||
///
|
||||
/// \since 4.0.0
|
||||
struct exception_arg_t {};
|
||||
|
||||
/// \copydoc exception_arg_t
|
||||
///
|
||||
/// \deprecated The dispatch_error_tag was deprecated in order to move closer
|
||||
/// to the types specified in the "A Unified Future" proposal
|
||||
/// especially regarding naming types similar.
|
||||
///
|
||||
[[deprecated("The dispatch_error_tag was replaced by exception_arg_t and will "
|
||||
"be removed in a later major version!")]] //
|
||||
typedef exception_arg_t dispatch_error_tag;
|
||||
|
||||
/// Represents the type that is used as exception type
|
||||
///
|
||||
/// By default this type deduces to `std::exception_ptr`.
|
||||
/// If `CONTINUABLE_WITH_NO_EXCEPTIONS` is defined the type
|
||||
/// will be a `std::error_condition`.
|
||||
/// A custom error type may be set through
|
||||
/// defining `CONTINUABLE_WITH_CUSTOM_ERROR_TYPE`.
|
||||
///
|
||||
/// \since 4.0.0
|
||||
using exception_t = detail::types::exception_t;
|
||||
|
||||
/// \copydoc exception_t
|
||||
///
|
||||
/// \deprecated The error_type was deprecated in order to move closer
|
||||
/// to the types specified in the "A Unified Future" proposal
|
||||
/// especially regarding naming types similar.
|
||||
///
|
||||
[[deprecated("The error_type was replaced by exception_t and will "
|
||||
"be removed in a later major version!")]] //
|
||||
typedef exception_t error_type;
|
||||
|
||||
/// Represents the type that is used to disable the special meaning of types
|
||||
/// which are returned by a asynchronous result handler.
|
||||
/// See cti::plain for details.
|
||||
///
|
||||
/// \since 4.0.0
|
||||
template <typename T>
|
||||
using plain_t = detail::types::plain_tag<T>;
|
||||
/// \}
|
||||
} // namespace cti
|
||||
|
||||
#endif // CONTINUABLE_PRIMITIVES_HPP_INCLUDED
|
||||
@ -5,9 +5,9 @@
|
||||
\_,(_)| | | || ||_|(_||_)|(/_
|
||||
|
||||
https://github.com/Naios/continuable
|
||||
v4.2.0
|
||||
v3.0.0
|
||||
|
||||
Copyright(c) 2015 - 2022 Denis Blank <denis.blank at outlook dot com>
|
||||
Copyright(c) 2015 - 2018 Denis Blank <denis.blank at outlook dot com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files(the "Software"), to deal
|
||||
@ -21,7 +21,7 @@
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
@ -31,14 +31,12 @@
|
||||
#ifndef CONTINUABLE_PROMISE_BASE_HPP_INCLUDED
|
||||
#define CONTINUABLE_PROMISE_BASE_HPP_INCLUDED
|
||||
|
||||
#include <cassert>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <continuable/continuable-primitives.hpp>
|
||||
#include <continuable/detail/core/annotation.hpp>
|
||||
#include <continuable/detail/core/types.hpp>
|
||||
#include <continuable/detail/utility/traits.hpp>
|
||||
#include <continuable/detail/utility/util.hpp>
|
||||
|
||||
#include <continuable/detail/hints.hpp>
|
||||
#include <continuable/detail/types.hpp>
|
||||
#include <continuable/detail/util.hpp>
|
||||
|
||||
namespace cti {
|
||||
/// \defgroup Base Base
|
||||
@ -53,7 +51,7 @@ namespace cti {
|
||||
///
|
||||
/// If we want to resolve the promise_base trough the call operator,
|
||||
/// and we want to resolve it through an exception, we must call it with a
|
||||
/// exception_arg_t as first and the exception as second argument.
|
||||
/// dispatch_error_tag as first and the exception as second argument.
|
||||
/// Additionally the promise is resolveable only through its call
|
||||
/// operator when invoked as an r-value.
|
||||
///
|
||||
@ -64,7 +62,7 @@ class promise_base
|
||||
/// \cond false
|
||||
;
|
||||
template <typename Data, typename... Args>
|
||||
class promise_base<Data, detail::identity<Args...>>
|
||||
class promise_base<Data, detail::hints::signature_hint_tag<Args...>>
|
||||
: detail::util::non_copyable
|
||||
/// \endcond
|
||||
{ // clang-format on
|
||||
@ -75,138 +73,51 @@ class promise_base<Data, detail::identity<Args...>>
|
||||
/// \endcond
|
||||
|
||||
public:
|
||||
/// Constructor for constructing an empty promise
|
||||
explicit promise_base() = default;
|
||||
/// Constructor accepting the data object
|
||||
explicit promise_base(Data data) : data_(std::move(data)) {
|
||||
}
|
||||
|
||||
/// \cond false
|
||||
promise_base(promise_base&&) = default;
|
||||
promise_base(promise_base const&) = delete;
|
||||
|
||||
promise_base& operator=(promise_base&&) = default;
|
||||
promise_base& operator=(promise_base const&) = delete;
|
||||
/// \endcond
|
||||
|
||||
/// Constructor accepting any object convertible to the data object
|
||||
template <typename OData,
|
||||
std::enable_if_t<std::is_convertible<
|
||||
detail::traits::unrefcv_t<OData>, Data>::value>* = nullptr>
|
||||
/* implicit */ promise_base(OData&& data) : data_(std::forward<OData>(data)) {
|
||||
}
|
||||
|
||||
/// Assignment operator accepting any object convertible to the data object
|
||||
template <typename OData,
|
||||
std::enable_if_t<std::is_convertible<
|
||||
detail::traits::unrefcv_t<OData>, Data>::value>* = nullptr>
|
||||
promise_base& operator=(OData&& data) {
|
||||
data_ = std::forward<OData>(data);
|
||||
return *this;
|
||||
template <typename OData, std::enable_if_t<std::is_convertible<
|
||||
std::decay_t<OData>, Data>::value>* = nullptr>
|
||||
promise_base(OData&& data) : data_(std::forward<OData>(data)) {
|
||||
}
|
||||
|
||||
/// Resolves the continuation with the given values.
|
||||
///
|
||||
/// \throws This method never throws an exception.
|
||||
///
|
||||
/// \attention This method may only be called once,
|
||||
/// when the promise is valid operator bool() returns true.
|
||||
/// Calling this method will invalidate the promise such that
|
||||
/// subsequent calls to operator bool() will return false.
|
||||
/// This behaviour is only consistent in promise_base and
|
||||
/// non type erased promises may behave differently.
|
||||
/// Invoking an invalid promise_base is undefined!
|
||||
///
|
||||
/// \since 2.0.0
|
||||
void operator()(Args... args) && noexcept {
|
||||
assert(data_);
|
||||
std::move(data_)(std::move(args)...);
|
||||
data_ = nullptr;
|
||||
}
|
||||
/// Resolves the continuation with the given exception.
|
||||
///
|
||||
/// \throws This method never throws an exception.
|
||||
///
|
||||
/// \attention This method may only be called once,
|
||||
/// when the promise is valid operator bool() returns true.
|
||||
/// Calling this method will invalidate the promise such that
|
||||
/// subsequent calls to operator bool() will return false.
|
||||
/// This behaviour is only consistent in promise_base and
|
||||
/// non type erased promises may behave differently.
|
||||
/// Invoking an invalid promise_base is undefined!
|
||||
///
|
||||
/// \since 2.0.0
|
||||
void operator()(exception_arg_t tag, exception_t exception) && noexcept {
|
||||
assert(data_);
|
||||
void operator()(detail::types::dispatch_error_tag tag,
|
||||
detail::types::error_type exception) &&
|
||||
noexcept {
|
||||
std::move(data_)(tag, std::move(exception));
|
||||
data_ = nullptr;
|
||||
}
|
||||
|
||||
/// Resolves the continuation with the given values.
|
||||
///
|
||||
/// \throws This method never throws an exception.
|
||||
///
|
||||
/// \attention This method may only be called once,
|
||||
/// when the promise is valid operator bool() returns true.
|
||||
/// Calling this method will invalidate the promise such that
|
||||
/// subsequent calls to operator bool() will return false.
|
||||
/// This behaviour is only consistent in promise_base and
|
||||
/// non type erased promises may behave differently.
|
||||
/// Invoking an invalid promise_base is undefined!
|
||||
///
|
||||
/// \since 2.0.0
|
||||
void set_value(Args... args) noexcept {
|
||||
// assert(data_);
|
||||
std::move(data_)(std::move(args)...);
|
||||
data_ = nullptr;
|
||||
}
|
||||
|
||||
/// Resolves the continuation with the given exception.
|
||||
///
|
||||
/// \throws This method never throws an exception.
|
||||
///
|
||||
/// \attention This method may only be called once,
|
||||
/// when the promise is valid operator bool() returns true.
|
||||
/// Calling this method will invalidate the promise such that
|
||||
/// subsequent calls to operator bool() will return false.
|
||||
/// This behaviour is only consistent in promise_base and
|
||||
/// non type erased promises may behave differently.
|
||||
/// Invoking an invalid promise_base is undefined!
|
||||
///
|
||||
/// \since 2.0.0
|
||||
void set_exception(exception_t exception) noexcept {
|
||||
assert(data_);
|
||||
std::move(data_)(exception_arg_t{}, std::move(exception));
|
||||
data_ = nullptr;
|
||||
}
|
||||
|
||||
/// Resolves the continuation with the cancellation token which is represented
|
||||
/// by a default constructed exception_t.
|
||||
///
|
||||
/// \throws This method never throws an exception.
|
||||
///
|
||||
/// \attention This method may only be called once,
|
||||
/// when the promise is valid operator bool() returns true.
|
||||
/// Calling this method will invalidate the promise such that
|
||||
/// subsequent calls to operator bool() will return false.
|
||||
/// This behaviour is only consistent in promise_base and
|
||||
/// non type erased promises may behave differently.
|
||||
/// Invoking an invalid promise_base is undefined!
|
||||
///
|
||||
/// \since 4.0.0
|
||||
void set_canceled() noexcept {
|
||||
assert(data_);
|
||||
std::move(data_)(exception_arg_t{}, exception_t{});
|
||||
data_ = nullptr;
|
||||
}
|
||||
|
||||
/// Returns true if the continuation is valid (non empty).
|
||||
///
|
||||
/// \throws This method never throws an exception.
|
||||
///
|
||||
/// \since 4.0.0
|
||||
explicit operator bool() const noexcept {
|
||||
return bool(data_);
|
||||
void set_exception(detail::types::error_type exception) noexcept {
|
||||
std::move(data_)(detail::types::dispatch_error_tag{}, std::move(exception));
|
||||
}
|
||||
};
|
||||
/// \}
|
||||
|
||||
@ -5,9 +5,9 @@
|
||||
\_,(_)| | | || ||_|(_||_)|(/_
|
||||
|
||||
https://github.com/Naios/continuable
|
||||
v4.2.0
|
||||
v3.0.0
|
||||
|
||||
Copyright(c) 2015 - 2022 Denis Blank <denis.blank at outlook dot com>
|
||||
Copyright(c) 2015 - 2018 Denis Blank <denis.blank at outlook dot com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files(the "Software"), to deal
|
||||
@ -21,7 +21,7 @@
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
@ -33,7 +33,8 @@
|
||||
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <continuable/detail/other/promisify.hpp>
|
||||
|
||||
#include <continuable/detail/promisify.hpp>
|
||||
|
||||
namespace cti {
|
||||
/// \defgroup Promisify Promisify
|
||||
@ -71,47 +72,18 @@ public:
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// A given error variable is converted to the used error type.
|
||||
/// If this isn't possible you need to create a custom resolver callable
|
||||
/// object \see with for details.
|
||||
/// If the error code which is passed as first parameter is set there are
|
||||
/// two behaviours depending whether exceptions are enabled:
|
||||
/// - If exceptions are enabled the error type is passed via
|
||||
/// an exception_ptr to the failure handler.
|
||||
/// - If exceptions are disabled the error type is converted to a
|
||||
/// `std::error_conditon` and passed down to the error handler.
|
||||
///
|
||||
/// \since 3.0.0
|
||||
template <typename Callable, typename... Args>
|
||||
static auto from(Callable&& callable, Args&&... args) {
|
||||
return helper::template from(detail::convert::default_resolver(),
|
||||
std::forward<Callable>(callable),
|
||||
std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
/// \copybrief from
|
||||
///
|
||||
/// This modification of \ref from additionally takes a resolver callable
|
||||
/// object which is used to resolve the promise from the given result.
|
||||
///
|
||||
/// See an example of how to promisify boost asio's async_resolve below:
|
||||
/// ```cpp
|
||||
/// auto async_resolve(std::string host, std::string service) {
|
||||
/// return cti::promisify<asio::ip::udp::resolver::iterator>::with(
|
||||
/// [](auto&& promise, auto&& e, auto&&... args) {
|
||||
/// if (e) {
|
||||
/// promise.set_exception(std::forward<decltype(e)>(e));
|
||||
/// } else {
|
||||
/// promise.set_value(std::forward<decltype(args)>(args)...);
|
||||
/// }
|
||||
/// },
|
||||
/// [&](auto&&... args) {
|
||||
/// resolver_.async_resolve(std::forward<decltype(args)>(args)...);
|
||||
/// },
|
||||
/// std::move(host), std::move(service));
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// \since 4.0.0
|
||||
template <typename Resolver, typename Callable, typename... Args>
|
||||
static auto with(Resolver&& resolver, Callable&& callable, Args&&... args) {
|
||||
return helper::template from(std::forward<Resolver>(resolver),
|
||||
std::forward<Callable>(callable),
|
||||
std::forward<Args>(args)...);
|
||||
return helper::template from<detail::convert::promisify_default>(
|
||||
std::forward<Callable>(callable), std::forward<Args>(args)...);
|
||||
}
|
||||
};
|
||||
/// \}
|
||||
|
||||
@ -1,356 +0,0 @@
|
||||
|
||||
/*
|
||||
|
||||
/~` _ _ _|_. _ _ |_ | _
|
||||
\_,(_)| | | || ||_|(_||_)|(/_
|
||||
|
||||
https://github.com/Naios/continuable
|
||||
v4.2.0
|
||||
|
||||
Copyright(c) 2015 - 2022 Denis Blank <denis.blank at outlook dot com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files(the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions :
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
**/
|
||||
|
||||
#ifndef CONTINUABLE_RESULT_HPP_INCLUDED
|
||||
#define CONTINUABLE_RESULT_HPP_INCLUDED
|
||||
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <continuable/continuable-primitives.hpp>
|
||||
#include <continuable/detail/utility/result-trait.hpp>
|
||||
#include <continuable/detail/utility/result-variant.hpp>
|
||||
#include <continuable/detail/utility/traits.hpp>
|
||||
#include <continuable/detail/utility/util.hpp>
|
||||
|
||||
namespace cti {
|
||||
/// \defgroup Result Result
|
||||
/// provides the \ref result class and corresponding utility functions to work
|
||||
/// with the result of an asynchronous operation which can possibly yield:
|
||||
/// - *no result*: If the operation didn't finish
|
||||
/// - *a value*: If the operation finished successfully
|
||||
/// - *an exception*: If the operation finished with an exception
|
||||
/// or was cancelled.
|
||||
/// \{
|
||||
|
||||
/// A tag which represents present void values in result.
|
||||
///
|
||||
/// \since 4.0.0
|
||||
using void_arg_t = detail::void_arg_t;
|
||||
|
||||
/// A class which is convertible to any \ref result and that definitely holds no
|
||||
/// value so the real result gets invalidated when this object is passed to it.
|
||||
///
|
||||
/// \since 4.0.0
|
||||
///
|
||||
struct empty_result {};
|
||||
|
||||
/// A class which is convertible to any \ref result and that definitely holds
|
||||
/// a default constructed exception which signals the cancellation of the
|
||||
/// asynchronous control flow.
|
||||
///
|
||||
/// \since 4.0.0
|
||||
///
|
||||
struct cancellation_result {};
|
||||
|
||||
/// A class which is convertible to any result and that holds
|
||||
/// an exception which is then passed to the converted result object.
|
||||
///
|
||||
/// \since 4.0.0
|
||||
///
|
||||
class exceptional_result {
|
||||
exception_t exception_;
|
||||
|
||||
public:
|
||||
exceptional_result() = delete;
|
||||
exceptional_result(exceptional_result const&) = default;
|
||||
exceptional_result(exceptional_result&&) = default;
|
||||
exceptional_result& operator=(exceptional_result const&) = default;
|
||||
exceptional_result& operator=(exceptional_result&&) = default;
|
||||
~exceptional_result() = default;
|
||||
|
||||
explicit exceptional_result(exception_t exception)
|
||||
// NOLINTNEXTLINE(hicpp-move-const-arg, performance-move-const-arg)
|
||||
: exception_(std::move(exception)) {}
|
||||
|
||||
exceptional_result& operator=(exception_t exception) {
|
||||
// NOLINTNEXTLINE(hicpp-move-const-arg, performance-move-const-arg)
|
||||
exception_ = std::move(exception);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Sets an exception
|
||||
void set_exception(exception_t exception) {
|
||||
// NOLINTNEXTLINE(hicpp-move-const-arg, performance-move-const-arg)
|
||||
exception_ = std::move(exception);
|
||||
}
|
||||
|
||||
/// Returns the contained exception
|
||||
exception_t& get_exception() & noexcept {
|
||||
return exception_;
|
||||
}
|
||||
/// \copydoc get_exception
|
||||
exception_t const& get_exception() const& noexcept {
|
||||
return exception_;
|
||||
}
|
||||
/// \copydoc get_exception
|
||||
exception_t&& get_exception() && noexcept {
|
||||
return std::move(exception_);
|
||||
}
|
||||
};
|
||||
|
||||
/// The result class can carry the three kinds of results an asynchronous
|
||||
/// operation possibly can return, it's implemented in a variant like
|
||||
/// data structure which is also specialized to hold arbitrary arguments.
|
||||
///
|
||||
/// The result can be in the following three states:
|
||||
/// - *no result*: If the operation didn't finish
|
||||
/// - *a value*: If the operation finished successfully
|
||||
/// - *an exception*: If the operation finished with an exception
|
||||
/// or was cancelled.
|
||||
///
|
||||
/// The interface of the result object is similar to the one proposed in
|
||||
/// the `std::expected` proposal:
|
||||
/// ```cpp
|
||||
/// result<std::string> result = make_result("Hello World!");
|
||||
/// bool(result);
|
||||
/// result.is_value();
|
||||
/// result.is_exception();
|
||||
/// *result; // Same as result.get_value()
|
||||
/// result.get_value();
|
||||
/// result.get_exception();
|
||||
/// ```
|
||||
///
|
||||
/// \since 4.0.0
|
||||
///
|
||||
template <typename... T>
|
||||
class result {
|
||||
using trait_t = detail::result_trait<T...>;
|
||||
|
||||
template <typename... Args>
|
||||
explicit result(detail::init_result_arg_t arg, Args&&... values)
|
||||
: variant_(arg, trait_t::wrap(std::forward<Args>(values)...)) {}
|
||||
explicit result(detail::init_exception_arg_t arg, exception_t exception)
|
||||
: variant_(arg, std::move(exception)) {}
|
||||
|
||||
public:
|
||||
using value_t = typename trait_t::value_t;
|
||||
using value_placeholder_t = typename trait_t::surrogate_t;
|
||||
|
||||
template <typename FirstArg, typename... Args>
|
||||
explicit result(FirstArg&& first, Args&&... values)
|
||||
: variant_(detail::init_result_arg_t{},
|
||||
trait_t::wrap(std::forward<FirstArg>(first),
|
||||
std::forward<Args>(values)...)) {}
|
||||
|
||||
result() = default;
|
||||
result(result const&) = delete;
|
||||
result(result&&) = default;
|
||||
result& operator=(result const&) = delete;
|
||||
result& operator=(result&&) = default;
|
||||
~result() = default;
|
||||
|
||||
explicit result(exception_t exception)
|
||||
: variant_(detail::init_exception_arg_t{}, std::move(exception)) {}
|
||||
/* implicit */ result(empty_result) {}
|
||||
/* implicit */ result(exceptional_result exceptional_result)
|
||||
: variant_(detail::init_exception_arg_t{},
|
||||
std::move(exceptional_result.get_exception())) {}
|
||||
/* implicit */ result(cancellation_result)
|
||||
: variant_(detail::init_exception_arg_t{}, exception_t{}) {}
|
||||
|
||||
result& operator=(empty_result) {
|
||||
variant_.set_empty();
|
||||
return *this;
|
||||
}
|
||||
result& operator=(value_placeholder_t value) {
|
||||
variant_.set_value(std::move(value));
|
||||
return *this;
|
||||
}
|
||||
result& operator=(exceptional_result exception) {
|
||||
variant_.set_exception(std::move(exception.get_exception()));
|
||||
return *this;
|
||||
}
|
||||
result& operator=(cancellation_result) {
|
||||
variant_.set_exception({});
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Set the result to an empty state
|
||||
void set_empty() {
|
||||
variant_.set_empty();
|
||||
}
|
||||
/// Set the result to a the state which holds the corresponding value
|
||||
void set_value(T... values) {
|
||||
variant_.set_value(trait_t::wrap(std::move(values)...));
|
||||
}
|
||||
/// Set the result into a state which holds the corresponding exception
|
||||
void set_exception(exception_t exception) {
|
||||
variant_.set_exception(std::move(exception));
|
||||
}
|
||||
/// Set the result into a state which holds the cancellation token
|
||||
void set_canceled() {
|
||||
variant_.set_exception(exception_t{});
|
||||
}
|
||||
|
||||
/// Returns true if the state of the result is empty
|
||||
bool is_empty() const noexcept {
|
||||
return variant_.is_empty();
|
||||
}
|
||||
/// Returns true if the state of the result holds the result
|
||||
bool is_value() const noexcept {
|
||||
return variant_.is_value();
|
||||
}
|
||||
/// Returns true if the state of the result holds a present exception
|
||||
bool is_exception() const noexcept {
|
||||
return variant_.is_exception();
|
||||
}
|
||||
|
||||
/// \copydoc is_value
|
||||
explicit constexpr operator bool() const noexcept {
|
||||
return is_value();
|
||||
}
|
||||
|
||||
/// Returns the values of the result, if the result doesn't hold the value
|
||||
/// the behaviour is undefined but will assert in debug mode.
|
||||
decltype(auto) get_value() & noexcept {
|
||||
return trait_t::unwrap(variant_.get_value());
|
||||
}
|
||||
///\copydoc get_value
|
||||
decltype(auto) get_value() const& noexcept {
|
||||
return trait_t::unwrap(variant_.get_value());
|
||||
}
|
||||
///\copydoc get_value
|
||||
decltype(auto) get_value() && noexcept {
|
||||
return trait_t::unwrap(std::move(variant_.get_value()));
|
||||
}
|
||||
|
||||
///\copydoc get_value
|
||||
decltype(auto) operator*() & noexcept {
|
||||
return get_value();
|
||||
}
|
||||
///\copydoc get_value
|
||||
decltype(auto) operator*() const& noexcept {
|
||||
return get_value();
|
||||
}
|
||||
///\copydoc get_value
|
||||
decltype(auto) operator*() && noexcept {
|
||||
return std::move(variant_.get_value());
|
||||
}
|
||||
|
||||
/// Returns the exception of the result, if the result doesn't hold an
|
||||
/// exception the behaviour is undefined but will assert in debug mode.
|
||||
exception_t& get_exception() & noexcept {
|
||||
return variant_.get_exception();
|
||||
}
|
||||
/// \copydoc get_exception
|
||||
exception_t const& get_exception() const& noexcept {
|
||||
return variant_.get_exception();
|
||||
}
|
||||
/// \copydoc get_exception
|
||||
exception_t&& get_exception() && noexcept {
|
||||
return std::move(variant_.get_exception());
|
||||
}
|
||||
|
||||
/// Creates a present result from the given values
|
||||
static result from(T... values) {
|
||||
return result{detail::init_result_arg_t{}, std::move(values)...};
|
||||
}
|
||||
/// Creates a present result from the given exception
|
||||
static result from(exception_arg_t, exception_t exception) {
|
||||
return result{detail::init_exception_arg_t{}, std::move(exception)};
|
||||
}
|
||||
|
||||
/// Creates an empty result
|
||||
static result empty() {
|
||||
return result{empty_result{}};
|
||||
}
|
||||
|
||||
private:
|
||||
detail::result_variant<value_placeholder_t> variant_;
|
||||
};
|
||||
|
||||
/// Returns the value at position I of the given result
|
||||
template <std::size_t I, typename... T>
|
||||
decltype(auto) get(result<T...>& result) {
|
||||
return detail::result_trait<T...>::template get<I>(result);
|
||||
}
|
||||
/// \copydoc get
|
||||
template <std::size_t I, typename... T>
|
||||
decltype(auto) get(result<T...> const& result) {
|
||||
return detail::result_trait<T...>::template get<I>(result);
|
||||
}
|
||||
/// \copydoc get
|
||||
template <std::size_t I, typename... T>
|
||||
decltype(auto) get(result<T...>&& result) {
|
||||
return detail::result_trait<T...>::template get<I>(std::move(result));
|
||||
}
|
||||
|
||||
/// Creates a present result from the given values.
|
||||
///
|
||||
/// This could be used to pass the result of the next handler to the same
|
||||
/// asynchronous path it came from as shown below:
|
||||
/// ```cpp
|
||||
/// make_ready_continuable().next([&](auto&&... args) {
|
||||
/// result<> captured = make_result(std::forward<decltype(args)>(args)...);
|
||||
/// return shutdown().then([captured = std::move(captured)]() mutable {
|
||||
/// return std::move(captured);
|
||||
/// });
|
||||
/// });
|
||||
/// ```
|
||||
///
|
||||
/// \since 4.0.0
|
||||
template <typename... T,
|
||||
typename Result = result<detail::traits::unrefcv_t<T>...>>
|
||||
Result make_result(T&&... values) {
|
||||
return Result::from(std::forward<T>(values)...);
|
||||
}
|
||||
|
||||
/// Creates an exceptional_result from the given exception.
|
||||
///
|
||||
/// \copydetails make_result
|
||||
///
|
||||
/// \since 4.0.0
|
||||
inline exceptional_result make_result(exception_arg_t, exception_t exception) {
|
||||
// NOLINTNEXTLINE(hicpp-move-const-arg, performance-move-const-arg)
|
||||
return exceptional_result{std::move(exception)};
|
||||
}
|
||||
/// \}
|
||||
} // namespace cti
|
||||
|
||||
namespace std {
|
||||
// The GCC standard library defines tuple_size as class and struct which
|
||||
// triggers a warning here.
|
||||
#if defined(__clang__)
|
||||
# pragma GCC diagnostic push
|
||||
# pragma GCC diagnostic ignored "-Wmismatched-tags"
|
||||
#endif
|
||||
template <typename... Args>
|
||||
struct tuple_size<cti::result<Args...>>
|
||||
: std::integral_constant<size_t, sizeof...(Args)> {};
|
||||
|
||||
template <std::size_t I, typename... Args>
|
||||
struct tuple_element<I, cti::result<Args...>>
|
||||
: tuple_element<I, tuple<Args...>> {};
|
||||
#if defined(__clang__)
|
||||
# pragma GCC diagnostic pop
|
||||
#endif
|
||||
} // namespace std
|
||||
|
||||
#endif // CONTINUABLE_RESULT_HPP_INCLUDED
|
||||
@ -5,9 +5,9 @@
|
||||
\_,(_)| | | || ||_|(_||_)|(/_
|
||||
|
||||
https://github.com/Naios/continuable
|
||||
v4.2.0
|
||||
v3.0.0
|
||||
|
||||
Copyright(c) 2015 - 2022 Denis Blank <denis.blank at outlook dot com>
|
||||
Copyright(c) 2015 - 2018 Denis Blank <denis.blank at outlook dot com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files(the "Software"), to deal
|
||||
@ -21,18 +21,18 @@
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
**/
|
||||
|
||||
#ifndef CONTINUABLE_EXTERNAL_GTEST_HPP_INCLUDED
|
||||
#define CONTINUABLE_EXTERNAL_GTEST_HPP_INCLUDED
|
||||
#ifndef CONTINUABLE_TESTING_HPP_INCLUDED
|
||||
#define CONTINUABLE_TESTING_HPP_INCLUDED
|
||||
|
||||
#include <continuable/detail/other/testing.hpp>
|
||||
#include <continuable/detail/utility/traits.hpp>
|
||||
#include <continuable/detail/testing.hpp>
|
||||
#include <continuable/detail/traits.hpp>
|
||||
|
||||
/// \defgroup Testing Testing
|
||||
/// provides macro shortcuts for testing asynchronous continuations through
|
||||
@ -53,14 +53,6 @@
|
||||
#define ASSERT_ASYNC_EXCEPTION_COMPLETION(CONTINUABLE) \
|
||||
cti::detail::testing::assert_async_exception_completion(CONTINUABLE);
|
||||
|
||||
/// Asserts that the final callback of the given continuable is called
|
||||
/// with a cancelled result which is represented by a default constructed
|
||||
/// exception_t.
|
||||
///
|
||||
/// \since 4.0.0
|
||||
#define ASSERT_ASYNC_CANCELLATION(CONTINUABLE) \
|
||||
cti::detail::testing::assert_async_cancellation(CONTINUABLE);
|
||||
|
||||
/// Asserts that the final callback of the given continuable is never called
|
||||
/// with any result.
|
||||
///
|
||||
@ -166,7 +158,7 @@
|
||||
/// \since 1.0.0
|
||||
#define ASSERT_ASYNC_TYPES(CONTINUABLE, ...) \
|
||||
cti::detail::testing::assert_async_types( \
|
||||
CONTINUABLE, cti::detail::identity<__VA_ARGS__>{})
|
||||
CONTINUABLE, cti::detail::traits::identity<__VA_ARGS__>{})
|
||||
|
||||
/// Asserts that the continuable is finished with the given exception
|
||||
///
|
||||
@ -177,4 +169,4 @@
|
||||
|
||||
/// \}
|
||||
|
||||
#endif // CONTINUABLE_EXTERNAL_GTEST_HPP_INCLUDED
|
||||
#endif // CONTINUABLE_TESTING_HPP_INCLUDED
|
||||
80
include/continuable/continuable-trait.hpp
Normal file
80
include/continuable/continuable-trait.hpp
Normal file
@ -0,0 +1,80 @@
|
||||
|
||||
/*
|
||||
|
||||
/~` _ _ _|_. _ _ |_ | _
|
||||
\_,(_)| | | || ||_|(_||_)|(/_
|
||||
|
||||
https://github.com/Naios/continuable
|
||||
v3.0.0
|
||||
|
||||
Copyright(c) 2015 - 2018 Denis Blank <denis.blank at outlook dot com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files(the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions :
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
**/
|
||||
|
||||
#ifndef CONTINUABLE_TRAIT_HPP_INCLUDED
|
||||
#define CONTINUABLE_TRAIT_HPP_INCLUDED
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include <continuable/continuable-base.hpp>
|
||||
#include <continuable/continuable-promise-base.hpp>
|
||||
#include <continuable/detail/hints.hpp>
|
||||
#include <continuable/detail/types.hpp>
|
||||
|
||||
namespace cti {
|
||||
/// \defgroup Types Types
|
||||
/// provides the \link cti::continuable continuable\endlink and \link
|
||||
/// cti::promise promise\endlink facility for type erasure.
|
||||
/// \{
|
||||
|
||||
/// Trait to retrieve a continuable_base type with a given type-erasure backend.
|
||||
///
|
||||
/// Every object may me used as type-erasure backend as long as the
|
||||
/// requirements of a `std::function` like wrapper are satisfied.
|
||||
///
|
||||
/// \tparam CallbackWrapper The type which is used to erase the callback.
|
||||
///
|
||||
/// \tparam ContinuationWrapper The type which is used to erase the
|
||||
/// continuation data.
|
||||
///
|
||||
/// \tparam Args The current signature of the continuable.
|
||||
template <template <std::size_t, typename...> class CallbackWrapper,
|
||||
template <std::size_t, typename...> class ContinuationWrapper,
|
||||
typename... Args>
|
||||
class continuable_trait {
|
||||
|
||||
using callback = CallbackWrapper<0U, void(Args...)&&,
|
||||
void(detail::types::dispatch_error_tag,
|
||||
detail::types::error_type) &&>;
|
||||
|
||||
public:
|
||||
/// The promise type which is used to resolve continuations
|
||||
using promise =
|
||||
promise_base<callback, detail::hints::signature_hint_tag<Args...>>;
|
||||
|
||||
/// The continuable type for the given parameters.
|
||||
using continuable =
|
||||
continuable_base<ContinuationWrapper<sizeof(callback), void(promise)>,
|
||||
detail::hints::signature_hint_tag<Args...>>;
|
||||
};
|
||||
/// \}
|
||||
} // namespace cti
|
||||
|
||||
#endif // CONTINUABLE_TRAIT_HPP_INCLUDED
|
||||
@ -5,9 +5,9 @@
|
||||
\_,(_)| | | || ||_|(_||_)|(/_
|
||||
|
||||
https://github.com/Naios/continuable
|
||||
v4.2.0
|
||||
v3.0.0
|
||||
|
||||
Copyright(c) 2015 - 2022 Denis Blank <denis.blank at outlook dot com>
|
||||
Copyright(c) 2015 - 2018 Denis Blank <denis.blank at outlook dot com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files(the "Software"), to deal
|
||||
@ -21,7 +21,7 @@
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
@ -31,8 +31,8 @@
|
||||
#ifndef CONTINUABLE_TRANSFORMS_HPP_INCLUDED
|
||||
#define CONTINUABLE_TRANSFORMS_HPP_INCLUDED
|
||||
|
||||
#include <continuable/transforms/wait.hpp>
|
||||
#include <continuable/transforms/future.hpp>
|
||||
#include <continuable/detail/transforms.hpp>
|
||||
#include <continuable/detail/types.hpp>
|
||||
|
||||
namespace cti {
|
||||
/// \defgroup Transforms Transforms
|
||||
@ -41,12 +41,70 @@ namespace cti {
|
||||
/// types such as (`std::future`).
|
||||
/// \{
|
||||
|
||||
/// A callable tag object which marks a wrapped callable object
|
||||
/// as continuable transformation which enables some useful overloads.
|
||||
///
|
||||
/// \since 3.0.0
|
||||
template <typename T>
|
||||
using transform = detail::types::transform<T>;
|
||||
|
||||
/// Wraps the given callable object into a transform class.
|
||||
///
|
||||
/// \since 3.0.0
|
||||
template <typename T>
|
||||
auto make_transform(T&& callable) {
|
||||
return transform<std::decay_t<T>>(std::forward<T>(callable));
|
||||
}
|
||||
|
||||
/// The namespace transforms declares callable objects that transform
|
||||
/// any continuable_base to an object or to a continuable_base itself.
|
||||
///
|
||||
/// Transforms can be applied to continuables through using
|
||||
/// the cti::continuable_base::apply method accordingly.
|
||||
namespace transforms {}
|
||||
namespace transforms {
|
||||
/// Returns a transform that if applied to a continuable,
|
||||
/// it will start the continuation chain and returns the asynchronous
|
||||
/// result as `std::future<...>`.
|
||||
///
|
||||
/// \returns Returns a `std::future<...>` which becomes ready as soon
|
||||
/// as the the continuation chain has finished.
|
||||
/// The signature of the future depends on the result type:
|
||||
/// | Continuation type | Return type |
|
||||
/// | : ------------------------------- | : -------------------------------- |
|
||||
/// | `continuable_base with <>` | `std::future<void>` |
|
||||
/// | `continuable_base with <Arg>` | `std::future<Arg>` |
|
||||
/// | `continuable_base with <Args...>` | `std::future<std::tuple<Args...>>` |
|
||||
///
|
||||
/// \attention If exceptions are used, exceptions that are thrown, are forwarded
|
||||
/// to the returned future. If there are no exceptions supported,
|
||||
/// you shall not pass any errors to the end of the asynchronous
|
||||
/// call chain!
|
||||
/// Otherwise this will yield a trap that causes application exit.
|
||||
///
|
||||
/// \since 2.0.0
|
||||
inline auto futurize() {
|
||||
return make_transform([](auto&& continuable) {
|
||||
using detail::transforms::as_future;
|
||||
return as_future(std::forward<decltype(continuable)>(continuable));
|
||||
});
|
||||
}
|
||||
|
||||
/// Returns a transform that if applied to a continuable, it will ignores all
|
||||
/// error which ocured until the point the transform was applied.
|
||||
///
|
||||
/// \returns Returns a continuable with the same signature as applied to.
|
||||
///
|
||||
/// \attention This can be used to create a continuable which doesn't resolve
|
||||
/// the continuation on errors.
|
||||
///
|
||||
/// \since 2.0.0
|
||||
inline auto flatten() {
|
||||
return make_transform([](auto&& continuable) {
|
||||
return std::forward<decltype(continuable)>(continuable).fail([](auto&&) {});
|
||||
});
|
||||
}
|
||||
/// \}
|
||||
} // namespace transforms
|
||||
} // namespace cti
|
||||
|
||||
#endif // CONTINUABLE_TRANSFORMS_HPP_INCLUDED
|
||||
|
||||
@ -5,9 +5,9 @@
|
||||
\_,(_)| | | || ||_|(_||_)|(/_
|
||||
|
||||
https://github.com/Naios/continuable
|
||||
v4.2.0
|
||||
v3.0.0
|
||||
|
||||
Copyright(c) 2015 - 2022 Denis Blank <denis.blank at outlook dot com>
|
||||
Copyright(c) 2015 - 2018 Denis Blank <denis.blank at outlook dot com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files(the "Software"), to deal
|
||||
@ -21,7 +21,7 @@
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
@ -32,7 +32,8 @@
|
||||
#define CONTINUABLE_TRAVERSE_ASYNC_HPP_INCLUDED
|
||||
|
||||
#include <utility>
|
||||
#include <continuable/detail/traversal/traverse-async.hpp>
|
||||
|
||||
#include <continuable/detail/traverse-async.hpp>
|
||||
|
||||
namespace cti {
|
||||
/// \defgroup Traversal Traversal
|
||||
@ -74,7 +75,7 @@ using async_traverse_in_place_tag =
|
||||
/// ```cpp
|
||||
/// struct my_async_visitor {
|
||||
/// /// The synchronous overload is called for each object,
|
||||
/// /// it may return false to suspend the current control flow.
|
||||
/// /// it may return false to suspend the current control.
|
||||
/// /// In that case the overload below is called.
|
||||
/// template <typename T>
|
||||
/// bool operator()(async_traverse_visit_tag, T&& element) {
|
||||
|
||||
@ -5,9 +5,9 @@
|
||||
\_,(_)| | | || ||_|(_||_)|(/_
|
||||
|
||||
https://github.com/Naios/continuable
|
||||
v4.2.0
|
||||
v3.0.0
|
||||
|
||||
Copyright(c) 2015 - 2022 Denis Blank <denis.blank at outlook dot com>
|
||||
Copyright(c) 2015 - 2018 Denis Blank <denis.blank at outlook dot com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files(the "Software"), to deal
|
||||
@ -21,7 +21,7 @@
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
@ -34,7 +34,8 @@
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <continuable/detail/traversal/traverse.hpp>
|
||||
|
||||
#include <continuable/detail/traverse.hpp>
|
||||
|
||||
namespace cti {
|
||||
/// \defgroup Traversal Traversal
|
||||
|
||||
@ -5,9 +5,9 @@
|
||||
\_,(_)| | | || ||_|(_||_)|(/_
|
||||
|
||||
https://github.com/Naios/continuable
|
||||
v4.2.0
|
||||
v3.0.0
|
||||
|
||||
Copyright(c) 2015 - 2022 Denis Blank <denis.blank at outlook dot com>
|
||||
Copyright(c) 2015 - 2018 Denis Blank <denis.blank at outlook dot com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files(the "Software"), to deal
|
||||
@ -21,7 +21,7 @@
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
@ -31,11 +31,11 @@
|
||||
#ifndef CONTINUABLE_TYPES_HPP_INCLUDED
|
||||
#define CONTINUABLE_TYPES_HPP_INCLUDED
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include <function2/function2.hpp>
|
||||
#include <continuable/continuable-base.hpp>
|
||||
#include <continuable/continuable-primitives.hpp>
|
||||
#include <continuable/continuable-promise-base.hpp>
|
||||
#include <continuable/detail/other/erasure.hpp>
|
||||
|
||||
#include <continuable/continuable-trait.hpp>
|
||||
|
||||
namespace cti {
|
||||
/// \defgroup Types Types
|
||||
@ -43,59 +43,48 @@ namespace cti {
|
||||
/// cti::promise promise\endlink facility for type erasure.
|
||||
/// \{
|
||||
|
||||
/// Deduces to the preferred continuation capacity for a possible
|
||||
/// small functor optimization. The given capacity size is always enough to
|
||||
/// to avoid any allocation when storing a ready continuable_base.
|
||||
///
|
||||
/// \since 4.0.0
|
||||
template <typename... Args>
|
||||
using continuation_capacity = detail::erasure::continuation_capacity<Args...>;
|
||||
// clang-format off
|
||||
namespace detail {
|
||||
/// A function which isn't size adjusted and move only
|
||||
template<std::size_t, typename... Args>
|
||||
using unique_function_adapter = fu2::unique_function<Args...>;
|
||||
/// A function which is size adjusted and move only
|
||||
template<std::size_t Size, typename... Args>
|
||||
using unique_function_adjustable = fu2::function_base<true, false, Size,
|
||||
true, false, Args...>;
|
||||
|
||||
/// We adjust the internal capacity of the outer function wrapper so
|
||||
/// we don't have to allocate twice when using `continuable<...>`.
|
||||
template<typename... Args>
|
||||
using unique_trait_of = continuable_trait<
|
||||
unique_function_adapter,
|
||||
unique_function_adjustable,
|
||||
Args...
|
||||
>;
|
||||
} // namespace detail
|
||||
|
||||
/// Defines a non-copyable continuation type which uses the
|
||||
/// function2 backend for type erasure.
|
||||
///
|
||||
/// Usable like: `continuable<int, float>`
|
||||
///
|
||||
/// \note You can always define your own continuable with a type erasure of
|
||||
/// choice, the type erasure wrapper just needs to accept a
|
||||
/// callable object with a continuation signature as specified
|
||||
/// in the Primitives section.
|
||||
///
|
||||
/// \since 1.0.0
|
||||
template <typename... Args>
|
||||
using continuable = continuable_base<detail::erasure::continuation<Args...>, //
|
||||
signature_arg_t<Args...>>;
|
||||
using continuable = typename detail::unique_trait_of<
|
||||
Args...
|
||||
>::continuable;
|
||||
|
||||
/// Defines a non-copyable promise type which is using the
|
||||
/// function2 backend for type erasure.
|
||||
///
|
||||
/// Usable like: `promise<int, float>`
|
||||
///
|
||||
/// \note You can always define your own promise with a type erasure of
|
||||
/// choice, the type erasure wrapper just needs to accept a
|
||||
/// callable object with a callback signature as specified
|
||||
/// in the Primitives section.
|
||||
///
|
||||
/// \since 1.0.0
|
||||
template <typename... Args>
|
||||
using promise = promise_base<detail::erasure::callback<Args...>, //
|
||||
signature_arg_t<Args...>>;
|
||||
using promise = typename detail::unique_trait_of<
|
||||
Args...
|
||||
>::promise;
|
||||
|
||||
/// Defines a non-copyable type erasure which is capable of carrying
|
||||
/// callable objects passed to executors.
|
||||
///
|
||||
/// The work behaves like a `promise<>` but the work type erasure uses extra
|
||||
/// stack space for small object optimization.
|
||||
/// Additionally the outstanding work can be resolved through an exception.
|
||||
///
|
||||
/// \note You can always define your own cancelable_work with a type erasure of
|
||||
/// choice, the type erasure wrapper just needs to accept a
|
||||
/// callable object which is callable with a `void()` and
|
||||
/// `void(exception_arg_t, exception_t)` signature.
|
||||
///
|
||||
/// \since 4.0.0
|
||||
using work = promise_base<detail::erasure::work, //
|
||||
signature_arg_t<>>;
|
||||
// TODO channel
|
||||
// TODO sink
|
||||
|
||||
// clang-format on
|
||||
/// \}
|
||||
} // namespace cti
|
||||
|
||||
|
||||
@ -5,9 +5,9 @@
|
||||
\_,(_)| | | || ||_|(_||_)|(/_
|
||||
|
||||
https://github.com/Naios/continuable
|
||||
v4.2.0
|
||||
v3.0.0
|
||||
|
||||
Copyright(c) 2015 - 2022 Denis Blank <denis.blank at outlook dot com>
|
||||
Copyright(c) 2015 - 2018 Denis Blank <denis.blank at outlook dot com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files(the "Software"), to deal
|
||||
@ -21,7 +21,7 @@
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
@ -47,12 +47,9 @@ namespace cti {}
|
||||
|
||||
#include <continuable/continuable-base.hpp>
|
||||
#include <continuable/continuable-connections.hpp>
|
||||
#include <continuable/continuable-coroutine.hpp>
|
||||
#include <continuable/continuable-operations.hpp>
|
||||
#include <continuable/continuable-primitives.hpp>
|
||||
#include <continuable/continuable-promise-base.hpp>
|
||||
#include <continuable/continuable-promisify.hpp>
|
||||
#include <continuable/continuable-result.hpp>
|
||||
#include <continuable/continuable-trait.hpp>
|
||||
#include <continuable/continuable-transforms.hpp>
|
||||
#include <continuable/continuable-traverse-async.hpp>
|
||||
#include <continuable/continuable-traverse.hpp>
|
||||
|
||||
144
include/continuable/detail/awaiting.hpp
Normal file
144
include/continuable/detail/awaiting.hpp
Normal file
@ -0,0 +1,144 @@
|
||||
|
||||
/*
|
||||
|
||||
/~` _ _ _|_. _ _ |_ | _
|
||||
\_,(_)| | | || ||_|(_||_)|(/_
|
||||
|
||||
https://github.com/Naios/continuable
|
||||
v3.0.0
|
||||
|
||||
Copyright(c) 2015 - 2018 Denis Blank <denis.blank at outlook dot com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files(the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions :
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
**/
|
||||
|
||||
// Exclude this header when coroutines are not available
|
||||
#ifndef CONTINUABLE_DETAIL_AWAITING_HPP_INCLUDED
|
||||
#define CONTINUABLE_DETAIL_AWAITING_HPP_INCLUDED
|
||||
|
||||
#include <cassert>
|
||||
#include <experimental/coroutine>
|
||||
|
||||
#include <continuable/detail/expected.hpp>
|
||||
#include <continuable/detail/features.hpp>
|
||||
#include <continuable/detail/hints.hpp>
|
||||
#include <continuable/detail/types.hpp>
|
||||
#include <continuable/detail/util.hpp>
|
||||
|
||||
#if defined(CONTINUABLE_HAS_EXCEPTIONS)
|
||||
#include <exception>
|
||||
#endif // CONTINUABLE_HAS_EXCEPTIONS
|
||||
|
||||
namespace cti {
|
||||
namespace detail {
|
||||
namespace awaiting {
|
||||
/// We import the coroutine handle in our namespace
|
||||
using std::experimental::coroutine_handle;
|
||||
|
||||
/// An object which provides the internal buffer and helper methods
|
||||
/// for waiting on a continuable in a stackless coroutine.
|
||||
template <typename Continuable>
|
||||
class awaitable {
|
||||
using trait_t = container::expected_result_trait_t<Continuable>;
|
||||
|
||||
/// The continuable which is invoked upon suspension
|
||||
Continuable continuable_;
|
||||
/// A cache which is used to pass the result of the continuation
|
||||
/// to the coroutine.
|
||||
typename trait_t::expected_type result_;
|
||||
|
||||
public:
|
||||
explicit constexpr awaitable(Continuable&& continuable)
|
||||
: continuable_(std::move(continuable)) {
|
||||
}
|
||||
|
||||
/// Since continuables are evaluated lazily we are not
|
||||
/// capable to say whether the resumption will be instantly.
|
||||
bool await_ready() const noexcept {
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Suspend the current context
|
||||
// TODO Convert this to an r-value function once possible
|
||||
void await_suspend(coroutine_handle<> h) {
|
||||
// Forward every result to the current awaitable
|
||||
std::move(continuable_)
|
||||
.next([h, this](auto&&... args) mutable {
|
||||
resolve(std::forward<decltype(args)>(args)...);
|
||||
h.resume();
|
||||
})
|
||||
.done();
|
||||
}
|
||||
|
||||
/// Resume the coroutine represented by the handle
|
||||
auto await_resume() noexcept(false) {
|
||||
if (result_) {
|
||||
// When the result was resolved return it
|
||||
return trait_t::unwrap(std::move(result_));
|
||||
}
|
||||
|
||||
#if defined(CONTINUABLE_HAS_EXCEPTIONS)
|
||||
std::rethrow_exception(result_.get_exception());
|
||||
#else // CONTINUABLE_HAS_EXCEPTIONS
|
||||
// Returning error types in await isn't supported as of now
|
||||
util::trap();
|
||||
#endif // CONTINUABLE_HAS_EXCEPTIONS
|
||||
}
|
||||
|
||||
private:
|
||||
/// Resolve the continuation through the result
|
||||
template <typename... Args>
|
||||
void resolve(Args&&... args) {
|
||||
result_.set_value(trait_t::wrap(std::forward<Args>(args)...));
|
||||
}
|
||||
|
||||
/// Resolve the continuation through an error
|
||||
void resolve(types::dispatch_error_tag, types::error_type error) {
|
||||
result_.set_exception(std::move(error));
|
||||
}
|
||||
};
|
||||
|
||||
/// Converts a continuable into an awaitable object as described by
|
||||
/// the C++ coroutine TS.
|
||||
template <typename T>
|
||||
constexpr auto create_awaiter(T&& continuable) {
|
||||
return awaitable<std::decay_t<T>>(std::forward<T>(continuable));
|
||||
}
|
||||
} // namespace awaiting
|
||||
} // namespace detail
|
||||
} // namespace cti
|
||||
|
||||
// As far as I know there is no other was to implement this specialization...
|
||||
// NOLINTNEXTLINE(cert-dcl58-cpp)
|
||||
namespace std {
|
||||
namespace experimental {
|
||||
template <typename Data, typename... Args, typename... FunctionArgs>
|
||||
struct coroutine_traits<
|
||||
cti::continuable_base<Data,
|
||||
cti::detail::hints::signature_hint_tag<Args...>>,
|
||||
FunctionArgs...> {
|
||||
|
||||
static_assert(cti::detail::traits::fail<Data>::value,
|
||||
"Using a continuable as return type from co_return "
|
||||
"expressions isn't supported yet!");
|
||||
};
|
||||
} // namespace experimental
|
||||
} // namespace std
|
||||
|
||||
#endif // CONTINUABLE_DETAIL_UTIL_HPP_INCLUDED
|
||||
593
include/continuable/detail/base.hpp
Normal file
593
include/continuable/detail/base.hpp
Normal file
@ -0,0 +1,593 @@
|
||||
|
||||
/*
|
||||
|
||||
/~` _ _ _|_. _ _ |_ | _
|
||||
\_,(_)| | | || ||_|(_||_)|(/_
|
||||
|
||||
https://github.com/Naios/continuable
|
||||
v3.0.0
|
||||
|
||||
Copyright(c) 2015 - 2018 Denis Blank <denis.blank at outlook dot com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files(the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions :
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
**/
|
||||
|
||||
#ifndef CONTINUABLE_DETAIL_BASE_HPP_INCLUDED
|
||||
#define CONTINUABLE_DETAIL_BASE_HPP_INCLUDED
|
||||
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#include <continuable/detail/features.hpp>
|
||||
#include <continuable/detail/hints.hpp>
|
||||
#include <continuable/detail/traits.hpp>
|
||||
#include <continuable/detail/types.hpp>
|
||||
#include <continuable/detail/util.hpp>
|
||||
|
||||
#if defined(CONTINUABLE_HAS_EXCEPTIONS)
|
||||
#include <exception>
|
||||
#endif // CONTINUABLE_HAS_EXCEPTIONS
|
||||
|
||||
namespace cti {
|
||||
namespace detail {
|
||||
/// The namespace `base` provides the low level API for working
|
||||
/// with continuable types.
|
||||
///
|
||||
/// Important methods are:
|
||||
/// - Creating a continuation from a callback taking functional
|
||||
/// base::attorney::create(auto&& callback)
|
||||
/// -> base::continuation<auto>
|
||||
/// - Chaining a continuation together with a callback
|
||||
/// base::chain_continuation(base::continuation<auto> continuation,
|
||||
/// auto&& callback)
|
||||
/// -> base::continuation<auto>
|
||||
/// - Finally invoking the continuation chain
|
||||
/// base::finalize_continuation(base::continuation<auto> continuation)
|
||||
/// -> void
|
||||
namespace base {
|
||||
template <typename T>
|
||||
struct is_continuable : std::false_type {};
|
||||
template <typename Data, typename Annotation>
|
||||
struct is_continuable<continuable_base<Data, Annotation>> : std::true_type {};
|
||||
|
||||
/// Helper class to access private methods and members of
|
||||
/// the continuable_base class.
|
||||
struct attorney {
|
||||
/// Makes a continuation wrapper from the given argument
|
||||
template <typename T, typename A>
|
||||
static auto create(T&& continuation, A /*hint*/, util::ownership ownership_) {
|
||||
return continuable_base<std::decay_t<T>, std::decay_t<A>>(
|
||||
std::forward<T>(continuation), ownership_);
|
||||
}
|
||||
|
||||
/// Invokes a continuation object in a reference correct way
|
||||
template <typename Data, typename Annotation, typename Callback>
|
||||
static auto
|
||||
invoke_continuation(continuable_base<Data, Annotation>&& continuation,
|
||||
Callback&& callback) noexcept {
|
||||
auto materialized = std::move(continuation).materialize();
|
||||
materialized.release();
|
||||
return materialized.data_(std::forward<Callback>(callback));
|
||||
}
|
||||
|
||||
template <typename Data, typename Annotation>
|
||||
static auto materialize(continuable_base<Data, Annotation>&& continuation) {
|
||||
return std::move(continuation).materialize();
|
||||
}
|
||||
|
||||
template <typename Data, typename Annotation>
|
||||
static Data&&
|
||||
consume_data(continuable_base<Data, Annotation>&& continuation) {
|
||||
return std::move(continuation).consume_data();
|
||||
}
|
||||
|
||||
template <typename Continuable>
|
||||
static util::ownership ownership_of(Continuable&& continuation) noexcept {
|
||||
return continuation.ownership_;
|
||||
}
|
||||
};
|
||||
|
||||
// Returns the invoker of a callback, the next callback
|
||||
// and the arguments of the previous continuation.
|
||||
//
|
||||
// The return type of the invokerOf function matches a callable of:
|
||||
// void(auto&& callback, auto&& next_callback, auto&&... args)
|
||||
//
|
||||
// The invoker decorates the result type in the following way
|
||||
// - void -> next_callback()
|
||||
// - ? -> next_callback(?)
|
||||
// - std::pair<?, ?> -> next_callback(?, ?)
|
||||
// - std::tuple<?...> -> next_callback(?...)
|
||||
//
|
||||
// When the result is a continuation itself pass the callback to it
|
||||
// - continuation<?...> -> result(next_callback);
|
||||
namespace decoration {
|
||||
/// Helper class wrapping the underlaying unwrapping lambda
|
||||
/// in order to extend it with a hint method.
|
||||
template <typename T, typename Hint>
|
||||
class invoker : public T {
|
||||
public:
|
||||
constexpr explicit invoker(T invoke) : T(std::move(invoke)) {
|
||||
}
|
||||
|
||||
using T::operator();
|
||||
|
||||
/// Returns the underlaying signature hint
|
||||
static constexpr Hint hint() noexcept {
|
||||
return {};
|
||||
}
|
||||
};
|
||||
|
||||
#if defined(CONTINUABLE_HAS_EXCEPTIONS)
|
||||
#define CONTINUABLE_BLOCK_TRY_BEGIN try {
|
||||
#define CONTINUABLE_BLOCK_TRY_END \
|
||||
} \
|
||||
catch (...) { \
|
||||
std::forward<decltype(next_callback)>(next_callback)( \
|
||||
types::dispatch_error_tag{}, std::current_exception()); \
|
||||
}
|
||||
|
||||
#else // CONTINUABLE_HAS_EXCEPTIONS
|
||||
#define CONTINUABLE_BLOCK_TRY_BEGIN {
|
||||
#define CONTINUABLE_BLOCK_TRY_END }
|
||||
#endif // CONTINUABLE_HAS_EXCEPTIONS
|
||||
|
||||
/// Invokes the given callable object with the given arguments while
|
||||
/// marking the operation as non exceptional.
|
||||
template <typename T, typename... Args>
|
||||
constexpr auto invoke_no_except(T&& callable, Args&&... args) noexcept {
|
||||
return std::forward<T>(callable)(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <typename T, typename... Args>
|
||||
constexpr auto make_invoker(T&& invoke, hints::signature_hint_tag<Args...>) {
|
||||
return invoker<std::decay_t<T>, hints::signature_hint_tag<Args...>>(
|
||||
std::forward<T>(invoke));
|
||||
}
|
||||
|
||||
/// - continuable<?...> -> result(next_callback);
|
||||
template <typename Data, typename Annotation>
|
||||
constexpr auto
|
||||
invoker_of(traits::identity<continuable_base<Data, Annotation>>) {
|
||||
/// Get the hint of the unwrapped returned continuable
|
||||
using Type = decltype(attorney::materialize(
|
||||
std::declval<continuable_base<Data, Annotation>>()));
|
||||
|
||||
auto constexpr const hint = hints::hint_of(traits::identify<Type>{});
|
||||
|
||||
return make_invoker(
|
||||
[](auto&& callback, auto&& next_callback, auto&&... args) {
|
||||
CONTINUABLE_BLOCK_TRY_BEGIN
|
||||
auto continuation_ =
|
||||
util::partial_invoke(std::forward<decltype(callback)>(callback),
|
||||
std::forward<decltype(args)>(args)...);
|
||||
|
||||
attorney::invoke_continuation(
|
||||
std::move(continuation_),
|
||||
std::forward<decltype(next_callback)>(next_callback));
|
||||
CONTINUABLE_BLOCK_TRY_END
|
||||
},
|
||||
hint);
|
||||
}
|
||||
|
||||
/// - ? -> next_callback(?)
|
||||
template <typename T>
|
||||
constexpr auto invoker_of(traits::identity<T>) {
|
||||
return make_invoker(
|
||||
[](auto&& callback, auto&& next_callback, auto&&... args) {
|
||||
CONTINUABLE_BLOCK_TRY_BEGIN
|
||||
auto result =
|
||||
util::partial_invoke(std::forward<decltype(callback)>(callback),
|
||||
std::forward<decltype(args)>(args)...);
|
||||
|
||||
invoke_no_except(std::forward<decltype(next_callback)>(next_callback),
|
||||
std::move(result));
|
||||
CONTINUABLE_BLOCK_TRY_END
|
||||
},
|
||||
traits::identify<T>{});
|
||||
}
|
||||
|
||||
/// - void -> next_callback()
|
||||
inline auto invoker_of(traits::identity<void>) {
|
||||
return make_invoker(
|
||||
[](auto&& callback, auto&& next_callback, auto&&... args) {
|
||||
CONTINUABLE_BLOCK_TRY_BEGIN
|
||||
util::partial_invoke(std::forward<decltype(callback)>(callback),
|
||||
std::forward<decltype(args)>(args)...);
|
||||
invoke_no_except(
|
||||
std::forward<decltype(next_callback)>(next_callback));
|
||||
CONTINUABLE_BLOCK_TRY_END
|
||||
},
|
||||
traits::identity<>{});
|
||||
}
|
||||
|
||||
/// Returns a sequenced invoker which is able to invoke
|
||||
/// objects where std::get is applicable.
|
||||
inline auto sequenced_unpack_invoker() {
|
||||
return [](auto&& callback, auto&& next_callback, auto&&... args) {
|
||||
CONTINUABLE_BLOCK_TRY_BEGIN
|
||||
auto result =
|
||||
util::partial_invoke(std::forward<decltype(callback)>(callback),
|
||||
std::forward<decltype(args)>(args)...);
|
||||
|
||||
// Workaround for MSVC not capturing the reference correctly inside
|
||||
// the lambda.
|
||||
using Next = decltype(next_callback);
|
||||
|
||||
traits::unpack(std::move(result), [&](auto&&... types) {
|
||||
/// TODO Add inplace resolution here
|
||||
|
||||
invoke_no_except(std::forward<Next>(next_callback),
|
||||
std::forward<decltype(types)>(types)...);
|
||||
});
|
||||
CONTINUABLE_BLOCK_TRY_END
|
||||
};
|
||||
} // namespace decoration
|
||||
|
||||
// - std::pair<?, ?> -> next_callback(?, ?)
|
||||
template <typename First, typename Second>
|
||||
constexpr auto invoker_of(traits::identity<std::pair<First, Second>>) {
|
||||
return make_invoker(sequenced_unpack_invoker(),
|
||||
traits::identity<First, Second>{});
|
||||
}
|
||||
|
||||
// - std::tuple<?...> -> next_callback(?...)
|
||||
template <typename... Args>
|
||||
constexpr auto invoker_of(traits::identity<std::tuple<Args...>>) {
|
||||
return make_invoker(sequenced_unpack_invoker(), traits::identity<Args...>{});
|
||||
}
|
||||
|
||||
#undef CONTINUABLE_BLOCK_TRY_BEGIN
|
||||
#undef CONTINUABLE_BLOCK_TRY_END
|
||||
} // namespace decoration
|
||||
|
||||
/// Invoke the callback immediately
|
||||
template <typename Invoker, typename... Args>
|
||||
void packed_dispatch(types::this_thread_executor_tag, Invoker&& invoker,
|
||||
Args&&... args) {
|
||||
|
||||
// Invoke the callback with the decorated invoker immediately
|
||||
std::forward<Invoker>(invoker)(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
/// Invoke the callback through the given executor
|
||||
template <typename Executor, typename Invoker, typename... Args>
|
||||
void packed_dispatch(Executor&& executor, Invoker&& invoker, Args&&... args) {
|
||||
|
||||
// Create a worker object which when invoked calls the callback with the
|
||||
// the returned arguments.
|
||||
auto work = [
|
||||
invoker = std::forward<Invoker>(invoker),
|
||||
args = std::make_tuple(std::forward<Args>(args)...)
|
||||
]() mutable {
|
||||
traits::unpack(std::move(args), [&](auto&&... captured_args) {
|
||||
// Just use the packed dispatch method which dispatches the work on
|
||||
// the current thread.
|
||||
packed_dispatch(types::this_thread_executor_tag{}, std::move(invoker),
|
||||
std::forward<decltype(captured_args)>(captured_args)...);
|
||||
});
|
||||
};
|
||||
|
||||
// Pass the work callable object to the executor
|
||||
std::forward<Executor>(executor)(std::move(work));
|
||||
}
|
||||
|
||||
/// Tells whether we potentially move the chain upwards and handle the result
|
||||
enum class handle_results {
|
||||
no, //< The result is forwarded to the next callable
|
||||
yes //< The result is handled by the current callable
|
||||
};
|
||||
|
||||
// Silences a doxygen bug, it tries to map forward to std::forward
|
||||
/// \cond false
|
||||
/// Tells whether we handle the error through the callback
|
||||
enum class handle_errors {
|
||||
no, //< The error is forwarded to the next callable
|
||||
plain, //< The error is the only argument accepted by the callable
|
||||
forward //< The error is forwarded to the callable while keeping its tag
|
||||
};
|
||||
/// \endcond
|
||||
|
||||
namespace callbacks {
|
||||
namespace proto {
|
||||
template <handle_results HandleResults, typename Base, typename Hint>
|
||||
struct result_handler_base;
|
||||
template <typename Base, typename... Args>
|
||||
struct result_handler_base<handle_results::no, Base,
|
||||
hints::signature_hint_tag<Args...>> {
|
||||
void operator()(Args... args) && {
|
||||
// Forward the arguments to the next callback
|
||||
std::move(static_cast<Base*>(this)->next_callback_)(std::move(args)...);
|
||||
}
|
||||
};
|
||||
template <typename Base, typename... Args>
|
||||
struct result_handler_base<handle_results::yes, Base,
|
||||
hints::signature_hint_tag<Args...>> {
|
||||
/// The operator which is called when the result was provided
|
||||
void operator()(Args... args) && {
|
||||
// In order to retrieve the correct decorator we must know what the
|
||||
// result type is.
|
||||
auto result = traits::identify<decltype(util::partial_invoke(
|
||||
std::move(static_cast<Base*>(this)->callback_), std::move(args)...))>{};
|
||||
|
||||
// Pick the correct invoker that handles decorating of the result
|
||||
auto invoker = decoration::invoker_of(result);
|
||||
|
||||
// Invoke the callback
|
||||
packed_dispatch(std::move(static_cast<Base*>(this)->executor_),
|
||||
std::move(invoker),
|
||||
std::move(static_cast<Base*>(this)->callback_),
|
||||
std::move(static_cast<Base*>(this)->next_callback_),
|
||||
std::move(args)...);
|
||||
}
|
||||
};
|
||||
|
||||
inline auto make_error_invoker(
|
||||
std::integral_constant<handle_errors, handle_errors::plain>) noexcept {
|
||||
return [](auto&& callback, types::error_type&& error) {
|
||||
// Errors are not partial invoked
|
||||
// NOLINTNEXTLINE(hicpp-move-const-arg)
|
||||
std::forward<decltype(callback)>(callback)(std::move(error));
|
||||
};
|
||||
}
|
||||
inline auto make_error_invoker(
|
||||
std::integral_constant<handle_errors, handle_errors::forward>) noexcept {
|
||||
return [](auto&& callback, types::error_type&& error) {
|
||||
// Errors are not partial invoked
|
||||
std::forward<decltype(callback)>(callback)(
|
||||
types::dispatch_error_tag{},
|
||||
std::move(error)); // NOLINT(hicpp-move-const-arg)
|
||||
};
|
||||
}
|
||||
|
||||
template <handle_errors HandleErrors /* = plain or forward*/, typename Base>
|
||||
struct error_handler_base {
|
||||
void operator()(types::dispatch_error_tag, types::error_type error) && {
|
||||
// Just invoke the error handler, cancel the calling hierarchy after
|
||||
auto invoker = make_error_invoker(
|
||||
std::integral_constant<handle_errors, HandleErrors>{});
|
||||
|
||||
// Invoke the error handler
|
||||
packed_dispatch(
|
||||
std::move(static_cast<Base*>(this)->executor_), std::move(invoker),
|
||||
std::move(static_cast<Base*>(this)->callback_), std::move(error));
|
||||
}
|
||||
};
|
||||
template <typename Base>
|
||||
struct error_handler_base<handle_errors::no, Base> {
|
||||
/// The operator which is called when an error occurred
|
||||
void operator()(types::dispatch_error_tag tag, types::error_type error) && {
|
||||
// Forward the error to the next callback
|
||||
std::move(static_cast<Base*>(this)->next_callback_)(tag, std::move(error));
|
||||
}
|
||||
};
|
||||
} // namespace proto
|
||||
|
||||
template <typename Hint, handle_results HandleResults,
|
||||
handle_errors HandleErrors, typename Callback, typename Executor,
|
||||
typename NextCallback>
|
||||
struct callback_base;
|
||||
|
||||
template <typename... Args, handle_results HandleResults,
|
||||
handle_errors HandleErrors, typename Callback, typename Executor,
|
||||
typename NextCallback>
|
||||
struct callback_base<hints::signature_hint_tag<Args...>, HandleResults,
|
||||
HandleErrors, Callback, Executor, NextCallback>
|
||||
: proto::result_handler_base<
|
||||
HandleResults,
|
||||
callback_base<hints::signature_hint_tag<Args...>, HandleResults,
|
||||
HandleErrors, Callback, Executor, NextCallback>,
|
||||
hints::signature_hint_tag<Args...>>,
|
||||
proto::error_handler_base<
|
||||
HandleErrors,
|
||||
callback_base<hints::signature_hint_tag<Args...>, HandleResults,
|
||||
HandleErrors, Callback, Executor, NextCallback>>,
|
||||
util::non_copyable {
|
||||
|
||||
Callback callback_;
|
||||
Executor executor_;
|
||||
NextCallback next_callback_;
|
||||
|
||||
explicit callback_base(Callback callback, Executor executor,
|
||||
NextCallback next_callback)
|
||||
: callback_(std::move(callback)), executor_(std::move(executor)),
|
||||
next_callback_(std::move(next_callback)) {
|
||||
}
|
||||
|
||||
/// Pull the result handling operator() in
|
||||
using proto::result_handler_base<
|
||||
HandleResults,
|
||||
callback_base<hints::signature_hint_tag<Args...>, HandleResults,
|
||||
HandleErrors, Callback, Executor, NextCallback>,
|
||||
hints::signature_hint_tag<Args...>>::operator();
|
||||
|
||||
/// Pull the error handling operator() in
|
||||
using proto::error_handler_base<
|
||||
HandleErrors,
|
||||
callback_base<hints::signature_hint_tag<Args...>, HandleResults,
|
||||
HandleErrors, Callback, Executor, NextCallback>>::
|
||||
operator();
|
||||
|
||||
/// Resolves the continuation with the given values
|
||||
void set_value(Args... args) {
|
||||
std::move (*this)(std::move(args)...);
|
||||
}
|
||||
|
||||
/// Resolves the continuation with the given error variable.
|
||||
void set_exception(types::error_type error) {
|
||||
std::move (*this)(types::dispatch_error_tag{}, std::move(error));
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Hint, handle_results HandleResults,
|
||||
handle_errors HandleErrors, typename Callback, typename Executor,
|
||||
typename NextCallback>
|
||||
auto make_callback(Callback&& callback, Executor&& executor,
|
||||
NextCallback&& next_callback) {
|
||||
return callback_base<Hint, HandleResults, HandleErrors,
|
||||
std::decay_t<Callback>, std::decay_t<Executor>,
|
||||
std::decay_t<NextCallback>>{
|
||||
std::forward<Callback>(callback), std::forward<Executor>(executor),
|
||||
std::forward<NextCallback>(next_callback)};
|
||||
}
|
||||
|
||||
/// Once this was a workaround for GCC bug:
|
||||
/// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=64095
|
||||
struct final_callback : util::non_copyable {
|
||||
template <typename... Args>
|
||||
void operator()(Args... /*args*/) && {
|
||||
}
|
||||
|
||||
void operator()(types::dispatch_error_tag, types::error_type error) && {
|
||||
(void)error;
|
||||
#ifndef CONTINUABLE_WITH_UNHANDLED_EXCEPTIONS
|
||||
// There were unhandled errors inside the asynchronous call chain!
|
||||
// Define `CONTINUABLE_WITH_UNHANDLED_EXCEPTIONS` in order
|
||||
// to ignore unhandled errors!"
|
||||
util::trap();
|
||||
#endif // CONTINUABLE_WITH_UNHANDLED_EXCEPTIONS
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
void set_value(Args... args) {
|
||||
std::move (*this)(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
void set_exception(types::error_type error) {
|
||||
// NOLINTNEXTLINE(hicpp-move-const-arg)
|
||||
std::move (*this)(types::dispatch_error_tag{}, std::move(error));
|
||||
}
|
||||
};
|
||||
} // namespace callbacks
|
||||
|
||||
/// Returns the next hint when the callback is invoked with the given hint
|
||||
template <typename T, typename... Args>
|
||||
constexpr auto
|
||||
next_hint_of(std::integral_constant<handle_results, handle_results::yes>,
|
||||
traits::identity<T> /*callback*/,
|
||||
hints::signature_hint_tag<Args...> /*current*/) {
|
||||
// Partial Invoke the given callback
|
||||
using Result = decltype(
|
||||
util::partial_invoke(std::declval<T>(), std::declval<Args>()...));
|
||||
|
||||
// Return the hint of thr given invoker
|
||||
return decltype(decoration::invoker_of(traits::identify<Result>{}).hint()){};
|
||||
}
|
||||
/// Don't progress the hint when we don't continue
|
||||
template <typename T, typename... Args>
|
||||
constexpr auto
|
||||
next_hint_of(std::integral_constant<handle_results, handle_results::no>,
|
||||
traits::identity<T> /*callback*/,
|
||||
hints::signature_hint_tag<Args...> current) {
|
||||
return current;
|
||||
}
|
||||
|
||||
/// Chains a callback together with a continuation and returns a continuation:
|
||||
///
|
||||
/// For example given:
|
||||
/// - Continuation: continuation<[](auto&& callback) { callback("hi"); }>
|
||||
/// - Callback: [](std::string) { }
|
||||
///
|
||||
/// This function returns a function accepting the next callback in the chain:
|
||||
/// - Result: continuation<[](auto&& callback) { /*...*/ }>
|
||||
///
|
||||
template <handle_results HandleResults, handle_errors HandleErrors,
|
||||
typename Continuation, typename Callback, typename Executor>
|
||||
auto chain_continuation(Continuation&& continuation, Callback&& callback,
|
||||
Executor&& executor) {
|
||||
static_assert(is_continuable<std::decay_t<Continuation>>{},
|
||||
"Expected a continuation!");
|
||||
|
||||
using Hint = decltype(hints::hint_of(traits::identify<Continuation>()));
|
||||
constexpr auto next_hint =
|
||||
next_hint_of(std::integral_constant<handle_results, HandleResults>{},
|
||||
traits::identify<decltype(callback)>{}, Hint{});
|
||||
|
||||
// TODO consume only the data here so the freeze isn't needed
|
||||
auto ownership_ = attorney::ownership_of(continuation);
|
||||
continuation.freeze();
|
||||
|
||||
return attorney::create(
|
||||
[
|
||||
continuation = std::forward<Continuation>(continuation),
|
||||
callback = std::forward<Callback>(callback),
|
||||
executor = std::forward<Executor>(executor)
|
||||
](auto&& next_callback) mutable {
|
||||
|
||||
// Invokes a continuation with a given callback.
|
||||
// Passes the next callback to the resulting continuable or
|
||||
// invokes the next callback directly if possible.
|
||||
//
|
||||
// For example given:
|
||||
// - Continuation: continuation<[](auto&& callback) { callback("hi"); }>
|
||||
// - Callback: [](std::string) { }
|
||||
// - NextCallback: []() { }
|
||||
auto proxy =
|
||||
callbacks::make_callback<Hint, HandleResults, HandleErrors>(
|
||||
std::move(callback), std::move(executor),
|
||||
std::forward<decltype(next_callback)>(next_callback));
|
||||
|
||||
// Invoke the continuation with a proxy callback.
|
||||
// The proxy callback is responsible for passing
|
||||
// the result to the callback as well as decorating it.
|
||||
attorney::invoke_continuation(std::move(continuation),
|
||||
std::move(proxy));
|
||||
},
|
||||
next_hint, ownership_);
|
||||
}
|
||||
|
||||
/// Final invokes the given continuation chain:
|
||||
///
|
||||
/// For example given:
|
||||
/// - Continuation: continuation<[](auto&& callback) { callback("hi"); }>
|
||||
template <typename Continuation>
|
||||
void finalize_continuation(Continuation&& continuation) {
|
||||
attorney::invoke_continuation(std::forward<Continuation>(continuation),
|
||||
callbacks::final_callback{});
|
||||
}
|
||||
|
||||
/// Workaround for GCC bug:
|
||||
/// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=64095
|
||||
template <typename T>
|
||||
class supplier_callback {
|
||||
T data_;
|
||||
|
||||
public:
|
||||
explicit supplier_callback(T data) : data_(std::move(data)) {
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
auto operator()(Args...) {
|
||||
return std::move(data_);
|
||||
}
|
||||
};
|
||||
|
||||
/// Returns a continuable into a callable object returning the continuable
|
||||
template <typename Continuation>
|
||||
auto wrap_continuation(Continuation&& continuation) {
|
||||
continuation.freeze();
|
||||
return supplier_callback<std::decay_t<Continuation>>(
|
||||
std::forward<Continuation>(continuation));
|
||||
}
|
||||
} // namespace base
|
||||
} // namespace detail
|
||||
} // namespace cti
|
||||
|
||||
#endif // CONTINUABLE_DETAIL_BASE_HPP_INCLUDED
|
||||
@ -5,9 +5,9 @@
|
||||
\_,(_)| | | || ||_|(_||_)|(/_
|
||||
|
||||
https://github.com/Naios/continuable
|
||||
v4.2.0
|
||||
v3.0.0
|
||||
|
||||
Copyright(c) 2015 - 2022 Denis Blank <denis.blank at outlook dot com>
|
||||
Copyright(c) 2015 - 2018 Denis Blank <denis.blank at outlook dot com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files(the "Software"), to deal
|
||||
@ -21,7 +21,7 @@
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
@ -35,10 +35,11 @@
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <continuable/continuable-result.hpp>
|
||||
|
||||
#include <continuable/continuable-traverse.hpp>
|
||||
#include <continuable/detail/core/base.hpp>
|
||||
#include <continuable/detail/utility/traits.hpp>
|
||||
#include <continuable/detail/base.hpp>
|
||||
#include <continuable/detail/flat-variant.hpp>
|
||||
#include <continuable/detail/traits.hpp>
|
||||
|
||||
namespace cti {
|
||||
namespace detail {
|
||||
@ -54,69 +55,62 @@ namespace connection {
|
||||
/// - single async value -> single value
|
||||
/// - multiple async value -> tuple of async values.
|
||||
namespace aggregated {
|
||||
|
||||
/// Guards a type to be default constructible,
|
||||
/// and wraps it into an optional type if it isn't default constructible.
|
||||
template <typename T>
|
||||
using lazy_value_t = std::conditional_t<std::is_default_constructible<T>::value,
|
||||
T, result<T>>;
|
||||
T, container::flat_variant<T>>;
|
||||
|
||||
template <typename T>
|
||||
decltype(auto) unpack_lazy(std::true_type /*is_default_constructible*/,
|
||||
T&& value) {
|
||||
decltype(auto) unpack_lazy(T&& value) {
|
||||
return std::forward<T>(value);
|
||||
}
|
||||
template <typename T>
|
||||
T&& unpack_lazy(std::false_type /*is_default_constructible*/,
|
||||
result<T>&& value) {
|
||||
assert(value.is_value() &&
|
||||
T&& unpack_lazy(container::flat_variant<T>&& value) {
|
||||
assert(value.template is<T>() &&
|
||||
"The connection was finalized before all values were present!");
|
||||
|
||||
return std::move(value).get_value();
|
||||
return std::move(value.template cast<T>());
|
||||
}
|
||||
|
||||
template <typename Continuable>
|
||||
class continuable_box;
|
||||
template <typename Data>
|
||||
class continuable_box<continuable_base<Data, identity<>>> {
|
||||
class continuable_box<continuable_base<Data, hints::signature_hint_tag<>>> {
|
||||
|
||||
continuable_base<Data, identity<>> continuable_;
|
||||
continuable_base<Data, hints::signature_hint_tag<>> continuable_;
|
||||
|
||||
public:
|
||||
explicit continuable_box(continuable_base<Data, identity<>>&& continuable)
|
||||
: continuable_(std::move(continuable)) {}
|
||||
|
||||
auto const& peek() const {
|
||||
return continuable_;
|
||||
explicit continuable_box(
|
||||
continuable_base<Data, hints::signature_hint_tag<>>&& continuable)
|
||||
: continuable_(std::move(continuable)) {
|
||||
}
|
||||
|
||||
auto&& fetch() {
|
||||
continuable_base<Data, hints::signature_hint_tag<>>&& fetch() {
|
||||
return std::move(continuable_);
|
||||
}
|
||||
|
||||
void assign() {}
|
||||
void assign() {
|
||||
}
|
||||
|
||||
auto unbox() && {
|
||||
return spread_this();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Data, typename First>
|
||||
class continuable_box<continuable_base<Data, identity<First>>> {
|
||||
class continuable_box<
|
||||
continuable_base<Data, hints::signature_hint_tag<First>>> {
|
||||
|
||||
continuable_base<Data, identity<First>> continuable_;
|
||||
continuable_base<Data, hints::signature_hint_tag<First>> continuable_;
|
||||
lazy_value_t<First> first_;
|
||||
|
||||
public:
|
||||
explicit continuable_box(
|
||||
continuable_base<Data, identity<First>>&& continuable)
|
||||
: continuable_(std::move(continuable)) {}
|
||||
|
||||
auto const& peek() const {
|
||||
return continuable_;
|
||||
continuable_base<Data, hints::signature_hint_tag<First>>&& continuable)
|
||||
: continuable_(std::move(continuable)) {
|
||||
}
|
||||
|
||||
auto&& fetch() {
|
||||
continuable_base<Data, hints::signature_hint_tag<First>>&& fetch() {
|
||||
return std::move(continuable_);
|
||||
}
|
||||
|
||||
@ -125,27 +119,27 @@ public:
|
||||
}
|
||||
|
||||
auto unbox() && {
|
||||
return unpack_lazy(std::is_default_constructible<First>{},
|
||||
std::move(first_));
|
||||
return unpack_lazy(std::move(first_));
|
||||
}
|
||||
};
|
||||
template <typename Data, typename First, typename Second, typename... Rest>
|
||||
class continuable_box<
|
||||
continuable_base<Data, identity<First, Second, Rest...>>> {
|
||||
continuable_base<Data, hints::signature_hint_tag<First, Second, Rest...>>> {
|
||||
|
||||
continuable_base<Data, identity<First, Second, Rest...>> continuable_;
|
||||
continuable_base<Data, hints::signature_hint_tag<First, Second, Rest...>>
|
||||
continuable_;
|
||||
lazy_value_t<std::tuple<First, Second, Rest...>> args_;
|
||||
|
||||
public:
|
||||
explicit continuable_box(
|
||||
continuable_base<Data, identity<First, Second, Rest...>>&& continuable)
|
||||
: continuable_(std::move(continuable)) {}
|
||||
|
||||
auto const& peek() const {
|
||||
return continuable_;
|
||||
continuable_base<Data,
|
||||
hints::signature_hint_tag<First, Second, Rest...>>&&
|
||||
continuable)
|
||||
: continuable_(std::move(continuable)) {
|
||||
}
|
||||
|
||||
auto&& fetch() {
|
||||
continuable_base<Data, hints::signature_hint_tag<First, Second, Rest...>>&&
|
||||
fetch() {
|
||||
return std::move(continuable_);
|
||||
}
|
||||
|
||||
@ -155,13 +149,9 @@ public:
|
||||
}
|
||||
|
||||
auto unbox() && {
|
||||
return traits::unpack(
|
||||
[](auto&&... args) {
|
||||
return spread_this(std::forward<decltype(args)>(args)...);
|
||||
},
|
||||
unpack_lazy(
|
||||
std::is_default_constructible<std::tuple<First, Second, Rest...>>{},
|
||||
std::move(args_)));
|
||||
return traits::unpack(unpack_lazy(std::move(args_)), [](auto&&... args) {
|
||||
return spread_this(std::forward<decltype(args)>(args)...);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
@ -210,20 +200,21 @@ constexpr auto unbox_continuables(Args&&... args) {
|
||||
|
||||
namespace detail {
|
||||
template <typename Callback, typename Data>
|
||||
constexpr auto finalize_impl(identity<void>, Callback&& callback, Data&&) {
|
||||
constexpr auto finalize_impl(traits::identity<void>, Callback&& callback,
|
||||
Data&&) {
|
||||
return std::forward<Callback>(callback)();
|
||||
}
|
||||
template <typename... Args, typename Callback, typename Data>
|
||||
constexpr auto finalize_impl(identity<std::tuple<Args...>>, Callback&& callback,
|
||||
Data&& data) {
|
||||
constexpr auto finalize_impl(traits::identity<std::tuple<Args...>>,
|
||||
Callback&& callback, Data&& data) {
|
||||
// Call the final callback with the cleaned result
|
||||
return traits::unpack(std::forward<Callback>(callback),
|
||||
unbox_continuables(std::forward<Data>(data)));
|
||||
return traits::unpack(unbox_continuables(std::forward<Data>(data)),
|
||||
std::forward<Callback>(callback));
|
||||
}
|
||||
|
||||
struct hint_mapper {
|
||||
template <typename... T>
|
||||
constexpr auto operator()(T...) -> identity<T...> {
|
||||
constexpr auto operator()(T...) -> hints::signature_hint_tag<T...> {
|
||||
return {};
|
||||
}
|
||||
};
|
||||
@ -233,7 +224,7 @@ template <typename Callback, typename Data>
|
||||
constexpr auto finalize_data(Callback&& callback, Data&& data) {
|
||||
using result_t = decltype(unbox_continuables(std::forward<Data>(data)));
|
||||
// Guard the final result against void
|
||||
return detail::finalize_impl(identity<std::decay_t<result_t>>{},
|
||||
return detail::finalize_impl(traits::identity<std::decay_t<result_t>>{},
|
||||
std::forward<Callback>(callback),
|
||||
std::forward<Data>(data));
|
||||
}
|
||||
@ -5,9 +5,9 @@
|
||||
\_,(_)| | | || ||_|(_||_)|(/_
|
||||
|
||||
https://github.com/Naios/continuable
|
||||
v4.2.0
|
||||
v3.0.0
|
||||
|
||||
Copyright(c) 2015 - 2022 Denis Blank <denis.blank at outlook dot com>
|
||||
Copyright(c) 2015 - 2018 Denis Blank <denis.blank at outlook dot com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files(the "Software"), to deal
|
||||
@ -21,7 +21,7 @@
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
@ -37,13 +37,13 @@
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <continuable/continuable-primitives.hpp>
|
||||
#include <continuable/detail/connection/connection-aggregated.hpp>
|
||||
#include <continuable/detail/connection/connection.hpp>
|
||||
#include <continuable/detail/core/annotation.hpp>
|
||||
#include <continuable/detail/core/base.hpp>
|
||||
#include <continuable/detail/core/types.hpp>
|
||||
#include <continuable/detail/utility/traits.hpp>
|
||||
|
||||
#include <continuable/detail/base.hpp>
|
||||
#include <continuable/detail/connection-aggregated.hpp>
|
||||
#include <continuable/detail/connection.hpp>
|
||||
#include <continuable/detail/hints.hpp>
|
||||
#include <continuable/detail/traits.hpp>
|
||||
#include <continuable/detail/types.hpp>
|
||||
|
||||
namespace cti {
|
||||
namespace detail {
|
||||
@ -99,11 +99,11 @@ class result_submitter
|
||||
}
|
||||
|
||||
template <typename... PartialArgs>
|
||||
void operator()(exception_arg_t tag, exception_t exception) && {
|
||||
void operator()(types::dispatch_error_tag tag, types::error_type error) && {
|
||||
// We never complete the connection, but we forward the first error
|
||||
// which was raised.
|
||||
std::call_once(me->flag_, std::move(me->callback_), tag,
|
||||
std::move(exception));
|
||||
std::move(error));
|
||||
}
|
||||
};
|
||||
|
||||
@ -157,21 +157,22 @@ struct connection_finalizer<connection_strategy_all_tag> {
|
||||
template <typename Connection>
|
||||
static auto finalize(Connection&& connection, util::ownership ownership) {
|
||||
// Create the target result from the connection
|
||||
auto res =
|
||||
auto result =
|
||||
aggregated::box_continuables(std::forward<Connection>(connection));
|
||||
|
||||
auto signature = aggregated::hint_of_data<decltype(res)>();
|
||||
auto signature = aggregated::hint_of_data<decltype(result)>();
|
||||
|
||||
return base::attorney::create(
|
||||
[result = std::move(result)](auto&& callback) mutable {
|
||||
|
||||
return base::attorney::create_from(
|
||||
[res = std::move(res)](auto&& callback) mutable {
|
||||
using submitter_t =
|
||||
all::result_submitter<std::decay_t<decltype(callback)>,
|
||||
std::decay_t<decltype(res)>>;
|
||||
std::decay_t<decltype(result)>>;
|
||||
|
||||
// Create the shared state which holds the result
|
||||
// and the final callback
|
||||
// Create the shared state which holds the result and the final
|
||||
// callback
|
||||
auto state = std::make_shared<submitter_t>(
|
||||
std::forward<decltype(callback)>(callback), std::move(res));
|
||||
std::forward<decltype(callback)>(callback), std::move(result));
|
||||
|
||||
// Dispatch the continuables and store its partial result
|
||||
// in the whole result
|
||||
@ -185,13 +186,6 @@ struct connection_finalizer<connection_strategy_all_tag> {
|
||||
}
|
||||
};
|
||||
} // namespace connection
|
||||
|
||||
/// Specialization for a connection annotation
|
||||
template <>
|
||||
struct annotation_trait<connection::connection_strategy_all_tag>
|
||||
: connection::connection_annotation_trait<
|
||||
connection::connection_strategy_all_tag> {};
|
||||
|
||||
} // namespace detail
|
||||
} // namespace cti
|
||||
|
||||
@ -5,9 +5,9 @@
|
||||
\_,(_)| | | || ||_|(_||_)|(/_
|
||||
|
||||
https://github.com/Naios/continuable
|
||||
v4.2.0
|
||||
v3.0.0
|
||||
|
||||
Copyright(c) 2015 - 2022 Denis Blank <denis.blank at outlook dot com>
|
||||
Copyright(c) 2015 - 2018 Denis Blank <denis.blank at outlook dot com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files(the "Software"), to deal
|
||||
@ -21,7 +21,7 @@
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
@ -37,14 +37,14 @@
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <continuable/continuable-primitives.hpp>
|
||||
|
||||
#include <continuable/continuable-promise-base.hpp>
|
||||
#include <continuable/continuable-traverse.hpp>
|
||||
#include <continuable/detail/core/annotation.hpp>
|
||||
#include <continuable/detail/core/base.hpp>
|
||||
#include <continuable/detail/core/types.hpp>
|
||||
#include <continuable/detail/traversal/container-category.hpp>
|
||||
#include <continuable/detail/utility/traits.hpp>
|
||||
#include <continuable/detail/base.hpp>
|
||||
#include <continuable/detail/container-category.hpp>
|
||||
#include <continuable/detail/hints.hpp>
|
||||
#include <continuable/detail/traits.hpp>
|
||||
#include <continuable/detail/types.hpp>
|
||||
|
||||
namespace cti {
|
||||
namespace detail {
|
||||
@ -88,30 +88,30 @@ private:
|
||||
|
||||
struct result_deducer {
|
||||
template <typename T>
|
||||
static auto deduce_one(std::false_type, identity<T>) {
|
||||
static auto deduce_one(std::false_type, traits::identity<T>) {
|
||||
static_assert(traits::fail<T>::value,
|
||||
"Non continuable types except tuple like and homogeneous "
|
||||
"containers aren't allowed inside an any expression!");
|
||||
}
|
||||
template <typename T>
|
||||
static auto deduce_one(std::true_type, identity<T> id) {
|
||||
return base::annotation_of(id);
|
||||
static auto deduce_one(std::true_type, traits::identity<T> id) {
|
||||
return hints::hint_of(id);
|
||||
}
|
||||
template <typename T>
|
||||
static auto deduce(traversal::container_category_tag<false, false>,
|
||||
identity<T> id) {
|
||||
traits::identity<T> id) {
|
||||
return deduce_one<T>(base::is_continuable<T>{}, id);
|
||||
}
|
||||
|
||||
/// Deduce a homogeneous container
|
||||
template <bool IsTupleLike, typename T>
|
||||
static auto deduce(traversal::container_category_tag<true, IsTupleLike>,
|
||||
identity<T>) {
|
||||
traits::identity<T>) {
|
||||
|
||||
// Deduce the containing type
|
||||
using element_t = std::decay_t<decltype(*std::declval<T>().begin())>;
|
||||
return deduce(traversal::container_category_of_t<element_t>{},
|
||||
identity<element_t>{});
|
||||
traits::identity<element_t>{});
|
||||
}
|
||||
|
||||
template <typename First, typename... T>
|
||||
@ -125,18 +125,19 @@ struct result_deducer {
|
||||
|
||||
template <std::size_t... I, typename T>
|
||||
static auto deduce_tuple_like(std::integer_sequence<std::size_t, I...>,
|
||||
identity<T>) {
|
||||
traits::identity<T>) {
|
||||
|
||||
return deduce_same_hints(deduce(
|
||||
traversal::container_category_of_t<
|
||||
std::decay_t<decltype(std::get<I>(std::declval<T>()))>>{},
|
||||
identity<std::decay_t<decltype(std::get<I>(std::declval<T>()))>>{})...);
|
||||
traits::identity<
|
||||
std::decay_t<decltype(std::get<I>(std::declval<T>()))>>{})...);
|
||||
}
|
||||
|
||||
/// Traverse tuple like container
|
||||
template <typename T>
|
||||
static auto deduce(traversal::container_category_tag<false, true>,
|
||||
identity<T> id) {
|
||||
traits::identity<T> id) {
|
||||
|
||||
constexpr auto const size = std::tuple_size<T>::value;
|
||||
return deduce_tuple_like(std::make_index_sequence<size>{}, id);
|
||||
@ -171,11 +172,12 @@ struct connection_finalizer<connection_strategy_any_tag> {
|
||||
static auto finalize(Connection&& connection, util::ownership ownership) {
|
||||
constexpr auto const signature = decltype(any::result_deducer::deduce(
|
||||
traversal::container_category_of_t<std::decay_t<Connection>>{},
|
||||
identity<std::decay_t<Connection>>{})){};
|
||||
traits::identity<std::decay_t<Connection>>{})){};
|
||||
|
||||
return base::attorney::create_from(
|
||||
return base::attorney::create(
|
||||
[connection =
|
||||
std::forward<Connection>(connection)](auto&& callback) mutable {
|
||||
|
||||
using submitter_t =
|
||||
any::any_result_submitter<std::decay_t<decltype(callback)>>;
|
||||
|
||||
@ -191,13 +193,6 @@ struct connection_finalizer<connection_strategy_any_tag> {
|
||||
}
|
||||
};
|
||||
} // namespace connection
|
||||
|
||||
/// Specialization for a connection annotation
|
||||
template <>
|
||||
struct annotation_trait<connection::connection_strategy_any_tag>
|
||||
: connection::connection_annotation_trait<
|
||||
connection::connection_strategy_any_tag> {};
|
||||
|
||||
} // namespace detail
|
||||
} // namespace cti
|
||||
|
||||
@ -5,9 +5,9 @@
|
||||
\_,(_)| | | || ||_|(_||_)|(/_
|
||||
|
||||
https://github.com/Naios/continuable
|
||||
v4.2.0
|
||||
v3.0.0
|
||||
|
||||
Copyright(c) 2015 - 2022 Denis Blank <denis.blank at outlook dot com>
|
||||
Copyright(c) 2015 - 2018 Denis Blank <denis.blank at outlook dot com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files(the "Software"), to deal
|
||||
@ -21,7 +21,7 @@
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
@ -36,12 +36,12 @@
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <continuable/continuable-primitives.hpp>
|
||||
|
||||
#include <continuable/continuable-traverse-async.hpp>
|
||||
#include <continuable/detail/connection/connection-aggregated.hpp>
|
||||
#include <continuable/detail/core/base.hpp>
|
||||
#include <continuable/detail/utility/traits.hpp>
|
||||
#include <continuable/detail/utility/util.hpp>
|
||||
#include <continuable/detail/base.hpp>
|
||||
#include <continuable/detail/connection-aggregated.hpp>
|
||||
#include <continuable/detail/traits.hpp>
|
||||
#include <continuable/detail/util.hpp>
|
||||
|
||||
namespace cti {
|
||||
namespace detail {
|
||||
@ -56,16 +56,16 @@ auto sequential_connect(Left&& left, Right&& right) {
|
||||
left.freeze(right.is_frozen());
|
||||
right.freeze();
|
||||
|
||||
return std::forward<Left>(left).then(
|
||||
[right = std::forward<Right>(right)](auto&&... args) mutable {
|
||||
return std::move(right).then(
|
||||
[previous = std::make_tuple(std::forward<decltype(args)>(args)...)](
|
||||
auto&&... args) mutable {
|
||||
return std::tuple_cat(
|
||||
std::move(previous),
|
||||
std::make_tuple(std::forward<decltype(args)>(args)...));
|
||||
});
|
||||
});
|
||||
return std::forward<Left>(left).then([right = std::forward<Right>(right)](
|
||||
auto&&... args) mutable {
|
||||
return std::move(right).then([previous = std::make_tuple(
|
||||
std::forward<decltype(args)>(args)...)](
|
||||
auto&&... args) mutable {
|
||||
return traits::merge(
|
||||
std::move(previous),
|
||||
std::make_tuple(std::forward<decltype(args)>(args)...));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
template <typename Callback, typename Box>
|
||||
@ -94,34 +94,25 @@ public:
|
||||
|
||||
template <typename Box, std::enable_if_t<aggregated::is_continuable_box<
|
||||
std::decay_t<Box>>::value>* = nullptr>
|
||||
bool operator()(async_traverse_visit_tag, Box&& box) {
|
||||
if (base::attorney::is_ready(box.peek())) {
|
||||
// The result can be resolved directly
|
||||
traits::unpack(
|
||||
[&](auto&&... args) mutable {
|
||||
box.assign(std::forward<decltype(args)>(args)...);
|
||||
},
|
||||
base::attorney::query(box.fetch()));
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
bool operator()(async_traverse_visit_tag, Box&& /*box*/) {
|
||||
return false;
|
||||
}
|
||||
|
||||
template <typename Box, typename N>
|
||||
void operator()(async_traverse_detach_tag, Box&& box, N&& next) {
|
||||
box.fetch()
|
||||
.then([box = std::addressof(box),
|
||||
next = std::forward<N>(next)](auto&&... args) mutable {
|
||||
.then([ box = std::addressof(box),
|
||||
next = std::forward<N>(next) ](auto&&... args) mutable {
|
||||
|
||||
// Assign the result to the target
|
||||
box->assign(std::forward<decltype(args)>(args)...);
|
||||
|
||||
// Continue the asynchronous sequential traversal
|
||||
next();
|
||||
})
|
||||
.fail([me = this->shared_from_this()](exception_t exception) {
|
||||
.fail([me = this->shared_from_this()](types::error_type exception) {
|
||||
// Abort the traversal when an error occurred
|
||||
std::move(me->data_.callback)(exception_arg_t{},
|
||||
std::move(me->data_.callback)(types::dispatch_error_tag{},
|
||||
std::move(exception));
|
||||
})
|
||||
.done();
|
||||
@ -147,36 +138,30 @@ struct connection_finalizer<connection_strategy_seq_tag> {
|
||||
template <typename Connection>
|
||||
static auto finalize(Connection&& connection, util::ownership ownership) {
|
||||
|
||||
auto res =
|
||||
auto result =
|
||||
aggregated::box_continuables(std::forward<Connection>(connection));
|
||||
|
||||
auto signature = aggregated::hint_of_data<decltype(res)>();
|
||||
auto signature = aggregated::hint_of_data<decltype(result)>();
|
||||
|
||||
return base::attorney::create(
|
||||
[result = std::move(result)](auto&& callback) mutable {
|
||||
|
||||
return base::attorney::create_from(
|
||||
[res = std::move(res)](auto&& callback) mutable {
|
||||
// The data from which the visitor is constructed in-place
|
||||
using data_t =
|
||||
seq::sequential_dispatch_data<std::decay_t<decltype(callback)>,
|
||||
std::decay_t<decltype(res)>>;
|
||||
std::decay_t<decltype(result)>>;
|
||||
|
||||
// The visitor type
|
||||
using visitor_t = seq::sequential_dispatch_visitor<data_t>;
|
||||
|
||||
traverse_pack_async(async_traverse_in_place_tag<visitor_t>{},
|
||||
data_t{std::forward<decltype(callback)>(callback),
|
||||
std::move(res)});
|
||||
std::move(result)});
|
||||
},
|
||||
signature, std::move(ownership));
|
||||
}
|
||||
};
|
||||
} // namespace connection
|
||||
|
||||
/// Specialization for a connection annotation
|
||||
template <>
|
||||
struct annotation_trait<connection::connection_strategy_seq_tag>
|
||||
: connection::connection_annotation_trait<
|
||||
connection::connection_strategy_seq_tag> {};
|
||||
|
||||
} // namespace detail
|
||||
} // namespace cti
|
||||
|
||||
@ -5,9 +5,9 @@
|
||||
\_,(_)| | | || ||_|(_||_)|(/_
|
||||
|
||||
https://github.com/Naios/continuable
|
||||
v4.2.0
|
||||
v3.0.0
|
||||
|
||||
Copyright(c) 2015 - 2022 Denis Blank <denis.blank at outlook dot com>
|
||||
Copyright(c) 2015 - 2018 Denis Blank <denis.blank at outlook dot com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files(the "Software"), to deal
|
||||
@ -21,7 +21,7 @@
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
@ -35,11 +35,12 @@
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#include <continuable/continuable-traverse.hpp>
|
||||
#include <continuable/detail/core/base.hpp>
|
||||
#include <continuable/detail/core/types.hpp>
|
||||
#include <continuable/detail/utility/traits.hpp>
|
||||
#include <continuable/detail/utility/util.hpp>
|
||||
#include <continuable/detail/base.hpp>
|
||||
#include <continuable/detail/traits.hpp>
|
||||
#include <continuable/detail/types.hpp>
|
||||
#include <continuable/detail/util.hpp>
|
||||
|
||||
namespace cti {
|
||||
namespace detail {
|
||||
@ -55,7 +56,7 @@ template <typename... LeftArgs, typename... RightArgs>
|
||||
auto chain_connection(std::tuple<LeftArgs...> leftPack,
|
||||
std::tuple<RightArgs...> rightPack) {
|
||||
|
||||
return std::tuple_cat(std::move(leftPack), std::move(rightPack));
|
||||
return traits::merge(std::move(leftPack), std::move(rightPack));
|
||||
}
|
||||
|
||||
/// Normalizes a continuation to a tuple holding an arbitrary count of
|
||||
@ -83,7 +84,7 @@ auto normalize(Strategy /*strategy*/,
|
||||
|
||||
// If the right continuation is a different strategy materialize it
|
||||
// in order to keep the precedence in cases where: `c1 && (c2 || c3)`.
|
||||
return std::make_tuple(std::move(continuation).finish());
|
||||
return std::make_tuple(base::attorney::materialize(std::move(continuation)));
|
||||
}
|
||||
/// - The continuable is inside the current strategy state:
|
||||
/// -> return the data of the tuple
|
||||
@ -92,7 +93,7 @@ auto normalize(Strategy /*strategy*/,
|
||||
continuable_base<Data, Strategy>&& continuation) {
|
||||
|
||||
// If we are in the given strategy we can just use the data of the continuable
|
||||
return base::attorney::consume(std::move(continuation));
|
||||
return base::attorney::consume_data(std::move(continuation));
|
||||
}
|
||||
|
||||
/// Entry function for connecting two continuables with a given strategy.
|
||||
@ -114,7 +115,7 @@ auto connect(Strategy strategy, continuable_base<LData, LAnnotation>&& left,
|
||||
|
||||
// Return a new continuable containing the tuple and holding
|
||||
// the current strategy as annotation.
|
||||
return base::attorney::create_from_raw(std::move(data), strategy, ownership_);
|
||||
return base::attorney::create(std::move(data), strategy, ownership_);
|
||||
}
|
||||
|
||||
/// All strategies should specialize this class in order to provide:
|
||||
@ -124,24 +125,32 @@ auto connect(Strategy strategy, continuable_base<LData, LAnnotation>&& left,
|
||||
template <typename Strategy>
|
||||
struct connection_finalizer;
|
||||
|
||||
template <typename Strategy>
|
||||
struct connection_annotation_trait {
|
||||
/// Finalizes the connection logic of a given connection
|
||||
template <typename Continuable>
|
||||
static auto finish(Continuable&& continuable) {
|
||||
using finalizer = connection_finalizer<Strategy>;
|
||||
/// Finalizes the connection logic of a given connection
|
||||
template <typename Data, typename Strategy>
|
||||
auto finalize_connection(continuable_base<Data, Strategy>&& continuation) {
|
||||
using finalizer = connection_finalizer<Strategy>;
|
||||
|
||||
util::ownership ownership = base::attorney::ownership_of(continuable);
|
||||
auto connection =
|
||||
base::attorney::consume(std::forward<Continuable>(continuable));
|
||||
util::ownership ownership = base::attorney::ownership_of(continuation);
|
||||
auto connection = base::attorney::consume_data(std::move(continuation));
|
||||
|
||||
// Return a new continuable which
|
||||
return finalizer::finalize(std::move(connection), std::move(ownership));
|
||||
// Return a new continuable which
|
||||
return finalizer::finalize(std::move(connection), std::move(ownership));
|
||||
}
|
||||
|
||||
/// A base class from which the continuable may inherit in order to
|
||||
/// provide a materializer method which will finalize an oustanding strategy.
|
||||
template <typename Continuable, typename = void>
|
||||
struct materializer {
|
||||
static constexpr auto&& apply(Continuable&& continuable) {
|
||||
return std::move(continuable);
|
||||
}
|
||||
};
|
||||
template <typename Data, typename Strategy>
|
||||
struct materializer<continuable_base<Data, Strategy>,
|
||||
std::enable_if_t<is_connection_strategy<Strategy>::value>> {
|
||||
|
||||
template <typename Continuable>
|
||||
static bool is_ready(Continuable const& /*continuable*/) noexcept {
|
||||
return false;
|
||||
static constexpr auto apply(continuable_base<Data, Strategy>&& continuable) {
|
||||
return finalize_connection(std::move(continuable));
|
||||
}
|
||||
};
|
||||
|
||||
@ -171,7 +180,7 @@ public:
|
||||
|
||||
// Materialize every continuable
|
||||
// TODO Actually we would just need to consume the data here
|
||||
return std::forward<Continuable>(continuable).finish();
|
||||
return base::attorney::materialize(std::forward<Continuable>(continuable));
|
||||
}
|
||||
};
|
||||
|
||||
@ -5,9 +5,9 @@
|
||||
\_,(_)| | | || ||_|(_||_)|(/_
|
||||
|
||||
https://github.com/Naios/continuable
|
||||
v4.2.0
|
||||
v3.0.0
|
||||
|
||||
Copyright(c) 2015 - 2022 Denis Blank <denis.blank at outlook dot com>
|
||||
Copyright(c) 2015 - 2018 Denis Blank <denis.blank at outlook dot com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files(the "Software"), to deal
|
||||
@ -21,7 +21,7 @@
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
@ -33,7 +33,8 @@
|
||||
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <continuable/detail/utility/traits.hpp>
|
||||
|
||||
#include <continuable/detail/traits.hpp>
|
||||
|
||||
namespace cti {
|
||||
namespace detail {
|
||||
File diff suppressed because it is too large
Load Diff
164
include/continuable/detail/expected.hpp
Normal file
164
include/continuable/detail/expected.hpp
Normal file
@ -0,0 +1,164 @@
|
||||
|
||||
/*
|
||||
|
||||
/~` _ _ _|_. _ _ |_ | _
|
||||
\_,(_)| | | || ||_|(_||_)|(/_
|
||||
|
||||
https://github.com/Naios/continuable
|
||||
v3.0.0
|
||||
|
||||
Copyright(c) 2015 - 2018 Denis Blank <denis.blank at outlook dot com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files(the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions :
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
**/
|
||||
|
||||
#ifndef CONTINUABLE_DETAIL_EXPECTED_HPP_INCLUDED
|
||||
#define CONTINUABLE_DETAIL_EXPECTED_HPP_INCLUDED
|
||||
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#include <continuable/detail/flat-variant.hpp>
|
||||
#include <continuable/detail/hints.hpp>
|
||||
#include <continuable/detail/types.hpp>
|
||||
|
||||
namespace cti {
|
||||
namespace detail {
|
||||
namespace container {
|
||||
/// A class similar to the one in the expected proposal,
|
||||
/// however it is capable of carrying an exception_ptr if
|
||||
/// exceptions are used.
|
||||
template <typename T>
|
||||
class expected {
|
||||
flat_variant<T, types::error_type> variant_;
|
||||
|
||||
public:
|
||||
explicit expected() = default;
|
||||
explicit expected(expected const&) = default;
|
||||
explicit expected(expected&&) = default;
|
||||
expected& operator=(expected const&) = default;
|
||||
expected& operator=(expected&&) = default;
|
||||
~expected() = default;
|
||||
|
||||
explicit expected(T value) : variant_(std::move(value)) {
|
||||
}
|
||||
explicit expected(types::error_type exception)
|
||||
: variant_(std::move(exception)) {
|
||||
}
|
||||
|
||||
expected& operator=(T value) {
|
||||
variant_ = std::move(value);
|
||||
return *this;
|
||||
}
|
||||
expected& operator=(types::error_type exception) {
|
||||
variant_ = std::move(exception);
|
||||
return *this;
|
||||
}
|
||||
|
||||
void set_value(T value) {
|
||||
variant_ = std::move(value);
|
||||
}
|
||||
void set_exception(types::error_type exception) {
|
||||
variant_ = std::move(exception);
|
||||
}
|
||||
|
||||
bool is_value() const noexcept {
|
||||
return variant_.template is<T>();
|
||||
}
|
||||
bool is_exception() const noexcept {
|
||||
return variant_.template is<types::error_type>();
|
||||
}
|
||||
|
||||
explicit constexpr operator bool() const noexcept {
|
||||
return is_value();
|
||||
}
|
||||
|
||||
T& get_value() noexcept {
|
||||
return variant_.template cast<T>();
|
||||
}
|
||||
T const& get_value() const noexcept {
|
||||
return variant_.template cast<T>();
|
||||
}
|
||||
types::error_type& get_exception() noexcept {
|
||||
return variant_.template cast<types::error_type>();
|
||||
}
|
||||
types::error_type const& get_exception() const noexcept {
|
||||
return variant_.template cast<types::error_type>();
|
||||
}
|
||||
|
||||
T& operator*() noexcept {
|
||||
return get_value();
|
||||
}
|
||||
T const& operator*() const noexcept {
|
||||
return get_value();
|
||||
}
|
||||
};
|
||||
|
||||
namespace detail {
|
||||
struct void_guard_tag {};
|
||||
|
||||
template <typename T>
|
||||
struct expected_result_trait;
|
||||
template <>
|
||||
struct expected_result_trait<traits::identity<>> {
|
||||
using expected_type = expected<void_guard_tag>;
|
||||
|
||||
static constexpr void_guard_tag wrap() noexcept {
|
||||
return {};
|
||||
}
|
||||
static void unwrap(expected_type&& e) {
|
||||
assert(e.is_value());
|
||||
(void)e;
|
||||
}
|
||||
};
|
||||
template <typename T>
|
||||
struct expected_result_trait<traits::identity<T>> {
|
||||
using expected_type = expected<T>;
|
||||
|
||||
static auto wrap(T arg) {
|
||||
return std::move(arg);
|
||||
}
|
||||
static auto unwrap(expected_type&& e) {
|
||||
assert(e.is_value());
|
||||
return std::move(e.get_value());
|
||||
}
|
||||
};
|
||||
template <typename First, typename Second, typename... Rest>
|
||||
struct expected_result_trait<traits::identity<First, Second, Rest...>> {
|
||||
using expected_type = expected<std::tuple<First, Second, Rest...>>;
|
||||
|
||||
static auto wrap(First first, Second second, Rest... rest) {
|
||||
return std::make_tuple(std::move(first), std::move(second),
|
||||
std::move(rest)...);
|
||||
}
|
||||
static auto unwrap(expected_type&& e) {
|
||||
assert(e.is_value());
|
||||
return std::move(e.get_value());
|
||||
}
|
||||
};
|
||||
} // namespace detail
|
||||
|
||||
template <typename Continuable>
|
||||
using expected_result_trait_t = detail::expected_result_trait<decltype(
|
||||
hints::hint_of(traits::identify<Continuable>{}))>;
|
||||
} // namespace container
|
||||
} // namespace detail
|
||||
} // namespace cti
|
||||
|
||||
#endif // CONTINUABLE_DETAIL_EXPECTED_HPP_INCLUDED
|
||||
242
include/continuable/detail/external/asio.hpp
vendored
242
include/continuable/detail/external/asio.hpp
vendored
@ -1,242 +0,0 @@
|
||||
/*
|
||||
|
||||
/~` _ _ _|_. _ _ |_ | _
|
||||
\_,(_)| | | || ||_|(_||_)|(/_
|
||||
|
||||
https://github.com/Naios/continuable
|
||||
v4.2.0
|
||||
|
||||
Copyright(c) 2015 - 2022 Denis Blank <denis.blank at outlook dot com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files(the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions :
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
**/
|
||||
|
||||
#ifndef CONTINUABLE_DETAIL_ASIO_HPP_INCLUDED
|
||||
#define CONTINUABLE_DETAIL_ASIO_HPP_INCLUDED
|
||||
|
||||
#include <array>
|
||||
#include <utility>
|
||||
#include <continuable/continuable-base.hpp>
|
||||
#include <continuable/detail/core/base.hpp>
|
||||
#include <continuable/detail/features.hpp>
|
||||
|
||||
#if defined(ASIO_STANDALONE)
|
||||
# include <asio/async_result.hpp>
|
||||
# include <asio/error.hpp>
|
||||
# include <asio/error_code.hpp>
|
||||
# include <asio/version.hpp>
|
||||
|
||||
# if defined(CONTINUABLE_HAS_EXCEPTIONS)
|
||||
# include <asio/system_error.hpp>
|
||||
# endif
|
||||
|
||||
# if (ASIO_VERSION < 101300) // 1.13.0
|
||||
# define CTI_DETAIL_ASIO_HAS_NO_INTEGRATION
|
||||
# elif (ASIO_VERSION < 101600) // 1.16.0 (boost 1.72 baseline)
|
||||
# define CTI_DETAIL_ASIO_HAS_EXPLICIT_RET_TYPE_INTEGRATION
|
||||
# endif
|
||||
|
||||
# define CTI_DETAIL_ASIO_NAMESPACE_BEGIN namespace asio {
|
||||
# define CTI_DETAIL_ASIO_NAMESPACE_END }
|
||||
#else
|
||||
# include <boost/asio/async_result.hpp>
|
||||
# include <boost/asio/error.hpp>
|
||||
# include <boost/system/error_code.hpp>
|
||||
# include <boost/version.hpp>
|
||||
|
||||
# if defined(CONTINUABLE_HAS_EXCEPTIONS)
|
||||
# include <boost/system/system_error.hpp>
|
||||
# endif
|
||||
|
||||
# if (BOOST_VERSION < 107000) // 1.70
|
||||
# define CTI_DETAIL_ASIO_HAS_NO_INTEGRATION
|
||||
# elif (BOOST_VERSION < 107200) // 1.72
|
||||
# define CTI_DETAIL_ASIO_HAS_EXPLICIT_RET_TYPE_INTEGRATION
|
||||
# endif
|
||||
|
||||
# define CTI_DETAIL_ASIO_NAMESPACE_BEGIN \
|
||||
namespace boost { \
|
||||
namespace asio {
|
||||
# define CTI_DETAIL_ASIO_NAMESPACE_END \
|
||||
} \
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(CTI_DETAIL_ASIO_HAS_NO_INTEGRATION)
|
||||
# error "First-class ASIO support for continuable requires the form of "\
|
||||
"`async_result` with an `initiate` static member function, which was added " \
|
||||
"in standalone ASIO 1.13.0 and Boost ASIO 1.70. Older versions can be " \
|
||||
"integrated manually with `cti::promisify`."
|
||||
#endif
|
||||
|
||||
#if defined(CONTINUABLE_HAS_EXCEPTIONS)
|
||||
# include <exception>
|
||||
#endif
|
||||
|
||||
namespace cti {
|
||||
namespace detail {
|
||||
namespace asio {
|
||||
|
||||
#if defined(ASIO_STANDALONE)
|
||||
using error_code_t = ::asio::error_code;
|
||||
using basic_errors_t = ::asio::error::basic_errors;
|
||||
|
||||
# if defined(CONTINUABLE_HAS_EXCEPTIONS)
|
||||
using system_error_t = ::asio::system_error;
|
||||
# endif
|
||||
#else
|
||||
using error_code_t = ::boost::system::error_code;
|
||||
using basic_errors_t = ::boost::asio::error::basic_errors;
|
||||
|
||||
# if defined(CONTINUABLE_HAS_EXCEPTIONS)
|
||||
using system_error_t = ::boost::system::system_error;
|
||||
# endif
|
||||
#endif
|
||||
|
||||
template <typename Promise, typename Token>
|
||||
class promise_resolver {
|
||||
public:
|
||||
explicit promise_resolver(Promise promise, Token token)
|
||||
: promise_(std::move(promise))
|
||||
, token_(std::move(token)) {}
|
||||
|
||||
template <typename... T>
|
||||
void operator()(T&&... args) noexcept {
|
||||
promise_.set_value(std::forward<T>(args)...);
|
||||
}
|
||||
|
||||
template <typename... T>
|
||||
void operator()(error_code_t e, T&&... args) noexcept {
|
||||
if (e) {
|
||||
if (!token_.is_ignored(e)) {
|
||||
if (token_.is_cancellation(e)) {
|
||||
promise_.set_canceled();
|
||||
return;
|
||||
} else {
|
||||
#if defined(CONTINUABLE_HAS_EXCEPTIONS)
|
||||
promise_.set_exception(
|
||||
std::make_exception_ptr(system_error_t(std::move(e))));
|
||||
#else
|
||||
promise_.set_exception(exception_t(e.value(), e.category()));
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
promise_.set_value(std::forward<T>(args)...);
|
||||
}
|
||||
|
||||
private:
|
||||
Promise promise_;
|
||||
Token token_;
|
||||
};
|
||||
|
||||
// Binds `promise` to the first argument of a continuable resolver, giving it
|
||||
// the signature of an ASIO handler.
|
||||
template <typename Promise, typename Token>
|
||||
auto promise_resolver_handler(Promise&& promise, Token&& token) noexcept {
|
||||
return promise_resolver<std::decay_t<Promise>, std::decay_t<Token>>(
|
||||
std::forward<Promise>(promise), std::forward<Token>(token));
|
||||
}
|
||||
|
||||
// Helper struct wrapping a call to `cti::make_continuable` and, if needed,
|
||||
// providing an erased, explicit `return_type` for `async_result`.
|
||||
template <typename Signature>
|
||||
struct initiate_make_continuable;
|
||||
|
||||
template <typename... Args>
|
||||
struct initiate_make_continuable<void(Args...)> {
|
||||
#if defined(CTI_DETAIL_ASIO_HAS_EXPLICIT_RET_TYPE_INTEGRATION)
|
||||
using erased_return_type = continuable<Args...>;
|
||||
#endif
|
||||
|
||||
template <typename Continuation>
|
||||
auto operator()(Continuation&& continuation) {
|
||||
return base::attorney::create_from(std::forward<Continuation>(continuation),
|
||||
identity<Args...>{}, util::ownership{});
|
||||
}
|
||||
};
|
||||
|
||||
template <typename... Args>
|
||||
struct initiate_make_continuable<void(error_code_t, Args...)> {
|
||||
#if defined(CTI_DETAIL_ASIO_HAS_EXPLICIT_RET_TYPE_INTEGRATION)
|
||||
using erased_return_type = continuable<Args...>;
|
||||
#endif
|
||||
|
||||
template <typename Continuation>
|
||||
auto operator()(Continuation&& continuation) {
|
||||
return base::attorney::create_from(std::forward<Continuation>(continuation),
|
||||
identity<Args...>{}, util::ownership{});
|
||||
}
|
||||
};
|
||||
|
||||
template <typename... Args>
|
||||
struct initiate_make_continuable<void(error_code_t const&, Args...)>
|
||||
: initiate_make_continuable<void(error_code_t, Args...)> {};
|
||||
|
||||
struct map_default {
|
||||
constexpr map_default() noexcept {}
|
||||
|
||||
bool is_cancellation(error_code_t const& ec) const noexcept {
|
||||
// Continuable uses a default constructed exception type to signal
|
||||
// cancellation to the followed asynchronous control flow.
|
||||
return ec == basic_errors_t::operation_aborted;
|
||||
}
|
||||
bool is_ignored(error_code_t const& /*ec*/) const noexcept {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
struct map_none {
|
||||
constexpr map_none() noexcept {}
|
||||
|
||||
bool is_cancellation(error_code_t const& /*ec*/) const noexcept {
|
||||
return false;
|
||||
}
|
||||
bool is_ignored(error_code_t const& /*ec*/) const noexcept {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
template <std::size_t Size>
|
||||
class map_ignore {
|
||||
public:
|
||||
map_ignore(std::array<basic_errors_t, Size> ignored) noexcept
|
||||
: ignored_(ignored) {}
|
||||
|
||||
bool is_cancellation(error_code_t const& ec) const noexcept {
|
||||
return ec == basic_errors_t::operation_aborted;
|
||||
}
|
||||
bool is_ignored(error_code_t const& ec) const noexcept {
|
||||
for (basic_errors_t ignored : ignored_) {
|
||||
if (ec == ignored) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
std::array<basic_errors_t, Size> ignored_;
|
||||
};
|
||||
} // namespace asio
|
||||
} // namespace detail
|
||||
} // namespace cti
|
||||
|
||||
#endif // CONTINUABLE_DETAIL_ASIO_HPP_INCLUDED
|
||||
@ -5,9 +5,9 @@
|
||||
\_,(_)| | | || ||_|(_||_)|(/_
|
||||
|
||||
https://github.com/Naios/continuable
|
||||
v4.2.0
|
||||
v3.0.0
|
||||
|
||||
Copyright(c) 2015 - 2022 Denis Blank <denis.blank at outlook dot com>
|
||||
Copyright(c) 2015 - 2018 Denis Blank <denis.blank at outlook dot com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files(the "Software"), to deal
|
||||
@ -21,7 +21,7 @@
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
@ -33,19 +33,19 @@
|
||||
|
||||
// Defines CONTINUABLE_WITH_NO_EXCEPTIONS when exception support is disabled
|
||||
#ifndef CONTINUABLE_WITH_NO_EXCEPTIONS
|
||||
# if defined(_MSC_VER)
|
||||
# if !defined(_HAS_EXCEPTIONS) || (_HAS_EXCEPTIONS == 0)
|
||||
# define CONTINUABLE_WITH_NO_EXCEPTIONS
|
||||
# endif
|
||||
# elif defined(__clang__)
|
||||
# if !(__EXCEPTIONS && __has_feature(cxx_exceptions))
|
||||
# define CONTINUABLE_WITH_NO_EXCEPTIONS
|
||||
# endif
|
||||
# elif defined(__GNUC__)
|
||||
# if !__EXCEPTIONS
|
||||
# define CONTINUABLE_WITH_NO_EXCEPTIONS
|
||||
# endif
|
||||
# endif
|
||||
#if defined(_MSC_VER)
|
||||
#if !defined(_HAS_EXCEPTIONS) || (_HAS_EXCEPTIONS == 0)
|
||||
#define CONTINUABLE_WITH_NO_EXCEPTIONS
|
||||
#endif
|
||||
#elif defined(__clang__)
|
||||
#if !(__EXCEPTIONS && __has_feature(cxx_exceptions))
|
||||
#define CONTINUABLE_WITH_NO_EXCEPTIONS
|
||||
#endif
|
||||
#elif defined(__GNUC__)
|
||||
#if !__EXCEPTIONS
|
||||
#define CONTINUABLE_WITH_NO_EXCEPTIONS
|
||||
#endif
|
||||
#endif
|
||||
#endif // CONTINUABLE_WITH_NO_EXCEPTIONS
|
||||
|
||||
// clang-format off
|
||||
@ -55,11 +55,8 @@
|
||||
#define CONTINUABLE_HAS_CXX17_CONSTEXPR_IF
|
||||
#define CONTINUABLE_HAS_CXX17_DISJUNCTION
|
||||
#define CONTINUABLE_HAS_CXX17_CONJUNCTION
|
||||
#define CONTINUABLE_HAS_CXX17_VOID_T
|
||||
#else
|
||||
// Generic feature detection based on __has_feature
|
||||
// and other preprocessor definitions based on:
|
||||
// http://en.cppreference.com/w/User:D41D8CD98F/feature_testing_macros
|
||||
#if defined(__has_feature)
|
||||
#if !defined(CONTINUABLE_HAS_CXX17_CONSTEXPR_IF) && \
|
||||
__has_feature(cxx_if_constexpr)
|
||||
@ -78,49 +75,19 @@
|
||||
(__cpp_lib_experimental_logical_traits >= 201511)
|
||||
#define CONTINUABLE_HAS_CXX17_CONJUNCTION
|
||||
#endif
|
||||
|
||||
#if !defined(CONTINUABLE_HAS_CXX17_VOID_T) && \
|
||||
defined(__cpp_lib_void_t) && \
|
||||
(__cpp_lib_void_t >= 201411)
|
||||
#define CONTINUABLE_HAS_CXX17_VOID_T
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Automatically detects support for coroutines.
|
||||
// Parts of this detection mechanism were adapted from boost::asio,
|
||||
// with support added for experimental coroutines.
|
||||
#if !defined(CONTINUABLE_HAS_DISABLED_COROUTINE) \
|
||||
&& !defined(CONTINUABLE_HAS_COROUTINE)
|
||||
/// Define CONTINUABLE_HAS_EXPERIMENTAL_COROUTINE when
|
||||
/// CONTINUABLE_WITH_EXPERIMENTAL_COROUTINE is defined.
|
||||
#if defined(CONTINUABLE_WITH_EXPERIMENTAL_COROUTINE)
|
||||
#define CONTINUABLE_HAS_COROUTINE 1
|
||||
#elif defined(CONTINUABLE_WITH_COROUTINE)
|
||||
#define CONTINUABLE_HAS_COROUTINE 1
|
||||
#define CONTINUABLE_HAS_EXPERIMENTAL_COROUTINE 1
|
||||
#elif defined(_MSC_VER) // Visual Studio
|
||||
#if (_MSC_VER >= 1928) && (_MSVC_LANG >= 201705)
|
||||
#define CONTINUABLE_HAS_COROUTINE 1
|
||||
#elif _MSC_FULL_VER >= 190023506
|
||||
#if defined(_RESUMABLE_FUNCTIONS_SUPPORTED)
|
||||
#define CONTINUABLE_HAS_COROUTINE 1
|
||||
#define CONTINUABLE_HAS_EXPERIMENTAL_COROUTINE 1
|
||||
#endif // defined(_RESUMABLE_FUNCTIONS_SUPPORTED)
|
||||
#endif // _MSC_FULL_VER >= 190023506
|
||||
#elif defined(__clang__) // Clang
|
||||
#if defined(__cpp_coroutines) && (__cpp_coroutines >= 201703L)
|
||||
#define CONTINUABLE_HAS_COROUTINE 1
|
||||
#if defined(_LIBCPP_EXPERIMENTAL_COROUTINE)
|
||||
#define CONTINUABLE_HAS_EXPERIMENTAL_COROUTINE 1
|
||||
#endif
|
||||
#endif // defined(__cpp_coroutines) && (__cpp_coroutines >= 201703L)
|
||||
#elif defined(__GNUC__) // GCC
|
||||
#if (__cplusplus >= 201709) && (__cpp_impl_coroutine >= 201902)
|
||||
#if __has_include(<coroutine>)
|
||||
#define CONTINUABLE_HAS_COROUTINE 1
|
||||
#endif // __has_include(<coroutine>)
|
||||
#endif // (__cplusplus >= 201709) && (__cpp_impl_coroutine >= 201902)
|
||||
#endif
|
||||
/// Usually this is enabled by the CMake project
|
||||
#if !defined(CONTINUABLE_HAS_EXPERIMENTAL_COROUTINE) && \
|
||||
defined(__cpp_coroutines) && (__cpp_coroutines >= 201707)
|
||||
#define CONTINUABLE_HAS_EXPERIMENTAL_COROUTINE
|
||||
#endif
|
||||
|
||||
/// Define CONTINUABLE_HAS_EXPERIMENTAL_COROUTINE when
|
||||
/// CONTINUABLE_WITH_EXPERIMENTAL_COROUTINE is defined.
|
||||
#if !defined(CONTINUABLE_HAS_EXPERIMENTAL_COROUTINE) && \
|
||||
defined(CONTINUABLE_WITH_EXPERIMENTAL_COROUTINE)
|
||||
#define CONTINUABLE_HAS_EXPERIMENTAL_COROUTINE
|
||||
#endif
|
||||
|
||||
/// Define CONTINUABLE_HAS_EXCEPTIONS when exceptions are used
|
||||
@ -130,18 +97,6 @@
|
||||
#else
|
||||
#undef CONTINUABLE_HAS_EXCEPTIONS
|
||||
#endif
|
||||
|
||||
/// Define CONTINUABLE_HAS_IMMEDIATE_TYPES when either
|
||||
/// - CONTINUABLE_WITH_IMMEDIATE_TYPES is defined
|
||||
/// - Building in release mode (NDEBUG is defined)
|
||||
///
|
||||
/// Build error messages will become more readable in debug mode while
|
||||
/// we don't suffer any runtime penalty in release.
|
||||
#if defined(CONTINUABLE_WITH_IMMEDIATE_TYPES) || defined(NDEBUG)
|
||||
#define CONTINUABLE_HAS_IMMEDIATE_TYPES 1
|
||||
#else
|
||||
#undef CONTINUABLE_HAS_IMMEDIATE_TYPES
|
||||
#endif
|
||||
// clang-format on
|
||||
|
||||
#endif // CONTINUABLE_DETAIL_FEATURES_HPP_INCLUDED
|
||||
|
||||
357
include/continuable/detail/flat-variant.hpp
Normal file
357
include/continuable/detail/flat-variant.hpp
Normal file
@ -0,0 +1,357 @@
|
||||
|
||||
/*
|
||||
|
||||
/~` _ _ _|_. _ _ |_ | _
|
||||
\_,(_)| | | || ||_|(_||_)|(/_
|
||||
|
||||
https://github.com/Naios/continuable
|
||||
v3.0.0
|
||||
|
||||
Copyright(c) 2015 - 2018 Denis Blank <denis.blank at outlook dot com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files(the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions :
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
**/
|
||||
|
||||
#ifndef CONTINUABLE_DETAIL_FLAT_VARIANT_HPP_INCLUDED
|
||||
#define CONTINUABLE_DETAIL_FLAT_VARIANT_HPP_INCLUDED
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
#include <limits>
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#include <continuable/detail/traits.hpp>
|
||||
|
||||
namespace cti {
|
||||
namespace detail {
|
||||
namespace container {
|
||||
namespace detail {
|
||||
// We don't want to pull the algorithm header in
|
||||
template <typename... T>
|
||||
constexpr std::size_t max_element_of(std::initializer_list<std::size_t> list) {
|
||||
std::size_t m = 0;
|
||||
for (auto current : list) {
|
||||
if (current > m) {
|
||||
m = current;
|
||||
}
|
||||
}
|
||||
return m;
|
||||
}
|
||||
template <typename... T>
|
||||
constexpr auto storage_of_impl() {
|
||||
constexpr auto size = max_element_of({sizeof(T)...});
|
||||
constexpr auto align = max_element_of({alignof(T)...});
|
||||
return std::aligned_storage_t<size, align>{};
|
||||
}
|
||||
|
||||
/// Declares the aligned storage union for the given types
|
||||
template <typename... T>
|
||||
using storage_of_t = decltype(storage_of_impl<T...>());
|
||||
|
||||
/// The value fpr the empty slot
|
||||
using slot_t = std::uint8_t;
|
||||
|
||||
/// The value which is used to mark the empty slot
|
||||
using empty_slot =
|
||||
std::integral_constant<slot_t, std::numeric_limits<slot_t>::max()>;
|
||||
|
||||
template <typename... T>
|
||||
struct flat_variant_base {
|
||||
storage_of_t<T...> storage_;
|
||||
slot_t slot_;
|
||||
|
||||
constexpr flat_variant_base() : slot_(empty_slot::value) {
|
||||
}
|
||||
|
||||
flat_variant_base(flat_variant_base const&) noexcept {
|
||||
}
|
||||
flat_variant_base(flat_variant_base&&) noexcept {
|
||||
}
|
||||
flat_variant_base& operator=(flat_variant_base const&) {
|
||||
return *this;
|
||||
}
|
||||
flat_variant_base& operator=(flat_variant_base&&) {
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Base>
|
||||
struct flat_variant_move_base {
|
||||
constexpr flat_variant_move_base() = default;
|
||||
|
||||
flat_variant_move_base(flat_variant_move_base const&) = default;
|
||||
explicit flat_variant_move_base(flat_variant_move_base&& right) {
|
||||
Base& me = *static_cast<Base*>(this);
|
||||
Base& other = *static_cast<Base*>(&right);
|
||||
|
||||
if (other.is_empty()) {
|
||||
me.set_slot(empty_slot::value);
|
||||
} else {
|
||||
|
||||
other.visit([&](auto&& value) {
|
||||
#ifndef NDEBUG
|
||||
me.set_slot(empty_slot::value);
|
||||
#endif
|
||||
// NOLINTNEXTLINE(misc-move-forwarding-reference)
|
||||
me.init(std::move(value), other.get_slot());
|
||||
});
|
||||
}
|
||||
|
||||
other.destroy();
|
||||
}
|
||||
flat_variant_move_base& operator=(flat_variant_move_base const&) = default;
|
||||
flat_variant_move_base& operator=(flat_variant_move_base&& right) {
|
||||
Base& me = *static_cast<Base*>(this);
|
||||
Base& other = *static_cast<Base*>(&right);
|
||||
|
||||
me.weak_destroy();
|
||||
|
||||
if (other.is_empty()) {
|
||||
me.set_slot(empty_slot::value);
|
||||
} else {
|
||||
other.visit([&](auto&& value) {
|
||||
// ...
|
||||
me.init(std::move(value), other.get_slot());
|
||||
});
|
||||
}
|
||||
other.destroy();
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
template <typename Base, bool IsCopyable /*= true*/>
|
||||
struct flat_variant_copy_base : flat_variant_move_base<Base> {
|
||||
constexpr flat_variant_copy_base() = default;
|
||||
|
||||
flat_variant_copy_base(flat_variant_copy_base&&) = default;
|
||||
explicit flat_variant_copy_base(flat_variant_copy_base const& right)
|
||||
: flat_variant_move_base<Base>()
|
||||
// TODO noexcept(Base::is_nothrow_move_constructible)
|
||||
{
|
||||
Base& me = *static_cast<Base*>(this);
|
||||
Base const& other = *static_cast<Base const*>(&right);
|
||||
|
||||
if (other.is_empty()) {
|
||||
me.set_slot(empty_slot::value);
|
||||
} else {
|
||||
other.visit([&](auto&& value) {
|
||||
#ifndef NDEBUG
|
||||
me.set_slot(empty_slot::value);
|
||||
#endif
|
||||
me.init(std::move(value), other.get_slot());
|
||||
});
|
||||
}
|
||||
}
|
||||
flat_variant_copy_base& operator=(flat_variant_copy_base&&) = default;
|
||||
flat_variant_copy_base& operator=(flat_variant_copy_base const& right)
|
||||
// TODO noexcept(Base::is_nothrow_move_constructible)
|
||||
{
|
||||
Base& me = *static_cast<Base*>(this);
|
||||
Base const& other = *static_cast<Base const*>(&right);
|
||||
|
||||
me.weak_destroy();
|
||||
|
||||
if (other.is_empty()) {
|
||||
me.set_slot(empty_slot::value);
|
||||
} else {
|
||||
other.visit([&](auto&& value) {
|
||||
// ...
|
||||
me.init(std::move(value), other.get_slot());
|
||||
});
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
template <typename Base /*, bool IsCopyable = false*/>
|
||||
struct flat_variant_copy_base<Base, false> : flat_variant_move_base<Base> {
|
||||
constexpr flat_variant_copy_base() = default;
|
||||
|
||||
flat_variant_copy_base(flat_variant_copy_base const&) = delete;
|
||||
explicit flat_variant_copy_base(flat_variant_copy_base&& right) = default;
|
||||
flat_variant_copy_base& operator=(flat_variant_copy_base const&) = delete;
|
||||
flat_variant_copy_base& operator=(flat_variant_copy_base&&) = default;
|
||||
};
|
||||
|
||||
/// Deduces to a true_type if all parameters T satisfy the predicate.
|
||||
template <template <typename> class Predicate, typename... T>
|
||||
using every = traits::conjunction<Predicate<T>...>;
|
||||
} // namespace detail
|
||||
|
||||
/// A class similar to the one in the variant proposal,
|
||||
/// however it is capable of carrying an empty state by default.
|
||||
template <typename... T>
|
||||
class flat_variant;
|
||||
|
||||
template <typename T>
|
||||
struct is_flat_variant : std::false_type {};
|
||||
template <typename... T>
|
||||
struct is_flat_variant<flat_variant<T...>> : std::true_type {};
|
||||
|
||||
template <typename... T>
|
||||
class flat_variant
|
||||
: detail::flat_variant_copy_base<
|
||||
flat_variant<T...>,
|
||||
detail::every<std::is_copy_constructible, T...>::value>,
|
||||
detail::flat_variant_base<T...> {
|
||||
|
||||
static_assert(sizeof...(T) > 0, "At least one paremeter T is required!");
|
||||
|
||||
template <typename...>
|
||||
friend class flat_variant;
|
||||
template <typename>
|
||||
friend struct detail::flat_variant_move_base;
|
||||
template <typename, bool>
|
||||
friend struct detail::flat_variant_copy_base;
|
||||
|
||||
template <typename V>
|
||||
flat_variant(V&& value, detail::slot_t const slot) {
|
||||
#ifndef NDEBUG
|
||||
set_slot(detail::empty_slot::value);
|
||||
#endif
|
||||
init(std::forward<V>(value), slot);
|
||||
}
|
||||
|
||||
public:
|
||||
constexpr flat_variant() = default;
|
||||
flat_variant(flat_variant const&) = default;
|
||||
flat_variant(flat_variant&&) = default;
|
||||
flat_variant& operator=(flat_variant const&) = default;
|
||||
flat_variant& operator=(flat_variant&&) = default;
|
||||
|
||||
~flat_variant() noexcept(
|
||||
detail::every<std::is_nothrow_destructible, T...>::value) {
|
||||
weak_destroy();
|
||||
}
|
||||
|
||||
template <
|
||||
typename V,
|
||||
std::enable_if_t<!is_flat_variant<std::decay_t<V>>::value>* = nullptr>
|
||||
// Since the flat_variant isn't allowed through SFINAE
|
||||
// this overload is safed against the linted issue.
|
||||
// NOLINTNEXTLINE(misc-forwarding-reference-overload)
|
||||
explicit flat_variant(V&& value)
|
||||
: flat_variant(std::forward<V>(value),
|
||||
traits::index_of_t<std::decay_t<V>, T...>::value) {
|
||||
}
|
||||
|
||||
template <
|
||||
typename V,
|
||||
std::enable_if_t<!is_flat_variant<std::decay_t<V>>::value>* = nullptr>
|
||||
flat_variant& operator=(V&& value) {
|
||||
weak_destroy();
|
||||
init(std::forward<V>(value),
|
||||
traits::index_of_t<std::decay_t<V>, T...>::value);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename V, std::size_t Index =
|
||||
traits::index_of_t<std::decay_t<V>, T...>::value>
|
||||
bool is() const noexcept {
|
||||
return is_slot(Index);
|
||||
}
|
||||
|
||||
bool is_empty() const noexcept {
|
||||
return is_slot(detail::empty_slot::value);
|
||||
}
|
||||
|
||||
explicit constexpr operator bool() const noexcept {
|
||||
return !is_empty();
|
||||
}
|
||||
|
||||
template <typename V>
|
||||
V& cast() noexcept {
|
||||
assert(is_slot(traits::index_of_t<std::decay_t<V>, T...>::value));
|
||||
return *reinterpret_cast<std::decay_t<V>*>(&this->storage_);
|
||||
}
|
||||
|
||||
template <typename V>
|
||||
V const& cast() const noexcept {
|
||||
assert(is_slot(traits::index_of_t<std::decay_t<V>, T...>::value));
|
||||
return *reinterpret_cast<std::decay_t<V> const*>(&this->storage_);
|
||||
}
|
||||
|
||||
private:
|
||||
template <typename C, typename V>
|
||||
static void visit_dispatch(flat_variant* me, V&& visitor) {
|
||||
std::forward<V>(visitor)(me->cast<C>());
|
||||
}
|
||||
template <typename C, typename V>
|
||||
static void visit_dispatch_const(flat_variant const* me, V&& visitor) {
|
||||
std::forward<V>(visitor)(me->cast<C>());
|
||||
}
|
||||
|
||||
template <typename V>
|
||||
void visit(V&& visitor) {
|
||||
if (!is_empty()) {
|
||||
using callback_t = void (*)(flat_variant*, V &&);
|
||||
constexpr callback_t const callbacks[] = {&visit_dispatch<T, V>...};
|
||||
callbacks[get_slot()](this, std::forward<V>(visitor));
|
||||
}
|
||||
}
|
||||
template <typename V>
|
||||
void visit(V&& visitor) const {
|
||||
if (!is_empty()) {
|
||||
using callback_t = void (*)(flat_variant const*, V&&);
|
||||
constexpr callback_t const callbacks[] = {&visit_dispatch_const<T, V>...};
|
||||
callbacks[get_slot()](this, std::forward<V>(visitor));
|
||||
}
|
||||
}
|
||||
|
||||
template <typename V>
|
||||
void init(V&& value, detail::slot_t const slot) {
|
||||
assert(is_empty());
|
||||
assert(sizeof(this->storage_) >= sizeof(std::decay_t<V>));
|
||||
|
||||
using type = std::decay_t<V>;
|
||||
new (&this->storage_) type(std::forward<V>(value));
|
||||
set_slot(slot);
|
||||
}
|
||||
void destroy() {
|
||||
weak_destroy();
|
||||
|
||||
#ifdef NDEBUG
|
||||
set_slot(detail::empty_slot::value);
|
||||
#endif
|
||||
}
|
||||
void weak_destroy() {
|
||||
visit([&](auto&& value) {
|
||||
using type = std::decay_t<decltype(value)>;
|
||||
value.~type();
|
||||
});
|
||||
|
||||
#ifndef NDEBUG
|
||||
set_slot(detail::empty_slot::value);
|
||||
#endif
|
||||
}
|
||||
detail::slot_t get_slot() const noexcept {
|
||||
return this->slot_;
|
||||
}
|
||||
bool is_slot(detail::slot_t const slot) const noexcept {
|
||||
return get_slot() == slot;
|
||||
}
|
||||
void set_slot(detail::slot_t const slot) {
|
||||
this->slot_ = slot;
|
||||
}
|
||||
};
|
||||
} // namespace container
|
||||
} // namespace detail
|
||||
} // namespace cti
|
||||
|
||||
#endif // CONTINUABLE_DETAIL_FLAT_VARIANT_HPP_INCLUDED
|
||||
@ -5,9 +5,9 @@
|
||||
\_,(_)| | | || ||_|(_||_)|(/_
|
||||
|
||||
https://github.com/Naios/continuable
|
||||
v4.2.0
|
||||
v3.0.0
|
||||
|
||||
Copyright(c) 2015 - 2022 Denis Blank <denis.blank at outlook dot com>
|
||||
Copyright(c) 2015 - 2018 Denis Blank <denis.blank at outlook dot com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files(the "Software"), to deal
|
||||
@ -21,33 +21,51 @@
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
**/
|
||||
|
||||
#ifndef CONTINUABLE_DETAIL_ANNOTATION_HPP_INCLUDED
|
||||
#define CONTINUABLE_DETAIL_ANNOTATION_HPP_INCLUDED
|
||||
#ifndef CONTINUABLE_DETAIL_HINTS_HPP_INCLUDED
|
||||
#define CONTINUABLE_DETAIL_HINTS_HPP_INCLUDED
|
||||
|
||||
#include <type_traits>
|
||||
#include <continuable/detail/core/types.hpp>
|
||||
#include <continuable/detail/utility/traits.hpp>
|
||||
|
||||
#include <continuable/detail/traits.hpp>
|
||||
#include <continuable/detail/types.hpp>
|
||||
|
||||
namespace cti {
|
||||
namespace detail {
|
||||
namespace hints {
|
||||
/// Represents a present signature hint
|
||||
template <typename... Args>
|
||||
using signature_hint_tag = traits::identity<Args...>;
|
||||
|
||||
/// Returns the signature hint of the given continuable
|
||||
template <typename Data, typename... Args>
|
||||
constexpr auto
|
||||
hint_of(traits::identity<continuable_base<Data, signature_hint_tag<Args...>>>) {
|
||||
return hints::signature_hint_tag<Args...>{};
|
||||
}
|
||||
|
||||
/// Extracts the signature we pass to the internal continuable
|
||||
/// from an argument pack as specified by make_continuable.
|
||||
///
|
||||
/// This is the overload taking an arbitrary amount of args
|
||||
template <typename... HintArgs>
|
||||
struct from_args : std::common_type<signature_arg_t<HintArgs...>> {};
|
||||
template <>
|
||||
struct from_args<void> : std::common_type<signature_arg_t<>> {};
|
||||
constexpr auto extract(traits::identity<HintArgs...> hint) {
|
||||
return hint;
|
||||
}
|
||||
/// \copybrief extract
|
||||
///
|
||||
/// This is the overload taking a void arg.
|
||||
constexpr auto extract(traits::identity<void> /*hint*/) {
|
||||
return traits::identity<>{};
|
||||
}
|
||||
} // namespace hints
|
||||
} // namespace detail
|
||||
} // namespace cti
|
||||
|
||||
#endif // CONTINUABLE_DETAIL_ANNOTATION_HPP_INCLUDED
|
||||
#endif // CONTINUABLE_DETAIL_HINTS_HPP_INCLUDED
|
||||
@ -1,80 +0,0 @@
|
||||
|
||||
/*
|
||||
|
||||
/~` _ _ _|_. _ _ |_ | _
|
||||
\_,(_)| | | || ||_|(_||_)|(/_
|
||||
|
||||
https://github.com/Naios/continuable
|
||||
v4.2.0
|
||||
|
||||
Copyright(c) 2015 - 2022 Denis Blank <denis.blank at outlook dot com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files(the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions :
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
**/
|
||||
|
||||
#ifndef CONTINUABLE_DETAIL_OPERATIONS_ASYNC_HPP_INCLUDED
|
||||
#define CONTINUABLE_DETAIL_OPERATIONS_ASYNC_HPP_INCLUDED
|
||||
|
||||
#include <continuable/continuable-base.hpp>
|
||||
#include <continuable/detail/core/annotation.hpp>
|
||||
#include <continuable/detail/core/base.hpp>
|
||||
#include <continuable/detail/utility/identity.hpp>
|
||||
|
||||
namespace cti {
|
||||
namespace detail {
|
||||
namespace operations {
|
||||
template <typename Callable, typename Executor, typename... Args>
|
||||
auto async(Callable&& callable, Executor&& executor, Args&&... args) {
|
||||
using result_t =
|
||||
decltype(util::invoke(std::forward<decltype(callable)>(callable),
|
||||
std::forward<decltype(args)>(args)...));
|
||||
|
||||
constexpr auto hint =
|
||||
decltype(base::decoration::invoker_of(identity<result_t>{}))::hint();
|
||||
|
||||
auto continuation = [callable = std::forward<decltype(callable)>(callable),
|
||||
executor = std::forward<decltype(executor)>(executor),
|
||||
args = std::make_tuple(std::forward<decltype(args)>(
|
||||
args)...)](auto&& promise) mutable {
|
||||
auto invoker = base::decoration::invoker_of(identity<result_t>{});
|
||||
|
||||
using promise_t = decltype(promise);
|
||||
|
||||
// Invoke the callback
|
||||
traits::unpack(
|
||||
[&](auto&&... args) mutable {
|
||||
// Invoke the promise through the dedicated invoker
|
||||
// and through the given executor
|
||||
base::on_executor(std::move(executor), std::move(invoker),
|
||||
std::move(callable),
|
||||
std::forward<promise_t>(promise),
|
||||
std::forward<decltype(args)>(args)...);
|
||||
},
|
||||
std::move(args));
|
||||
};
|
||||
|
||||
return base::attorney::create_from(std::move(continuation), //
|
||||
hint, util::ownership{});
|
||||
}
|
||||
} // namespace operations
|
||||
|
||||
} // namespace detail
|
||||
} // namespace cti
|
||||
|
||||
#endif // CONTINUABLE_DETAIL_OPERATIONS_ASYNC_HPP_INCLUDED
|
||||
@ -1,180 +0,0 @@
|
||||
|
||||
/*
|
||||
|
||||
/~` _ _ _|_. _ _ |_ | _
|
||||
\_,(_)| | | || ||_|(_||_)|(/_
|
||||
|
||||
https://github.com/Naios/continuable
|
||||
v4.2.0
|
||||
|
||||
Copyright(c) 2015 - 2022 Denis Blank <denis.blank at outlook dot com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files(the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions :
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
**/
|
||||
|
||||
#ifndef CONTINUABLE_DETAIL_OPERATIONS_LOOP_HPP_INCLUDED
|
||||
#define CONTINUABLE_DETAIL_OPERATIONS_LOOP_HPP_INCLUDED
|
||||
|
||||
#include <cassert>
|
||||
#include <memory>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <continuable/continuable-base.hpp>
|
||||
#include <continuable/continuable-result.hpp>
|
||||
#include <continuable/detail/features.hpp>
|
||||
#include <continuable/detail/utility/traits.hpp>
|
||||
#include <continuable/detail/utility/util.hpp>
|
||||
|
||||
#if defined(CONTINUABLE_HAS_EXCEPTIONS)
|
||||
#include <exception>
|
||||
#endif // CONTINUABLE_HAS_EXCEPTIONS
|
||||
|
||||
namespace cti {
|
||||
namespace detail {
|
||||
template <typename T>
|
||||
struct loop_trait {
|
||||
static_assert(!std::is_same<T, T>::value,
|
||||
"The callable passed to cti::loop must always return a "
|
||||
"cti::continuable_base which resolves to a cti::result.");
|
||||
};
|
||||
|
||||
template <typename... Args>
|
||||
struct loop_trait<identity<result<Args...>>> {
|
||||
template <typename Callable>
|
||||
static auto make(Callable&& callable) {
|
||||
return make_continuable<Args...>(std::forward<Callable>(callable));
|
||||
}
|
||||
};
|
||||
template <>
|
||||
struct loop_trait<identity<result<>>> {
|
||||
template <typename Callable>
|
||||
static auto make(Callable&& callable) {
|
||||
return make_continuable<void>(std::forward<Callable>(callable));
|
||||
}
|
||||
};
|
||||
|
||||
namespace operations {
|
||||
template <typename Promise, typename Callable, typename ArgsTuple>
|
||||
class loop_frame : public std::enable_shared_from_this<
|
||||
loop_frame<Promise, Callable, ArgsTuple>> {
|
||||
Promise promise_;
|
||||
Callable callable_;
|
||||
ArgsTuple args_;
|
||||
|
||||
public:
|
||||
explicit loop_frame(Promise promise, Callable callable, ArgsTuple args)
|
||||
: promise_(std::move(promise)), callable_(std::move(callable)),
|
||||
args_(std::move(args)) {
|
||||
}
|
||||
|
||||
void loop() {
|
||||
// MSVC can't evaluate this inside the lambda capture
|
||||
auto me = this->shared_from_this();
|
||||
|
||||
traits::unpack(
|
||||
[&](auto&&... args) mutable {
|
||||
|
||||
#if defined(CONTINUABLE_HAS_EXCEPTIONS)
|
||||
try {
|
||||
#endif // CONTINUABLE_HAS_EXCEPTIONS
|
||||
|
||||
util::invoke(callable_, std::forward<decltype(args)>(args)...)
|
||||
.next([me = std::move(me)](auto&&... args) {
|
||||
me->resolve(std::forward<decltype(args)>(args)...);
|
||||
});
|
||||
|
||||
#if defined(CONTINUABLE_HAS_EXCEPTIONS)
|
||||
} catch (...) {
|
||||
me->resolve(exception_arg_t{}, std::current_exception());
|
||||
}
|
||||
#endif // CONTINUABLE_HAS_EXCEPTIONS
|
||||
},
|
||||
args_);
|
||||
}
|
||||
|
||||
template <typename Result>
|
||||
void resolve(Result&& result) {
|
||||
if (result.is_empty()) {
|
||||
loop();
|
||||
} else if (result.is_value()) {
|
||||
traits::unpack(std::move(promise_), std::forward<Result>(result));
|
||||
} else {
|
||||
assert(result.is_exception());
|
||||
std::move(promise_).set_exception(
|
||||
std::forward<Result>(result).get_exception());
|
||||
}
|
||||
}
|
||||
|
||||
void resolve(exception_arg_t, exception_t exception) {
|
||||
promise_.set_exception(std::move(exception));
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Promise, typename Callable, typename ArgsTuple>
|
||||
auto make_loop_frame(Promise&& promise, Callable&& callable,
|
||||
ArgsTuple&& args_tuple) {
|
||||
using frame_t =
|
||||
loop_frame<traits::unrefcv_t<Promise>, traits::unrefcv_t<Callable>,
|
||||
traits::unrefcv_t<ArgsTuple>>;
|
||||
|
||||
return std::make_shared<frame_t>(std::forward<Promise>(promise),
|
||||
std::forward<Callable>(callable),
|
||||
std::forward<ArgsTuple>(args_tuple));
|
||||
}
|
||||
|
||||
template <typename Callable, typename... Args>
|
||||
auto loop(Callable&& callable, Args&&... args) {
|
||||
using invocation_result_t =
|
||||
decltype(util::invoke(callable, args...).finish());
|
||||
|
||||
auto constexpr hint = base::annotation_of(identify<invocation_result_t>{});
|
||||
|
||||
using trait_t = loop_trait<std::remove_const_t<decltype(hint)>>;
|
||||
|
||||
return trait_t::make([callable = std::forward<decltype(callable)>(callable),
|
||||
args = std::make_tuple(std::forward<decltype(args)>(
|
||||
args)...)](auto&& promise) mutable {
|
||||
// Do the actual looping
|
||||
auto frame = make_loop_frame(std::forward<decltype(promise)>(promise),
|
||||
std::move(callable), std::move(args));
|
||||
frame->loop();
|
||||
});
|
||||
}
|
||||
|
||||
template <typename Callable, typename Begin, typename End>
|
||||
auto make_range_looper(Callable&& callable, Begin&& begin, End&& end) {
|
||||
return [callable = std::forward<Callable>(callable),
|
||||
begin = std::forward<Begin>(begin),
|
||||
end = std::forward<End>(end)]() mutable {
|
||||
return util::invoke(callable, begin)
|
||||
.then([&begin, &end]() mutable -> plain_t<result<>> {
|
||||
// begin and end stays valid over the `then` here
|
||||
if (++begin != end) {
|
||||
return make_plain(result<>::empty());
|
||||
} else {
|
||||
return make_plain(make_result());
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
} // namespace operations
|
||||
} // namespace detail
|
||||
} // namespace cti
|
||||
|
||||
#endif // CONTINUABLE_DETAIL_OPERATIONS_LOOP_HPP_INCLUDED
|
||||
@ -1,118 +0,0 @@
|
||||
|
||||
/*
|
||||
|
||||
/~` _ _ _|_. _ _ |_ | _
|
||||
\_,(_)| | | || ||_|(_||_)|(/_
|
||||
|
||||
https://github.com/Naios/continuable
|
||||
v4.2.0
|
||||
|
||||
Copyright(c) 2015 - 2022 Denis Blank <denis.blank at outlook dot com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files(the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions :
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
**/
|
||||
|
||||
#ifndef CONTINUABLE_DETAIL_OPERATIONS_SPLIT_HPP_INCLUDED
|
||||
#define CONTINUABLE_DETAIL_OPERATIONS_SPLIT_HPP_INCLUDED
|
||||
|
||||
#include <tuple>
|
||||
#include <utility>
|
||||
#include <continuable/continuable-base.hpp>
|
||||
#include <continuable/continuable-traverse.hpp>
|
||||
#include <continuable/continuable-types.hpp>
|
||||
#include <continuable/detail/utility/traits.hpp>
|
||||
|
||||
namespace cti {
|
||||
namespace detail {
|
||||
namespace operations {
|
||||
template <typename T, bool Else, typename = void>
|
||||
struct operator_bool_or {
|
||||
template <typename O>
|
||||
static bool get(O&& /*obj*/) noexcept {
|
||||
return Else;
|
||||
}
|
||||
};
|
||||
template <typename T, bool Else>
|
||||
struct operator_bool_or<T, Else,
|
||||
traits::void_t<decltype(bool(std::declval<T&>()))>> {
|
||||
template <typename O>
|
||||
static bool get(O&& obj) noexcept {
|
||||
return bool(obj);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename First, typename... Promises>
|
||||
class split_promise {
|
||||
First first_;
|
||||
std::tuple<Promises...> promises_;
|
||||
|
||||
public:
|
||||
explicit split_promise(First first, Promises... promises)
|
||||
: first_(std::move(first)), promises_(std::move(promises)...) {
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
void operator()(Args&&... args) && {
|
||||
traverse_pack(
|
||||
[&](auto&& promise) mutable -> void {
|
||||
using accessor =
|
||||
operator_bool_or<traits::unrefcv_t<decltype(promise)>, true>;
|
||||
if (accessor::get(promise)) {
|
||||
std::forward<decltype(promise)>(promise)(args...);
|
||||
}
|
||||
},
|
||||
std::move(promises_));
|
||||
|
||||
if (operator_bool_or<First, true>::get(first_)) {
|
||||
std::move(first_)(std::forward<Args>(args)...);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
void set_value(Args... args) noexcept {
|
||||
std::move (*this)(std::move(args)...);
|
||||
}
|
||||
|
||||
void set_exception(exception_t error) noexcept {
|
||||
std::move (*this)(exception_arg_t{}, std::move(error));
|
||||
}
|
||||
|
||||
void set_canceled() noexcept {
|
||||
std::move (*this)(exception_arg_t{}, exception_t{});
|
||||
}
|
||||
|
||||
explicit operator bool() const noexcept {
|
||||
bool is_valid = operator_bool_or<First, true>::get(first_);
|
||||
traverse_pack(
|
||||
[&](auto&& promise) mutable -> void {
|
||||
using accessor =
|
||||
operator_bool_or<traits::unrefcv_t<decltype(promise)>, true>;
|
||||
if (!is_valid && accessor::get(promise)) {
|
||||
is_valid = true;
|
||||
}
|
||||
},
|
||||
promises_);
|
||||
return is_valid;
|
||||
}
|
||||
};
|
||||
} // namespace operations
|
||||
} // namespace detail
|
||||
} // namespace cti
|
||||
|
||||
#endif // CONTINUABLE_DETAIL_OPERATIONS_SPLIT_HPP_INCLUDED
|
||||
@ -1,273 +0,0 @@
|
||||
|
||||
/*
|
||||
|
||||
/~` _ _ _|_. _ _ |_ | _
|
||||
\_,(_)| | | || ||_|(_||_)|(/_
|
||||
|
||||
https://github.com/Naios/continuable
|
||||
v4.2.0
|
||||
|
||||
Copyright(c) 2015 - 2022 Denis Blank <denis.blank at outlook dot com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files(the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions :
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
**/
|
||||
|
||||
// Exclude this header when coroutines are not available
|
||||
#ifndef CONTINUABLE_DETAIL_AWAITING_HPP_INCLUDED
|
||||
#define CONTINUABLE_DETAIL_AWAITING_HPP_INCLUDED
|
||||
|
||||
#include <cassert>
|
||||
#include <type_traits>
|
||||
#include <continuable/continuable-primitives.hpp>
|
||||
#include <continuable/continuable-result.hpp>
|
||||
#include <continuable/detail/core/annotation.hpp>
|
||||
#include <continuable/detail/core/base.hpp>
|
||||
#include <continuable/detail/core/types.hpp>
|
||||
#include <continuable/detail/features.hpp>
|
||||
#include <continuable/detail/utility/traits.hpp>
|
||||
#include <continuable/detail/utility/util.hpp>
|
||||
|
||||
#if defined(CONTINUABLE_HAS_EXCEPTIONS)
|
||||
# include <exception>
|
||||
#endif // CONTINUABLE_HAS_EXCEPTIONS
|
||||
|
||||
#if defined(CONTINUABLE_HAS_EXPERIMENTAL_COROUTINE)
|
||||
# include <experimental/coroutine>
|
||||
#elif defined(CONTINUABLE_HAS_COROUTINE)
|
||||
# include <coroutine>
|
||||
#endif
|
||||
|
||||
#if defined(CONTINUABLE_HAS_COROUTINE)
|
||||
namespace cti {
|
||||
namespace detail {
|
||||
namespace awaiting {
|
||||
/// We import the coroutine handle in our namespace
|
||||
# if defined(CONTINUABLE_HAS_EXPERIMENTAL_COROUTINE)
|
||||
using std::experimental::coroutine_handle;
|
||||
using std::experimental::suspend_never;
|
||||
# else
|
||||
using std::coroutine_handle;
|
||||
using std::suspend_never;
|
||||
# endif
|
||||
|
||||
# if defined(CONTINUABLE_HAS_EXCEPTIONS)
|
||||
class await_canceled_exception : public std::exception {
|
||||
public:
|
||||
await_canceled_exception() noexcept = default;
|
||||
|
||||
char const* what() const noexcept override {
|
||||
return "co_await canceled due to cancellation of the continuation";
|
||||
}
|
||||
};
|
||||
# endif // CONTINUABLE_HAS_EXCEPTIONS
|
||||
|
||||
template <typename T>
|
||||
struct result_from_identity;
|
||||
template <typename... T>
|
||||
struct result_from_identity<identity<T...>> {
|
||||
using result_t = result<T...>;
|
||||
};
|
||||
|
||||
/// An object which provides the internal buffer and helper methods
|
||||
/// for waiting on a continuable in a stackless coroutine.
|
||||
template <typename Continuable>
|
||||
class awaitable {
|
||||
using hint_t = decltype(base::annotation_of(identify<Continuable>{}));
|
||||
using result_t = typename result_from_identity<hint_t>::result_t;
|
||||
|
||||
/// The continuable which is invoked upon suspension
|
||||
Continuable continuable_;
|
||||
/// A cache which is used to pass the result of the continuation
|
||||
/// to the coroutine.
|
||||
result_t result_;
|
||||
/// Enumeration that represents the suspension state of the awaitable.
|
||||
enum class state : std::uint8_t {
|
||||
suspended,
|
||||
pending,
|
||||
resolved,
|
||||
};
|
||||
/// An atomic that specifies whether the awaitable has suspended or not.
|
||||
/// Allows to perform symmetric transfer on continuables that are
|
||||
/// immediately resolved.
|
||||
std::atomic<state> state_{state::pending};
|
||||
|
||||
public:
|
||||
explicit constexpr awaitable(Continuable&& continuable)
|
||||
: continuable_(std::move(continuable)) {
|
||||
|
||||
// If the continuable is ready resolve the result from the
|
||||
// continuable immediately.
|
||||
if (base::attorney::is_ready(continuable_)) {
|
||||
assert(result_.is_empty());
|
||||
result_ = base::attorney::query(std::move(continuable_));
|
||||
}
|
||||
}
|
||||
|
||||
/// Return whether the continuable can provide its result instantly,
|
||||
/// which also means its execution is side-effect free.
|
||||
bool await_ready() const noexcept {
|
||||
return !result_.is_empty();
|
||||
}
|
||||
|
||||
/// Suspend the current context
|
||||
// TODO Convert this to an r-value function once possible
|
||||
bool await_suspend(coroutine_handle<> h) {
|
||||
assert(result_.is_empty());
|
||||
// Forward every result to the current awaitable
|
||||
std::move(continuable_)
|
||||
.next([h, this](auto&&... args) mutable {
|
||||
assert(result_.is_empty());
|
||||
result_ = result_t::from(std::forward<decltype(args)>(args)...);
|
||||
|
||||
// If true, it means that the promise was suspended (i.e., the
|
||||
// awaitable await_suspend method has already returned). That
|
||||
// means we must call the resume coroutine from the continuation
|
||||
// chain.
|
||||
if (state_.exchange(state::resolved, std::memory_order_acq_rel) ==
|
||||
state::suspended) {
|
||||
return h.resume();
|
||||
}
|
||||
})
|
||||
.done();
|
||||
|
||||
return state_.exchange(state::suspended, std::memory_order_acq_rel) !=
|
||||
state::resolved;
|
||||
}
|
||||
|
||||
/// Resume the coroutine represented by the handle
|
||||
typename result_t::value_t await_resume() noexcept(false) {
|
||||
if (result_.is_value()) {
|
||||
// When the result was resolved return it
|
||||
return std::move(result_).get_value();
|
||||
}
|
||||
|
||||
assert(result_.is_exception());
|
||||
|
||||
# if defined(CONTINUABLE_HAS_EXCEPTIONS)
|
||||
if (exception_t e = result_.get_exception()) {
|
||||
std::rethrow_exception(std::move(e));
|
||||
} else {
|
||||
throw await_canceled_exception();
|
||||
}
|
||||
# else // CONTINUABLE_HAS_EXCEPTIONS
|
||||
// Returning error types from co_await isn't supported!
|
||||
CTI_DETAIL_TRAP();
|
||||
# endif // CONTINUABLE_HAS_EXCEPTIONS
|
||||
}
|
||||
};
|
||||
|
||||
/// Converts a continuable into an awaitable object as described by
|
||||
/// the C++ coroutine TS.
|
||||
template <typename T>
|
||||
constexpr auto create_awaiter(T&& continuable) {
|
||||
return awaitable<std::decay_t<T>>(std::forward<T>(continuable));
|
||||
}
|
||||
|
||||
/// This makes it possible to take the coroutine_handle over on suspension
|
||||
struct handle_takeover {
|
||||
coroutine_handle<>& handle_;
|
||||
|
||||
bool await_ready() noexcept {
|
||||
return false;
|
||||
}
|
||||
|
||||
void await_suspend(coroutine_handle<> handle) noexcept {
|
||||
handle_ = handle;
|
||||
}
|
||||
|
||||
void await_resume() noexcept {}
|
||||
};
|
||||
|
||||
/// The type which is passed to the compiler that describes the properties
|
||||
/// of a continuable_base used as coroutine promise type.
|
||||
template <typename Continuable, typename Promise, typename... Args>
|
||||
struct promise_type;
|
||||
|
||||
/// Implements the resolving method return_void and return_value accordingly
|
||||
template <typename Base>
|
||||
struct promise_resolver_base;
|
||||
|
||||
template <typename Continuable, typename Promise>
|
||||
struct promise_resolver_base<promise_type<Continuable, Promise>> {
|
||||
void return_void() {
|
||||
auto me = static_cast<promise_type<Continuable, Promise>*>(this);
|
||||
me->promise_.set_value();
|
||||
}
|
||||
};
|
||||
template <typename Continuable, typename Promise, typename T>
|
||||
struct promise_resolver_base<promise_type<Continuable, Promise, T>> {
|
||||
void return_value(T value) {
|
||||
auto me = static_cast<promise_type<Continuable, Promise, T>*>(this);
|
||||
me->promise_.set_value(std::move(value));
|
||||
}
|
||||
};
|
||||
template <typename Continuable, typename Promise, typename... Args>
|
||||
struct promise_resolver_base<promise_type<Continuable, Promise, Args...>> {
|
||||
template <typename T>
|
||||
void return_value(T&& tuple_like) {
|
||||
auto me = static_cast<promise_type<Continuable, Promise, Args...>*>(this);
|
||||
traits::unpack(std::move(me->promise_), std::forward<T>(tuple_like));
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Continuable, typename Promise, typename... Args>
|
||||
struct promise_type
|
||||
: promise_resolver_base<promise_type<Continuable, Promise, Args...>> {
|
||||
|
||||
coroutine_handle<> handle_;
|
||||
Promise promise_;
|
||||
|
||||
explicit promise_type() = default;
|
||||
|
||||
Continuable get_return_object() {
|
||||
return [this](auto&& promise) {
|
||||
promise_ = std::forward<decltype(promise)>(promise);
|
||||
handle_.resume();
|
||||
};
|
||||
}
|
||||
|
||||
handle_takeover initial_suspend() {
|
||||
return {handle_};
|
||||
}
|
||||
|
||||
suspend_never final_suspend() noexcept {
|
||||
return {};
|
||||
}
|
||||
|
||||
void unhandled_exception() noexcept {
|
||||
# if defined(CONTINUABLE_HAS_EXCEPTIONS)
|
||||
try {
|
||||
std::rethrow_exception(std::current_exception());
|
||||
} catch (await_canceled_exception const&) {
|
||||
promise_.set_canceled();
|
||||
} catch (...) {
|
||||
promise_.set_exception(std::current_exception());
|
||||
}
|
||||
# else // CONTINUABLE_HAS_EXCEPTIONS
|
||||
// Returning exception types from a coroutine isn't supported
|
||||
CTI_DETAIL_TRAP();
|
||||
# endif // CONTINUABLE_HAS_EXCEPTIONS
|
||||
}
|
||||
};
|
||||
} // namespace awaiting
|
||||
} // namespace detail
|
||||
} // namespace cti
|
||||
#endif // defined(CONTINUABLE_HAS_COROUTINE)
|
||||
|
||||
#endif // CONTINUABLE_DETAIL_UTIL_HPP_INCLUDED
|
||||
@ -1,241 +0,0 @@
|
||||
|
||||
/*
|
||||
|
||||
/~` _ _ _|_. _ _ |_ | _
|
||||
\_,(_)| | | || ||_|(_||_)|(/_
|
||||
|
||||
https://github.com/Naios/continuable
|
||||
v4.2.0
|
||||
|
||||
Copyright(c) 2015 - 2022 Denis Blank <denis.blank at outlook dot com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files(the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions :
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
**/
|
||||
|
||||
#ifndef CONTINUABLE_DETAIL_ERASURE_HPP_INCLUDED
|
||||
#define CONTINUABLE_DETAIL_ERASURE_HPP_INCLUDED
|
||||
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <function2/function2.hpp>
|
||||
#include <continuable/detail/core/base.hpp>
|
||||
#include <continuable/detail/features.hpp>
|
||||
#include <continuable/detail/utility/traits.hpp>
|
||||
|
||||
namespace cti {
|
||||
namespace detail {
|
||||
namespace erasure {
|
||||
template <typename... Args>
|
||||
using callback_erasure_t =
|
||||
fu2::function_base<true, false, fu2::capacity_none, true, false,
|
||||
void(Args...)&&, void(exception_arg_t, exception_t) &&>;
|
||||
|
||||
#ifdef CONTINUABLE_HAS_IMMEDIATE_TYPES
|
||||
template <typename... Args>
|
||||
using callback = callback_erasure_t<Args...>;
|
||||
#else
|
||||
template <typename... Args>
|
||||
class callback;
|
||||
|
||||
template <typename T>
|
||||
struct is_callback : std::false_type {};
|
||||
template <typename... Args>
|
||||
struct is_callback<callback<Args...>> : std::true_type {};
|
||||
|
||||
template <typename... Args>
|
||||
class callback : public callback_erasure_t<Args...> {
|
||||
public:
|
||||
using erasure_t = callback_erasure_t<Args...>;
|
||||
erasure_t erasure_;
|
||||
|
||||
callback() = default;
|
||||
~callback() = default;
|
||||
callback(callback const&) = delete;
|
||||
callback(callback&&) = default;
|
||||
callback& operator=(callback const&) = delete;
|
||||
callback& operator=(callback&&) = default;
|
||||
|
||||
template <
|
||||
typename T,
|
||||
std::enable_if_t<std::is_convertible<T, erasure_t>::value>* = nullptr,
|
||||
std::enable_if_t<!is_callback<traits::unrefcv_t<T>>::value>* = nullptr>
|
||||
/* implicit */ callback(T&& callable) : erasure_(std::forward<T>(callable)) {
|
||||
}
|
||||
|
||||
template <
|
||||
typename T,
|
||||
std::enable_if_t<std::is_assignable<erasure_t, T>::value>* = nullptr,
|
||||
std::enable_if_t<!is_callback<traits::unrefcv_t<T>>::value>* = nullptr>
|
||||
callback& operator=(T&& callable) {
|
||||
erasure_ = std::forward<T>(callable);
|
||||
return *this;
|
||||
}
|
||||
|
||||
void operator()(Args... args) && noexcept {
|
||||
std::move(erasure_)(std::move(args)...);
|
||||
}
|
||||
|
||||
void operator()(exception_arg_t exception_arg, exception_t exception) &&
|
||||
noexcept {
|
||||
std::move(erasure_)(exception_arg, std::move(exception));
|
||||
}
|
||||
|
||||
explicit operator bool() const noexcept {
|
||||
return bool(erasure_);
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
using work_erasure_t =
|
||||
fu2::function_base<true, false, fu2::capacity_fixed<32UL>, true, false,
|
||||
void()&&, void(exception_arg_t, exception_t) &&>;
|
||||
|
||||
#ifdef CONTINUABLE_HAS_IMMEDIATE_TYPES
|
||||
using work = work_erasure_t;
|
||||
#else
|
||||
class work;
|
||||
|
||||
template <typename T>
|
||||
struct is_work : std::false_type {};
|
||||
template <>
|
||||
struct is_work<work> : std::true_type {};
|
||||
|
||||
class work {
|
||||
using erasure_t = work_erasure_t;
|
||||
erasure_t erasure_;
|
||||
|
||||
public:
|
||||
work() = default;
|
||||
~work() = default;
|
||||
work(work const&) = delete;
|
||||
work(work&&) = default;
|
||||
work& operator=(work const&) = delete;
|
||||
work& operator=(work&&) = default;
|
||||
|
||||
template <
|
||||
typename T,
|
||||
std::enable_if_t<std::is_convertible<T, erasure_t>::value>* = nullptr,
|
||||
std::enable_if_t<!is_work<traits::unrefcv_t<T>>::value>* = nullptr>
|
||||
/* implicit */ work(T&& callable) : erasure_(std::forward<T>(callable)) {
|
||||
}
|
||||
|
||||
template <
|
||||
typename T,
|
||||
std::enable_if_t<std::is_assignable<erasure_t, T>::value>* = nullptr,
|
||||
std::enable_if_t<!is_work<traits::unrefcv_t<T>>::value>* = nullptr>
|
||||
work& operator=(T&& callable) {
|
||||
erasure_ = std::forward<T>(callable);
|
||||
return *this;
|
||||
}
|
||||
|
||||
void operator()() && noexcept {
|
||||
std::move(erasure_)();
|
||||
}
|
||||
|
||||
void operator()(exception_arg_t, exception_t exception) && noexcept {
|
||||
std::move(erasure_)(exception_arg_t{}, std::move(exception));
|
||||
}
|
||||
|
||||
explicit operator bool() const noexcept {
|
||||
return bool(erasure_);
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
template <typename... Args>
|
||||
struct continuation_capacity {
|
||||
using type = union {
|
||||
void* pointer_;
|
||||
base::ready_continuation<Args...> continuation_;
|
||||
};
|
||||
|
||||
static constexpr std::size_t capacity = sizeof(type);
|
||||
static constexpr std::size_t alignment = alignof(type);
|
||||
};
|
||||
|
||||
template <typename... Args>
|
||||
using continuation_erasure_t = fu2::function_base<
|
||||
true, false, continuation_capacity<Args...>, true, false,
|
||||
void(promise_base<callback<Args...>, signature_arg_t<Args...>>),
|
||||
bool(is_ready_arg_t) const, result<Args...>(unpack_arg_t)>;
|
||||
|
||||
#ifdef CONTINUABLE_HAS_IMMEDIATE_TYPES
|
||||
template <typename... Args>
|
||||
using continuation = continuation_erasure_t<Args...>;
|
||||
#else
|
||||
template <typename... Args>
|
||||
class continuation;
|
||||
|
||||
template <typename T>
|
||||
struct is_continuation : std::false_type {};
|
||||
template <typename... Args>
|
||||
struct is_continuation<continuation<Args...>> : std::true_type {};
|
||||
|
||||
template <typename... Args>
|
||||
class continuation {
|
||||
using erasure_t = continuation_erasure_t<Args...>;
|
||||
erasure_t erasure_;
|
||||
|
||||
public:
|
||||
continuation() = default;
|
||||
~continuation() = default;
|
||||
continuation(continuation const&) = delete;
|
||||
continuation(continuation&&) = default;
|
||||
continuation& operator=(continuation const&) = delete;
|
||||
continuation& operator=(continuation&&) = default;
|
||||
|
||||
template <
|
||||
typename T,
|
||||
std::enable_if_t<std::is_convertible<T, erasure_t>::value>* = nullptr,
|
||||
std::enable_if_t<!is_continuation<traits::unrefcv_t<T>>::value>* =
|
||||
nullptr>
|
||||
/* implicit */ continuation(T&& callable)
|
||||
: erasure_(std::forward<T>(callable)) {
|
||||
}
|
||||
|
||||
template <
|
||||
typename T,
|
||||
std::enable_if_t<std::is_assignable<erasure_t, T>::value>* = nullptr,
|
||||
std::enable_if_t<!is_continuation<traits::unrefcv_t<T>>::value>* =
|
||||
nullptr>
|
||||
continuation& operator=(T&& callable) {
|
||||
erasure_ = std::forward<T>(callable);
|
||||
return *this;
|
||||
}
|
||||
|
||||
void operator()(promise_base<callback<Args...>, //
|
||||
signature_arg_t<Args...>>
|
||||
promise) {
|
||||
erasure_(std::move(promise));
|
||||
}
|
||||
|
||||
bool operator()(is_ready_arg_t is_ready_arg) const {
|
||||
return erasure_(is_ready_arg);
|
||||
}
|
||||
|
||||
result<Args...> operator()(unpack_arg_t query_arg) {
|
||||
return erasure_(query_arg);
|
||||
}
|
||||
};
|
||||
#endif
|
||||
} // namespace erasure
|
||||
} // namespace detail
|
||||
} // namespace cti
|
||||
|
||||
#endif // CONTINUABLE_DETAIL_ERASURE_HPP_INCLUDED
|
||||
@ -1,97 +0,0 @@
|
||||
|
||||
/*
|
||||
|
||||
/~` _ _ _|_. _ _ |_ | _
|
||||
\_,(_)| | | || ||_|(_||_)|(/_
|
||||
|
||||
https://github.com/Naios/continuable
|
||||
v4.2.0
|
||||
|
||||
Copyright(c) 2015 - 2022 Denis Blank <denis.blank at outlook dot com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files(the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions :
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
**/
|
||||
|
||||
#ifndef CONTINUABLE_DETAIL_PROMISIFY_HPP_INCLUDED
|
||||
#define CONTINUABLE_DETAIL_PROMISIFY_HPP_INCLUDED
|
||||
|
||||
#include <type_traits>
|
||||
#include <continuable/continuable-base.hpp>
|
||||
#include <continuable/continuable-primitives.hpp>
|
||||
#include <continuable/detail/features.hpp>
|
||||
#include <continuable/detail/utility/traits.hpp>
|
||||
#include <continuable/detail/utility/util.hpp>
|
||||
|
||||
#if defined(CONTINUABLE_HAS_EXCEPTIONS)
|
||||
#include <exception>
|
||||
#endif // CONTINUABLE_HAS_EXCEPTIONS
|
||||
|
||||
namespace cti {
|
||||
namespace detail {
|
||||
namespace convert {
|
||||
/// A resolver for promisifying asio and js style callbacks.
|
||||
inline auto default_resolver() {
|
||||
return [](auto&& promise, auto&& e, auto&&... args) {
|
||||
static_assert(
|
||||
std::is_convertible<std::decay_t<decltype(e)>, exception_t>::value,
|
||||
"The given error type must be convertible to the error type used! "
|
||||
"Specify a custom resolver in order to apply a conversion to the "
|
||||
"used error type.");
|
||||
|
||||
if (e) {
|
||||
promise.set_exception(std::forward<decltype(e)>(e));
|
||||
} else {
|
||||
promise.set_value(std::forward<decltype(args)>(args)...);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
template <typename... Result>
|
||||
struct promisify_helper {
|
||||
template <typename Resolver, typename Callable, typename... Args>
|
||||
static auto from(Resolver&& resolver, Callable&& callable, Args&&... args) {
|
||||
return make_continuable<Result...>(
|
||||
[resolver = std::forward<Resolver>(resolver),
|
||||
args = traits::make_flat_tuple(std::forward<Callable>(callable),
|
||||
std::forward<Args>(args)...)](
|
||||
auto&& promise) mutable {
|
||||
traits::unpack(
|
||||
[promise = std::forward<decltype(promise)>(promise),
|
||||
&resolver](auto&&... args) mutable {
|
||||
// Call the resolver from with the promise and result
|
||||
auto callback =
|
||||
[resolver = std::move(resolver),
|
||||
promise = std::move(promise)](auto&&... args) mutable {
|
||||
resolver(std::move(promise),
|
||||
std::forward<decltype(args)>(args)...);
|
||||
};
|
||||
|
||||
// Invoke the callback taking function
|
||||
util::invoke(std::forward<decltype(args)>(args)...,
|
||||
std::move(callback));
|
||||
},
|
||||
std::move(args));
|
||||
});
|
||||
}
|
||||
};
|
||||
} // namespace convert
|
||||
} // namespace detail
|
||||
} // namespace cti
|
||||
|
||||
#endif // CONTINUABLE_DETAIL_PROMISIFY_HPP_INCLUDED
|
||||
95
include/continuable/detail/promisify.hpp
Normal file
95
include/continuable/detail/promisify.hpp
Normal file
@ -0,0 +1,95 @@
|
||||
|
||||
/*
|
||||
|
||||
/~` _ _ _|_. _ _ |_ | _
|
||||
\_,(_)| | | || ||_|(_||_)|(/_
|
||||
|
||||
https://github.com/Naios/continuable
|
||||
v3.0.0
|
||||
|
||||
Copyright(c) 2015 - 2018 Denis Blank <denis.blank at outlook dot com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files(the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions :
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
**/
|
||||
|
||||
#ifndef CONTINUABLE_DETAIL_PROMISIFY_HPP_INCLUDED
|
||||
#define CONTINUABLE_DETAIL_PROMISIFY_HPP_INCLUDED
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
#if defined(CONTINUABLE_HAS_EXCEPTIONS)
|
||||
#include <exception>
|
||||
#endif // CONTINUABLE_HAS_EXCEPTIONS
|
||||
|
||||
#include <continuable/continuable-base.hpp>
|
||||
#include <continuable/detail/traits.hpp>
|
||||
#include <continuable/detail/util.hpp>
|
||||
|
||||
namespace cti {
|
||||
namespace detail {
|
||||
namespace convert {
|
||||
/// A helper class for promisifying asio and js style callback
|
||||
/// taking functions into a continuable.
|
||||
template <typename P>
|
||||
struct promisify_default {
|
||||
P promise;
|
||||
|
||||
template <typename E, typename... T>
|
||||
void operator()(E&& error, T&&... result) {
|
||||
if (error) {
|
||||
#if defined(CONTINUABLE_HAS_EXCEPTIONS)
|
||||
promise.set_exception(std::make_exception_ptr(std::forward<E>(error)));
|
||||
#else
|
||||
promise.set_exception(
|
||||
std::error_condition(error.value(), error.category()));
|
||||
#endif // CONTINUABLE_HAS_EXCEPTIONS
|
||||
|
||||
} else {
|
||||
promise.set_value(std::forward<T>(result)...);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <typename... Result>
|
||||
struct promisify_helper {
|
||||
template <template <class T> class Evaluator, typename Callable,
|
||||
typename... Args>
|
||||
static auto from(Callable&& callable, Args&&... args) {
|
||||
return make_continuable<Result...>([args = std::make_tuple(
|
||||
std::forward<Callable>(callable),
|
||||
std::forward<Args>(args)...)](
|
||||
auto&& promise) mutable {
|
||||
|
||||
traits::unpack(
|
||||
std::move(args), [promise = std::forward<decltype(promise)>(promise)](
|
||||
auto&&... args) mutable {
|
||||
Evaluator<std::decay_t<decltype(promise)>> evaluator{
|
||||
std::move(promise)};
|
||||
|
||||
util::invoke(std::forward<decltype(args)>(args)...,
|
||||
std::move(evaluator));
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
} // namespace convert
|
||||
} // namespace detail
|
||||
} // namespace cti
|
||||
|
||||
#endif // CONTINUABLE_DETAIL_PROMISIFY_HPP_INCLUDED
|
||||
@ -5,9 +5,9 @@
|
||||
\_,(_)| | | || ||_|(_||_)|(/_
|
||||
|
||||
https://github.com/Naios/continuable
|
||||
v4.2.0
|
||||
v3.0.0
|
||||
|
||||
Copyright(c) 2015 - 2022 Denis Blank <denis.blank at outlook dot com>
|
||||
Copyright(c) 2015 - 2018 Denis Blank <denis.blank at outlook dot com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files(the "Software"), to deal
|
||||
@ -21,7 +21,7 @@
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
@ -35,7 +35,8 @@
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include <continuable/detail/utility/traits.hpp>
|
||||
|
||||
#include <continuable/detail/traits.hpp>
|
||||
|
||||
namespace cti {
|
||||
namespace detail {
|
||||
@ -5,9 +5,9 @@
|
||||
\_,(_)| | | || ||_|(_||_)|(/_
|
||||
|
||||
https://github.com/Naios/continuable
|
||||
v4.2.0
|
||||
v3.0.0
|
||||
|
||||
Copyright(c) 2015 - 2022 Denis Blank <denis.blank at outlook dot com>
|
||||
Copyright(c) 2015 - 2018 Denis Blank <denis.blank at outlook dot com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files(the "Software"), to deal
|
||||
@ -21,7 +21,7 @@
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
@ -33,12 +33,13 @@
|
||||
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <continuable/continuable-primitives.hpp>
|
||||
#include <continuable/detail/core/types.hpp>
|
||||
|
||||
#include <continuable/detail/features.hpp>
|
||||
#include <continuable/detail/utility/traits.hpp>
|
||||
#include <continuable/detail/utility/util.hpp>
|
||||
#include <continuable/detail/traits.hpp>
|
||||
#include <continuable/detail/types.hpp>
|
||||
#include <continuable/detail/util.hpp>
|
||||
|
||||
namespace cti {
|
||||
namespace detail {
|
||||
@ -54,7 +55,7 @@ void assert_async_completion(C&& continuable) {
|
||||
// Workaround for our known GCC bug.
|
||||
util::unused(std::forward<decltype(args)>(args)...);
|
||||
})
|
||||
.fail([](cti::exception_t /*error*/) {
|
||||
.fail([](cti::error_type /*error*/) {
|
||||
// ...
|
||||
FAIL();
|
||||
});
|
||||
@ -73,28 +74,7 @@ void assert_async_exception_completion(C&& continuable) {
|
||||
// ...
|
||||
FAIL();
|
||||
})
|
||||
.fail([called](cti::exception_t error) {
|
||||
ASSERT_TRUE(bool(error));
|
||||
ASSERT_FALSE(*called);
|
||||
*called = true;
|
||||
});
|
||||
|
||||
ASSERT_TRUE(*called);
|
||||
}
|
||||
|
||||
template <typename C>
|
||||
void assert_async_cancellation(C&& continuable) {
|
||||
auto called = std::make_shared<bool>(false);
|
||||
std::forward<C>(continuable)
|
||||
.then([](auto&&... args) {
|
||||
// Workaround for our known GCC bug.
|
||||
util::unused(std::forward<decltype(args)>(args)...);
|
||||
|
||||
// ...
|
||||
FAIL();
|
||||
})
|
||||
.fail([called](cti::exception_t error) {
|
||||
ASSERT_FALSE(bool(error));
|
||||
.fail([called](cti::error_type /*error*/) {
|
||||
ASSERT_FALSE(*called);
|
||||
*called = true;
|
||||
});
|
||||
@ -111,7 +91,7 @@ void assert_async_never_completed(C&& continuable) {
|
||||
|
||||
FAIL();
|
||||
})
|
||||
.fail([](cti::exception_t) {
|
||||
.fail([](cti::error_type /*error*/) {
|
||||
// ...
|
||||
FAIL();
|
||||
});
|
||||
@ -121,10 +101,11 @@ template <typename C, typename V>
|
||||
void assert_async_validation(C&& continuable, V&& validator) {
|
||||
assert_async_completion(
|
||||
std::forward<C>(continuable)
|
||||
.then(
|
||||
[validator = std::forward<V>(validator)](auto&&... args) mutable {
|
||||
validator(std::forward<decltype(args)>(args)...);
|
||||
}));
|
||||
.then([validator =
|
||||
std::forward<V>(validator)](auto&&... args) mutable {
|
||||
|
||||
validator(std::forward<decltype(args)>(args)...);
|
||||
}));
|
||||
}
|
||||
|
||||
/// Expects that the continuable is finished with the given arguments
|
||||
@ -134,17 +115,18 @@ void assert_async_binary_validation(V&& validator, C&& continuable,
|
||||
|
||||
using size = std::integral_constant<std::size_t, sizeof...(expected)>;
|
||||
|
||||
assert_async_validation(
|
||||
std::forward<C>(continuable),
|
||||
[expected_pack = std::make_tuple(std::forward<Args>(expected)...),
|
||||
validator = std::forward<V>(validator)](auto&&... args) mutable {
|
||||
static_assert(size::value == sizeof...(args),
|
||||
"Async completion handler called with a different count "
|
||||
"of arguments!");
|
||||
assert_async_validation(std::forward<C>(continuable), [
|
||||
expected_pack = std::make_tuple(std::forward<Args>(expected)...),
|
||||
validator = std::forward<V>(validator)
|
||||
](auto&&... args) mutable {
|
||||
|
||||
validator(std::make_tuple(std::forward<decltype(args)>(args)...),
|
||||
expected_pack);
|
||||
});
|
||||
static_assert(size::value == sizeof...(args),
|
||||
"Async completion handler called with a different count "
|
||||
"of arguments!");
|
||||
|
||||
validator(std::make_tuple(std::forward<decltype(args)>(args)...),
|
||||
expected_pack);
|
||||
});
|
||||
}
|
||||
|
||||
/// Expects that the continuable is finished with the given arguments
|
||||
@ -157,19 +139,20 @@ void assert_async_binary_exception_validation(V&& validator, C&& continuable,
|
||||
// Workaround for our known GCC bug.
|
||||
util::unused(std::forward<decltype(args)>(args)...);
|
||||
|
||||
// The exception was not thrown!
|
||||
// ...
|
||||
FAIL();
|
||||
})
|
||||
.fail([called, validator = std::forward<decltype(validator)>(validator),
|
||||
expected = std::forward<decltype(expected)>(expected)](
|
||||
exception_t error) {
|
||||
.fail([
|
||||
called, validator = std::forward<decltype(validator)>(validator),
|
||||
expected = std::forward<decltype(expected)>(expected)
|
||||
](types::error_type error) {
|
||||
ASSERT_FALSE(*called);
|
||||
*called = true;
|
||||
|
||||
#if defined(CONTINUABLE_HAS_EXCEPTIONS)
|
||||
try {
|
||||
std::rethrow_exception(error);
|
||||
} catch (std::decay_t<decltype(expected)> const& exception) {
|
||||
} catch (std::decay_t<decltype(expected)>& exception) {
|
||||
validator(exception, expected);
|
||||
} catch (...) {
|
||||
FAIL();
|
||||
@ -200,14 +183,15 @@ template <typename... Expected>
|
||||
struct assert_async_types_validator {
|
||||
template <typename... Actual>
|
||||
void operator()(Actual...) {
|
||||
static_assert(
|
||||
std::is_same<identity<Actual...>, identity<Expected...>>::value,
|
||||
"The called arguments don't match with the expected ones!");
|
||||
static_assert(std::is_same<traits::identity<Actual...>,
|
||||
traits::identity<Expected...>>::value,
|
||||
"The called arguments don't match with the expected ones!");
|
||||
}
|
||||
};
|
||||
|
||||
template <typename C, typename... Args>
|
||||
void assert_async_types(C&& continuable, identity<Args...> /*expected*/) {
|
||||
void assert_async_types(C&& continuable,
|
||||
traits::identity<Args...> /*expected*/) {
|
||||
assert_async_validation(std::forward<C>(continuable),
|
||||
assert_async_types_validator<Args...>{});
|
||||
}
|
||||
358
include/continuable/detail/traits.hpp
Normal file
358
include/continuable/detail/traits.hpp
Normal file
@ -0,0 +1,358 @@
|
||||
|
||||
/*
|
||||
|
||||
/~` _ _ _|_. _ _ |_ | _
|
||||
\_,(_)| | | || ||_|(_||_)|(/_
|
||||
|
||||
https://github.com/Naios/continuable
|
||||
v3.0.0
|
||||
|
||||
Copyright(c) 2015 - 2018 Denis Blank <denis.blank at outlook dot com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files(the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions :
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
**/
|
||||
|
||||
#ifndef CONTINUABLE_DETAIL_TRAITS_HPP_INCLUDED
|
||||
#define CONTINUABLE_DETAIL_TRAITS_HPP_INCLUDED
|
||||
|
||||
#include <cstdint>
|
||||
#include <initializer_list>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#include <continuable/detail/features.hpp>
|
||||
|
||||
namespace cti {
|
||||
namespace detail {
|
||||
namespace traits {
|
||||
/// Evaluates to the element at position I.
|
||||
template <std::size_t I, typename... Args>
|
||||
using at_t = decltype(std::get<I>(std::declval<std::tuple<Args...>>()));
|
||||
|
||||
namespace detail {
|
||||
template <typename T, typename... Args>
|
||||
struct index_of_impl;
|
||||
template <typename T, typename... Args>
|
||||
struct index_of_impl<T, T, Args...> : std::integral_constant<std::size_t, 0U> {
|
||||
};
|
||||
template <typename T, typename U, typename... Args>
|
||||
struct index_of_impl<T, U, Args...>
|
||||
: std::integral_constant<std::size_t,
|
||||
1 + index_of_impl<T, Args...>::value> {};
|
||||
} // namespace detail
|
||||
|
||||
/// Evaluates to the index of T in the given pack
|
||||
template <typename T, typename... Args>
|
||||
using index_of_t = detail::index_of_impl<T, Args...>;
|
||||
|
||||
/// A tagging type for wrapping other types
|
||||
template <typename... T>
|
||||
struct identity {};
|
||||
template <typename T>
|
||||
struct identity<T> : std::common_type<T> {};
|
||||
|
||||
template <typename>
|
||||
struct is_identity : std::false_type {};
|
||||
template <typename... Args>
|
||||
struct is_identity<identity<Args...>> : std::true_type {};
|
||||
|
||||
template <typename T>
|
||||
constexpr identity<std::decay_t<T>> identity_of(T const& /*type*/) noexcept {
|
||||
return {};
|
||||
}
|
||||
template <typename... Args>
|
||||
constexpr identity<Args...> identity_of(identity<Args...> /*type*/) noexcept {
|
||||
return {};
|
||||
}
|
||||
template <typename T>
|
||||
using identify = std::conditional_t<is_identity<std::decay_t<T>>::value, T,
|
||||
identity<std::decay_t<T>>>;
|
||||
|
||||
template <std::size_t I, typename... T>
|
||||
constexpr auto get(identity<T...>) noexcept {
|
||||
return identify<at_t<I, T...>>{};
|
||||
}
|
||||
|
||||
namespace detail {
|
||||
// Equivalent to C++17's std::void_t which targets a bug in GCC,
|
||||
// that prevents correct SFINAE behavior.
|
||||
// See http://stackoverflow.com/questions/35753920 for details.
|
||||
template <typename...>
|
||||
struct deduce_to_void : std::common_type<void> {};
|
||||
} // namespace detail
|
||||
|
||||
/// C++17 like void_t type
|
||||
template <typename... T>
|
||||
using void_t = typename detail::deduce_to_void<T...>::type;
|
||||
|
||||
namespace detail {
|
||||
template <typename Type, typename TrueCallback>
|
||||
constexpr void static_if_impl(std::true_type, Type&& type,
|
||||
TrueCallback&& trueCallback) {
|
||||
std::forward<TrueCallback>(trueCallback)(std::forward<Type>(type));
|
||||
}
|
||||
|
||||
template <typename Type, typename TrueCallback>
|
||||
constexpr void static_if_impl(std::false_type, Type&& /*type*/,
|
||||
TrueCallback&& /*trueCallback*/) {
|
||||
}
|
||||
|
||||
template <typename Type, typename TrueCallback, typename FalseCallback>
|
||||
constexpr auto static_if_impl(std::true_type, Type&& type,
|
||||
TrueCallback&& trueCallback,
|
||||
FalseCallback&& /*falseCallback*/) {
|
||||
return std::forward<TrueCallback>(trueCallback)(std::forward<Type>(type));
|
||||
}
|
||||
|
||||
template <typename Type, typename TrueCallback, typename FalseCallback>
|
||||
constexpr auto static_if_impl(std::false_type, Type&& type,
|
||||
TrueCallback&& /*trueCallback*/,
|
||||
FalseCallback&& falseCallback) {
|
||||
return std::forward<FalseCallback>(falseCallback)(std::forward<Type>(type));
|
||||
}
|
||||
|
||||
/// Evaluates to the size of the given tuple like type,
|
||||
// / if the type has no static size it will be one.
|
||||
template <typename T, typename Enable = void>
|
||||
struct tuple_like_size : std::integral_constant<std::size_t, 1U> {};
|
||||
template <typename T>
|
||||
struct tuple_like_size<T, void_t<decltype(std::tuple_size<T>::value)>>
|
||||
: std::tuple_size<T> {};
|
||||
} // namespace detail
|
||||
|
||||
/// Returns the pack size of the given empty pack
|
||||
constexpr std::size_t pack_size_of(identity<>) noexcept {
|
||||
return 0U;
|
||||
}
|
||||
/// Returns the pack size of the given type
|
||||
template <typename T>
|
||||
constexpr std::size_t pack_size_of(identity<T>) noexcept {
|
||||
return detail::tuple_like_size<T>::value;
|
||||
}
|
||||
/// Returns the pack size of the given type
|
||||
template <typename First, typename Second, typename... Args>
|
||||
constexpr std::size_t pack_size_of(identity<First, Second, Args...>) noexcept {
|
||||
return 2U + sizeof...(Args);
|
||||
}
|
||||
|
||||
/// Returns an index sequence of the given type
|
||||
template <typename T>
|
||||
constexpr auto sequence_of(identity<T>) noexcept {
|
||||
constexpr auto const size = pack_size_of(identity<T>{});
|
||||
return std::make_index_sequence<size>();
|
||||
}
|
||||
|
||||
/// Invokes the callback only if the given type matches the check
|
||||
template <typename Type, typename Check, typename TrueCallback>
|
||||
constexpr void static_if(Type&& type, Check&& check,
|
||||
TrueCallback&& trueCallback) {
|
||||
detail::static_if_impl(std::forward<Check>(check)(type),
|
||||
std::forward<Type>(type),
|
||||
std::forward<TrueCallback>(trueCallback));
|
||||
}
|
||||
|
||||
/// Invokes the callback only if the given type matches the check
|
||||
template <typename Type, typename Check, typename TrueCallback,
|
||||
typename FalseCallback>
|
||||
constexpr auto static_if(Type&& type, Check&& check,
|
||||
TrueCallback&& trueCallback,
|
||||
FalseCallback&& falseCallback) {
|
||||
return detail::static_if_impl(std::forward<Check>(check)(type),
|
||||
std::forward<Type>(type),
|
||||
std::forward<TrueCallback>(trueCallback),
|
||||
std::forward<FalseCallback>(falseCallback));
|
||||
}
|
||||
|
||||
/// Calls the given unpacker with the content of the given sequence
|
||||
template <typename U, std::size_t... I>
|
||||
constexpr decltype(auto) unpack(std::integer_sequence<std::size_t, I...>,
|
||||
U&& unpacker) {
|
||||
return std::forward<U>(unpacker)(std::integral_constant<std::size_t, I>{}...);
|
||||
}
|
||||
|
||||
/// Calls the given unpacker with the content of the given sequenceable
|
||||
template <typename F, typename U, std::size_t... I>
|
||||
constexpr auto unpack(F&& first_sequenceable, U&& unpacker,
|
||||
std::integer_sequence<std::size_t, I...>)
|
||||
-> decltype(std::forward<U>(unpacker)(
|
||||
get<I>(std::forward<F>(first_sequenceable))...)) {
|
||||
(void)first_sequenceable;
|
||||
return std::forward<U>(unpacker)(
|
||||
get<I>(std::forward<F>(first_sequenceable))...);
|
||||
}
|
||||
/// Calls the given unpacker with the content of the given sequenceable
|
||||
template <typename F, typename S, typename U, std::size_t... If,
|
||||
std::size_t... Is>
|
||||
constexpr auto unpack(F&& first_sequenceable, S&& second_sequenceable,
|
||||
U&& unpacker, std::integer_sequence<std::size_t, If...>,
|
||||
std::integer_sequence<std::size_t, Is...>)
|
||||
-> decltype(std::forward<U>(unpacker)(
|
||||
get<If>(std::forward<F>(first_sequenceable))...,
|
||||
get<Is>(std::forward<S>(second_sequenceable))...)) {
|
||||
(void)first_sequenceable;
|
||||
(void)second_sequenceable;
|
||||
return std::forward<U>(unpacker)(
|
||||
get<If>(std::forward<F>(first_sequenceable))...,
|
||||
get<Is>(std::forward<S>(second_sequenceable))...);
|
||||
}
|
||||
/// Calls the given unpacker with the content of the given sequenceable
|
||||
template <typename F, typename U>
|
||||
constexpr auto unpack(F&& first_sequenceable, U&& unpacker)
|
||||
-> decltype(unpack(std::forward<F>(first_sequenceable),
|
||||
std::forward<U>(unpacker),
|
||||
sequence_of(identify<decltype(first_sequenceable)>{}))) {
|
||||
return unpack(std::forward<F>(first_sequenceable), std::forward<U>(unpacker),
|
||||
sequence_of(identify<decltype(first_sequenceable)>{}));
|
||||
}
|
||||
/// Calls the given unpacker with the content of the given sequenceables
|
||||
template <typename F, typename S, typename U>
|
||||
constexpr auto unpack(F&& first_sequenceable, S&& second_sequenceable,
|
||||
U&& unpacker)
|
||||
-> decltype(unpack(std::forward<F>(first_sequenceable),
|
||||
std::forward<S>(second_sequenceable),
|
||||
std::forward<U>(unpacker),
|
||||
sequence_of(identity_of(first_sequenceable)),
|
||||
sequence_of(identity_of(second_sequenceable)))) {
|
||||
return unpack(std::forward<F>(first_sequenceable),
|
||||
std::forward<S>(second_sequenceable), std::forward<U>(unpacker),
|
||||
sequence_of(identity_of(first_sequenceable)),
|
||||
sequence_of(identity_of(second_sequenceable)));
|
||||
}
|
||||
|
||||
/// Adds the given type at the back of the left sequenceable
|
||||
template <typename Left, typename Element>
|
||||
constexpr auto push(Left&& left, Element&& element) {
|
||||
return unpack(std::forward<Left>(left), [&](auto&&... args) {
|
||||
return std::make_tuple(std::forward<decltype(args)>(args)...,
|
||||
std::forward<Element>(element));
|
||||
});
|
||||
}
|
||||
|
||||
/// Adds the element to the back of the identity
|
||||
template <typename... Args, typename Element>
|
||||
constexpr auto push(identity<Args...>, identity<Element>) noexcept {
|
||||
return identity<Args..., Element>{};
|
||||
}
|
||||
|
||||
/// Removes the first element from the identity
|
||||
template <typename First, typename... Rest>
|
||||
constexpr auto pop_first(identity<First, Rest...>) noexcept {
|
||||
return identity<Rest...>{};
|
||||
}
|
||||
|
||||
/// Returns the merged sequence
|
||||
template <typename Left>
|
||||
constexpr auto merge(Left&& left) {
|
||||
return std::forward<Left>(left);
|
||||
}
|
||||
/// Merges the left sequenceable with the right ones
|
||||
template <typename Left, typename Right, typename... Rest>
|
||||
constexpr auto merge(Left&& left, Right&& right, Rest&&... rest) {
|
||||
// Merge the left with the right sequenceable and
|
||||
// merge the result with the rest.
|
||||
return merge(unpack(std::forward<Left>(left), std::forward<Right>(right),
|
||||
[&](auto&&... args) {
|
||||
// Maybe use: template <template<typename...> class T,
|
||||
// typename... Args>
|
||||
return std::make_tuple(
|
||||
std::forward<decltype(args)>(args)...);
|
||||
}),
|
||||
std::forward<Rest>(rest)...);
|
||||
}
|
||||
/// Merges the left identity with the right ones
|
||||
template <typename... LeftArgs, typename... RightArgs, typename... Rest>
|
||||
constexpr auto merge(identity<LeftArgs...> /*left*/,
|
||||
identity<RightArgs...> /*right*/, Rest&&... rest) {
|
||||
return merge(identity<LeftArgs..., RightArgs...>{},
|
||||
std::forward<Rest>(rest)...);
|
||||
}
|
||||
|
||||
namespace detail {
|
||||
template <typename T, typename Args, typename = traits::void_t<>>
|
||||
struct is_invokable_impl : std::common_type<std::false_type> {};
|
||||
|
||||
template <typename T, typename... Args>
|
||||
struct is_invokable_impl<
|
||||
T, std::tuple<Args...>,
|
||||
void_t<decltype(std::declval<T>()(std::declval<Args>()...))>>
|
||||
: std::common_type<std::true_type> {};
|
||||
} // namespace detail
|
||||
|
||||
/// Deduces to a std::true_type if the given type is callable with the arguments
|
||||
/// inside the given tuple.
|
||||
/// The main reason for implementing it with the detection idiom instead of
|
||||
/// hana like detection is that MSVC has issues with capturing raw template
|
||||
/// arguments inside lambda closures.
|
||||
///
|
||||
/// ```cpp
|
||||
/// traits::is_invokable<object, std::tuple<Args...>>
|
||||
/// ```
|
||||
template <typename T, typename Args>
|
||||
using is_invokable_from_tuple =
|
||||
typename detail::is_invokable_impl<T, Args>::type;
|
||||
|
||||
// Checks whether the given callable object is invocable with the given
|
||||
// arguments. This doesn't take member functions into account!
|
||||
template <typename T, typename... Args>
|
||||
using is_invocable = is_invokable_from_tuple<T, std::tuple<Args...>>;
|
||||
|
||||
/// Deduces to a std::false_type
|
||||
template <typename T>
|
||||
using fail = std::integral_constant<bool, !std::is_same<T, T>::value>;
|
||||
|
||||
#ifdef CONTINUABLE_HAS_CXX17_DISJUNCTION
|
||||
using std::disjunction;
|
||||
#else
|
||||
namespace detail {
|
||||
/// Declares a C++14 polyfill for C++17 std::disjunction.
|
||||
template <typename Args, typename = void_t<>>
|
||||
struct disjunction_impl : std::common_type<std::true_type> {};
|
||||
template <typename... Args>
|
||||
struct disjunction_impl<identity<Args...>,
|
||||
void_t<std::enable_if_t<!bool(Args::value)>...>>
|
||||
: std::common_type<std::false_type> {};
|
||||
} // namespace detail
|
||||
|
||||
template <typename... Args>
|
||||
using disjunction = typename detail::disjunction_impl<identity<Args...>>::type;
|
||||
#endif // CONTINUABLE_HAS_CXX17_DISJUNCTION
|
||||
|
||||
#ifdef CONTINUABLE_HAS_CXX17_CONJUNCTION
|
||||
using std::conjunction;
|
||||
#else
|
||||
namespace detail {
|
||||
/// Declares a C++14 polyfill for C++17 std::conjunction.
|
||||
template <typename Args, typename = void_t<>>
|
||||
struct conjunction_impl : std::common_type<std::false_type> {};
|
||||
template <typename... Args>
|
||||
struct conjunction_impl<identity<Args...>,
|
||||
void_t<std::enable_if_t<bool(Args::value)>...>>
|
||||
: std::common_type<std::true_type> {};
|
||||
} // namespace detail
|
||||
|
||||
template <typename... Args>
|
||||
using conjunction = typename detail::conjunction_impl<identity<Args...>>::type;
|
||||
#endif // CONTINUABLE_HAS_CXX17_CONJUNCTION
|
||||
|
||||
} // namespace traits
|
||||
} // namespace detail
|
||||
} // namespace cti
|
||||
|
||||
#endif // CONTINUABLE_DETAIL_TRAITS_HPP_INCLUDED
|
||||
@ -5,9 +5,9 @@
|
||||
\_,(_)| | | || ||_|(_||_)|(/_
|
||||
|
||||
https://github.com/Naios/continuable
|
||||
v4.2.0
|
||||
v3.0.0
|
||||
|
||||
Copyright(c) 2015 - 2022 Denis Blank <denis.blank at outlook dot com>
|
||||
Copyright(c) 2015 - 2018 Denis Blank <denis.blank at outlook dot com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files(the "Software"), to deal
|
||||
@ -21,23 +21,23 @@
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
**/
|
||||
|
||||
#ifndef CONTINUABLE_DETAIL_TRANSFORMS_FUTURE_HPP_INCLUDED
|
||||
#define CONTINUABLE_DETAIL_TRANSFORMS_FUTURE_HPP_INCLUDED
|
||||
#ifndef CONTINUABLE_DETAIL_TRANSFORMS_HPP_INCLUDED
|
||||
#define CONTINUABLE_DETAIL_TRANSFORMS_HPP_INCLUDED
|
||||
|
||||
#include <future>
|
||||
#include <continuable/continuable-primitives.hpp>
|
||||
#include <continuable/detail/core/annotation.hpp>
|
||||
#include <continuable/detail/core/base.hpp>
|
||||
#include <continuable/detail/core/types.hpp>
|
||||
|
||||
#include <continuable/detail/base.hpp>
|
||||
#include <continuable/detail/features.hpp>
|
||||
#include <continuable/detail/utility/util.hpp>
|
||||
#include <continuable/detail/hints.hpp>
|
||||
#include <continuable/detail/types.hpp>
|
||||
#include <continuable/detail/util.hpp>
|
||||
|
||||
namespace cti {
|
||||
namespace detail {
|
||||
@ -77,7 +77,8 @@ template <typename Hint>
|
||||
class promise_callback;
|
||||
|
||||
template <typename... Args>
|
||||
class promise_callback<identity<Args...>> : public future_trait<Args...> {
|
||||
class promise_callback<hints::signature_hint_tag<Args...>>
|
||||
: public future_trait<Args...> {
|
||||
|
||||
typename future_trait<Args...>::promise_t promise_;
|
||||
|
||||
@ -94,7 +95,7 @@ public:
|
||||
}
|
||||
|
||||
/// Resolves the promise through the exception
|
||||
void operator()(exception_arg_t, exception_t error) {
|
||||
void operator()(types::dispatch_error_tag, types::error_type error) {
|
||||
#if defined(CONTINUABLE_HAS_EXCEPTIONS)
|
||||
promise_.set_exception(error);
|
||||
#else
|
||||
@ -103,7 +104,7 @@ public:
|
||||
// Can't forward a std::error_condition or custom error type
|
||||
// to a std::promise. Handle the error first in order
|
||||
// to prevent this trap!
|
||||
CTI_DETAIL_TRAP();
|
||||
util::trap();
|
||||
#endif // CONTINUABLE_HAS_EXCEPTIONS
|
||||
}
|
||||
|
||||
@ -115,10 +116,10 @@ public:
|
||||
|
||||
/// Transforms the continuation to a future
|
||||
template <typename Data, typename Annotation>
|
||||
auto to_future(continuable_base<Data, Annotation>&& continuable) {
|
||||
auto as_future(continuable_base<Data, Annotation>&& continuable) {
|
||||
// Create the promise which is able to supply the current arguments
|
||||
constexpr auto const hint =
|
||||
base::annotation_of(identify<decltype(continuable)>{});
|
||||
hints::hint_of(traits::identify<decltype(continuable)>{});
|
||||
|
||||
promise_callback<std::decay_t<decltype(hint)>> callback;
|
||||
(void)hint;
|
||||
@ -135,4 +136,4 @@ auto to_future(continuable_base<Data, Annotation>&& continuable) {
|
||||
} // namespace detail
|
||||
} // namespace cti
|
||||
|
||||
#endif // CONTINUABLE_DETAIL_TRANSFORMS_FUTURE_HPP_INCLUDED
|
||||
#endif // CONTINUABLE_DETAIL_TRANSFORMS_HPP_INCLUDED
|
||||
@ -1,264 +0,0 @@
|
||||
|
||||
/*
|
||||
|
||||
/~` _ _ _|_. _ _ |_ | _
|
||||
\_,(_)| | | || ||_|(_||_)|(/_
|
||||
|
||||
https://github.com/Naios/continuable
|
||||
v4.2.0
|
||||
|
||||
Copyright(c) 2015 - 2022 Denis Blank <denis.blank at outlook dot com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files(the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions :
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
**/
|
||||
|
||||
#ifndef CONTINUABLE_DETAIL_TRANSFORMS_WAIT_HPP_INCLUDED
|
||||
#define CONTINUABLE_DETAIL_TRANSFORMS_WAIT_HPP_INCLUDED
|
||||
|
||||
#include <atomic>
|
||||
#include <cassert>
|
||||
#include <condition_variable>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <continuable/continuable-primitives.hpp>
|
||||
#include <continuable/continuable-result.hpp>
|
||||
#include <continuable/detail/core/annotation.hpp>
|
||||
#include <continuable/detail/core/base.hpp>
|
||||
#include <continuable/detail/core/types.hpp>
|
||||
#include <continuable/detail/features.hpp>
|
||||
|
||||
#if defined(CONTINUABLE_HAS_EXCEPTIONS)
|
||||
# include <exception>
|
||||
#endif
|
||||
|
||||
namespace cti {
|
||||
namespace detail {
|
||||
namespace transforms {
|
||||
#if defined(CONTINUABLE_HAS_EXCEPTIONS)
|
||||
class wait_transform_canceled_exception : public std::exception {
|
||||
public:
|
||||
wait_transform_canceled_exception() noexcept = default;
|
||||
|
||||
char const* what() const noexcept override {
|
||||
return "cti::transforms::wait canceled due to cancellation of the "
|
||||
"continuation";
|
||||
}
|
||||
};
|
||||
#endif // CONTINUABLE_HAS_EXCEPTIONS
|
||||
|
||||
template <typename Hint>
|
||||
struct sync_trait;
|
||||
template <typename... Args>
|
||||
struct sync_trait<identity<Args...>> {
|
||||
using result_t = result<Args...>;
|
||||
};
|
||||
|
||||
using lock_t = std::unique_lock<std::mutex>;
|
||||
using condition_variable_t = std::condition_variable;
|
||||
|
||||
template <typename Result>
|
||||
struct unsafe_unlocker {
|
||||
explicit unsafe_unlocker(std::atomic_bool* ready, condition_variable_t* cv,
|
||||
std::mutex* mutex, Result* result)
|
||||
: ready_(ready)
|
||||
, cv_(cv)
|
||||
, mutex_(mutex)
|
||||
, result_(result) {}
|
||||
|
||||
unsafe_unlocker(unsafe_unlocker const&) = delete;
|
||||
unsafe_unlocker(unsafe_unlocker&&) = default;
|
||||
unsafe_unlocker& operator=(unsafe_unlocker const&) = delete;
|
||||
unsafe_unlocker& operator=(unsafe_unlocker&&) = default;
|
||||
|
||||
~unsafe_unlocker() {
|
||||
unlock(Result::empty());
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
void operator()(Args&&... args) {
|
||||
unlock(Result::from(std::forward<Args>(args)...));
|
||||
}
|
||||
|
||||
void unlock(Result&& result) {
|
||||
if (!ownership_.is_acquired()) {
|
||||
return;
|
||||
}
|
||||
ownership_.release();
|
||||
|
||||
lock_t lock(*mutex_);
|
||||
|
||||
*result_ = std::move(result);
|
||||
|
||||
assert(!ready_->load(std::memory_order_acquire));
|
||||
ready_->store(true, std::memory_order_release);
|
||||
|
||||
cv_->notify_all();
|
||||
}
|
||||
|
||||
std::atomic_bool* ready_;
|
||||
condition_variable_t* cv_;
|
||||
std::mutex* mutex_;
|
||||
Result* result_;
|
||||
util::ownership ownership_;
|
||||
};
|
||||
|
||||
template <typename Data, typename Annotation,
|
||||
typename Result = typename sync_trait<Annotation>::result_t>
|
||||
Result wait_relaxed(continuable_base<Data, Annotation>&& continuable) {
|
||||
|
||||
// Do an immediate unpack if the continuable is ready
|
||||
if (continuable.is_ready()) {
|
||||
return std::move(continuable).unpack();
|
||||
}
|
||||
|
||||
condition_variable_t cv;
|
||||
std::mutex cv_mutex;
|
||||
|
||||
std::atomic_bool ready{false};
|
||||
Result sync_result;
|
||||
|
||||
std::move(continuable)
|
||||
.next(unsafe_unlocker<Result>{
|
||||
&ready,
|
||||
&cv,
|
||||
&cv_mutex,
|
||||
&sync_result,
|
||||
})
|
||||
.done();
|
||||
|
||||
lock_t lock(cv_mutex);
|
||||
if (!ready.load(std::memory_order_acquire)) {
|
||||
cv.wait(lock, [&] {
|
||||
return ready.load(std::memory_order_acquire);
|
||||
});
|
||||
}
|
||||
|
||||
return sync_result;
|
||||
}
|
||||
|
||||
/// Transforms the continuation to sync execution and unpacks the result the if
|
||||
/// possible
|
||||
template <typename Data, typename Annotation>
|
||||
auto wait_and_unpack(continuable_base<Data, Annotation>&& continuable) {
|
||||
|
||||
auto sync_result = wait_relaxed(std::move(continuable));
|
||||
|
||||
#if defined(CONTINUABLE_HAS_EXCEPTIONS)
|
||||
if (sync_result.is_value()) {
|
||||
return std::move(sync_result).get_value();
|
||||
} else if (sync_result.is_exception()) {
|
||||
if (sync_result.is_exception()) {
|
||||
if (exception_t e = sync_result.get_exception()) {
|
||||
std::rethrow_exception(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
throw wait_transform_canceled_exception();
|
||||
#else
|
||||
return sync_result;
|
||||
#endif // CONTINUABLE_HAS_EXCEPTIONS
|
||||
}
|
||||
|
||||
template <typename Result>
|
||||
struct wait_frame {
|
||||
std::mutex cv_mutex;
|
||||
std::mutex rw_mutex;
|
||||
condition_variable_t cv;
|
||||
std::atomic_bool ready{false};
|
||||
Result sync_result;
|
||||
};
|
||||
|
||||
template <typename Result>
|
||||
struct unlocker {
|
||||
unlocker(unlocker const&) = delete;
|
||||
unlocker(unlocker&&) = default;
|
||||
unlocker& operator=(unlocker const&) = delete;
|
||||
unlocker& operator=(unlocker&&) = default;
|
||||
|
||||
explicit unlocker(std::weak_ptr<wait_frame<Result>> frame)
|
||||
: frame_(std::move(frame)) {}
|
||||
|
||||
~unlocker() {
|
||||
unlock(Result::empty());
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
void operator()(Args&&... args) {
|
||||
unlock(Result::from(std::forward<decltype(args)>(args)...));
|
||||
}
|
||||
|
||||
void unlock(Result&& result) {
|
||||
if (!ownership_.is_acquired()) {
|
||||
return;
|
||||
}
|
||||
ownership_.release();
|
||||
|
||||
if (auto locked = frame_.lock()) {
|
||||
{
|
||||
std::lock_guard<std::mutex> rw_lock(locked->rw_mutex);
|
||||
assert(!locked->ready.load(std::memory_order_acquire));
|
||||
locked->sync_result = std::move(result);
|
||||
}
|
||||
|
||||
locked->ready.store(true, std::memory_order_release);
|
||||
locked->cv.notify_all();
|
||||
}
|
||||
}
|
||||
|
||||
std::weak_ptr<wait_frame<Result>> frame_;
|
||||
util::ownership ownership_;
|
||||
};
|
||||
|
||||
template <typename Data, typename Annotation, typename Waiter,
|
||||
typename Result = typename sync_trait<Annotation>::result_t>
|
||||
Result wait_unsafe(continuable_base<Data, Annotation>&& continuable,
|
||||
Waiter&& waiter) {
|
||||
|
||||
// Do an immediate unpack if the continuable is ready
|
||||
if (continuable.is_ready()) {
|
||||
return std::move(continuable).unpack();
|
||||
}
|
||||
|
||||
using frame_t = wait_frame<Result>;
|
||||
|
||||
auto frame = std::make_shared<frame_t>();
|
||||
|
||||
std::move(continuable)
|
||||
.next(unlocker<Result>{std::weak_ptr<frame_t>(frame)})
|
||||
.done();
|
||||
|
||||
if (!frame->ready.load(std::memory_order_acquire)) {
|
||||
lock_t lock(frame->cv_mutex);
|
||||
std::forward<Waiter>(waiter)(frame->cv, lock, [&] {
|
||||
return frame->ready.load(std::memory_order_acquire);
|
||||
});
|
||||
}
|
||||
|
||||
return ([&] {
|
||||
std::lock_guard<std::mutex> rw_lock(frame->rw_mutex);
|
||||
Result cached = std::move(frame->sync_result);
|
||||
return cached;
|
||||
})();
|
||||
}
|
||||
} // namespace transforms
|
||||
} // namespace detail
|
||||
} // namespace cti
|
||||
|
||||
#endif // CONTINUABLE_DETAIL_TRANSFORMS_WAIT_HPP_INCLUDED
|
||||
@ -5,9 +5,9 @@
|
||||
\_,(_)| | | || ||_|(_||_)|(/_
|
||||
|
||||
https://github.com/Naios/continuable
|
||||
v4.2.0
|
||||
v3.0.0
|
||||
|
||||
Copyright(c) 2015 - 2022 Denis Blank <denis.blank at outlook dot com>
|
||||
Copyright(c) 2015 - 2018 Denis Blank <denis.blank at outlook dot com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files(the "Software"), to deal
|
||||
@ -21,7 +21,7 @@
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
@ -39,8 +39,9 @@
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <continuable/detail/traversal/container-category.hpp>
|
||||
#include <continuable/detail/utility/traits.hpp>
|
||||
|
||||
#include <continuable/detail/container-category.hpp>
|
||||
#include <continuable/detail/traits.hpp>
|
||||
|
||||
namespace cti {
|
||||
namespace detail {
|
||||
@ -97,8 +98,10 @@ public:
|
||||
/// given iterator tuple.
|
||||
template <typename Frame, typename State>
|
||||
auto make_resume_traversal_callable(Frame&& frame, State&& state)
|
||||
-> resume_traversal_callable<std::decay_t<Frame>, std::decay_t<State>> {
|
||||
return resume_traversal_callable<std::decay_t<Frame>, std::decay_t<State>>(
|
||||
-> resume_traversal_callable<typename std::decay<Frame>::type,
|
||||
typename std::decay<State>::type> {
|
||||
return resume_traversal_callable<typename std::decay<Frame>::type,
|
||||
typename std::decay<State>::type>(
|
||||
std::forward<Frame>(frame), std::forward<State>(state));
|
||||
}
|
||||
|
||||
@ -228,8 +231,7 @@ struct static_async_range {
|
||||
}
|
||||
|
||||
template <std::size_t Position>
|
||||
constexpr auto relocate(std::integral_constant<std::size_t, Position>) const
|
||||
noexcept {
|
||||
constexpr auto relocate() const noexcept {
|
||||
return static_async_range<Target, Position, End>{target_};
|
||||
}
|
||||
|
||||
@ -289,9 +291,9 @@ struct dynamic_async_range {
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
using dynamic_async_range_of_t =
|
||||
dynamic_async_range<std::decay_t<decltype(std::begin(std::declval<T>()))>,
|
||||
std::decay_t<decltype(std::end(std::declval<T>()))>>;
|
||||
using dynamic_async_range_of_t = dynamic_async_range<
|
||||
typename std::decay<decltype(std::begin(std::declval<T>()))>::type,
|
||||
typename std::decay<decltype(std::end(std::declval<T>()))>::type>;
|
||||
|
||||
/// Returns a dynamic range for the given type
|
||||
template <typename T>
|
||||
@ -335,8 +337,9 @@ public:
|
||||
auto hierarchy = std::tuple_cat(
|
||||
std::make_tuple(std::forward<Parent>(parent)), hierarchy_);
|
||||
|
||||
return async_traversal_point<Frame, std::decay_t<Parent>, Hierarchy...>(
|
||||
frame_, std::move(hierarchy), detached_);
|
||||
return async_traversal_point<Frame, typename std::decay<Parent>::type,
|
||||
Hierarchy...>(frame_, std::move(hierarchy),
|
||||
detached_);
|
||||
}
|
||||
|
||||
/// Forks the current traversal point and continues the child
|
||||
@ -402,7 +405,7 @@ public:
|
||||
/// Async traverse the current iterator
|
||||
template <typename Current>
|
||||
void async_traverse_one(Current&& current) {
|
||||
using ElementType = std::decay_t<decltype(*current)>;
|
||||
using ElementType = typename std::decay<decltype(*current)>::type;
|
||||
return async_traverse_one_impl(container_category_of_t<ElementType>{},
|
||||
std::forward<Current>(current));
|
||||
}
|
||||
@ -419,8 +422,8 @@ public:
|
||||
template <std::size_t... Sequence, typename Current>
|
||||
void async_traverse_static_async_range(
|
||||
std::integer_sequence<std::size_t, Sequence...>, Current&& current) {
|
||||
int dummy[] = {0, (async_traverse_one_checked(current.relocate(
|
||||
std::integral_constant<std::size_t, Sequence>{})),
|
||||
int dummy[] = {0, ((void)async_traverse_one_checked(
|
||||
current.template relocate<Sequence>()),
|
||||
0)...};
|
||||
(void)dummy;
|
||||
(void)current;
|
||||
@ -450,7 +453,8 @@ public:
|
||||
/// given frame and hierarchy
|
||||
template <typename Frame, typename... Hierarchy>
|
||||
using traversal_point_of_t =
|
||||
async_traversal_point<std::decay_t<Frame>, std::decay_t<Hierarchy>...>;
|
||||
async_traversal_point<typename std::decay<Frame>::type,
|
||||
typename std::decay<Hierarchy>::type...>;
|
||||
|
||||
/// A callable object which is capable of resuming an asynchronous
|
||||
/// pack traversal.
|
||||
@ -516,7 +520,7 @@ struct resume_state_callable {
|
||||
template <typename Frame, typename State>
|
||||
void resume_traversal_callable<Frame, State>::operator()() {
|
||||
auto hierarchy = std::tuple_cat(std::make_tuple(frame_), state_);
|
||||
traits::unpack(resume_state_callable{}, std::move(hierarchy));
|
||||
traits::unpack(std::move(hierarchy), resume_state_callable{});
|
||||
}
|
||||
|
||||
/// Gives access to types related to the traversal frame
|
||||
@ -524,8 +528,8 @@ template <typename Visitor, typename... Args>
|
||||
struct async_traversal_types {
|
||||
/// Deduces to the async traversal frame type of the given
|
||||
/// traversal arguments and mapper
|
||||
using frame_t =
|
||||
async_traversal_frame<std::decay_t<Visitor>, std::decay_t<Args>...>;
|
||||
using frame_t = async_traversal_frame<typename std::decay<Visitor>::type,
|
||||
typename std::decay<Args>::type...>;
|
||||
|
||||
/// The type of the demoted visitor type
|
||||
using visitor_t = Visitor;
|
||||
@ -5,9 +5,9 @@
|
||||
\_,(_)| | | || ||_|(_||_)|(/_
|
||||
|
||||
https://github.com/Naios/continuable
|
||||
v4.2.0
|
||||
v3.0.0
|
||||
|
||||
Copyright(c) 2015 - 2022 Denis Blank <denis.blank at outlook dot com>
|
||||
Copyright(c) 2015 - 2018 Denis Blank <denis.blank at outlook dot com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files(the "Software"), to deal
|
||||
@ -21,7 +21,7 @@
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
@ -37,8 +37,9 @@
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <continuable/detail/traversal/container-category.hpp>
|
||||
#include <continuable/detail/utility/traits.hpp>
|
||||
|
||||
#include <continuable/detail/container-category.hpp>
|
||||
#include <continuable/detail/traits.hpp>
|
||||
|
||||
namespace cti {
|
||||
namespace detail {
|
||||
@ -169,7 +170,8 @@ struct flat_arraylizer {
|
||||
/// Deduces to the array type when the array is instantiated
|
||||
/// with the given arguments.
|
||||
template <typename First, typename... Rest>
|
||||
using array_type_of_t = Type<std::decay_t<First>, 1 + sizeof...(Rest)>;
|
||||
using array_type_of_t =
|
||||
Type<typename std::decay<First>::type, 1 + sizeof...(Rest)>;
|
||||
|
||||
// We overload with one argument here so Clang and GCC don't
|
||||
// have any issues with overloading against zero arguments.
|
||||
@ -190,10 +192,10 @@ struct flat_arraylizer {
|
||||
template <typename C, typename... T>
|
||||
constexpr auto apply_spread_impl(std::true_type, C&& callable, T&&... args)
|
||||
-> decltype(
|
||||
traits::unpack(std::forward<C>(callable),
|
||||
std::tuple_cat(undecorate(std::forward<T>(args))...))) {
|
||||
return traits::unpack(std::forward<C>(callable),
|
||||
std::tuple_cat(undecorate(std::forward<T>(args))...));
|
||||
traits::unpack(std::tuple_cat(undecorate(std::forward<T>(args))...),
|
||||
std::forward<C>(callable))) {
|
||||
return traits::unpack(std::tuple_cat(undecorate(std::forward<T>(args))...),
|
||||
std::forward<C>(callable));
|
||||
}
|
||||
|
||||
/// Use the linear instantiation for variadic packs which don't
|
||||
@ -406,8 +408,9 @@ using element_of_t = typename std::conditional<
|
||||
/// Removes all qualifier and references from the given type
|
||||
/// if the type is a l-value or r-value reference.
|
||||
template <typename T>
|
||||
using dereferenced_of_t = typename std::conditional<std::is_reference<T>::value,
|
||||
std::decay_t<T>, T>::type;
|
||||
using dereferenced_of_t =
|
||||
typename std::conditional<std::is_reference<T>::value,
|
||||
typename std::decay<T>::type, T>::type;
|
||||
|
||||
/// Returns the type which is resulting if the mapping is applied to
|
||||
/// an element in the container.
|
||||
@ -421,8 +424,8 @@ using mapped_type_from_t = dereferenced_of_t<spreading::unpacked_of_t<decltype(
|
||||
|
||||
/// Deduces to a true_type if the mapping maps to zero elements.
|
||||
template <typename T, typename M>
|
||||
using is_empty_mapped = spreading::is_empty_spread<
|
||||
std::decay_t<decltype(std::declval<M>()(std::declval<element_of_t<T>>()))>>;
|
||||
using is_empty_mapped = spreading::is_empty_spread<typename std::decay<decltype(
|
||||
std::declval<M>()(std::declval<element_of_t<T>>()))>::type>;
|
||||
|
||||
/// We are allowed to reuse the container if we map to the same
|
||||
/// type we are accepting and when we have
|
||||
@ -470,9 +473,10 @@ template <typename M, typename T>
|
||||
auto remap_container(container_mapping_tag<false, false>, M&& mapper,
|
||||
T&& container)
|
||||
-> decltype(rebind_container<mapped_type_from_t<T, M>>(container)) {
|
||||
static_assert(has_push_back<std::decay_t<T>, element_of_t<T>>::value,
|
||||
"Can only remap containers that provide a push_back "
|
||||
"method!");
|
||||
static_assert(
|
||||
has_push_back<typename std::decay<T>::type, element_of_t<T>>::value,
|
||||
"Can only remap containers that provide a push_back "
|
||||
"method!");
|
||||
|
||||
// Create the new container, which is capable of holding
|
||||
// the remappped types.
|
||||
@ -500,7 +504,7 @@ auto remap_container(container_mapping_tag<false, false>, M&& mapper,
|
||||
/// type we accepted such as int -> int.
|
||||
template <typename M, typename T>
|
||||
auto remap_container(container_mapping_tag<false, true>, M&& mapper,
|
||||
T&& container) -> std::decay_t<T> {
|
||||
T&& container) -> typename std::decay<T>::type {
|
||||
for (auto&& val : container_accessor_of(std::forward<T>(container))) {
|
||||
val = spreading::unpack(
|
||||
std::forward<M>(mapper)(std::forward<decltype(val)>(val)));
|
||||
@ -626,13 +630,14 @@ struct tuple_like_remapper<
|
||||
/// different types.
|
||||
template <typename Strategy, typename T, typename M>
|
||||
auto remap(Strategy, T&& container, M&& mapper) -> decltype(traits::unpack(
|
||||
std::declval<
|
||||
tuple_like_remapper<Strategy, std::decay_t<M>, std::decay_t<T>>>(),
|
||||
std::forward<T>(container))) {
|
||||
std::forward<T>(container),
|
||||
std::declval<tuple_like_remapper<Strategy, typename std::decay<M>::type,
|
||||
typename std::decay<T>::type>>())) {
|
||||
return traits::unpack(
|
||||
tuple_like_remapper<Strategy, std::decay_t<M>, std::decay_t<T>>{
|
||||
std::forward<M>(mapper)},
|
||||
std::forward<T>(container));
|
||||
std::forward<T>(container),
|
||||
tuple_like_remapper<Strategy, typename std::decay<M>::type,
|
||||
typename std::decay<T>::type>{
|
||||
std::forward<M>(mapper)});
|
||||
}
|
||||
} // end namespace tuple_like_remapping
|
||||
|
||||
@ -641,7 +646,7 @@ auto remap(Strategy, T&& container, M&& mapper) -> decltype(traits::unpack(
|
||||
template <typename Strategy>
|
||||
struct mapping_strategy_base {
|
||||
template <typename T>
|
||||
auto may_void(T&& element) const -> std::decay_t<T> {
|
||||
auto may_void(T&& element) const -> typename std::decay<T>::type {
|
||||
return std::forward<T>(element);
|
||||
}
|
||||
};
|
||||
@ -799,19 +804,19 @@ class mapping_helper : protected mapping_strategy_base<Strategy> {
|
||||
template <typename T>
|
||||
auto traverse(Strategy, T&& element)
|
||||
-> decltype(std::declval<mapping_helper>().match(
|
||||
std::declval<container_category_of_t<std::decay_t<T>>>(),
|
||||
std::declval<container_category_of_t<typename std::decay<T>::type>>(),
|
||||
std::declval<T>()));
|
||||
|
||||
/// \copybrief traverse
|
||||
template <typename T>
|
||||
auto try_traverse(Strategy, T&& element)
|
||||
-> decltype(std::declval<mapping_helper>().try_match(
|
||||
std::declval<container_category_of_t<std::decay_t<T>>>(),
|
||||
std::declval<container_category_of_t<typename std::decay<T>::type>>(),
|
||||
std::declval<T>())) {
|
||||
// We use tag dispatching here, to categorize the type T whether
|
||||
// it satisfies the container or tuple like requirements.
|
||||
// Then we can choose the underlying implementation accordingly.
|
||||
return try_match(container_category_of_t<std::decay_t<T>>{},
|
||||
return try_match(container_category_of_t<typename std::decay<T>::type>{},
|
||||
std::forward<T>(element));
|
||||
}
|
||||
|
||||
@ -857,7 +862,7 @@ public:
|
||||
/// Traverses the given pack with the given mapper and strategy
|
||||
template <typename Strategy, typename Mapper, typename... T>
|
||||
decltype(auto) transform(Strategy strategy, Mapper&& mapper, T&&... pack) {
|
||||
mapping_helper<Strategy, std::decay_t<Mapper>> helper(
|
||||
mapping_helper<Strategy, typename std::decay<Mapper>::type> helper(
|
||||
std::forward<Mapper>(mapper));
|
||||
return helper.init_traverse(strategy, std::forward<T>(pack)...);
|
||||
}
|
||||
@ -5,9 +5,9 @@
|
||||
\_,(_)| | | || ||_|(_||_)|(/_
|
||||
|
||||
https://github.com/Naios/continuable
|
||||
v4.2.0
|
||||
v3.0.0
|
||||
|
||||
Copyright(c) 2015 - 2022 Denis Blank <denis.blank at outlook dot com>
|
||||
Copyright(c) 2015 - 2018 Denis Blank <denis.blank at outlook dot com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files(the "Software"), to deal
|
||||
@ -21,7 +21,7 @@
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
@ -31,10 +31,9 @@
|
||||
#ifndef CONTINUABLE_DETAIL_TYPES_HPP_INCLUDED
|
||||
#define CONTINUABLE_DETAIL_TYPES_HPP_INCLUDED
|
||||
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#include <continuable/detail/features.hpp>
|
||||
#include <continuable/detail/utility/identity.hpp>
|
||||
|
||||
#ifndef CONTINUABLE_WITH_CUSTOM_ERROR_TYPE
|
||||
#ifndef CONTINUABLE_WITH_NO_EXCEPTIONS
|
||||
@ -52,37 +51,32 @@ namespace detail {
|
||||
/// Contains types used globally across the library
|
||||
namespace types {
|
||||
#ifdef CONTINUABLE_WITH_CUSTOM_ERROR_TYPE
|
||||
using exception_t = CONTINUABLE_WITH_CUSTOM_ERROR_TYPE;
|
||||
using error_type = CONTINUABLE_WITH_CUSTOM_ERROR_TYPE;
|
||||
#else // CONTINUABLE_WITH_CUSTOM_ERROR_TYPE
|
||||
#ifndef CONTINUABLE_WITH_NO_EXCEPTIONS
|
||||
/// Represents the exception type when exceptions are enabled
|
||||
using exception_t = std::exception_ptr;
|
||||
/// Represents the error type when exceptions are enabled
|
||||
using error_type = std::exception_ptr;
|
||||
#else // CONTINUABLE_WITH_NO_EXCEPTIONS
|
||||
/// Represents the error type when exceptions are disabled
|
||||
using exception_t = std::error_condition;
|
||||
using error_type = std::error_condition;
|
||||
#endif // CONTINUABLE_WITH_NO_EXCEPTIONS
|
||||
#endif // CONTINUABLE_WITH_CUSTOM_ERROR_TYPE
|
||||
|
||||
/// A tag which is used to execute the continuation inside the current thread
|
||||
struct this_thread_executor_tag {};
|
||||
/// A tag which is used to continue with an error
|
||||
struct dispatch_error_tag {};
|
||||
|
||||
/// Marks a given callable object as transformation
|
||||
template <typename T>
|
||||
class plain_tag {
|
||||
T value_;
|
||||
|
||||
class transform : T {
|
||||
public:
|
||||
template <typename O, std::enable_if_t<std::is_constructible<
|
||||
T, std::decay_t<O>>::value>* = nullptr>
|
||||
/* implicit */ plain_tag(O&& value) : value_(std::forward<O>(value)) {
|
||||
}
|
||||
explicit plain_tag(T value) : value_(std::move(value)) {
|
||||
explicit transform(T callable) : T(std::move(callable)) {
|
||||
}
|
||||
|
||||
T&& consume() && {
|
||||
return std::move(value_);
|
||||
}
|
||||
using T::operator();
|
||||
};
|
||||
|
||||
} // namespace types
|
||||
} // namespace detail
|
||||
} // namespace cti
|
||||
@ -5,9 +5,9 @@
|
||||
\_,(_)| | | || ||_|(_||_)|(/_
|
||||
|
||||
https://github.com/Naios/continuable
|
||||
v4.2.0
|
||||
v3.0.0
|
||||
|
||||
Copyright(c) 2015 - 2022 Denis Blank <denis.blank at outlook dot com>
|
||||
Copyright(c) 2015 - 2018 Denis Blank <denis.blank at outlook dot com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files(the "Software"), to deal
|
||||
@ -21,7 +21,7 @@
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
@ -32,184 +32,108 @@
|
||||
#define CONTINUABLE_DETAIL_UTIL_HPP_INCLUDED
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdlib>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#include <continuable/detail/features.hpp>
|
||||
#include <continuable/detail/utility/traits.hpp>
|
||||
|
||||
/// Hint for the compiler that this point should be unreachable
|
||||
#if defined(_MSC_VER)
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
|
||||
#define CTI_DETAIL_UNREACHABLE_INTRINSIC() __assume(false)
|
||||
#elif defined(__GNUC__)
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
|
||||
#define CTI_DETAIL_UNREACHABLE_INTRINSIC() __builtin_unreachable()
|
||||
#elif defined(__has_builtin) && __has_builtin(__builtin_unreachable)
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
|
||||
#define CTI_DETAIL_UNREACHABLE_INTRINSIC() __builtin_unreachable()
|
||||
#else
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
|
||||
#define CTI_DETAIL_UNREACHABLE_INTRINSIC() abort()
|
||||
#endif
|
||||
|
||||
/// Causes the application to exit abnormally
|
||||
#if defined(_MSC_VER)
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
|
||||
#define CTI_DETAIL_TRAP() __debugbreak()
|
||||
#elif defined(__GNUC__)
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
|
||||
#define CTI_DETAIL_TRAP() __builtin_trap()
|
||||
#elif defined(__has_builtin) && __has_builtin(__builtin_trap)
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
|
||||
#define CTI_DETAIL_TRAP() __builtin_trap()
|
||||
#else
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
|
||||
#define CTI_DETAIL_TRAP() *(volatile int*)0x11 = 0
|
||||
#endif
|
||||
|
||||
#ifndef NDEBUG
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
|
||||
#define CTI_DETAIL_UNREACHABLE() ::cti::detail::util::unreachable_debug()
|
||||
#else
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
|
||||
#define CTI_DETAIL_UNREACHABLE() CTI_DETAIL_UNREACHABLE_INTRINSIC()
|
||||
#endif
|
||||
#include <continuable/detail/traits.hpp>
|
||||
|
||||
namespace cti {
|
||||
namespace detail {
|
||||
/// Utility namespace which provides useful meta-programming support
|
||||
namespace util {
|
||||
#ifndef NDEBUG
|
||||
[[noreturn]] inline void unreachable_debug() {
|
||||
CTI_DETAIL_TRAP();
|
||||
std::abort();
|
||||
}
|
||||
#endif
|
||||
|
||||
/// Helper to trick compilers about that a parameter pack is used
|
||||
template <typename... T>
|
||||
constexpr void unused(T&&...) noexcept {
|
||||
}
|
||||
|
||||
namespace detail {
|
||||
template <typename T, std::size_t... I>
|
||||
auto forward_except_last_impl(T&& tuple,
|
||||
std::integer_sequence<std::size_t, I...>) {
|
||||
(void)tuple;
|
||||
return std::forward_as_tuple(std::get<I>(std::forward<T>(tuple))...);
|
||||
}
|
||||
|
||||
template <std::size_t Size>
|
||||
constexpr auto make_decreased_index_sequence(
|
||||
std::integral_constant<std::size_t, Size>) noexcept {
|
||||
return std::make_index_sequence<Size - 1>();
|
||||
}
|
||||
inline void make_decreased_index_sequence(
|
||||
std::integral_constant<std::size_t, 0U>) noexcept {
|
||||
// This function is only instantiated on a compiler error and
|
||||
// should not be included in valid code.
|
||||
// See https://github.com/Naios/continuable/issues/21 for details.
|
||||
CTI_DETAIL_UNREACHABLE();
|
||||
}
|
||||
|
||||
/// Forwards every element in the tuple except the last one
|
||||
template <typename T>
|
||||
auto forward_except_last(T&& sequenceable) {
|
||||
static_assert(
|
||||
std::tuple_size<std::decay_t<T>>::value > 0U,
|
||||
"Attempt to remove a parameter from an empty tuple like type! If you see "
|
||||
"this your compiler could run into possible infinite recursion! Open a "
|
||||
"ticket at https://github.com/Naios/continuable/issues with a small "
|
||||
"reproducible example if your compiler doesn't stop!");
|
||||
constexpr auto const size = pack_size_of(traits::identify<T>()) - 1U;
|
||||
constexpr auto const sequence = std::make_index_sequence<size>();
|
||||
|
||||
constexpr auto size = std::tuple_size<std::decay_t<T>>::value;
|
||||
constexpr auto sequence = make_decreased_index_sequence(
|
||||
std::integral_constant<std::size_t, size>{});
|
||||
|
||||
return forward_except_last_impl(std::forward<T>(sequenceable), sequence);
|
||||
return traits::unpack(std::forward<T>(sequenceable),
|
||||
[](auto&&... args) {
|
||||
return std::forward_as_tuple(
|
||||
std::forward<decltype(args)>(args)...);
|
||||
},
|
||||
sequence);
|
||||
}
|
||||
|
||||
template <std::size_t Keep>
|
||||
struct invocation_env {
|
||||
/// We are able to call the callable with the arguments given in the tuple
|
||||
template <typename T, typename... Args>
|
||||
static auto partial_invoke_impl(std::true_type, T&& callable,
|
||||
std::tuple<Args...> args) {
|
||||
return traits::unpack(std::forward<T>(callable), std::move(args));
|
||||
}
|
||||
/// We are able to call the callable with the arguments given in the tuple
|
||||
template <typename T, typename... Args>
|
||||
auto partial_invoke_impl(std::true_type, T&& callable,
|
||||
std::tuple<Args...> args) {
|
||||
return traits::unpack(std::move(args), [&](auto&&... arg) {
|
||||
return std::forward<T>(callable)(std::forward<decltype(arg)>(arg)...);
|
||||
});
|
||||
}
|
||||
|
||||
/// We were unable to call the callable with the arguments in the tuple.
|
||||
/// Remove the last argument from the tuple and try it again.
|
||||
template <typename T, typename... Args>
|
||||
static auto partial_invoke_impl(std::false_type, T&& callable,
|
||||
std::tuple<Args...> args) {
|
||||
/// We were unable to call the callable with the arguments in the tuple.
|
||||
/// Remove the last argument from the tuple and try it again.
|
||||
template <typename T, typename... Args>
|
||||
auto partial_invoke_impl(std::false_type, T&& callable,
|
||||
std::tuple<Args...> args) {
|
||||
|
||||
// If you are encountering this assertion you tried to attach a callback
|
||||
// which can't accept the arguments of the continuation.
|
||||
//
|
||||
// ```cpp
|
||||
// continuable<int, int> c;
|
||||
// std::move(c).then([](std::vector<int> v) { /*...*/ })
|
||||
// ```
|
||||
static_assert(
|
||||
sizeof...(Args) > Keep,
|
||||
"There is no way to call the given object with these arguments!");
|
||||
// If you are encountering this assertion you tried to attach a callback
|
||||
// which can't accept the arguments of the continuation.
|
||||
//
|
||||
// ```cpp
|
||||
// continuable<int, int> c;
|
||||
// std::move(c).then([](std::vector<int> v) { /*...*/ })
|
||||
// ```
|
||||
static_assert(
|
||||
sizeof...(Args) > 0,
|
||||
"There is no way to call the given object with these arguments!");
|
||||
|
||||
// Remove the last argument from the tuple
|
||||
auto next = forward_except_last(std::move(args));
|
||||
// Remove the last argument from the tuple
|
||||
auto next = forward_except_last(std::move(args));
|
||||
|
||||
// Test whether we are able to call the function with the given tuple
|
||||
constexpr std::integral_constant<
|
||||
bool, traits::is_invocable_from_tuple<decltype(callable),
|
||||
decltype(next)>::value ||
|
||||
(sizeof...(Args) <= Keep)>
|
||||
is_callable;
|
||||
// Test whether we are able to call the function with the given tuple
|
||||
traits::is_invokable_from_tuple<decltype(callable), decltype(next)>
|
||||
is_invokable;
|
||||
|
||||
return partial_invoke_impl(is_callable, std::forward<T>(callable),
|
||||
std::move(next));
|
||||
}
|
||||
return partial_invoke_impl(is_invokable, std::forward<T>(callable),
|
||||
std::move(next));
|
||||
}
|
||||
|
||||
/// Shortcut - we can call the callable directly
|
||||
template <typename T, typename... Args>
|
||||
static auto partial_invoke_impl_shortcut(std::true_type, T&& callable,
|
||||
Args&&... args) {
|
||||
return std::forward<T>(callable)(std::forward<Args>(args)...);
|
||||
}
|
||||
/// Shortcut - we can call the callable directly
|
||||
template <typename T, typename... Args>
|
||||
auto partial_invoke_impl_shortcut(std::true_type, T&& callable,
|
||||
Args&&... args) {
|
||||
return std::forward<T>(callable)(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
/// Failed shortcut - we were unable to invoke the callable with the
|
||||
/// original arguments.
|
||||
template <typename T, typename... Args>
|
||||
static auto partial_invoke_impl_shortcut(std::false_type failed, T&& callable,
|
||||
Args&&... args) {
|
||||
/// Failed shortcut - we were unable to invoke the callable with the
|
||||
/// original arguments.
|
||||
template <typename T, typename... Args>
|
||||
auto partial_invoke_impl_shortcut(std::false_type failed, T&& callable,
|
||||
Args&&... args) {
|
||||
|
||||
// Our shortcut failed, convert the arguments into a forwarding tuple
|
||||
return partial_invoke_impl(
|
||||
failed, std::forward<T>(callable),
|
||||
std::forward_as_tuple(std::forward<Args>(args)...));
|
||||
}
|
||||
};
|
||||
// Our shortcut failed, convert the arguments into a forwarding tuple
|
||||
return partial_invoke_impl(
|
||||
failed, std::forward<T>(callable),
|
||||
std::forward_as_tuple(std::forward<Args>(args)...));
|
||||
}
|
||||
} // namespace detail
|
||||
|
||||
/// Partially invokes the given callable with the given arguments.
|
||||
///
|
||||
/// \note This function will assert statically if there is no way to call the
|
||||
/// given object with less arguments.
|
||||
template <std::size_t KeepArgs, typename T, typename... Args>
|
||||
/*keep this inline*/ inline auto
|
||||
partial_invoke(std::integral_constant<std::size_t, KeepArgs>, T&& callable,
|
||||
Args&&... args) {
|
||||
template <typename T, typename... Args>
|
||||
/*keep this inline*/ inline auto partial_invoke(T&& callable, Args&&... args) {
|
||||
// Test whether we are able to call the function with the given arguments.
|
||||
constexpr traits::is_invocable_from_tuple<decltype(callable),
|
||||
std::tuple<Args...>>
|
||||
is_invocable;
|
||||
traits::is_invokable_from_tuple<decltype(callable), std::tuple<Args...>>
|
||||
is_invokable;
|
||||
|
||||
// The implementation is done in a shortcut way so there are less
|
||||
// type instantiations needed to call the callable with its full signature.
|
||||
using env = detail::invocation_env<KeepArgs>;
|
||||
return env::partial_invoke_impl_shortcut(
|
||||
is_invocable, std::forward<T>(callable), std::forward<Args>(args)...);
|
||||
return detail::partial_invoke_impl_shortcut(
|
||||
is_invokable, std::forward<T>(callable), std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
/// Invokes the given callable object with the given arguments
|
||||
@ -237,12 +161,6 @@ constexpr auto invoke(Type T::*member, Self&& self, Args&&... args) noexcept(
|
||||
return (std::forward<Self>(self)->*member)(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
/// Returns a constant view on the object
|
||||
template <typename T>
|
||||
constexpr std::add_const_t<T>& as_const(T& object) noexcept {
|
||||
return object;
|
||||
}
|
||||
|
||||
// Class for making child classes non copyable
|
||||
struct non_copyable {
|
||||
constexpr non_copyable() = default;
|
||||
@ -319,8 +237,39 @@ private:
|
||||
/// Is true when the automatic invocation on destruction is disabled
|
||||
bool frozen_ : 1;
|
||||
};
|
||||
|
||||
/// Hint for the compiler that this point should be unreachable
|
||||
[[noreturn]] inline void unreachable() {
|
||||
#if defined(_MSC_VER)
|
||||
__assume(false);
|
||||
#elif defined(__GNUC__)
|
||||
__builtin_unreachable();
|
||||
#elif defined(__has_builtin) && __has_builtin(__builtin_unreachable)
|
||||
__builtin_unreachable();
|
||||
#endif
|
||||
}
|
||||
|
||||
/// Causes the application to exit abnormally because we are
|
||||
/// in an invalid state.
|
||||
[[noreturn]] inline void trap() {
|
||||
#if defined(_MSC_VER)
|
||||
__debugbreak();
|
||||
#elif defined(__GNUC__)
|
||||
__builtin_trap();
|
||||
#elif defined(__has_builtin) && __has_builtin(__builtin_trap)
|
||||
__builtin_trap();
|
||||
#else
|
||||
*(volatile int*)0 = 0;
|
||||
#endif
|
||||
}
|
||||
} // namespace util
|
||||
} // namespace detail
|
||||
} // namespace cti
|
||||
|
||||
#ifdef CONTINUABLE_CONSTEXPR_IF
|
||||
#define CONTINUABLE_CONSTEXPR_IF(EXPR, TRUE_BRANCH, FALSE_BRANCH)
|
||||
#else
|
||||
#define CONTINUABLE_CONSTEXPR_IF(EXPR, TRUE_BRANCH, FALSE_BRANCH)
|
||||
#endif // CONTINUABLE_CONSTEXPR_IF
|
||||
|
||||
#endif // CONTINUABLE_DETAIL_UTIL_HPP_INCLUDED
|
||||
@ -1,54 +0,0 @@
|
||||
|
||||
/*
|
||||
|
||||
/~` _ _ _|_. _ _ |_ | _
|
||||
\_,(_)| | | || ||_|(_||_)|(/_
|
||||
|
||||
https://github.com/Naios/continuable
|
||||
v4.2.0
|
||||
|
||||
Copyright(c) 2015 - 2022 Denis Blank <denis.blank at outlook dot com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files(the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions :
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
**/
|
||||
|
||||
#ifndef CONTINUABLE_DETAIL_IDENTITY_HPP_INCLUDED
|
||||
#define CONTINUABLE_DETAIL_IDENTITY_HPP_INCLUDED
|
||||
|
||||
#include <type_traits>
|
||||
#include <continuable/detail/features.hpp>
|
||||
|
||||
namespace cti {
|
||||
namespace detail {
|
||||
/// A tagging type for wrapping other types
|
||||
template <typename... T>
|
||||
struct identity {};
|
||||
|
||||
template <typename>
|
||||
struct is_identity : std::false_type {};
|
||||
template <typename... Args>
|
||||
struct is_identity<identity<Args...>> : std::true_type {};
|
||||
|
||||
template <typename T>
|
||||
using identify = std::conditional_t<is_identity<std::decay_t<T>>::value, T,
|
||||
identity<std::decay_t<T>>>;
|
||||
} // namespace detail
|
||||
} // namespace cti
|
||||
|
||||
#endif // CONTINUABLE_DETAIL_IDENTITY_HPP_INCLUDED
|
||||
@ -1,101 +0,0 @@
|
||||
|
||||
/*
|
||||
|
||||
/~` _ _ _|_. _ _ |_ | _
|
||||
\_,(_)| | | || ||_|(_||_)|(/_
|
||||
|
||||
https://github.com/Naios/continuable
|
||||
v4.2.0
|
||||
|
||||
Copyright(c) 2015 - 2022 Denis Blank <denis.blank at outlook dot com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files(the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions :
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
**/
|
||||
|
||||
#ifndef CONTINUABLE_DETAIL_RESULT_TRAIT_HPP_INCLUDED
|
||||
#define CONTINUABLE_DETAIL_RESULT_TRAIT_HPP_INCLUDED
|
||||
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <continuable/detail/core/annotation.hpp>
|
||||
#include <continuable/detail/utility/traits.hpp>
|
||||
#include <continuable/detail/utility/util.hpp>
|
||||
|
||||
namespace cti {
|
||||
namespace detail {
|
||||
struct void_arg_t { };
|
||||
|
||||
template <typename... T>
|
||||
struct result_trait;
|
||||
template <>
|
||||
struct result_trait<> {
|
||||
using value_t = void;
|
||||
using surrogate_t = void_arg_t;
|
||||
|
||||
static constexpr surrogate_t wrap() noexcept {
|
||||
return {};
|
||||
}
|
||||
|
||||
static constexpr void unwrap(surrogate_t) {
|
||||
}
|
||||
};
|
||||
template <typename T>
|
||||
struct result_trait<T> {
|
||||
using value_t = T;
|
||||
using surrogate_t = value_t;
|
||||
|
||||
static surrogate_t wrap(T arg) {
|
||||
return std::move(arg);
|
||||
}
|
||||
|
||||
template <typename R>
|
||||
static decltype(auto) unwrap(R&& unwrap) {
|
||||
return std::forward<R>(unwrap);
|
||||
}
|
||||
|
||||
template <std::size_t I, typename Result>
|
||||
static decltype(auto) get(Result&& result) {
|
||||
return std::forward<Result>(result).get_value();
|
||||
}
|
||||
};
|
||||
template <typename First, typename Second, typename... Rest>
|
||||
struct result_trait<First, Second, Rest...> {
|
||||
using value_t = std::tuple<First, Second, Rest...>;
|
||||
using surrogate_t = value_t;
|
||||
|
||||
static surrogate_t wrap(First first, Second second, Rest... rest) {
|
||||
return std::make_tuple(std::move(first), std::move(second),
|
||||
std::move(rest)...);
|
||||
}
|
||||
|
||||
template <typename R>
|
||||
static decltype(auto) unwrap(R&& unwrap) {
|
||||
return std::forward<R>(unwrap);
|
||||
}
|
||||
|
||||
template <std::size_t I, typename Result>
|
||||
static decltype(auto) get(Result&& result) {
|
||||
return std::get<I>(std::forward<Result>(result).get_value());
|
||||
}
|
||||
};
|
||||
} // namespace detail
|
||||
} // namespace cti
|
||||
|
||||
#endif // CONTINUABLE_DETAIL_RESULT_TRAIT_HPP_INCLUDED
|
||||
@ -1,217 +0,0 @@
|
||||
|
||||
/*
|
||||
|
||||
/~` _ _ _|_. _ _ |_ | _
|
||||
\_,(_)| | | || ||_|(_||_)|(/_
|
||||
|
||||
https://github.com/Naios/continuable
|
||||
v4.2.0
|
||||
|
||||
Copyright(c) 2015 - 2022 Denis Blank <denis.blank at outlook dot com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files(the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions :
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
**/
|
||||
|
||||
#ifndef CONTINUABLE_DETAIL_RESULT_VARIANT_HPP_INCLUDED
|
||||
#define CONTINUABLE_DETAIL_RESULT_VARIANT_HPP_INCLUDED
|
||||
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <initializer_list>
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <continuable/detail/utility/traits.hpp>
|
||||
|
||||
namespace cti {
|
||||
namespace detail {
|
||||
namespace container {
|
||||
enum class result_slot_t : std::uint8_t {
|
||||
slot_empty,
|
||||
slot_value,
|
||||
slot_exception,
|
||||
};
|
||||
} // namespace container
|
||||
|
||||
struct init_empty_arg_t {};
|
||||
struct init_result_arg_t {};
|
||||
struct init_exception_arg_t {};
|
||||
|
||||
template <typename T>
|
||||
class result_variant {
|
||||
static constexpr bool is_nothrow_destructible = //
|
||||
std::is_nothrow_destructible<T>::value &&
|
||||
std::is_nothrow_destructible<exception_t>::value;
|
||||
static constexpr bool is_nothrow_move_constructible = //
|
||||
std::is_nothrow_move_constructible<T>::value &&
|
||||
std::is_nothrow_move_constructible<exception_t>::value;
|
||||
|
||||
public:
|
||||
result_variant() = default;
|
||||
~result_variant() noexcept(is_nothrow_destructible) {
|
||||
destroy();
|
||||
}
|
||||
|
||||
explicit result_variant(init_empty_arg_t) noexcept
|
||||
: slot_(container::result_slot_t::slot_empty) {}
|
||||
explicit result_variant(init_result_arg_t, T value) noexcept(
|
||||
std::is_nothrow_destructible<T>::value&&
|
||||
std::is_nothrow_move_constructible<T>::value)
|
||||
: slot_(container::result_slot_t::slot_value) {
|
||||
new (value_ptr()) T(std::move(value));
|
||||
}
|
||||
explicit result_variant(init_exception_arg_t, exception_t exception) noexcept(
|
||||
std::is_nothrow_destructible<exception_t>::value&&
|
||||
std::is_nothrow_move_constructible<exception_t>::value)
|
||||
: slot_(container::result_slot_t::slot_exception) {
|
||||
new (exception_ptr()) exception_t(std::move(exception));
|
||||
}
|
||||
|
||||
result_variant(result_variant const&) = delete;
|
||||
result_variant& operator=(result_variant const&) = delete;
|
||||
|
||||
result_variant(result_variant&& other) noexcept(
|
||||
is_nothrow_destructible&& is_nothrow_move_constructible)
|
||||
: slot_(other.slot_) {
|
||||
|
||||
switch (other.slot_) {
|
||||
case container::result_slot_t::slot_value: {
|
||||
new (value_ptr()) T(std::move(*other.value_ptr()));
|
||||
break;
|
||||
}
|
||||
case container::result_slot_t::slot_exception: {
|
||||
new (exception_ptr()) exception_t(std::move(*other.exception_ptr()));
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
other.destroy();
|
||||
other.slot_ = container::result_slot_t::slot_empty;
|
||||
}
|
||||
|
||||
result_variant& operator=(result_variant&& other) noexcept(
|
||||
is_nothrow_destructible&& is_nothrow_move_constructible) {
|
||||
|
||||
destroy();
|
||||
slot_ = other.slot_;
|
||||
|
||||
switch (other.slot_) {
|
||||
case container::result_slot_t::slot_value: {
|
||||
new (value_ptr()) T(std::move(*other.value_ptr()));
|
||||
break;
|
||||
}
|
||||
case container::result_slot_t::slot_exception: {
|
||||
new (exception_ptr()) exception_t(std::move(*other.exception_ptr()));
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
other.destroy();
|
||||
other.slot_ = container::result_slot_t::slot_empty;
|
||||
return *this;
|
||||
}
|
||||
|
||||
void set_empty() {
|
||||
destroy();
|
||||
slot_ = container::result_slot_t::slot_empty;
|
||||
}
|
||||
void set_value(T value) {
|
||||
destroy();
|
||||
new (value_ptr()) T(std::move(value));
|
||||
slot_ = container::result_slot_t::slot_value;
|
||||
}
|
||||
void set_exception(exception_t exception) {
|
||||
destroy();
|
||||
new (exception_ptr()) exception_t(std::move(exception));
|
||||
slot_ = container::result_slot_t::slot_exception;
|
||||
}
|
||||
|
||||
container::result_slot_t slot() const noexcept {
|
||||
return slot_;
|
||||
}
|
||||
|
||||
bool is_empty() const noexcept {
|
||||
return slot_ == container::result_slot_t::slot_empty;
|
||||
}
|
||||
bool is_value() const noexcept {
|
||||
return slot_ == container::result_slot_t::slot_value;
|
||||
}
|
||||
bool is_exception() const noexcept {
|
||||
return slot_ == container::result_slot_t::slot_exception;
|
||||
}
|
||||
|
||||
T& get_value() noexcept {
|
||||
assert(is_value());
|
||||
return *reinterpret_cast<T*>(&storage_);
|
||||
}
|
||||
T const& get_value() const noexcept {
|
||||
assert(is_value());
|
||||
return *reinterpret_cast<T const*>(&storage_);
|
||||
}
|
||||
|
||||
exception_t& get_exception() noexcept {
|
||||
assert(is_exception());
|
||||
return *reinterpret_cast<exception_t*>(&storage_);
|
||||
}
|
||||
exception_t const& get_exception() const noexcept {
|
||||
assert(is_exception());
|
||||
return *reinterpret_cast<exception_t const*>(&storage_);
|
||||
}
|
||||
|
||||
private:
|
||||
constexpr T* value_ptr() noexcept {
|
||||
return reinterpret_cast<T*>(&storage_);
|
||||
}
|
||||
constexpr exception_t* exception_ptr() noexcept {
|
||||
return reinterpret_cast<exception_t*>(&storage_);
|
||||
}
|
||||
|
||||
void destroy() noexcept(is_nothrow_destructible) {
|
||||
switch (slot_) {
|
||||
case container::result_slot_t::slot_value: {
|
||||
value_ptr()->~T();
|
||||
break;
|
||||
}
|
||||
case container::result_slot_t::slot_exception: {
|
||||
exception_ptr()->~exception_t();
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
container::result_slot_t slot_{container::result_slot_t::slot_empty};
|
||||
std::aligned_storage_t<
|
||||
(sizeof(T) > sizeof(exception_t) ? sizeof(T) : sizeof(exception_t)),
|
||||
(alignof(T) > alignof(exception_t) ? alignof(T) : alignof(exception_t))>
|
||||
storage_;
|
||||
};
|
||||
} // namespace detail
|
||||
} // namespace cti
|
||||
|
||||
#endif // CONTINUABLE_DETAIL_RESULT_VARIANT_HPP_INCLUDED
|
||||
@ -1,192 +0,0 @@
|
||||
|
||||
/*
|
||||
|
||||
/~` _ _ _|_. _ _ |_ | _
|
||||
\_,(_)| | | || ||_|(_||_)|(/_
|
||||
|
||||
https://github.com/Naios/continuable
|
||||
v4.2.0
|
||||
|
||||
Copyright(c) 2015 - 2022 Denis Blank <denis.blank at outlook dot com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files(the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions :
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
**/
|
||||
|
||||
#ifndef CONTINUABLE_DETAIL_TRAITS_HPP_INCLUDED
|
||||
#define CONTINUABLE_DETAIL_TRAITS_HPP_INCLUDED
|
||||
|
||||
#include <cstddef>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <continuable/detail/features.hpp>
|
||||
#include <continuable/detail/utility/identity.hpp>
|
||||
|
||||
namespace cti {
|
||||
namespace detail {
|
||||
namespace traits {
|
||||
/// Removes all references and qualifiers from the given type T,
|
||||
/// since std::decay has too much overhead through checking for
|
||||
/// function pointers and arrays also.
|
||||
template <typename T>
|
||||
using unrefcv_t = std::remove_cv_t<std::remove_reference_t<T>>;
|
||||
|
||||
namespace detail {
|
||||
template <typename T, typename... Args>
|
||||
struct index_of_impl;
|
||||
template <typename T, typename... Args>
|
||||
struct index_of_impl<T, T, Args...> : std::integral_constant<std::size_t, 0U> {
|
||||
};
|
||||
template <typename T, typename U, typename... Args>
|
||||
struct index_of_impl<T, U, Args...>
|
||||
: std::integral_constant<std::size_t,
|
||||
1 + index_of_impl<T, Args...>::value> {};
|
||||
} // namespace detail
|
||||
|
||||
/// Evaluates to the index of T in the given pack
|
||||
template <typename T, typename... Args>
|
||||
using index_of_t = detail::index_of_impl<T, Args...>;
|
||||
|
||||
/// Creates a tuple in which r-values gets copied and
|
||||
/// l-values keep their l-value.
|
||||
template <typename... T>
|
||||
auto make_flat_tuple(T&&... args) {
|
||||
return std::tuple<T...>{std::forward<T>(args)...};
|
||||
}
|
||||
|
||||
#if defined(CONTINUABLE_HAS_CXX17_VOID_T)
|
||||
using std::void_t;
|
||||
#else
|
||||
namespace detail {
|
||||
// Equivalent to C++17's std::void_t which targets a bug in GCC,
|
||||
// that prevents correct SFINAE behavior.
|
||||
// See http://stackoverflow.com/questions/35753920 for details.
|
||||
template <typename...>
|
||||
struct deduce_to_void : std::common_type<void> {};
|
||||
} // namespace detail
|
||||
|
||||
/// C++17 like void_t type
|
||||
template <typename... T>
|
||||
using void_t = typename detail::deduce_to_void<T...>::type;
|
||||
#endif // CONTINUABLE_HAS_CXX17_VOID_T
|
||||
|
||||
namespace detail_unpack {
|
||||
using std::get;
|
||||
|
||||
/// Calls the given unpacker with the content of the given sequenceable
|
||||
template <typename U, typename F, std::size_t... I>
|
||||
constexpr auto unpack_impl(U&& unpacker, F&& first_sequenceable,
|
||||
std::integer_sequence<std::size_t, I...>)
|
||||
-> decltype(std::forward<U>(unpacker)(
|
||||
get<I>(std::forward<F>(first_sequenceable))...)) {
|
||||
(void)first_sequenceable;
|
||||
return std::forward<U>(unpacker)(
|
||||
get<I>(std::forward<F>(first_sequenceable))...);
|
||||
}
|
||||
} // namespace detail_unpack
|
||||
|
||||
/// Calls the given callable object with the content of the given sequenceable
|
||||
///
|
||||
/// \note We can't use std::apply here since this implementation is SFINAE
|
||||
/// aware and the std version not! This would lead to compilation errors.
|
||||
template <typename Callable, typename TupleLike,
|
||||
typename Sequence = std::make_index_sequence<
|
||||
std::tuple_size<std::decay_t<TupleLike>>::value>>
|
||||
constexpr auto unpack(Callable&& obj, TupleLike&& tuple_like)
|
||||
-> decltype(detail_unpack::unpack_impl(std::forward<Callable>(obj),
|
||||
std::forward<TupleLike>(tuple_like),
|
||||
Sequence{})) {
|
||||
|
||||
return detail_unpack::unpack_impl(std::forward<Callable>(obj),
|
||||
std::forward<TupleLike>(tuple_like),
|
||||
Sequence{});
|
||||
}
|
||||
|
||||
namespace detail {
|
||||
template <typename T, typename Args, typename = traits::void_t<>>
|
||||
struct is_invokable_impl : std::common_type<std::false_type> {};
|
||||
|
||||
template <typename T, typename... Args>
|
||||
struct is_invokable_impl<
|
||||
T, std::tuple<Args...>,
|
||||
void_t<decltype(std::declval<T>()(std::declval<Args>()...))>>
|
||||
: std::common_type<std::true_type> {};
|
||||
} // namespace detail
|
||||
|
||||
/// Deduces to a std::true_type if the given type is callable with the arguments
|
||||
/// inside the given tuple.
|
||||
/// The main reason for implementing it with the detection idiom instead of
|
||||
/// hana like detection is that MSVC has issues with capturing raw template
|
||||
/// arguments inside lambda closures.
|
||||
///
|
||||
/// ```cpp
|
||||
/// traits::is_invocable<object, std::tuple<Args...>>
|
||||
/// ```
|
||||
template <typename T, typename Args>
|
||||
using is_invocable_from_tuple =
|
||||
typename detail::is_invokable_impl<T, Args>::type;
|
||||
|
||||
// Checks whether the given callable object is invocable with the given
|
||||
// arguments. This doesn't take member functions into account!
|
||||
template <typename T, typename... Args>
|
||||
using is_invocable = is_invocable_from_tuple<T, std::tuple<Args...>>;
|
||||
|
||||
/// Deduces to a std::false_type
|
||||
template <typename T>
|
||||
using fail = std::integral_constant<bool, !std::is_same<T, T>::value>;
|
||||
|
||||
#ifdef CONTINUABLE_HAS_CXX17_DISJUNCTION
|
||||
using std::disjunction;
|
||||
#else
|
||||
namespace detail {
|
||||
/// Declares a C++14 polyfill for C++17 std::disjunction.
|
||||
template <typename Args, typename = void_t<>>
|
||||
struct disjunction_impl : std::common_type<std::true_type> {};
|
||||
template <typename... Args>
|
||||
struct disjunction_impl<identity<Args...>,
|
||||
void_t<std::enable_if_t<!bool(Args::value)>...>>
|
||||
: std::common_type<std::false_type> {};
|
||||
} // namespace detail
|
||||
|
||||
template <typename... Args>
|
||||
using disjunction = typename detail::disjunction_impl<identity<Args...>>::type;
|
||||
#endif // CONTINUABLE_HAS_CXX17_DISJUNCTION
|
||||
|
||||
#ifdef CONTINUABLE_HAS_CXX17_CONJUNCTION
|
||||
using std::conjunction;
|
||||
#else
|
||||
namespace detail {
|
||||
/// Declares a C++14 polyfill for C++17 std::conjunction.
|
||||
template <typename Args, typename = void_t<>>
|
||||
struct conjunction_impl : std::common_type<std::false_type> {};
|
||||
template <typename... Args>
|
||||
struct conjunction_impl<identity<Args...>,
|
||||
void_t<std::enable_if_t<bool(Args::value)>...>>
|
||||
: std::common_type<std::true_type> {};
|
||||
} // namespace detail
|
||||
|
||||
template <typename... Args>
|
||||
using conjunction = typename detail::conjunction_impl<identity<Args...>>::type;
|
||||
#endif // CONTINUABLE_HAS_CXX17_CONJUNCTION
|
||||
|
||||
} // namespace traits
|
||||
} // namespace detail
|
||||
} // namespace cti
|
||||
|
||||
#endif // CONTINUABLE_DETAIL_TRAITS_HPP_INCLUDED
|
||||
183
include/continuable/external/asio.hpp
vendored
183
include/continuable/external/asio.hpp
vendored
@ -1,183 +0,0 @@
|
||||
/*
|
||||
|
||||
/~` _ _ _|_. _ _ |_ | _
|
||||
\_,(_)| | | || ||_|(_||_)|(/_
|
||||
|
||||
https://github.com/Naios/continuable
|
||||
v4.2.0
|
||||
|
||||
Copyright(c) 2015 - 2022 Denis Blank <denis.blank at outlook dot com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files(the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions :
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
**/
|
||||
|
||||
#ifndef CONTINUABLE_EXTERNAL_ASIO_HPP_INCLUDED
|
||||
#define CONTINUABLE_EXTERNAL_ASIO_HPP_INCLUDED
|
||||
|
||||
#include <continuable/continuable-base.hpp>
|
||||
#include <continuable/detail/external/asio.hpp>
|
||||
#include <continuable/detail/utility/traits.hpp>
|
||||
|
||||
namespace cti {
|
||||
/// The error code type used by your asio distribution
|
||||
///
|
||||
/// \since 4.1.0
|
||||
using asio_error_code_t = detail::asio::error_code_t;
|
||||
|
||||
/// The basic error code enum used by your asio distribution
|
||||
///
|
||||
/// \since 4.1.0
|
||||
using asio_basic_errors_t = detail::asio::basic_errors_t;
|
||||
|
||||
#if defined(CONTINUABLE_HAS_EXCEPTIONS)
|
||||
/// The system error type used by your asio distribution
|
||||
///
|
||||
/// \since 4.1.0
|
||||
using asio_system_error_t = detail::asio::system_error_t;
|
||||
#endif // CONTINUABLE_HAS_EXCEPTIONS
|
||||
|
||||
/// Type used as an ASIO completion token to specify an asynchronous operation
|
||||
/// that should return a continuable_base.
|
||||
///
|
||||
/// - Boost 1.70 or asio 1.13.0 is required for the async initiation
|
||||
/// - Until boost 1.72 or asio 1.16.0 overhead through an additional type
|
||||
/// erasure is added. It is recommended to update to those versions.
|
||||
///
|
||||
/// The special static variable use_continuable can be appended to any
|
||||
/// (boost) asio function that accepts a callback to make it return a
|
||||
/// continuable_base.
|
||||
///
|
||||
/// ```cpp
|
||||
/// #include <continuable/continuable.hpp>
|
||||
/// #include <continuable/external/asio.hpp>
|
||||
/// #include <asio.hpp>
|
||||
///
|
||||
/// // ...
|
||||
///
|
||||
/// asio::tcp::resolver resolver(...);
|
||||
/// resolver.async_resolve("127.0.0.1", "daytime", cti::use_continuable)
|
||||
/// .then([](asio::udp::resolver::iterator iterator) {
|
||||
/// // ...
|
||||
/// });
|
||||
/// ```
|
||||
///
|
||||
/// \tparam Mapper The token can be instantiated with a custom mapper
|
||||
/// for asio error codes which makes it possible to ignore
|
||||
/// errors or treat them as cancellation types.
|
||||
/// The mapper has the following form:
|
||||
/// ```
|
||||
/// struct my_mapper {
|
||||
/// constexpr my_mapper() noexcept {}
|
||||
///
|
||||
/// /// Returns true when the error_code_t is a type which represents
|
||||
/// /// cancellation and
|
||||
/// bool is_cancellation(error_code_t const& /*ec*/) const noexcept {
|
||||
/// return false;
|
||||
/// }
|
||||
/// bool is_ignored(error_code_t const& /*ec*/) const noexcept {
|
||||
/// return false;
|
||||
/// }
|
||||
/// };
|
||||
/// ```
|
||||
///
|
||||
/// \attention `asio::error::basic_errors::operation_aborted` errors returned
|
||||
/// by asio are automatically transformed into a default constructed
|
||||
/// exception type which represents "operation canceled" by the
|
||||
/// user or program. If you intend to retrieve the full
|
||||
/// asio::error_code without remapping use the use_continuable_raw_t
|
||||
/// completion token instead!
|
||||
///
|
||||
/// \since 4.0.0
|
||||
template <typename Mapper = detail::asio::map_default>
|
||||
struct use_continuable_t : public Mapper {
|
||||
using Mapper::Mapper;
|
||||
};
|
||||
|
||||
/// \copydoc use_continuable_t
|
||||
///
|
||||
/// The raw async completion handler token does not remap the asio error
|
||||
/// `asio::error::basic_errors::operation_aborted` to a default constructed
|
||||
/// exception type.
|
||||
///
|
||||
/// \since 4.1.0
|
||||
using use_continuable_raw_t = use_continuable_t<detail::asio::map_none>;
|
||||
|
||||
/// Special value for instance of use_continuable_t which performs remapping
|
||||
/// of asio error codes to align the cancellation behaviour with the library.
|
||||
///
|
||||
/// \copydetails use_continuable_t
|
||||
constexpr use_continuable_t<> use_continuable{};
|
||||
|
||||
/// Special value for instance of use_continuable_raw_t which doesn't perform
|
||||
/// remapping of asio error codes and rethrows the raw error code.
|
||||
///
|
||||
/// \copydetails use_continuable_raw_t
|
||||
constexpr use_continuable_raw_t use_continuable_raw{};
|
||||
|
||||
/// Represents a special asio completion token which treats the given
|
||||
/// asio basic error codes as success instead of failure.
|
||||
///
|
||||
/// `asio::error::basic_errors::operation_aborted` is mapped
|
||||
/// as cancellation token.
|
||||
///
|
||||
/// \since 4.1.0
|
||||
template <typename... Args>
|
||||
auto use_continuable_ignoring(Args&&... args) noexcept {
|
||||
return use_continuable_t<detail::asio::map_ignore<sizeof...(Args)>>{
|
||||
{asio_basic_errors_t(std::forward<Args>(args))...}};
|
||||
}
|
||||
} // namespace cti
|
||||
|
||||
CTI_DETAIL_ASIO_NAMESPACE_BEGIN
|
||||
|
||||
template <typename Signature, typename Matcher>
|
||||
class async_result<cti::use_continuable_t<Matcher>, Signature> {
|
||||
public:
|
||||
#if defined(CTI_DETAIL_ASIO_HAS_EXPLICIT_RET_TYPE_INTEGRATION)
|
||||
using return_type = typename cti::detail::asio::initiate_make_continuable<
|
||||
Signature>::erased_return_type;
|
||||
#endif
|
||||
|
||||
template <typename Initiation, typename... Args>
|
||||
static auto initiate(Initiation initiation,
|
||||
cti::use_continuable_t<Matcher> token, Args... args) {
|
||||
return cti::detail::asio::initiate_make_continuable<Signature>{}(
|
||||
[initiation = std::move(initiation), token = std::move(token),
|
||||
init_args = std::make_tuple(std::move(args)...)](
|
||||
auto&& promise) mutable {
|
||||
cti::detail::traits::unpack(
|
||||
[initiation = std::move(initiation),
|
||||
handler = cti::detail::asio::promise_resolver_handler(
|
||||
std::forward<decltype(promise)>(promise), std::move(token))](
|
||||
auto&&... args) mutable {
|
||||
std::move(initiation)(std::move(handler),
|
||||
std::forward<decltype(args)>(args)...);
|
||||
},
|
||||
std::move(init_args));
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
CTI_DETAIL_ASIO_NAMESPACE_END
|
||||
|
||||
#undef CTI_DETAIL_ASIO_NAMESPACE_BEGIN
|
||||
#undef CTI_DETAIL_ASIO_NAMESPACE_END
|
||||
#undef CTI_DETAIL_ASIO_HAS_EXPLICIT_RET_TYPE_INTEGRATION
|
||||
|
||||
#endif // CONTINUABLE_EXTERNAL_ASIO_HPP_INCLUDED
|
||||
@ -1,116 +0,0 @@
|
||||
|
||||
/*
|
||||
|
||||
/~` _ _ _|_. _ _ |_ | _
|
||||
\_,(_)| | | || ||_|(_||_)|(/_
|
||||
|
||||
https://github.com/Naios/continuable
|
||||
v4.2.0
|
||||
|
||||
Copyright(c) 2015 - 2022 Denis Blank <denis.blank at outlook dot com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files(the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions :
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
**/
|
||||
|
||||
#ifndef CONTINUABLE_OPERATIONS_ASYNC_HPP_INCLUDED
|
||||
#define CONTINUABLE_OPERATIONS_ASYNC_HPP_INCLUDED
|
||||
|
||||
#include <utility>
|
||||
#include <continuable/detail/core/types.hpp>
|
||||
#include <continuable/detail/operations/async.hpp>
|
||||
|
||||
namespace cti {
|
||||
/// \ingroup Operations
|
||||
/// \{
|
||||
|
||||
/// Wraps the given callable inside a continuable_base such that it is
|
||||
/// invoked when the asynchronous result is requested to return the result.
|
||||
///
|
||||
/// The async function shall be seen as an equivalent to std::async.
|
||||
///
|
||||
/// The behaviour will be equal as when using make_ready_continuable together
|
||||
/// with continuable_base::then, but async is implemented in
|
||||
/// a more efficient way:
|
||||
/// ```cpp
|
||||
/// auto do_sth() {
|
||||
/// return async([] {
|
||||
/// do_sth_more();
|
||||
/// return 0;
|
||||
/// });
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// \param callable The callable type which is invoked on request.
|
||||
///
|
||||
/// \param args The arguments which are passed to the callable upon invocation.
|
||||
///
|
||||
/// \returns A continuable_base which asynchronous result type will
|
||||
/// be computed with the same rules as continuable_base::then .
|
||||
///
|
||||
/// \since 4.0.0
|
||||
///
|
||||
template <typename Callable, typename... Args>
|
||||
auto async(Callable&& callable, Args&&... args) {
|
||||
return detail::operations::async(std::forward<Callable>(callable),
|
||||
detail::types::this_thread_executor_tag{},
|
||||
std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
/// Wraps the given callable inside a continuable_base such that it is
|
||||
/// invoked through the given executor when the asynchronous result
|
||||
/// is requested to return the result.
|
||||
///
|
||||
/// The behaviour will be equal as when using make_ready_continuable together
|
||||
/// with continuable_base::then and the given executor but async_on
|
||||
/// is implemented in a more efficient way:
|
||||
/// ```cpp
|
||||
/// auto do_sth() {
|
||||
/// auto executor = [](auto&& work) {
|
||||
/// // Do something with the work here
|
||||
/// std::forward<decltype(work)>(work);
|
||||
/// };
|
||||
///
|
||||
/// return async_on([] {
|
||||
/// do_sth_more();
|
||||
/// return 0;
|
||||
/// }, my_executor);
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// \param callable The callable type which is invoked on request.
|
||||
///
|
||||
/// \param executor The executor that is used to dispatch the given callable.
|
||||
///
|
||||
/// \param args The arguments which are passed to the callable upon invocation.
|
||||
///
|
||||
/// \returns A continuable_base which asynchronous result type will
|
||||
/// be computed with the same rules as continuable_base::then .
|
||||
///
|
||||
/// \since 4.0.0
|
||||
///
|
||||
template <typename Callable, typename Executor, typename... Args>
|
||||
auto async_on(Callable&& callable, Executor&& executor, Args&&... args) {
|
||||
return detail::operations::async(std::forward<Callable>(callable),
|
||||
std::forward<Executor>(executor),
|
||||
std::forward<Args>(args)...);
|
||||
}
|
||||
/// \}
|
||||
} // namespace cti
|
||||
|
||||
#endif // CONTINUABLE_OPERATIONS_ASYNC_HPP_INCLUDED
|
||||
@ -1,141 +0,0 @@
|
||||
|
||||
/*
|
||||
|
||||
/~` _ _ _|_. _ _ |_ | _
|
||||
\_,(_)| | | || ||_|(_||_)|(/_
|
||||
|
||||
https://github.com/Naios/continuable
|
||||
v4.2.0
|
||||
|
||||
Copyright(c) 2015 - 2022 Denis Blank <denis.blank at outlook dot com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files(the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions :
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
**/
|
||||
|
||||
#ifndef CONTINUABLE_OPERATIONS_LOOP_HPP_INCLUDED
|
||||
#define CONTINUABLE_OPERATIONS_LOOP_HPP_INCLUDED
|
||||
|
||||
#include <utility>
|
||||
#include <continuable/continuable-primitives.hpp>
|
||||
#include <continuable/continuable-result.hpp>
|
||||
#include <continuable/detail/operations/loop.hpp>
|
||||
|
||||
namespace cti {
|
||||
/// \ingroup Operations
|
||||
/// \{
|
||||
|
||||
/// Can be used to create an asynchronous loop.
|
||||
///
|
||||
/// The callable will be called repeatedly until it returns a
|
||||
/// cti::continuable_base which then resolves to a present cti::result.
|
||||
///
|
||||
/// For better readability cti::loop_result, cti::loop_break and
|
||||
/// cti::loop_continue are provided which can be used as following:
|
||||
/// ```cpp
|
||||
/// auto while_answer_not_yes() {
|
||||
/// return loop([] {
|
||||
/// return ask_something().then([](std::string answer) -> loop_result<> {
|
||||
/// if (answer == "yes") {
|
||||
/// return loop_break();
|
||||
/// } else {
|
||||
/// return loop_continue();
|
||||
/// }
|
||||
/// });
|
||||
/// });
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// \param callable The callable type which must return a cti::continuable_base
|
||||
/// which then resolves to a cti::result of arbitrary values.
|
||||
///
|
||||
/// \param args The arguments that are passed to the callable upon
|
||||
/// each invocation.
|
||||
///
|
||||
/// \since 4.0.0
|
||||
///
|
||||
template <typename Callable, typename... Args>
|
||||
auto loop(Callable&& callable, Args&&... args) {
|
||||
return detail::operations::loop(std::forward<Callable>(callable),
|
||||
std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
/// Can be used to indicate a specific result inside an asynchronous loop.
|
||||
///
|
||||
/// See cti::loop for details.
|
||||
///
|
||||
/// \since 4.0.0
|
||||
template <typename... T>
|
||||
using loop_result = plain_t<result<T...>>;
|
||||
|
||||
/// Can be used to create a loop_result which causes the loop to be
|
||||
/// cancelled and resolved with the given arguments.
|
||||
///
|
||||
/// See cti::loop for details.
|
||||
///
|
||||
/// \since 4.0.0
|
||||
template <typename... T>
|
||||
auto loop_break(T&&... args) {
|
||||
return make_plain(make_result(std::forward<T>(args)...));
|
||||
}
|
||||
|
||||
/// Can be used to create a loop_result which causes the loop to be repeated.
|
||||
///
|
||||
/// See cti::loop for details.
|
||||
///
|
||||
/// \since 4.0.0
|
||||
inline auto loop_continue() noexcept {
|
||||
return empty_result{};
|
||||
}
|
||||
|
||||
/// Can be used to create an asynchronous loop over a specific range.
|
||||
///
|
||||
/// The callable will be called repeatedly with each with begin increased
|
||||
/// until end is reached.
|
||||
///
|
||||
/// ```cpp
|
||||
/// auto iterate_some() {
|
||||
/// // Iterate step from 0 to 9
|
||||
/// return range_loop([] (int step) {
|
||||
/// return do_something(i).then([] {
|
||||
/// // You don't have to return a result here
|
||||
/// });
|
||||
/// }, 0, 10);
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// \param callable The callable type which must return a cti::continuable_base
|
||||
/// which then resolves to a cti::result of arbitrary values.
|
||||
///
|
||||
/// \param begin The iterator to iterate over
|
||||
///
|
||||
/// \param end The iterator to iterate until
|
||||
///
|
||||
/// \since 4.0.0
|
||||
///
|
||||
template <typename Callable, typename Iterator>
|
||||
auto range_loop(Callable&& callable, Iterator begin, Iterator end) {
|
||||
return detail::operations::loop( //
|
||||
detail::operations::make_range_looper(std::forward<Callable>(callable),
|
||||
begin, end));
|
||||
}
|
||||
|
||||
/// \}
|
||||
} // namespace cti
|
||||
|
||||
#endif // CONTINUABLE_OPERATIONS_LOOP_HPP_INCLUDED
|
||||
@ -1,96 +0,0 @@
|
||||
|
||||
/*
|
||||
|
||||
/~` _ _ _|_. _ _ |_ | _
|
||||
\_,(_)| | | || ||_|(_||_)|(/_
|
||||
|
||||
https://github.com/Naios/continuable
|
||||
v4.2.0
|
||||
|
||||
Copyright(c) 2015 - 2022 Denis Blank <denis.blank at outlook dot com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files(the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions :
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
**/
|
||||
|
||||
#ifndef CONTINUABLE_OPERATIONS_SPLIT_HPP_INCLUDED
|
||||
#define CONTINUABLE_OPERATIONS_SPLIT_HPP_INCLUDED
|
||||
|
||||
#include <utility>
|
||||
#include <continuable/detail/operations/split.hpp>
|
||||
#include <continuable/detail/utility/traits.hpp>
|
||||
|
||||
namespace cti {
|
||||
/// \ingroup Operations
|
||||
/// \{
|
||||
|
||||
/// Splits the asynchronous control flow and merges multiple promises/callbacks
|
||||
/// together, which take the same types of arguments, into one.
|
||||
///
|
||||
/// The invocation order of all promises is undefined.
|
||||
///
|
||||
/// The split function is the opposite of the connection functions
|
||||
/// like `when_all` because is can merge multiple waiters together rather than
|
||||
/// joining those.
|
||||
///
|
||||
/// The split function can be used to resolve multiple waiters when resolving
|
||||
/// a single promise.
|
||||
/// ```cpp
|
||||
/// class my_class {
|
||||
/// cti::promise<> promise_;
|
||||
///
|
||||
/// public:
|
||||
/// cti::continuable<> wait_for_sth() {
|
||||
/// return [this](auto&& promise) mutable {
|
||||
/// // Make sure accessing promise_ is done in a thread safe way!
|
||||
/// promise_ = cti::split(std::move(promise_),
|
||||
/// std::forward<decltype(promise)>(promise));
|
||||
/// };
|
||||
/// }
|
||||
///
|
||||
/// void resolve_all() {
|
||||
/// // Resolves all waiting promises
|
||||
/// promise_.set_value();
|
||||
/// }
|
||||
/// };
|
||||
/// ```
|
||||
///
|
||||
/// \note The split function only works if all asynchronous arguments are
|
||||
/// copyable. All asynchronous arguments and exceptions will be passed
|
||||
/// to all split promises.
|
||||
///
|
||||
/// \param promises The promises to split the control flow into,
|
||||
/// can be single promises or heterogeneous or homogeneous
|
||||
/// containers of promises (see traverse_pack for a description
|
||||
/// of supported nested arguments).
|
||||
///
|
||||
/// \returns A new promise with the same asynchronous result types as
|
||||
/// the given promises.
|
||||
///
|
||||
/// \since 4.0.0
|
||||
///
|
||||
template <typename... Promises>
|
||||
auto split(Promises&&... promises) {
|
||||
return detail::operations::split_promise<
|
||||
detail::traits::unrefcv_t<Promises>...>(
|
||||
std::forward<Promises>(promises)...);
|
||||
}
|
||||
/// \}
|
||||
} // namespace cti
|
||||
|
||||
#endif // CONTINUABLE_OPERATIONS_SPLIT_HPP_INCLUDED
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user