mirror of
https://github.com/Naios/continuable.git
synced 2025-12-06 16:56:44 +08:00
Compare commits
199 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
23a724cf5c | ||
|
|
c7f5b1cbaf | ||
|
|
d1f9306eee | ||
|
|
0641a29f42 | ||
|
|
f7f304e971 | ||
|
|
63e3ed4edc | ||
|
|
b51be39e71 | ||
|
|
ed8310e345 | ||
|
|
01f9dbd1f4 | ||
|
|
2fcc2bf281 | ||
|
|
ace3317f65 | ||
|
|
e6f817ca7b | ||
|
|
e2b5fc36fe | ||
|
|
6bffb44d2b | ||
|
|
48c6abf5f2 | ||
|
|
f57c5898eb | ||
|
|
8187c16ede | ||
|
|
d80f5ef3ec | ||
|
|
5f84de0e86 | ||
|
|
8e63a45840 | ||
|
|
61826817c7 | ||
|
|
735697026b | ||
|
|
9593ba120c | ||
|
|
33bfc490ef | ||
|
|
77faf3120f | ||
|
|
26cd377831 | ||
|
|
923843cd44 | ||
|
|
8c1a79d17b | ||
|
|
5fbc9c4a59 | ||
|
|
adc75655f4 | ||
|
|
1e39bd85dd | ||
|
|
5f8b2aa317 | ||
|
|
37359dec0b | ||
|
|
2c76e6c367 | ||
|
|
0fb66a7eec | ||
|
|
c69385be5f | ||
|
|
ab9669fa2a | ||
|
|
df4d6ed971 | ||
|
|
957d3fa375 | ||
|
|
c8c4325b5b | ||
|
|
f1e9255eb9 | ||
|
|
85c0d76c7c | ||
|
|
ca26bbbc87 | ||
|
|
564d134c75 | ||
|
|
f7e00bcc8d | ||
|
|
89031d932c | ||
|
|
1a1c7b68c6 | ||
|
|
0b1b284e3a | ||
|
|
117a716de1 | ||
|
|
cacb84371a | ||
|
|
92d8bbad36 | ||
|
|
0afdbec2cc | ||
|
|
ffb3db7089 | ||
|
|
7aff2c0d9b | ||
|
|
959f059a25 | ||
|
|
91d51e6543 | ||
|
|
5e8bbe7c72 | ||
|
|
dce0fbcffe | ||
|
|
a2fdfdfceb | ||
|
|
389002e918 | ||
|
|
92368bccb7 | ||
|
|
e09d26f3c6 | ||
|
|
422b6138cd | ||
|
|
42af23fa03 | ||
|
|
bcf55e88dd | ||
|
|
88fbcdbc17 | ||
|
|
c9d0e871cd | ||
|
|
4cc7523380 | ||
|
|
d842c14268 | ||
|
|
e9be3eb8c3 | ||
|
|
67d77808dc | ||
|
|
03ae1b5c45 | ||
|
|
bc4d69735c | ||
|
|
daa2fdd686 | ||
|
|
41f3429c85 | ||
|
|
6b4f6de10f | ||
|
|
fdd9a061c4 | ||
|
|
2bc448b905 | ||
|
|
e23e363b03 | ||
|
|
d72e1bfb86 | ||
|
|
fa589a1e95 | ||
|
|
20cd0191fc | ||
|
|
76ecc3d26d | ||
|
|
7491022d0f | ||
|
|
4c807aec75 | ||
|
|
60b75a6134 | ||
|
|
b86fe7a255 | ||
|
|
a4da3e84ef | ||
|
|
ac175b4e57 | ||
|
|
135ebfccf3 | ||
|
|
5c1cd87739 | ||
|
|
20e8c7d3e3 | ||
|
|
a3a9695174 | ||
|
|
c066940d8d | ||
|
|
2d5aa36b67 | ||
|
|
3bd4dd40de | ||
|
|
a099c504e1 | ||
|
|
7a10363dce | ||
|
|
30f0dca27f | ||
|
|
d4cb7dd7b3 | ||
|
|
f469b7058a | ||
|
|
4127c02c3f | ||
|
|
d052a02595 | ||
|
|
7dbc95c4b3 | ||
|
|
fcf9a76029 | ||
|
|
49e3a659ad | ||
|
|
65916e29a8 | ||
|
|
121265df71 | ||
|
|
4c41995316 | ||
|
|
dd09c3d684 | ||
|
|
ff881091fc | ||
|
|
30d49141a8 | ||
|
|
c7ef5c6f64 | ||
|
|
b2726982ac | ||
|
|
57bb43138b | ||
|
|
1320c8eb63 | ||
|
|
1bdee5b371 | ||
|
|
bdada99096 | ||
|
|
7273891a4c | ||
|
|
9ceee76647 | ||
|
|
4b1f6281fc | ||
|
|
cb6ce5b43b | ||
|
|
24158583b7 | ||
|
|
6947091a27 | ||
|
|
bcafd1b333 | ||
|
|
d416698758 | ||
|
|
b5f353222c | ||
|
|
f5dd02ef8b | ||
|
|
969445c8a0 | ||
|
|
577b71b8ab | ||
|
|
b293d9a342 | ||
|
|
da8ec15c6f | ||
|
|
62ca39e59c | ||
|
|
f17cc4073c | ||
|
|
7a5bde328c | ||
|
|
7352cbf8a9 | ||
|
|
4d58e3bded | ||
|
|
1edd1e633d | ||
|
|
70c716bb28 | ||
|
|
bb7112eec2 | ||
|
|
f1f9d61952 | ||
|
|
b77e926c41 | ||
|
|
812420cf06 | ||
|
|
a9375c7f22 | ||
|
|
ca1c0bf1da | ||
|
|
82dd47b463 | ||
|
|
c5663bf1ad | ||
|
|
afe1a3298e | ||
|
|
9955f9e469 | ||
|
|
ba9ff9fce0 | ||
|
|
7767ce6fbb | ||
|
|
67964b0793 | ||
|
|
41da6ba293 | ||
|
|
cd367b3d43 | ||
|
|
5354d3512e | ||
|
|
2a80649084 | ||
|
|
782e1c6447 | ||
|
|
f4268f60f9 | ||
|
|
07c8ed0cf9 | ||
|
|
ffa3b9ee1b | ||
|
|
93b1d27b07 | ||
|
|
867ab38b8e | ||
|
|
c76fe9e973 | ||
|
|
3a70356f16 | ||
|
|
6969a9e392 | ||
|
|
0657445466 | ||
|
|
815c3d71b9 | ||
|
|
057fb37123 | ||
|
|
2ff7bb9b8d | ||
|
|
8e7af3a320 | ||
|
|
4ae5601563 | ||
|
|
6cd39a2e54 | ||
|
|
818b7a7314 | ||
|
|
7cf7314486 | ||
|
|
8f89835ca4 | ||
|
|
646707e5dc | ||
|
|
a9d4ee5ba8 | ||
|
|
cc83fd5251 | ||
|
|
c1b8aa8694 | ||
|
|
7b4ab90f9c | ||
|
|
fae030afa3 | ||
|
|
2cfbdaf673 | ||
|
|
2b4f31c121 | ||
|
|
ede7a4a72b | ||
|
|
9247e7b85f | ||
|
|
e59e6ae8b9 | ||
|
|
7dbf22a2d2 | ||
|
|
b68cd1b43a | ||
|
|
be6571091b | ||
|
|
358e13e06e | ||
|
|
3a5cea7779 | ||
|
|
139f7d39de | ||
|
|
65e41a2cbd | ||
|
|
83f736a93f | ||
|
|
f091cbb079 | ||
|
|
41c7cb008a | ||
|
|
084937e192 | ||
|
|
0e4b299b45 | ||
|
|
977feb3825 |
@ -1,12 +1,38 @@
|
|||||||
BasedOnStyle: LLVM
|
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
|
PointerAlignment: Left
|
||||||
IndentCaseLabels: true
|
|
||||||
AllowShortFunctionsOnASingleLine: false
|
|
||||||
AllowShortCaseLabelsOnASingleLine: false
|
|
||||||
AlwaysBreakTemplateDeclarations: true
|
|
||||||
BinPackArguments: true
|
|
||||||
FixNamespaceComments: true
|
|
||||||
# IndentPPDirectives: AfterHash
|
|
||||||
MacroBlockBegin: "^CONTINUABLE_BLOCK_.*_BEGIN$"
|
MacroBlockBegin: "^CONTINUABLE_BLOCK_.*_BEGIN$"
|
||||||
MacroBlockEnd: "^CONTINUABLE_BLOCK_.*_END$"
|
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,modernize--*,llvm-*,misc-*,readability-identifier-naming'
|
Checks: '-*,cppcoreguidelines-*,-cppcoreguidelines-pro-type-vararg,-cppcoreguidelines-macro-usage,bugprone-*,modernize-*,boost-*,llvm-*,misc-*,portability-*,readability-*'
|
||||||
CheckOptions:
|
CheckOptions:
|
||||||
- key: readability-identifier-naming.ClassCase
|
- key: readability-identifier-naming.ClassCase
|
||||||
value: lower_case
|
value: lower_case
|
||||||
@ -16,4 +16,4 @@ CheckOptions:
|
|||||||
value: lower_case
|
value: lower_case
|
||||||
- key: readability-identifier-naming.Macro
|
- key: readability-identifier-naming.Macro
|
||||||
value: UPPER_CASE
|
value: UPPER_CASE
|
||||||
HeaderFilterRegex: 'include/.(hpp)$'
|
HeaderFilterRegex: 'include/continuable/.(hpp)$'
|
||||||
|
|||||||
109
.github/workflows/build_and_install.yml
vendored
Normal file
109
.github/workflows/build_and_install.yml
vendored
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
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,3 +47,9 @@ bld/
|
|||||||
|
|
||||||
# Visual Studo 2015 cache/options directory
|
# Visual Studo 2015 cache/options directory
|
||||||
.vs/
|
.vs/
|
||||||
|
|
||||||
|
# VSCode
|
||||||
|
.vscode/
|
||||||
|
|
||||||
|
# TMP files generated from clang-format
|
||||||
|
*.TMP
|
||||||
|
|||||||
10
.gitmodules
vendored
10
.gitmodules
vendored
@ -1,12 +1,16 @@
|
|||||||
[submodule "dep/googletest/googletest"]
|
[submodule "dep/googletest/googletest"]
|
||||||
path = dep/googletest/googletest
|
path = dep/googletest/googletest
|
||||||
url = https://github.com/google/googletest.git
|
url = https://github.com/google/googletest.git
|
||||||
|
branch = master
|
||||||
[submodule "dep/function2/function2"]
|
[submodule "dep/function2/function2"]
|
||||||
path = dep/function2/function2
|
path = dep/function2/function2
|
||||||
url = https://github.com/Naios/function2.git
|
url = https://github.com/Naios/function2.git
|
||||||
[submodule "dep/cxx_function/cxx_function"]
|
branch = master
|
||||||
path = dep/cxx_function/cxx_function
|
|
||||||
url = https://github.com/potswa/cxx_function.git
|
|
||||||
[submodule "dep/asio/asio"]
|
[submodule "dep/asio/asio"]
|
||||||
path = dep/asio/asio
|
path = dep/asio/asio
|
||||||
url = https://github.com/chriskohlhoff/asio.git
|
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
|
||||||
|
|||||||
74
.travis.yml
74
.travis.yml
@ -1,74 +0,0 @@
|
|||||||
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
|
|
||||||
233
CMakeLists.txt
233
CMakeLists.txt
@ -1,5 +1,4 @@
|
|||||||
|
# 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
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
# of this software and associated documentation files(the "Software"), to deal
|
# of this software and associated documentation files(the "Software"), to deal
|
||||||
@ -8,74 +7,109 @@
|
|||||||
# copies of the Software, and to permit persons to whom the Software is
|
# copies of the Software, and to permit persons to whom the Software is
|
||||||
# furnished to do so, subject to the following conditions :
|
# furnished to do so, subject to the following conditions :
|
||||||
#
|
#
|
||||||
# The above copyright notice and this permission notice shall be included in
|
# The above copyright notice and this permission notice shall be included in all
|
||||||
# all copies or substantial portions of the Software.
|
# copies or substantial portions of the Software.
|
||||||
#
|
#
|
||||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
# 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
|
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
# 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
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
# SOFTWARE.
|
# SOFTWARE.
|
||||||
|
|
||||||
cmake_minimum_required(VERSION 3.2)
|
cmake_minimum_required(VERSION 3.11)
|
||||||
project(continuable VERSION 2.0.0 LANGUAGES C CXX)
|
|
||||||
|
|
||||||
string(COMPARE EQUAL ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_SOURCE_DIR}
|
project(
|
||||||
IS_TOP_LEVEL_PROJECT)
|
continuable
|
||||||
|
VERSION 4.0.0
|
||||||
|
LANGUAGES C CXX)
|
||||||
|
|
||||||
option(CTI_CONTINUABLE_WITH_TESTS
|
if(CTI_CONTINUABLE_IS_FIND_INCLUDED)
|
||||||
"Build the continuable unit tests"
|
set(CTI_CONTINUABLE_IS_TOP_LEVEL_PROJECT OFF)
|
||||||
${IS_TOP_LEVEL_PROJECT})
|
else()
|
||||||
|
string(COMPARE EQUAL ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_SOURCE_DIR}
|
||||||
|
CTI_CONTINUABLE_IS_TOP_LEVEL_PROJECT)
|
||||||
|
endif()
|
||||||
|
|
||||||
option(CTI_CONTINUABLE_WITH_EXAMPLES
|
if(CTI_CONTINUABLE_IS_TOP_LEVEL_PROJECT)
|
||||||
"Build the continuable examples"
|
message(
|
||||||
${IS_TOP_LEVEL_PROJECT})
|
STATUS
|
||||||
|
"Building with ${CMAKE_CXX_COMPILER_ID} (${CMAKE_CXX_COMPILER_VERSION})")
|
||||||
|
endif()
|
||||||
|
|
||||||
option(CTI_CONTINUABLE_WITH_NO_EXCEPTIONS
|
option(CTI_CONTINUABLE_WITH_INSTALL "Add the continuable install targets"
|
||||||
"Disable exception support"
|
${CTI_CONTINUABLE_IS_TOP_LEVEL_PROJECT})
|
||||||
OFF)
|
|
||||||
|
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_UNHANDLED_EXCEPTIONS
|
option(CTI_CONTINUABLE_WITH_UNHANDLED_EXCEPTIONS
|
||||||
"Enable unhandled asynchronous exceptions"
|
"Enable unhandled asynchronous exceptions" OFF)
|
||||||
OFF)
|
|
||||||
|
option(CTI_CONTINUABLE_WITH_COROUTINE "Enable C++20 coroutines" OFF)
|
||||||
|
|
||||||
option(CTI_CONTINUABLE_WITH_EXPERIMENTAL_COROUTINE
|
option(CTI_CONTINUABLE_WITH_EXPERIMENTAL_COROUTINE
|
||||||
"Enable co_await support"
|
"Enable experimental coroutines" OFF)
|
||||||
OFF)
|
|
||||||
|
|
||||||
option(CTI_CONTINUABLE_WITH_CPP_LATEST
|
option(CTI_CONTINUABLE_WITH_CPP_LATEST
|
||||||
"Enable the highest C++ standard available for testing polyfills"
|
"Enable the highest C++ standard available for testing polyfills" OFF)
|
||||||
OFF)
|
|
||||||
|
|
||||||
option(CTI_CONTINUABLE_WITH_LIGHT_TESTS
|
option(CTI_CONTINUABLE_WITH_LIGHT_TESTS
|
||||||
"Disable some template heavy unit tests (for CI usage)"
|
"Disable some template heavy unit tests (for CI usage)" OFF)
|
||||||
OFF)
|
|
||||||
|
|
||||||
include(cmake/CMakeLists.txt)
|
# 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()
|
||||||
|
|
||||||
set(THREADS_PREFER_PTHREAD_FLAG ON)
|
if(NOT TARGET Threads::Threads)
|
||||||
find_package(Threads REQUIRED)
|
set(THREADS_PREFER_PTHREAD_FLAG ON)
|
||||||
|
find_package(Threads REQUIRED)
|
||||||
|
endif()
|
||||||
|
|
||||||
add_subdirectory(dep)
|
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()
|
||||||
|
|
||||||
# continuable-base
|
# continuable-base
|
||||||
add_library(continuable-base INTERFACE)
|
if(CTI_CONTINUABLE_IS_TOP_LEVEL_PROJECT)
|
||||||
|
add_library(continuable-base INTERFACE)
|
||||||
|
else()
|
||||||
|
add_library(continuable-base INTERFACE IMPORTED GLOBAL)
|
||||||
|
endif()
|
||||||
|
|
||||||
add_library(continuable::continuable-base ALIAS continuable-base)
|
add_library(continuable::continuable-base ALIAS continuable-base)
|
||||||
|
|
||||||
target_include_directories(continuable-base
|
target_include_directories(
|
||||||
INTERFACE
|
continuable-base
|
||||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/include>
|
INTERFACE $<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/include>
|
||||||
$<INSTALL_INTERFACE:include>)
|
$<INSTALL_INTERFACE:include>)
|
||||||
|
|
||||||
target_link_libraries(continuable-base
|
target_link_libraries(continuable-base INTERFACE Threads::Threads)
|
||||||
INTERFACE
|
|
||||||
Threads::Threads)
|
|
||||||
|
|
||||||
target_compile_features(continuable-base
|
target_compile_features(
|
||||||
INTERFACE
|
continuable-base
|
||||||
cxx_alias_templates
|
INTERFACE cxx_alias_templates
|
||||||
cxx_auto_type
|
cxx_auto_type
|
||||||
cxx_constexpr
|
cxx_constexpr
|
||||||
cxx_decltype
|
cxx_decltype
|
||||||
@ -89,58 +123,99 @@ target_compile_features(continuable-base
|
|||||||
cxx_trailing_return_types
|
cxx_trailing_return_types
|
||||||
cxx_return_type_deduction)
|
cxx_return_type_deduction)
|
||||||
|
|
||||||
if (CTI_CONTINUABLE_WITH_EXPERIMENTAL_COROUTINE)
|
if(CTI_CONTINUABLE_WITH_CPP_LATEST)
|
||||||
target_compile_options(continuable-base
|
target_compile_features(continuable-base INTERFACE cxx_std_20)
|
||||||
INTERFACE
|
endif()
|
||||||
$<$<CXX_COMPILER_ID:MSVC>:/await>
|
|
||||||
|
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>)
|
$<$<CXX_COMPILER_ID:Clang>:-fcoroutines-ts>)
|
||||||
|
|
||||||
target_compile_definitions(continuable-base
|
|
||||||
INTERFACE
|
|
||||||
-DCONTINUABLE_WITH_EXPERIMENTAL_COROUTINE)
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (CTI_CONTINUABLE_WITH_UNHANDLED_EXCEPTIONS)
|
if(CTI_CONTINUABLE_WITH_UNHANDLED_EXCEPTIONS)
|
||||||
target_compile_definitions(continuable-base
|
target_compile_definitions(continuable-base
|
||||||
INTERFACE
|
INTERFACE CONTINUABLE_WITH_UNHANDLED_EXCEPTIONS)
|
||||||
-DCONTINUABLE_WITH_UNHANDLED_EXCEPTIONS)
|
endif()
|
||||||
|
|
||||||
|
if(CTI_CONTINUABLE_IS_TOP_LEVEL_PROJECT)
|
||||||
|
add_library(continuable INTERFACE)
|
||||||
|
else()
|
||||||
|
add_library(continuable INTERFACE IMPORTED GLOBAL)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
add_library(continuable INTERFACE)
|
|
||||||
add_library(continuable::continuable ALIAS continuable)
|
add_library(continuable::continuable ALIAS continuable)
|
||||||
|
|
||||||
target_link_libraries(continuable
|
target_link_libraries(continuable INTERFACE continuable::continuable-base
|
||||||
INTERFACE
|
function2::function2)
|
||||||
continuable-base
|
|
||||||
function2)
|
|
||||||
|
|
||||||
# Create an install target
|
if(CTI_CONTINUABLE_WITH_INSTALL)
|
||||||
install(TARGETS continuable-base continuable
|
include(ExternalProject)
|
||||||
EXPORT continuable-config
|
include(GNUInstallDirs)
|
||||||
INCLUDES DESTINATION include)
|
include(CMakePackageConfigHelpers)
|
||||||
|
|
||||||
install(EXPORT continuable-config
|
# Create an install target: Headers and license files
|
||||||
FILE continuable-config.cmake
|
install(DIRECTORY "${PROJECT_SOURCE_DIR}/include/continuable"
|
||||||
NAMESPACE continuable::
|
DESTINATION "include")
|
||||||
DESTINATION share/continuable/cmake)
|
install(FILES "LICENSE.txt" DESTINATION .)
|
||||||
|
install(FILES "Readme.md" DESTINATION .)
|
||||||
|
|
||||||
install(DIRECTORY include/continuable
|
# Config.cmake
|
||||||
DESTINATION include FILES_MATCHING PATTERN "*.hpp")
|
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(FILES LICENSE.txt DESTINATION . RENAME continuable-LICENSE.txt)
|
# ConfigVersion.cmake
|
||||||
install(FILES Readme.md DESTINATION . RENAME continuable-Readme.md)
|
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}")
|
||||||
|
|
||||||
# Setup CPack for bundling
|
# Targets.cmake
|
||||||
set(CPACK_GENERATOR "ZIP")
|
export(
|
||||||
set(CPACK_PACKAGE_VERSION_MAJOR ${PROJECT_VERSION_MAJOR})
|
TARGETS ${PROJECT_NAME} ${PROJECT_NAME}-base
|
||||||
set(CPACK_PACKAGE_VERSION_MINOR ${PROJECT_VERSION_MINOR})
|
NAMESPACE ${PROJECT_NAME}::
|
||||||
set(CPACK_PACKAGE_VERSION_PATCH ${PROJECT_VERSION_PATCH})
|
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}")
|
||||||
|
|
||||||
include(CPack)
|
# 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()
|
||||||
|
|
||||||
# Testing and examples
|
# Testing and examples
|
||||||
if (CTI_CONTINUABLE_WITH_TESTS OR CTI_CONTINUABLE_WITH_EXAMPLES)
|
if(CTI_CONTINUABLE_WITH_TESTS OR CTI_CONTINUABLE_WITH_EXAMPLES)
|
||||||
if (MSVC)
|
if(MSVC)
|
||||||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
|
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
|
||||||
string(REGEX REPLACE "/W[0-4]" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
|
string(REGEX REPLACE "/W[0-4]" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W4")
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W4")
|
||||||
@ -148,11 +223,11 @@ if (CTI_CONTINUABLE_WITH_TESTS OR CTI_CONTINUABLE_WITH_EXAMPLES)
|
|||||||
|
|
||||||
enable_testing()
|
enable_testing()
|
||||||
|
|
||||||
if (CTI_CONTINUABLE_WITH_TESTS)
|
if(CTI_CONTINUABLE_WITH_TESTS)
|
||||||
add_subdirectory(test)
|
add_subdirectory(test)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (CTI_CONTINUABLE_WITH_EXAMPLES)
|
if(CTI_CONTINUABLE_WITH_EXAMPLES)
|
||||||
add_subdirectory(examples)
|
add_subdirectory(examples)
|
||||||
endif()
|
endif()
|
||||||
endif ()
|
endif()
|
||||||
|
|||||||
10
Findcontinuable.cmake
Normal file
10
Findcontinuable.cmake
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
# 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
|
MIT License
|
||||||
|
|
||||||
Copyright (c) 2015 - 2018 Denis Blank <denis.blank at outlook dot com>
|
Copyright (c) 2015 - 2019 Denis Blank <denis.blank at outlook dot com>
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
|||||||
201
Readme.md
201
Readme.md
@ -6,12 +6,12 @@
|
|||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p align="center">
|
<p align="center">
|
||||||
<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://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://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>
|
<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">
|
<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://naios.github.io/continuable/"><img alt="Documentation" src="https://img.shields.io/badge/Documentation-Doxygen-26A69A.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>
|
<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>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
------
|
------
|
||||||
@ -35,8 +35,199 @@ The [documentation](https://naios.github.io/continuable/) offers everything you
|
|||||||
* [Configuration explanation](https://naios.github.io/continuable/configuration.html)
|
* [Configuration explanation](https://naios.github.io/continuable/configuration.html)
|
||||||
* [Changelog](https://naios.github.io/continuable/changelog.html)
|
* [Changelog](https://naios.github.io/continuable/changelog.html)
|
||||||
|
|
||||||
|
|
||||||
#### Issues and contributions
|
#### Issues and contributions
|
||||||
|
|
||||||
Issue reports are accepted through the Github issue tracker as well as Pull requests.
|
Issue reports and questions 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
|
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.
|
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)] |
|
||||||
|
|
||||||
|
.
|
||||||
|
|||||||
14
appveyor.yml
14
appveyor.yml
@ -1,5 +1,6 @@
|
|||||||
image:
|
image:
|
||||||
- Visual Studio 2017
|
- Visual Studio 2017
|
||||||
|
- Visual Studio 2019
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
matrix:
|
matrix:
|
||||||
@ -9,9 +10,8 @@ environment:
|
|||||||
WITH_CPP_LATEST: OFF
|
WITH_CPP_LATEST: OFF
|
||||||
- WITH_NO_EXCEPTIONS: OFF
|
- WITH_NO_EXCEPTIONS: OFF
|
||||||
WITH_CPP_LATEST: ON
|
WITH_CPP_LATEST: ON
|
||||||
|
- WITH_NO_EXCEPTIONS: ON
|
||||||
configuration:
|
WITH_CPP_LATEST: ON
|
||||||
- Debug
|
|
||||||
|
|
||||||
platform:
|
platform:
|
||||||
- x64
|
- x64
|
||||||
@ -30,12 +30,14 @@ before_build:
|
|||||||
-DCTI_CONTINUABLE_WITH_CPP_LATEST=%WITH_CPP_LATEST%
|
-DCTI_CONTINUABLE_WITH_CPP_LATEST=%WITH_CPP_LATEST%
|
||||||
|
|
||||||
build_script:
|
build_script:
|
||||||
- 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 Debug --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
|
- 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
|
||||||
|
|
||||||
test_script:
|
test_script:
|
||||||
- cmd: cd build
|
- cmd: cd build
|
||||||
- cmd: ctest -C %CONFIGURATION% -V .
|
- cmd: ctest -C Debug -V .
|
||||||
|
- cmd: ctest -C Release -V .
|
||||||
|
|
||||||
artifacts:
|
artifacts:
|
||||||
- path: 'build/*.zip'
|
- path: 'build/*.zip'
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
|
|
||||||
# Copyright(c) 2015 - 2018 Denis Blank <denis.blank at outlook dot com>
|
# 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
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
# of this software and associated documentation files(the "Software"), to deal
|
# 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
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
# 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
|
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
# 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
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
|
|
||||||
# Copyright(c) 2015 - 2018 Denis Blank <denis.blank at outlook dot com>
|
# 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
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
# of this software and associated documentation files(the "Software"), to deal
|
# 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
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
# 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
|
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
# 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
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
|
|
||||||
# Copyright(c) 2015 - 2018 Denis Blank <denis.blank at outlook dot com>
|
# 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
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
# of this software and associated documentation files(the "Software"), to deal
|
# 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
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
# 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
|
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
# 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
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
|
|
||||||
# Copyright(c) 2015 - 2018 Denis Blank <denis.blank at outlook dot com>
|
# 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
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
# of this software and associated documentation files(the "Software"), to deal
|
# 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
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
# 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
|
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
# 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
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
@ -31,9 +31,18 @@ if (PLATFORM EQUAL 64)
|
|||||||
-D_WIN64)
|
-D_WIN64)
|
||||||
endif()
|
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
|
target_compile_options(continuable-features-flags
|
||||||
INTERFACE
|
INTERFACE
|
||||||
/MP
|
|
||||||
/bigobj
|
/bigobj
|
||||||
/permissive-)
|
/permissive-)
|
||||||
|
|
||||||
@ -41,11 +50,7 @@ target_compile_options(continuable-features-warnings
|
|||||||
INTERFACE
|
INTERFACE
|
||||||
/W4)
|
/W4)
|
||||||
|
|
||||||
if (CTI_CONTINUABLE_WITH_CPP_LATEST)
|
if (NOT CTI_CONTINUABLE_WITH_CPP_LATEST)
|
||||||
target_compile_options(continuable-features-flags
|
|
||||||
INTERFACE
|
|
||||||
/std:c++latest)
|
|
||||||
else()
|
|
||||||
target_compile_options(continuable-features-flags
|
target_compile_options(continuable-features-flags
|
||||||
INTERFACE
|
INTERFACE
|
||||||
/std:c++14)
|
/std:c++14)
|
||||||
|
|||||||
7
cmake/config.cmake.in
Normal file
7
cmake/config.cmake.in
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
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 - 2018 Denis Blank <denis.blank at outlook dot com>
|
# 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
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
# of this software and associated documentation files(the "Software"), to deal
|
# 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
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
# 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
|
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
# 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
|
# 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
|
# Select the compiler specific cmake file
|
||||||
set(MSVC_ID "MSVC")
|
set(MSVC_ID "MSVC")
|
||||||
if (${CMAKE_CXX_COMPILER_ID} STREQUAL "Clang")
|
if (${CMAKE_CXX_COMPILER_ID} MATCHES "(Apple)?Clang")
|
||||||
include(${CMAKE_SOURCE_DIR}/cmake/compiler/clang.cmake)
|
include(${PROJECT_SOURCE_DIR}/cmake/compiler/clang.cmake)
|
||||||
elseif (${CMAKE_CXX_COMPILER_ID} STREQUAL "GNU")
|
elseif (${CMAKE_CXX_COMPILER_ID} STREQUAL "GNU")
|
||||||
include(${CMAKE_SOURCE_DIR}/cmake/compiler/gcc.cmake)
|
include(${PROJECT_SOURCE_DIR}/cmake/compiler/gcc.cmake)
|
||||||
elseif (${CMAKE_CXX_COMPILER_ID} STREQUAL ${MSVC_ID})
|
elseif (${CMAKE_CXX_COMPILER_ID} STREQUAL ${MSVC_ID})
|
||||||
include(${CMAKE_SOURCE_DIR}/cmake/compiler/msvc.cmake)
|
include(${PROJECT_SOURCE_DIR}/cmake/compiler/msvc.cmake)
|
||||||
else()
|
else()
|
||||||
message(FATAL_ERROR "Unknown compiler!")
|
message(FATAL_ERROR "Unknown compiler!")
|
||||||
endif()
|
endif()
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
|
|
||||||
# Copyright(c) 2015 - 2018 Denis Blank <denis.blank at outlook dot com>
|
# 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
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
# of this software and associated documentation files(the "Software"), to deal
|
# 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
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
# 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
|
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
# 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
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
# SOFTWARE.
|
# SOFTWARE.
|
||||||
|
|
||||||
include(${CMAKE_SOURCE_DIR}/cmake/macros/group_sources.cmake)
|
include(${PROJECT_SOURCE_DIR}/cmake/macros/group_sources.cmake)
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
|
|
||||||
# Copyright(c) 2015 - 2018 Denis Blank <denis.blank at outlook dot com>
|
# 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
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
# of this software and associated documentation files(the "Software"), to deal
|
# of this software and associated documentation files(the "Software"), to deal
|
||||||
@ -13,18 +13,19 @@
|
|||||||
#
|
#
|
||||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
# 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
|
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
# 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
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
# SOFTWARE.
|
# SOFTWARE.
|
||||||
|
|
||||||
set(WITH_SOURCE_TREE "hierarchical")
|
set(WITH_SOURCE_TREE "hierarchical")
|
||||||
macro(group_sources dir)
|
macro(group_sources)
|
||||||
# Skip this if WITH_SOURCE_TREE is not set (empty string).
|
# Skip this if WITH_SOURCE_TREE is not set (empty string).
|
||||||
if (NOT ${WITH_SOURCE_TREE} STREQUAL "")
|
if (NOT ${WITH_SOURCE_TREE} STREQUAL "")
|
||||||
|
foreach(dir ${ARGN})
|
||||||
# Include all header and c files
|
# Include all header and c files
|
||||||
file(GLOB_RECURSE elements RELATIVE ${dir} *.h *.hpp *.inl *.inc *.c *.cpp *.cc)
|
file(GLOB_RECURSE elements RELATIVE ${dir} ${dir}/*)
|
||||||
|
|
||||||
foreach(element ${elements})
|
foreach(element ${elements})
|
||||||
# Extract filename and directory
|
# Extract filename and directory
|
||||||
@ -54,5 +55,6 @@ macro(group_sources dir)
|
|||||||
source_group("\\" FILES ${dir}/${element})
|
source_group("\\" FILES ${dir}/${element})
|
||||||
endif()
|
endif()
|
||||||
endforeach()
|
endforeach()
|
||||||
|
endforeach()
|
||||||
endif()
|
endif()
|
||||||
endmacro()
|
endmacro()
|
||||||
|
|||||||
37
conanfile.py
Normal file
37
conanfile.py
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
#!/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,13 +1,25 @@
|
|||||||
if(NOT TARGET function2)
|
if(NOT TARGET function2::function2)
|
||||||
add_subdirectory(function2)
|
add_subdirectory(function2)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (CTI_CONTINUABLE_WITH_TESTS OR CTI_CONTINUABLE_WITH_EXAMPLES)
|
if (CTI_CONTINUABLE_WITH_TESTS OR CTI_CONTINUABLE_WITH_BENCHMARKS)
|
||||||
if(NOT TARGET gtest)
|
if(NOT TARGET gtest)
|
||||||
add_subdirectory(googletest)
|
add_subdirectory(googletest)
|
||||||
endif()
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if (CTI_CONTINUABLE_WITH_EXAMPLES)
|
||||||
if(NOT TARGET asio)
|
if(NOT TARGET asio)
|
||||||
add_subdirectory(asio)
|
add_subdirectory(asio)
|
||||||
endif()
|
endif()
|
||||||
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,9 +1,11 @@
|
|||||||
add_library(asio STATIC
|
add_library(asio STATIC
|
||||||
${CMAKE_CURRENT_LIST_DIR}/asio/asio/src/asio.cpp)
|
${CMAKE_CURRENT_LIST_DIR}/asio/asio/src/asio.cpp
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/include/boost/throw_exception.hpp)
|
||||||
|
|
||||||
target_include_directories(asio
|
target_include_directories(asio
|
||||||
PUBLIC
|
PUBLIC
|
||||||
${CMAKE_CURRENT_LIST_DIR}/asio/asio/include)
|
${CMAKE_CURRENT_LIST_DIR}/asio/asio/include
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/include)
|
||||||
|
|
||||||
target_compile_definitions(asio
|
target_compile_definitions(asio
|
||||||
PUBLIC
|
PUBLIC
|
||||||
@ -11,6 +13,15 @@ target_compile_definitions(asio
|
|||||||
-DASIO_SEPARATE_COMPILATION=1
|
-DASIO_SEPARATE_COMPILATION=1
|
||||||
-DASIO_NO_TYPEID=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)
|
if(WIN32)
|
||||||
target_compile_definitions(asio
|
target_compile_definitions(asio
|
||||||
PUBLIC
|
PUBLIC
|
||||||
|
|||||||
@ -1 +1 @@
|
|||||||
Subproject commit 230c0d2ae035c5ce1292233fcab03cea0d341264
|
Subproject commit 6c054e98f3f53352d12b6cd46d63b6d404cc044b
|
||||||
47
dep/asio/include/boost/throw_exception.hpp
Normal file
47
dep/asio/include/boost/throw_exception.hpp
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
/~` _ _ _|_. _ _ |_ | _
|
||||||
|
\_,(_)| | | || ||_|(_||_)|(/_
|
||||||
|
|
||||||
|
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
|
||||||
9
dep/benchmark/CMakeLists.txt
Normal file
9
dep/benchmark/CMakeLists.txt
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
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
dep/benchmark/benchmark
Submodule
1
dep/benchmark/benchmark
Submodule
@ -0,0 +1 @@
|
|||||||
|
Subproject commit b874e72208b6e21b62287942e5e3b11f6630107f
|
||||||
43
dep/boost/CMakeLists.txt
Normal file
43
dep/boost/CMakeLists.txt
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
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 db03b55bc9b58999b1e653a1d57fe1056fe14778
|
Subproject commit 3a0746bf5f601dfed05330aefcb6854354fce07d
|
||||||
@ -1,3 +1,4 @@
|
|||||||
|
if(ON)
|
||||||
add_library(gtest STATIC
|
add_library(gtest STATIC
|
||||||
${CMAKE_CURRENT_LIST_DIR}/googletest/googletest/src/gtest-all.cc)
|
${CMAKE_CURRENT_LIST_DIR}/googletest/googletest/src/gtest-all.cc)
|
||||||
|
|
||||||
@ -42,3 +43,10 @@ target_include_directories(gmock
|
|||||||
${CMAKE_CURRENT_LIST_DIR}/googletest/googlemock
|
${CMAKE_CURRENT_LIST_DIR}/googletest/googlemock
|
||||||
PUBLIC
|
PUBLIC
|
||||||
${CMAKE_CURRENT_LIST_DIR}/googletest/googlemock/include)
|
${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 9bda90b7e5e08c4c37a832d0cea218aed6af6470
|
Subproject commit f2fb48c3b3d79a75a88a99fba6576b25d42ec528
|
||||||
@ -38,13 +38,13 @@ PROJECT_NAME = Continuable
|
|||||||
# could be handy for archiving the generated documentation or if some version
|
# could be handy for archiving the generated documentation or if some version
|
||||||
# control system is used.
|
# control system is used.
|
||||||
|
|
||||||
PROJECT_NUMBER = 3.0.0
|
PROJECT_NUMBER = 4.1.0
|
||||||
|
|
||||||
# Using the PROJECT_BRIEF tag one can provide an optional one line description
|
# 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
|
# 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.
|
# quick idea about the purpose of the project. Keep the description short.
|
||||||
|
|
||||||
PROJECT_BRIEF =
|
PROJECT_BRIEF = "C++14 asynchronous allocation aware futures"
|
||||||
|
|
||||||
# With the PROJECT_LOGO tag one can specify a logo or an icon that is included
|
# 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
|
# in the documentation. The maximum height of the logo should not exceed 55
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
Copyright(c) 2015 - 2018 Denis Blank <denis.blank at outlook dot com>
|
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
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files(the "Software"), to deal
|
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
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
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
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
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
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
@ -28,20 +28,146 @@ namespace cti {
|
|||||||
|
|
||||||
Following versions were released:
|
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
|
\subsection changelog-versions-3-0-0 3.0.0
|
||||||
|
|
||||||
<B>New helper functions</B>
|
<B>New helper functions</B>
|
||||||
|
|
||||||
New helper functions were added to create ready continuables:
|
New helper functions were added to create ready continuables:
|
||||||
|
|
||||||
- \ref make_ready_continuable
|
- \ref make_ready_continuable \copybrief make_ready_continuable
|
||||||
- \ref make_exceptional_continuable
|
- \ref make_exceptional_continuable \copybrief make_exceptional_continuable
|
||||||
|
|
||||||
<B>Improvements to connections</B>
|
<B>Improvements to connections</B>
|
||||||
|
|
||||||
The implementation of connections were rewritten entirely.
|
The implementation of connections were rewritten entirely.
|
||||||
It is possible now to connect runtime sized containers as well as
|
It is possible now to connect runtime sized containers as well as
|
||||||
deeply nested sequences. See \ref tutorial-connections for details.
|
deeply nested sequences. See \ref tutorial-connecting-continuables for details.
|
||||||
|
|
||||||
Additionally connection overloads were added that accept two iterators
|
Additionally connection overloads were added that accept two iterators
|
||||||
in order to come closer to the interface of the standard library.
|
in order to come closer to the interface of the standard library.
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
Copyright(c) 2015 - 2018 Denis Blank <denis.blank at outlook dot com>
|
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
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files(the "Software"), to deal
|
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
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
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
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
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
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
@ -33,6 +33,8 @@ in order to change the libraries behaviour:
|
|||||||
| `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_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_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. |
|
| `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 - 2018 Denis Blank <denis.blank at outlook dot com>
|
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
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files(the "Software"), to deal
|
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
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
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
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
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
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
@ -76,7 +76,7 @@ your personal experience in using the library to improve it.
|
|||||||
Continuable is licensed under the MIT license:
|
Continuable is licensed under the MIT license:
|
||||||
|
|
||||||
>
|
>
|
||||||
> Copyright(c) 2015 - 2018 Denis Blank <denis.blank at outlook dot com>
|
> 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
|
> Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
> of this software and associated documentation files(the "Software"), to deal
|
> 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
|
> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
> IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
> 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
|
> AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
> LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
> 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
|
> OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
Copyright(c) 2015 - 2018 Denis Blank <denis.blank at outlook dot com>
|
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
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files(the "Software"), to deal
|
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
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
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
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
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
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
@ -49,7 +49,7 @@ Continuable is a header-only library with one required header-only dependency:
|
|||||||
erasure wrapper to convert a \ref continuable_base into a \ref continuable.
|
erasure wrapper to convert a \ref continuable_base into a \ref continuable.
|
||||||
|
|
||||||
Additionally GTest is required as optional dependency for the asynchronous
|
Additionally GTest is required as optional dependency for the asynchronous
|
||||||
unit testing macros defined in `continuable/continuable-testing.hpp`
|
unit testing macros defined in `continuable/support/gtest.hpp`
|
||||||
if those are used:
|
if those are used:
|
||||||
|
|
||||||
- [google/googletest](https://github.com/google/googletest) is used as
|
- [google/googletest](https://github.com/google/googletest) is used as
|
||||||
@ -120,6 +120,14 @@ and might be installed from there.
|
|||||||
to make it available from various package managers in order to
|
to make it available from various package managers in order to
|
||||||
make the installation easier.
|
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
|
\subsection installation-installation-copy By copying the headers
|
||||||
|
|
||||||
If you don't want to rely on CMake or package managers it is possible to
|
If you don't want to rely on CMake or package managers it is possible to
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
Copyright(c) 2015 - 2018 Denis Blank <denis.blank at outlook dot com>
|
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
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files(the "Software"), to deal
|
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
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
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
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
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
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
@ -96,16 +96,34 @@ result.get_value();
|
|||||||
result.get_exception();
|
result.get_exception();
|
||||||
\endcode
|
\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}
|
\code{.cpp}
|
||||||
cti::continuable<int> do_sth() {
|
cti::continuable<> resolve_async_void() {
|
||||||
|
co_await http_request("github.com");
|
||||||
|
// ...
|
||||||
|
co_return;
|
||||||
|
}
|
||||||
|
|
||||||
|
cti::continuable<int> resolve_async() {
|
||||||
co_await http_request("github.com");
|
co_await http_request("github.com");
|
||||||
// ...
|
// ...
|
||||||
co_return 0;
|
co_return 0;
|
||||||
}
|
}
|
||||||
\endcode
|
\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 - 2018 Denis Blank <denis.blank at outlook dot com>
|
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
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files(the "Software"), to deal
|
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
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
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
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
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
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
Copyright(c) 2015 - 2018 Denis Blank <denis.blank at outlook dot com>
|
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
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files(the "Software"), to deal
|
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
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
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
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
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
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
@ -202,7 +202,7 @@ for (int i = 2; i < 5; ++i) {
|
|||||||
container.emplace_back(cti::make_ready_continuable(i));
|
container.emplace_back(cti::make_ready_continuable(i));
|
||||||
}
|
}
|
||||||
|
|
||||||
cti::when_all(v)
|
cti::when_all(std::move(v))
|
||||||
.then([](std::vector<int> resolved) {
|
.then([](std::vector<int> resolved) {
|
||||||
// ...
|
// ...
|
||||||
});
|
});
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
Copyright(c) 2015 - 2018 Denis Blank <denis.blank at outlook dot com>
|
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
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files(the "Software"), to deal
|
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
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
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
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
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
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
Copyright(c) 2015 - 2018 Denis Blank <denis.blank at outlook dot com>
|
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
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files(the "Software"), to deal
|
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
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
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
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
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
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
@ -70,5 +70,30 @@ async_resolve("127.0.0.1", "daytime")
|
|||||||
});
|
});
|
||||||
\endcode
|
\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 - 2018 Denis Blank <denis.blank at outlook dot com>
|
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
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files(the "Software"), to deal
|
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
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
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
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
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
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
@ -30,28 +30,37 @@ namespace cti {
|
|||||||
|
|
||||||
Sometimes it's required to change a \ref continuable_base object by its whole.
|
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
|
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 accepts a \ref continuable_base and returns
|
A transformation is a callable object that accepts a \ref continuable_base
|
||||||
an arbitrary object.
|
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
|
The library provides several transforms already as part of the
|
||||||
\ref cti::transforms namespace.
|
\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
|
\section tutorial-transforming-continuables-future Conversion into std::future
|
||||||
|
|
||||||
The library is capable of converting (*futurizing*) every continuable into a
|
The library is capable of converting (*futurizing*) every continuable into a
|
||||||
fitting `std::future` through the \ref transforms::futurize transform:
|
fitting `std::future` through the \ref transforms::to_future transform:
|
||||||
|
|
||||||
\code{.cpp}
|
\code{.cpp}
|
||||||
std::future<std::string> future = http_request("github.com")
|
std::future<std::string> future = http_request("github.com")
|
||||||
@ -59,17 +68,17 @@ std::future<std::string> future = http_request("github.com")
|
|||||||
// Do sth...
|
// Do sth...
|
||||||
return http_request("travis-ci.org") || http_request("atom.io");
|
return http_request("travis-ci.org") || http_request("atom.io");
|
||||||
})
|
})
|
||||||
.apply(cti::transforms::futurize());
|
.apply(cti::transforms::to_future());
|
||||||
// ^^^^^^^^
|
// ^^^^^^^^
|
||||||
\endcode
|
\endcode
|
||||||
|
|
||||||
Multiple arguments which can't be handled by `std::future` itself are
|
Multiple arguments which can't be handled by `std::future` itself are
|
||||||
converted into `std::tuple`, see \ref transforms::futurize for details.
|
converted into `std::tuple`, see \ref transforms::to_future for details.
|
||||||
|
|
||||||
\code{.cpp}
|
\code{.cpp}
|
||||||
std::future<std::tuple<std::string, std::string>> future =
|
std::future<std::tuple<std::string, std::string>> future =
|
||||||
(http_request("travis-ci.org") && http_request("atom.io"))
|
(http_request("travis-ci.org") && http_request("atom.io"))
|
||||||
.apply(cti::transforms::futurize());
|
.apply(cti::transforms::to_future());
|
||||||
\endcode
|
\endcode
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
Copyright(c) 2015 - 2018 Denis Blank <denis.blank at outlook dot com>
|
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
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files(the "Software"), to deal
|
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
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
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
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
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
|
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
|
https://github.com/Naios/continuable
|
||||||
v3.0.0
|
v3.0.0
|
||||||
|
|
||||||
Copyright(c) 2015 - 2018 Denis Blank <denis.blank at outlook dot com>
|
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
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files(the "Software"), to deal
|
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
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
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
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
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
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
|||||||
@ -1,15 +1,28 @@
|
|||||||
|
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
|
add_executable(example-asio
|
||||||
${CMAKE_CURRENT_LIST_DIR}/example-asio.cpp)
|
${CMAKE_CURRENT_LIST_DIR}/example-asio.cpp)
|
||||||
|
|
||||||
target_include_directories(example-asio
|
|
||||||
PRIVATE
|
|
||||||
${CMAKE_CURRENT_LIST_DIR})
|
|
||||||
|
|
||||||
target_link_libraries(example-asio
|
target_link_libraries(example-asio
|
||||||
PRIVATE
|
PRIVATE
|
||||||
asio
|
asio-example-deps)
|
||||||
continuable)
|
|
||||||
|
|
||||||
target_compile_definitions(example-asio
|
target_compile_definitions(example-asio
|
||||||
PUBLIC
|
PUBLIC
|
||||||
-DCONTINUABLE_WITH_NO_EXCEPTIONS)
|
-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)
|
||||||
|
|||||||
176
examples/example-asio/example-asio-integration.cpp
Normal file
176
examples/example-asio/example-asio-integration.cpp
Normal file
@ -0,0 +1,176 @@
|
|||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
/~` _ _ _|_. _ _ |_ | _
|
||||||
|
\_,(_)| | | || ||_|(_||_)|(/_
|
||||||
|
|
||||||
|
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
|
https://github.com/Naios/continuable
|
||||||
v3.0.0
|
v4.0.0
|
||||||
|
|
||||||
Copyright(c) 2015 - 2018 Denis Blank <denis.blank at outlook dot com>
|
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
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files(the "Software"), to deal
|
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
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
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
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
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
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
@ -34,12 +34,30 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <system_error>
|
#include <system_error>
|
||||||
|
|
||||||
|
#if defined(CONTINUABLE_HAS_EXCEPTIONS)
|
||||||
|
#include <exception>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <asio.hpp>
|
#include <asio.hpp>
|
||||||
|
|
||||||
#include <continuable/continuable.hpp>
|
#include <continuable/continuable.hpp>
|
||||||
|
|
||||||
using namespace std::chrono_literals;
|
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 {
|
struct functional_io_service {
|
||||||
asio::io_context service_;
|
asio::io_context service_;
|
||||||
asio::ip::udp::resolver resolver_;
|
asio::ip::udp::resolver resolver_;
|
||||||
@ -49,7 +67,11 @@ struct functional_io_service {
|
|||||||
|
|
||||||
auto trough_post() noexcept {
|
auto trough_post() noexcept {
|
||||||
return [&](auto&& work) mutable {
|
return [&](auto&& work) mutable {
|
||||||
asio::post(service_, std::forward<decltype(work)>(work));
|
asio::post(service_,
|
||||||
|
[work = std::forward<decltype(work)>(work)]() mutable {
|
||||||
|
std::move(work)();
|
||||||
|
// .. or: work.set_value();
|
||||||
|
});
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -61,7 +83,8 @@ struct functional_io_service {
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto async_resolve(std::string host, std::string service) {
|
auto async_resolve(std::string host, std::string service) {
|
||||||
return cti::promisify<asio::ip::udp::resolver::iterator>::from(
|
return cti::promisify<asio::ip::udp::resolver::iterator>::with(
|
||||||
|
error_code_remapper(),
|
||||||
[&](auto&&... args) {
|
[&](auto&&... args) {
|
||||||
resolver_.async_resolve(std::forward<decltype(args)>(args)...);
|
resolver_.async_resolve(std::forward<decltype(args)>(args)...);
|
||||||
},
|
},
|
||||||
@ -89,7 +112,7 @@ int main(int, char**) {
|
|||||||
// auto socket = std::make_shared<udp::socket>(service);
|
// auto socket = std::make_shared<udp::socket>(service);
|
||||||
// socket->async_send_to()
|
// socket->async_send_to()
|
||||||
})
|
})
|
||||||
.fail([](cti::error_type /*error*/) {
|
.fail([](cti::exception_t /*error*/) {
|
||||||
// ...
|
// ...
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
Copyright(c) 2015 - 2018 Denis Blank <denis.blank at outlook dot com>
|
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
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files(the "Software"), to deal
|
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
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
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
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
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
|
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
|
https://github.com/Naios/continuable
|
||||||
v3.0.0
|
v4.2.0
|
||||||
|
|
||||||
Copyright(c) 2015 - 2018 Denis Blank <denis.blank at outlook dot com>
|
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
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files(the "Software"), to deal
|
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
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
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
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
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
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
@ -32,64 +32,30 @@
|
|||||||
#define CONTINUABLE_BASE_HPP_INCLUDED
|
#define CONTINUABLE_BASE_HPP_INCLUDED
|
||||||
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <cstdint>
|
#include <cstddef>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
#include <continuable/continuable-primitives.hpp>
|
||||||
#include <continuable/detail/base.hpp>
|
#include <continuable/continuable-result.hpp>
|
||||||
#include <continuable/detail/connection-all.hpp>
|
#include <continuable/detail/connection/connection-all.hpp>
|
||||||
#include <continuable/detail/connection-any.hpp>
|
#include <continuable/detail/connection/connection-any.hpp>
|
||||||
#include <continuable/detail/connection-seq.hpp>
|
#include <continuable/detail/connection/connection-seq.hpp>
|
||||||
#include <continuable/detail/connection.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/features.hpp>
|
||||||
#include <continuable/detail/traits.hpp>
|
#include <continuable/detail/utility/traits.hpp>
|
||||||
#include <continuable/detail/types.hpp>
|
#include <continuable/detail/utility/util.hpp>
|
||||||
#include <continuable/detail/util.hpp>
|
|
||||||
|
|
||||||
#ifdef CONTINUABLE_HAS_EXPERIMENTAL_COROUTINE
|
#if defined(CONTINUABLE_HAS_COROUTINE)
|
||||||
#include <continuable/detail/awaiting.hpp>
|
# include <continuable/detail/other/coroutines.hpp>
|
||||||
#endif // CONTINUABLE_HAS_EXPERIMENTAL_COROUTINE
|
#endif // defined(CONTINUABLE_HAS_COROUTINE)
|
||||||
|
|
||||||
namespace cti {
|
namespace cti {
|
||||||
/// \defgroup Base Base
|
/// \defgroup Base Base
|
||||||
/// provides classes and functions to create continuable_base objects.
|
/// 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.
|
/// Deduces to a true_type if the given type is a continuable_base.
|
||||||
///
|
///
|
||||||
/// \since 3.0.0
|
/// \since 3.0.0
|
||||||
@ -126,6 +92,10 @@ template <typename Data, typename Annotation>
|
|||||||
class continuable_base {
|
class continuable_base {
|
||||||
|
|
||||||
/// \cond false
|
/// \cond false
|
||||||
|
using ownership = detail::util::ownership;
|
||||||
|
|
||||||
|
using annotation_trait = detail::annotation_trait<Annotation>;
|
||||||
|
|
||||||
template <typename, typename>
|
template <typename, typename>
|
||||||
friend class continuable_base;
|
friend class continuable_base;
|
||||||
friend struct detail::base::attorney;
|
friend struct detail::base::attorney;
|
||||||
@ -133,25 +103,41 @@ class continuable_base {
|
|||||||
// The continuation type or intermediate result
|
// The continuation type or intermediate result
|
||||||
Data data_;
|
Data data_;
|
||||||
// The transferable state which represents the validity of the object
|
// The transferable state which represents the validity of the object
|
||||||
detail::util::ownership ownership_;
|
ownership ownership_;
|
||||||
/// \endcond
|
/// \endcond
|
||||||
|
|
||||||
/// Constructor accepting the data object while erasing the annotation
|
/// Constructor accepting the data object while erasing the annotation
|
||||||
explicit continuable_base(Data data, detail::util::ownership ownership)
|
explicit continuable_base(Data data, ownership ownership)
|
||||||
: data_(std::move(data)), ownership_(std::move(ownership)) {
|
: data_(std::move(data))
|
||||||
}
|
, ownership_(std::move(ownership)) {}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/// Constructor accepting the data object while erasing the annotation
|
/// 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,
|
/// Constructor accepting any object convertible to the data object,
|
||||||
/// while erasing the annotation
|
/// while erasing the annotation
|
||||||
template <typename OData, std::enable_if_t<std::is_convertible<
|
template <typename OtherData,
|
||||||
std::decay_t<OData>, Data>::value>* = nullptr>
|
std::enable_if_t<detail::base::can_accept_continuation<
|
||||||
continuable_base(OData&& data) : data_(std::forward<OData>(data)) {
|
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()) {}
|
||||||
|
|
||||||
/// Constructor taking the data of other continuable_base objects
|
/// Constructor taking the data of other continuable_base objects
|
||||||
/// while erasing the hint.
|
/// while erasing the hint.
|
||||||
@ -159,9 +145,8 @@ public:
|
|||||||
/// This constructor makes it possible to replace the internal data object of
|
/// This constructor makes it possible to replace the internal data object of
|
||||||
/// the continuable by any object which is useful for type-erasure.
|
/// the continuable by any object which is useful for type-erasure.
|
||||||
template <typename OData, typename OAnnotation>
|
template <typename OData, typename OAnnotation>
|
||||||
continuable_base(continuable_base<OData, OAnnotation>&& other)
|
/* implicit */ continuable_base(continuable_base<OData, OAnnotation>&& other)
|
||||||
: continuable_base(std::move(other).materialize().consume_data()) {
|
: continuable_base(std::move(other).finish().consume()) {}
|
||||||
}
|
|
||||||
|
|
||||||
/// \cond false
|
/// \cond false
|
||||||
continuable_base(continuable_base&&) = default;
|
continuable_base(continuable_base&&) = default;
|
||||||
@ -240,12 +225,17 @@ public:
|
|||||||
/// | `Arg` | `continuable_base with <Arg>` |
|
/// | `Arg` | `continuable_base with <Arg>` |
|
||||||
/// | `std::pair<First, Second>` | `continuable_base with <First, Second>` |
|
/// | `std::pair<First, Second>` | `continuable_base with <First, Second>` |
|
||||||
/// | `std::tuple<Args...>` | `continuable_base with <Args...>` |
|
/// | `std::tuple<Args...>` | `continuable_base with <Args...>` |
|
||||||
|
/// | `cti::result<Args...>` | `continuable_base with <Args...>` |
|
||||||
/// | `continuable_base<Arg...>` | `continuable_base with <Args...>` |
|
/// | `continuable_base<Arg...>` | `continuable_base with <Args...>` |
|
||||||
/// Which means the result type of the continuable_base is equal to
|
/// Which means the result type of the continuable_base is equal to
|
||||||
/// the plain types the callback returns (`std::tuple` and
|
/// the plain types the callback returns (`std::tuple` and
|
||||||
/// `std::pair` arguments are unwrapped).
|
/// `std::pair` arguments are unwrapped).
|
||||||
/// A single continuable_base as argument is resolved and the result
|
/// A single continuable_base as argument is resolved and the result
|
||||||
/// type is equal to the resolved continuable_base.
|
/// 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:
|
/// Consider the following examples:
|
||||||
/// ```cpp
|
/// ```cpp
|
||||||
/// http_request("github.com")
|
/// http_request("github.com")
|
||||||
@ -267,6 +257,17 @@ public:
|
|||||||
/// http_request("github.com")
|
/// http_request("github.com")
|
||||||
/// .then([](std::string github) { return http_request("atom.io"); })
|
/// .then([](std::string github) { return http_request("atom.io"); })
|
||||||
/// .then([](std::string atom) { }); // <std::string>
|
/// .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
|
/// \since 1.0.0
|
||||||
@ -275,7 +276,7 @@ public:
|
|||||||
E&& executor = detail::types::this_thread_executor_tag{}) && {
|
E&& executor = detail::types::this_thread_executor_tag{}) && {
|
||||||
return detail::base::chain_continuation<detail::base::handle_results::yes,
|
return detail::base::chain_continuation<detail::base::handle_results::yes,
|
||||||
detail::base::handle_errors::no>(
|
detail::base::handle_errors::no>(
|
||||||
std::move(*this).materialize(), std::forward<T>(callback),
|
std::move(*this).finish(), std::forward<T>(callback),
|
||||||
std::forward<E>(executor));
|
std::forward<E>(executor));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -301,7 +302,7 @@ public:
|
|||||||
template <typename OData, typename OAnnotation>
|
template <typename OData, typename OAnnotation>
|
||||||
auto then(continuable_base<OData, OAnnotation>&& continuation) && {
|
auto then(continuable_base<OData, OAnnotation>&& continuation) && {
|
||||||
return std::move(*this).then(
|
return std::move(*this).then(
|
||||||
detail::base::wrap_continuation(std::move(continuation).materialize()));
|
detail::base::wrap_continuation(std::move(continuation).finish()));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Main method of the continuable_base to catch exceptions and error codes
|
/// Main method of the continuable_base to catch exceptions and error codes
|
||||||
@ -316,13 +317,19 @@ public:
|
|||||||
/// ```cpp
|
/// ```cpp
|
||||||
/// http_request("github.com")
|
/// http_request("github.com")
|
||||||
/// .then([](std::string github) { })
|
/// .then([](std::string github) { })
|
||||||
/// .fail([](std::exception_ptr ptr) {
|
/// .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
|
/// // Handle the error here
|
||||||
/// try {
|
/// try {
|
||||||
/// std::rethrow_exception(ptr);
|
/// std::rethrow_exception(ep);
|
||||||
/// } catch (std::exception& e) {
|
/// } catch (std::exception& e) {
|
||||||
/// e.what(); // Handle the exception
|
/// e.what(); // Handle the exception
|
||||||
/// }
|
/// }
|
||||||
|
/// }
|
||||||
/// });
|
/// });
|
||||||
/// ```
|
/// ```
|
||||||
/// In case exceptions are disabled, `std::error_condition` is
|
/// In case exceptions are disabled, `std::error_condition` is
|
||||||
@ -341,14 +348,26 @@ public:
|
|||||||
/// \returns Returns a continuable_base with an asynchronous return type
|
/// \returns Returns a continuable_base with an asynchronous return type
|
||||||
/// depending on the previous result 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
|
/// \since 2.0.0
|
||||||
template <typename T, typename E = detail::types::this_thread_executor_tag>
|
template <typename T, typename E = detail::types::this_thread_executor_tag>
|
||||||
auto fail(T&& callback,
|
auto fail(T&& callback,
|
||||||
E&& executor = detail::types::this_thread_executor_tag{}) && {
|
E&& executor = detail::types::this_thread_executor_tag{}) && {
|
||||||
return detail::base::chain_continuation<detail::base::handle_results::no,
|
return detail::base::chain_continuation<
|
||||||
detail::base::handle_errors::plain>(
|
detail::base::handle_results::no, detail::base::handle_errors::forward>(
|
||||||
std::move(*this).materialize(), std::forward<T>(callback),
|
std::move(*this).finish(),
|
||||||
|
detail::base::strip_exception_arg(std::forward<T>(callback)),
|
||||||
std::forward<E>(executor));
|
std::forward<E>(executor));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -370,9 +389,11 @@ public:
|
|||||||
/// \since 2.0.0
|
/// \since 2.0.0
|
||||||
template <typename OData, typename OAnnotation>
|
template <typename OData, typename OAnnotation>
|
||||||
auto fail(continuable_base<OData, OAnnotation>&& continuation) && {
|
auto fail(continuable_base<OData, OAnnotation>&& continuation) && {
|
||||||
continuation.freeze();
|
return std::move(*this) //
|
||||||
return std::move(*this).fail([continuation = std::move(continuation)](
|
.fail([continuation = std::move(continuation).freeze()] //
|
||||||
error_type) mutable { std::move(continuation).done(); });
|
(exception_t) mutable {
|
||||||
|
std::move(continuation).done(); //
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A method which allows to use an overloaded callable for the error
|
/// A method which allows to use an overloaded callable for the error
|
||||||
@ -386,7 +407,7 @@ public:
|
|||||||
/// void operator() (std::string result) {
|
/// void operator() (std::string result) {
|
||||||
/// // ...
|
/// // ...
|
||||||
/// }
|
/// }
|
||||||
/// void operator() (cti::dispatch_error_tag, cti::error_type) {
|
/// void operator() (cti::exception_arg_t, cti::exception_t) {
|
||||||
/// // ...
|
/// // ...
|
||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
@ -407,22 +428,56 @@ public:
|
|||||||
E&& executor = detail::types::this_thread_executor_tag{}) && {
|
E&& executor = detail::types::this_thread_executor_tag{}) && {
|
||||||
return detail::base::chain_continuation<
|
return detail::base::chain_continuation<
|
||||||
detail::base::handle_results::yes,
|
detail::base::handle_results::yes,
|
||||||
detail::base::handle_errors::forward>(std::move(*this).materialize(),
|
detail::base::handle_errors::forward>(std::move(*this).finish(),
|
||||||
std::forward<T>(callback),
|
std::forward<T>(callback),
|
||||||
std::forward<E>(executor));
|
std::forward<E>(executor));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A method which allows to apply this continuable to the given callable.
|
/// Returns a continuable_base which continues its invocation through the
|
||||||
|
/// given executor.
|
||||||
///
|
///
|
||||||
/// \param transform A transform which shall accept this continuable
|
/// \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.
|
||||||
///
|
///
|
||||||
/// \returns Returns the result of the given transform when this
|
/// \returns Returns the result of the given transform when this
|
||||||
/// continuable is passed into it.
|
/// continuable is passed into it.
|
||||||
///
|
///
|
||||||
/// \since 2.0.0
|
/// \since 4.0.0
|
||||||
template <typename T>
|
template <typename T>
|
||||||
auto apply(T&& transform) && {
|
auto apply(T&& transform) && {
|
||||||
return std::forward<T>(transform)(std::move(*this).materialize());
|
return std::forward<T>(transform)(std::move(*this).finish());
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The pipe operator | is an alias for the continuable::then method.
|
/// The pipe operator | is an alias for the continuable::then method.
|
||||||
@ -438,22 +493,6 @@ public:
|
|||||||
return std::move(*this).then(std::forward<T>(right));
|
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
|
/// Invokes both continuable_base objects parallel and calls the
|
||||||
/// callback with the result of both continuable_base objects.
|
/// callback with the result of both continuable_base objects.
|
||||||
///
|
///
|
||||||
@ -572,7 +611,64 @@ public:
|
|||||||
///
|
///
|
||||||
/// \since 1.0.0
|
/// \since 1.0.0
|
||||||
void done() && {
|
void done() && {
|
||||||
detail::base::finalize_continuation(std::move(*this));
|
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());
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Predicate to check whether the cti::continuable_base is frozen or not.
|
/// Predicate to check whether the cti::continuable_base is frozen or not.
|
||||||
@ -618,7 +714,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// \cond false
|
/// \cond false
|
||||||
#ifdef CONTINUABLE_HAS_EXPERIMENTAL_COROUTINE
|
#if defined(CONTINUABLE_HAS_COROUTINE)
|
||||||
/// \endcond
|
/// \endcond
|
||||||
/// Implements the operator for awaiting on continuables using `co_await`.
|
/// Implements the operator for awaiting on continuables using `co_await`.
|
||||||
///
|
///
|
||||||
@ -644,49 +740,47 @@ public:
|
|||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// In case the library is configured to use error codes or a custom
|
/// In case the library is configured to use error codes or a custom
|
||||||
/// error type the return type of the co_await expression is changed.
|
/// exception type the return type of the co_await expression is changed.
|
||||||
/// The result is returned through an internal proxy object which may
|
/// The result is returned through a cti::result<...>.
|
||||||
/// be queried for the error object.
|
|
||||||
/// | Continuation type | co_await returns |
|
/// | Continuation type | co_await returns |
|
||||||
/// | : ------------------------------- | : -------------------------------- |
|
/// | : ------------------------------- | : -------------------------------- |
|
||||||
/// | `continuable_base with <>` | `unspecified<void>` |
|
/// | `continuable_base with <>` | `result<void>` |
|
||||||
/// | `continuable_base with <Arg>` | `unspecified<Arg>` |
|
/// | `continuable_base with <Arg>` | `result<Arg>` |
|
||||||
/// | `continuable_base with <Args...>` | `unspecified<std::tuple<Args...>>` |
|
/// | `continuable_base with <Args...>` | `result<Args...>` |
|
||||||
/// The interface of the proxy object is similar to the one proposed in
|
///
|
||||||
/// the `std::expected` proposal:
|
/// \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.
|
||||||
/// ```cpp
|
/// ```cpp
|
||||||
/// if (auto&& result = co_await http_request("github.com")) {
|
/// cti::continuable<> resolve_async_void() {
|
||||||
/// auto value = *result;
|
/// co_await http_request("github.com");
|
||||||
/// } else {
|
/// // ...
|
||||||
/// cti::error_type error = result.get_exception();
|
/// co_return;
|
||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
/// auto result = co_await http_request("github.com");
|
/// cti::continuable<int> resolve_async() {
|
||||||
/// 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_await http_request("github.com");
|
||||||
/// // ...
|
/// // ...
|
||||||
/// co_return 0;
|
/// co_return 0;
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
/// Propably this will be added in a future version of the library.
|
/// 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);
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
///
|
///
|
||||||
/// \since 2.0.0
|
/// \since 2.0.0
|
||||||
auto operator co_await() && {
|
auto operator co_await() && {
|
||||||
return detail::awaiting::create_awaiter(std::move(*this).materialize());
|
return detail::awaiting::create_awaiter(std::move(*this).finish());
|
||||||
}
|
}
|
||||||
/// \cond false
|
/// \cond false
|
||||||
#endif // CONTINUABLE_HAS_EXPERIMENTAL_COROUTINE
|
#endif // defined(CONTINUABLE_HAS_COROUTINE)
|
||||||
/// \endcond
|
/// \endcond
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -694,12 +788,7 @@ private:
|
|||||||
ownership_.release();
|
ownership_.release();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto materialize() && {
|
Data&& consume() && {
|
||||||
return detail::connection::materializer<continuable_base>::apply(
|
|
||||||
std::move(*this));
|
|
||||||
}
|
|
||||||
|
|
||||||
Data&& consume_data() && {
|
|
||||||
assert_acquired();
|
assert_acquired();
|
||||||
release();
|
release();
|
||||||
return std::move(data_);
|
return std::move(data_);
|
||||||
@ -803,9 +892,9 @@ constexpr auto make_continuable(Continuation&& continuation) {
|
|||||||
"use make_continuable<void>(...). Continuables with an exact "
|
"use make_continuable<void>(...). Continuables with an exact "
|
||||||
"signature may be created through make_continuable<Args...>.");
|
"signature may be created through make_continuable<Args...>.");
|
||||||
|
|
||||||
return detail::base::attorney::create(
|
return detail::base::attorney::create_from(
|
||||||
std::forward<Continuation>(continuation),
|
std::forward<Continuation>(continuation),
|
||||||
detail::hints::extract(detail::traits::identity<Args...>{}),
|
typename detail::hints::from_args<Args...>::type{},
|
||||||
detail::util::ownership{});
|
detail::util::ownership{});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -815,46 +904,18 @@ constexpr auto make_continuable(Continuation&& continuation) {
|
|||||||
/// \attention Usually using this function isn't needed at all since
|
/// \attention Usually using this function isn't needed at all since
|
||||||
/// the continuable library is capable of working with
|
/// the continuable library is capable of working with
|
||||||
/// plain values in most cases.
|
/// plain values in most cases.
|
||||||
/// Try not to use it since it causes unneccessary recursive
|
/// Try not to use it since it causes unnecessary recursive
|
||||||
/// function calls.
|
/// function calls.
|
||||||
///
|
///
|
||||||
/// \since 3.0.0
|
/// \since 3.0.0
|
||||||
template <typename... Args>
|
template <typename... Args>
|
||||||
constexpr auto make_ready_continuable() {
|
auto make_ready_continuable(Args&&... args) {
|
||||||
return make_continuable<void>([](auto&& promise) {
|
return detail::base::attorney::create_from_raw(
|
||||||
std::forward<decltype(promise)>(promise).set_value();
|
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>...>{},
|
||||||
/// Returns a continuable_base with one result value which instantly resolves
|
detail::util::ownership{});
|
||||||
/// 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
|
/// Returns a continuable_base with the parameterized result which instantly
|
||||||
@ -867,20 +928,213 @@ constexpr auto make_ready_continuable(FirstResult&& first_result,
|
|||||||
/// auto ct = cti::make_exceptional_continuable<int>(ptr);
|
/// auto ct = cti::make_exceptional_continuable<int>(ptr);
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// \tparam Signature The fake signature of the returned continuable.
|
/// \tparam Args The fake signature of the returned continuable.
|
||||||
///
|
///
|
||||||
/// \since 3.0.0
|
/// \since 3.0.0
|
||||||
template <typename... Signature, typename Exception>
|
template <typename... Args, typename Exception>
|
||||||
constexpr auto make_exceptional_continuable(Exception&& 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() {
|
||||||
static_assert(sizeof...(Signature) > 0,
|
static_assert(sizeof...(Signature) > 0,
|
||||||
"Requires at least one type for the fake signature!");
|
"Requires at least one type for the fake signature!");
|
||||||
|
|
||||||
return make_continuable<Signature...>( // ...
|
return make_exceptional_continuable<Signature...>(exception_t{});
|
||||||
[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
|
} // namespace cti
|
||||||
|
|
||||||
|
|||||||
@ -5,9 +5,9 @@
|
|||||||
\_,(_)| | | || ||_|(_||_)|(/_
|
\_,(_)| | | || ||_|(_||_)|(/_
|
||||||
|
|
||||||
https://github.com/Naios/continuable
|
https://github.com/Naios/continuable
|
||||||
v3.0.0
|
v4.2.0
|
||||||
|
|
||||||
Copyright(c) 2015 - 2018 Denis Blank <denis.blank at outlook dot com>
|
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
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files(the "Software"), to deal
|
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
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
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
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
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
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
@ -35,12 +35,11 @@
|
|||||||
#include <memory>
|
#include <memory>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <continuable/detail/connection/connection-all.hpp>
|
||||||
#include <continuable/detail/connection-all.hpp>
|
#include <continuable/detail/connection/connection-any.hpp>
|
||||||
#include <continuable/detail/connection-any.hpp>
|
#include <continuable/detail/connection/connection-seq.hpp>
|
||||||
#include <continuable/detail/connection-seq.hpp>
|
#include <continuable/detail/connection/connection.hpp>
|
||||||
#include <continuable/detail/connection.hpp>
|
#include <continuable/detail/traversal/range.hpp>
|
||||||
#include <continuable/detail/range.hpp>
|
|
||||||
|
|
||||||
namespace cti {
|
namespace cti {
|
||||||
/// \defgroup Connections Connections
|
/// \defgroup Connections Connections
|
||||||
|
|||||||
97
include/continuable/continuable-coroutine.hpp
Normal file
97
include/continuable/continuable-coroutine.hpp
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
/*
|
||||||
|
|
||||||
|
/~` _ _ _|_. _ _ |_ | _
|
||||||
|
\_,(_)| | | || ||_|(_||_)|(/_
|
||||||
|
|
||||||
|
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
|
||||||
41
include/continuable/continuable-operations.hpp
Normal file
41
include/continuable/continuable-operations.hpp
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
/~` _ _ _|_. _ _ |_ | _
|
||||||
|
\_,(_)| | | || ||_|(_||_)|(/_
|
||||||
|
|
||||||
|
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
|
||||||
141
include/continuable/continuable-primitives.hpp
Normal file
141
include/continuable/continuable-primitives.hpp
Normal file
@ -0,0 +1,141 @@
|
|||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
/~` _ _ _|_. _ _ |_ | _
|
||||||
|
\_,(_)| | | || ||_|(_||_)|(/_
|
||||||
|
|
||||||
|
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
|
https://github.com/Naios/continuable
|
||||||
v3.0.0
|
v4.2.0
|
||||||
|
|
||||||
Copyright(c) 2015 - 2018 Denis Blank <denis.blank at outlook dot com>
|
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
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files(the "Software"), to deal
|
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
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
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
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
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
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
@ -31,12 +31,14 @@
|
|||||||
#ifndef CONTINUABLE_PROMISE_BASE_HPP_INCLUDED
|
#ifndef CONTINUABLE_PROMISE_BASE_HPP_INCLUDED
|
||||||
#define CONTINUABLE_PROMISE_BASE_HPP_INCLUDED
|
#define CONTINUABLE_PROMISE_BASE_HPP_INCLUDED
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
#include <continuable/continuable-primitives.hpp>
|
||||||
#include <continuable/detail/hints.hpp>
|
#include <continuable/detail/core/annotation.hpp>
|
||||||
#include <continuable/detail/types.hpp>
|
#include <continuable/detail/core/types.hpp>
|
||||||
#include <continuable/detail/util.hpp>
|
#include <continuable/detail/utility/traits.hpp>
|
||||||
|
#include <continuable/detail/utility/util.hpp>
|
||||||
|
|
||||||
namespace cti {
|
namespace cti {
|
||||||
/// \defgroup Base Base
|
/// \defgroup Base Base
|
||||||
@ -51,7 +53,7 @@ namespace cti {
|
|||||||
///
|
///
|
||||||
/// If we want to resolve the promise_base trough the call operator,
|
/// 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
|
/// and we want to resolve it through an exception, we must call it with a
|
||||||
/// dispatch_error_tag as first and the exception as second argument.
|
/// exception_arg_t as first and the exception as second argument.
|
||||||
/// Additionally the promise is resolveable only through its call
|
/// Additionally the promise is resolveable only through its call
|
||||||
/// operator when invoked as an r-value.
|
/// operator when invoked as an r-value.
|
||||||
///
|
///
|
||||||
@ -62,7 +64,7 @@ class promise_base
|
|||||||
/// \cond false
|
/// \cond false
|
||||||
;
|
;
|
||||||
template <typename Data, typename... Args>
|
template <typename Data, typename... Args>
|
||||||
class promise_base<Data, detail::hints::signature_hint_tag<Args...>>
|
class promise_base<Data, detail::identity<Args...>>
|
||||||
: detail::util::non_copyable
|
: detail::util::non_copyable
|
||||||
/// \endcond
|
/// \endcond
|
||||||
{ // clang-format on
|
{ // clang-format on
|
||||||
@ -73,51 +75,138 @@ class promise_base<Data, detail::hints::signature_hint_tag<Args...>>
|
|||||||
/// \endcond
|
/// \endcond
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
/// Constructor for constructing an empty promise
|
||||||
|
explicit promise_base() = default;
|
||||||
/// Constructor accepting the data object
|
/// Constructor accepting the data object
|
||||||
explicit promise_base(Data data) : data_(std::move(data)) {
|
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
|
/// Constructor accepting any object convertible to the data object
|
||||||
template <typename OData, std::enable_if_t<std::is_convertible<
|
template <typename OData,
|
||||||
std::decay_t<OData>, Data>::value>* = nullptr>
|
std::enable_if_t<std::is_convertible<
|
||||||
promise_base(OData&& data) : data_(std::forward<OData>(data)) {
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Resolves the continuation with the given values.
|
/// Resolves the continuation with the given values.
|
||||||
///
|
///
|
||||||
/// \throws This method never throws an 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
|
/// \since 2.0.0
|
||||||
void operator()(Args... args) && noexcept {
|
void operator()(Args... args) && noexcept {
|
||||||
|
assert(data_);
|
||||||
std::move(data_)(std::move(args)...);
|
std::move(data_)(std::move(args)...);
|
||||||
|
data_ = nullptr;
|
||||||
}
|
}
|
||||||
/// Resolves the continuation with the given exception.
|
/// Resolves the continuation with the given exception.
|
||||||
///
|
///
|
||||||
/// \throws This method never throws an 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
|
/// \since 2.0.0
|
||||||
void operator()(detail::types::dispatch_error_tag tag,
|
void operator()(exception_arg_t tag, exception_t exception) && noexcept {
|
||||||
detail::types::error_type exception) &&
|
assert(data_);
|
||||||
noexcept {
|
|
||||||
std::move(data_)(tag, std::move(exception));
|
std::move(data_)(tag, std::move(exception));
|
||||||
|
data_ = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Resolves the continuation with the given values.
|
/// Resolves the continuation with the given values.
|
||||||
///
|
///
|
||||||
/// \throws This method never throws an 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
|
/// \since 2.0.0
|
||||||
void set_value(Args... args) noexcept {
|
void set_value(Args... args) noexcept {
|
||||||
|
// assert(data_);
|
||||||
std::move(data_)(std::move(args)...);
|
std::move(data_)(std::move(args)...);
|
||||||
|
data_ = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Resolves the continuation with the given exception.
|
/// Resolves the continuation with the given exception.
|
||||||
///
|
///
|
||||||
/// \throws This method never throws an 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
|
/// \since 2.0.0
|
||||||
void set_exception(detail::types::error_type exception) noexcept {
|
void set_exception(exception_t exception) noexcept {
|
||||||
std::move(data_)(detail::types::dispatch_error_tag{}, std::move(exception));
|
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_);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
/// \}
|
/// \}
|
||||||
|
|||||||
@ -5,9 +5,9 @@
|
|||||||
\_,(_)| | | || ||_|(_||_)|(/_
|
\_,(_)| | | || ||_|(_||_)|(/_
|
||||||
|
|
||||||
https://github.com/Naios/continuable
|
https://github.com/Naios/continuable
|
||||||
v3.0.0
|
v4.2.0
|
||||||
|
|
||||||
Copyright(c) 2015 - 2018 Denis Blank <denis.blank at outlook dot com>
|
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
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files(the "Software"), to deal
|
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
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
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
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
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
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
@ -33,8 +33,7 @@
|
|||||||
|
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
#include <continuable/detail/other/promisify.hpp>
|
||||||
#include <continuable/detail/promisify.hpp>
|
|
||||||
|
|
||||||
namespace cti {
|
namespace cti {
|
||||||
/// \defgroup Promisify Promisify
|
/// \defgroup Promisify Promisify
|
||||||
@ -72,18 +71,47 @@ public:
|
|||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// If the error code which is passed as first parameter is set there are
|
/// A given error variable is converted to the used error type.
|
||||||
/// two behaviours depending whether exceptions are enabled:
|
/// If this isn't possible you need to create a custom resolver callable
|
||||||
/// - If exceptions are enabled the error type is passed via
|
/// object \see with for details.
|
||||||
/// 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
|
/// \since 3.0.0
|
||||||
template <typename Callable, typename... Args>
|
template <typename Callable, typename... Args>
|
||||||
static auto from(Callable&& callable, Args&&... args) {
|
static auto from(Callable&& callable, Args&&... args) {
|
||||||
return helper::template from<detail::convert::promisify_default>(
|
return helper::template from(detail::convert::default_resolver(),
|
||||||
std::forward<Callable>(callable), std::forward<Args>(args)...);
|
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)...);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
/// \}
|
/// \}
|
||||||
|
|||||||
356
include/continuable/continuable-result.hpp
Normal file
356
include/continuable/continuable-result.hpp
Normal file
@ -0,0 +1,356 @@
|
|||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
/~` _ _ _|_. _ _ |_ | _
|
||||||
|
\_,(_)| | | || ||_|(_||_)|(/_
|
||||||
|
|
||||||
|
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
|
||||||
@ -1,80 +0,0 @@
|
|||||||
|
|
||||||
/*
|
|
||||||
|
|
||||||
/~` _ _ _|_. _ _ |_ | _
|
|
||||||
\_,(_)| | | || ||_|(_||_)|(/_
|
|
||||||
|
|
||||||
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
|
https://github.com/Naios/continuable
|
||||||
v3.0.0
|
v4.2.0
|
||||||
|
|
||||||
Copyright(c) 2015 - 2018 Denis Blank <denis.blank at outlook dot com>
|
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
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files(the "Software"), to deal
|
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
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
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
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
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
|
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
|
#ifndef CONTINUABLE_TRANSFORMS_HPP_INCLUDED
|
||||||
#define CONTINUABLE_TRANSFORMS_HPP_INCLUDED
|
#define CONTINUABLE_TRANSFORMS_HPP_INCLUDED
|
||||||
|
|
||||||
#include <continuable/detail/transforms.hpp>
|
#include <continuable/transforms/wait.hpp>
|
||||||
#include <continuable/detail/types.hpp>
|
#include <continuable/transforms/future.hpp>
|
||||||
|
|
||||||
namespace cti {
|
namespace cti {
|
||||||
/// \defgroup Transforms Transforms
|
/// \defgroup Transforms Transforms
|
||||||
@ -41,70 +41,12 @@ namespace cti {
|
|||||||
/// types such as (`std::future`).
|
/// 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
|
/// The namespace transforms declares callable objects that transform
|
||||||
/// any continuable_base to an object or to a continuable_base itself.
|
/// any continuable_base to an object or to a continuable_base itself.
|
||||||
///
|
///
|
||||||
/// Transforms can be applied to continuables through using
|
/// Transforms can be applied to continuables through using
|
||||||
/// the cti::continuable_base::apply method accordingly.
|
/// 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
|
} // namespace cti
|
||||||
|
|
||||||
#endif // CONTINUABLE_TRANSFORMS_HPP_INCLUDED
|
#endif // CONTINUABLE_TRANSFORMS_HPP_INCLUDED
|
||||||
|
|||||||
@ -5,9 +5,9 @@
|
|||||||
\_,(_)| | | || ||_|(_||_)|(/_
|
\_,(_)| | | || ||_|(_||_)|(/_
|
||||||
|
|
||||||
https://github.com/Naios/continuable
|
https://github.com/Naios/continuable
|
||||||
v3.0.0
|
v4.2.0
|
||||||
|
|
||||||
Copyright(c) 2015 - 2018 Denis Blank <denis.blank at outlook dot com>
|
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
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files(the "Software"), to deal
|
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
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
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
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
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
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
@ -32,8 +32,7 @@
|
|||||||
#define CONTINUABLE_TRAVERSE_ASYNC_HPP_INCLUDED
|
#define CONTINUABLE_TRAVERSE_ASYNC_HPP_INCLUDED
|
||||||
|
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
#include <continuable/detail/traversal/traverse-async.hpp>
|
||||||
#include <continuable/detail/traverse-async.hpp>
|
|
||||||
|
|
||||||
namespace cti {
|
namespace cti {
|
||||||
/// \defgroup Traversal Traversal
|
/// \defgroup Traversal Traversal
|
||||||
@ -75,7 +74,7 @@ using async_traverse_in_place_tag =
|
|||||||
/// ```cpp
|
/// ```cpp
|
||||||
/// struct my_async_visitor {
|
/// struct my_async_visitor {
|
||||||
/// /// The synchronous overload is called for each object,
|
/// /// The synchronous overload is called for each object,
|
||||||
/// /// it may return false to suspend the current control.
|
/// /// it may return false to suspend the current control flow.
|
||||||
/// /// In that case the overload below is called.
|
/// /// In that case the overload below is called.
|
||||||
/// template <typename T>
|
/// template <typename T>
|
||||||
/// bool operator()(async_traverse_visit_tag, T&& element) {
|
/// bool operator()(async_traverse_visit_tag, T&& element) {
|
||||||
|
|||||||
@ -5,9 +5,9 @@
|
|||||||
\_,(_)| | | || ||_|(_||_)|(/_
|
\_,(_)| | | || ||_|(_||_)|(/_
|
||||||
|
|
||||||
https://github.com/Naios/continuable
|
https://github.com/Naios/continuable
|
||||||
v3.0.0
|
v4.2.0
|
||||||
|
|
||||||
Copyright(c) 2015 - 2018 Denis Blank <denis.blank at outlook dot com>
|
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
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files(the "Software"), to deal
|
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
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
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
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
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
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
@ -34,8 +34,7 @@
|
|||||||
#include <tuple>
|
#include <tuple>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
#include <continuable/detail/traversal/traverse.hpp>
|
||||||
#include <continuable/detail/traverse.hpp>
|
|
||||||
|
|
||||||
namespace cti {
|
namespace cti {
|
||||||
/// \defgroup Traversal Traversal
|
/// \defgroup Traversal Traversal
|
||||||
|
|||||||
@ -5,9 +5,9 @@
|
|||||||
\_,(_)| | | || ||_|(_||_)|(/_
|
\_,(_)| | | || ||_|(_||_)|(/_
|
||||||
|
|
||||||
https://github.com/Naios/continuable
|
https://github.com/Naios/continuable
|
||||||
v3.0.0
|
v4.2.0
|
||||||
|
|
||||||
Copyright(c) 2015 - 2018 Denis Blank <denis.blank at outlook dot com>
|
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
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files(the "Software"), to deal
|
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
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
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
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
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
|
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
|
#ifndef CONTINUABLE_TYPES_HPP_INCLUDED
|
||||||
#define CONTINUABLE_TYPES_HPP_INCLUDED
|
#define CONTINUABLE_TYPES_HPP_INCLUDED
|
||||||
|
|
||||||
#include <cstdint>
|
|
||||||
|
|
||||||
#include <function2/function2.hpp>
|
#include <function2/function2.hpp>
|
||||||
|
#include <continuable/continuable-base.hpp>
|
||||||
#include <continuable/continuable-trait.hpp>
|
#include <continuable/continuable-primitives.hpp>
|
||||||
|
#include <continuable/continuable-promise-base.hpp>
|
||||||
|
#include <continuable/detail/other/erasure.hpp>
|
||||||
|
|
||||||
namespace cti {
|
namespace cti {
|
||||||
/// \defgroup Types Types
|
/// \defgroup Types Types
|
||||||
@ -43,48 +43,59 @@ namespace cti {
|
|||||||
/// cti::promise promise\endlink facility for type erasure.
|
/// cti::promise promise\endlink facility for type erasure.
|
||||||
/// \{
|
/// \{
|
||||||
|
|
||||||
// clang-format off
|
/// Deduces to the preferred continuation capacity for a possible
|
||||||
namespace detail {
|
/// small functor optimization. The given capacity size is always enough to
|
||||||
/// A function which isn't size adjusted and move only
|
/// to avoid any allocation when storing a ready continuable_base.
|
||||||
template<std::size_t, typename... Args>
|
///
|
||||||
using unique_function_adapter = fu2::unique_function<Args...>;
|
/// \since 4.0.0
|
||||||
/// A function which is size adjusted and move only
|
template <typename... Args>
|
||||||
template<std::size_t Size, typename... Args>
|
using continuation_capacity = detail::erasure::continuation_capacity<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
|
/// Defines a non-copyable continuation type which uses the
|
||||||
/// function2 backend for type erasure.
|
/// function2 backend for type erasure.
|
||||||
///
|
///
|
||||||
/// Usable like: `continuable<int, float>`
|
/// 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>
|
template <typename... Args>
|
||||||
using continuable = typename detail::unique_trait_of<
|
using continuable = continuable_base<detail::erasure::continuation<Args...>, //
|
||||||
Args...
|
signature_arg_t<Args...>>;
|
||||||
>::continuable;
|
|
||||||
|
|
||||||
/// Defines a non-copyable promise type which is using the
|
/// Defines a non-copyable promise type which is using the
|
||||||
/// function2 backend for type erasure.
|
/// function2 backend for type erasure.
|
||||||
///
|
///
|
||||||
/// Usable like: `promise<int, float>`
|
/// 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>
|
template <typename... Args>
|
||||||
using promise = typename detail::unique_trait_of<
|
using promise = promise_base<detail::erasure::callback<Args...>, //
|
||||||
Args...
|
signature_arg_t<Args...>>;
|
||||||
>::promise;
|
|
||||||
|
|
||||||
// TODO channel
|
/// Defines a non-copyable type erasure which is capable of carrying
|
||||||
// TODO sink
|
/// callable objects passed to executors.
|
||||||
|
///
|
||||||
// clang-format on
|
/// 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<>>;
|
||||||
/// \}
|
/// \}
|
||||||
} // namespace cti
|
} // namespace cti
|
||||||
|
|
||||||
|
|||||||
@ -5,9 +5,9 @@
|
|||||||
\_,(_)| | | || ||_|(_||_)|(/_
|
\_,(_)| | | || ||_|(_||_)|(/_
|
||||||
|
|
||||||
https://github.com/Naios/continuable
|
https://github.com/Naios/continuable
|
||||||
v3.0.0
|
v4.2.0
|
||||||
|
|
||||||
Copyright(c) 2015 - 2018 Denis Blank <denis.blank at outlook dot com>
|
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
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files(the "Software"), to deal
|
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
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
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
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
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
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
@ -47,9 +47,12 @@ namespace cti {}
|
|||||||
|
|
||||||
#include <continuable/continuable-base.hpp>
|
#include <continuable/continuable-base.hpp>
|
||||||
#include <continuable/continuable-connections.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-promise-base.hpp>
|
||||||
#include <continuable/continuable-promisify.hpp>
|
#include <continuable/continuable-promisify.hpp>
|
||||||
#include <continuable/continuable-trait.hpp>
|
#include <continuable/continuable-result.hpp>
|
||||||
#include <continuable/continuable-transforms.hpp>
|
#include <continuable/continuable-transforms.hpp>
|
||||||
#include <continuable/continuable-traverse-async.hpp>
|
#include <continuable/continuable-traverse-async.hpp>
|
||||||
#include <continuable/continuable-traverse.hpp>
|
#include <continuable/continuable-traverse.hpp>
|
||||||
|
|||||||
@ -1,144 +0,0 @@
|
|||||||
|
|
||||||
/*
|
|
||||||
|
|
||||||
/~` _ _ _|_. _ _ |_ | _
|
|
||||||
\_,(_)| | | || ||_|(_||_)|(/_
|
|
||||||
|
|
||||||
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
|
|
||||||
@ -1,593 +0,0 @@
|
|||||||
|
|
||||||
/*
|
|
||||||
|
|
||||||
/~` _ _ _|_. _ _ |_ | _
|
|
||||||
\_,(_)| | | || ||_|(_||_)|(/_
|
|
||||||
|
|
||||||
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
|
https://github.com/Naios/continuable
|
||||||
v3.0.0
|
v4.2.0
|
||||||
|
|
||||||
Copyright(c) 2015 - 2018 Denis Blank <denis.blank at outlook dot com>
|
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
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files(the "Software"), to deal
|
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
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
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
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
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
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
@ -35,11 +35,10 @@
|
|||||||
#include <tuple>
|
#include <tuple>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
#include <continuable/continuable-result.hpp>
|
||||||
#include <continuable/continuable-traverse.hpp>
|
#include <continuable/continuable-traverse.hpp>
|
||||||
#include <continuable/detail/base.hpp>
|
#include <continuable/detail/core/base.hpp>
|
||||||
#include <continuable/detail/flat-variant.hpp>
|
#include <continuable/detail/utility/traits.hpp>
|
||||||
#include <continuable/detail/traits.hpp>
|
|
||||||
|
|
||||||
namespace cti {
|
namespace cti {
|
||||||
namespace detail {
|
namespace detail {
|
||||||
@ -55,62 +54,69 @@ namespace connection {
|
|||||||
/// - single async value -> single value
|
/// - single async value -> single value
|
||||||
/// - multiple async value -> tuple of async values.
|
/// - multiple async value -> tuple of async values.
|
||||||
namespace aggregated {
|
namespace aggregated {
|
||||||
|
|
||||||
/// Guards a type to be default constructible,
|
/// Guards a type to be default constructible,
|
||||||
/// and wraps it into an optional type if it isn't default constructible.
|
/// and wraps it into an optional type if it isn't default constructible.
|
||||||
template <typename T>
|
template <typename T>
|
||||||
using lazy_value_t = std::conditional_t<std::is_default_constructible<T>::value,
|
using lazy_value_t = std::conditional_t<std::is_default_constructible<T>::value,
|
||||||
T, container::flat_variant<T>>;
|
T, result<T>>;
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
decltype(auto) unpack_lazy(T&& value) {
|
decltype(auto) unpack_lazy(std::true_type /*is_default_constructible*/,
|
||||||
|
T&& value) {
|
||||||
return std::forward<T>(value);
|
return std::forward<T>(value);
|
||||||
}
|
}
|
||||||
template <typename T>
|
template <typename T>
|
||||||
T&& unpack_lazy(container::flat_variant<T>&& value) {
|
T&& unpack_lazy(std::false_type /*is_default_constructible*/,
|
||||||
assert(value.template is<T>() &&
|
result<T>&& value) {
|
||||||
|
assert(value.is_value() &&
|
||||||
"The connection was finalized before all values were present!");
|
"The connection was finalized before all values were present!");
|
||||||
|
|
||||||
return std::move(value.template cast<T>());
|
return std::move(value).get_value();
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Continuable>
|
template <typename Continuable>
|
||||||
class continuable_box;
|
class continuable_box;
|
||||||
template <typename Data>
|
template <typename Data>
|
||||||
class continuable_box<continuable_base<Data, hints::signature_hint_tag<>>> {
|
class continuable_box<continuable_base<Data, identity<>>> {
|
||||||
|
|
||||||
continuable_base<Data, hints::signature_hint_tag<>> continuable_;
|
continuable_base<Data, identity<>> continuable_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit continuable_box(
|
explicit continuable_box(continuable_base<Data, identity<>>&& continuable)
|
||||||
continuable_base<Data, hints::signature_hint_tag<>>&& continuable)
|
: continuable_(std::move(continuable)) {}
|
||||||
: continuable_(std::move(continuable)) {
|
|
||||||
|
auto const& peek() const {
|
||||||
|
return continuable_;
|
||||||
}
|
}
|
||||||
|
|
||||||
continuable_base<Data, hints::signature_hint_tag<>>&& fetch() {
|
auto&& fetch() {
|
||||||
return std::move(continuable_);
|
return std::move(continuable_);
|
||||||
}
|
}
|
||||||
|
|
||||||
void assign() {
|
void assign() {}
|
||||||
}
|
|
||||||
|
|
||||||
auto unbox() && {
|
auto unbox() && {
|
||||||
return spread_this();
|
return spread_this();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
template <typename Data, typename First>
|
|
||||||
class continuable_box<
|
|
||||||
continuable_base<Data, hints::signature_hint_tag<First>>> {
|
|
||||||
|
|
||||||
continuable_base<Data, hints::signature_hint_tag<First>> continuable_;
|
template <typename Data, typename First>
|
||||||
|
class continuable_box<continuable_base<Data, identity<First>>> {
|
||||||
|
|
||||||
|
continuable_base<Data, identity<First>> continuable_;
|
||||||
lazy_value_t<First> first_;
|
lazy_value_t<First> first_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit continuable_box(
|
explicit continuable_box(
|
||||||
continuable_base<Data, hints::signature_hint_tag<First>>&& continuable)
|
continuable_base<Data, identity<First>>&& continuable)
|
||||||
: continuable_(std::move(continuable)) {
|
: continuable_(std::move(continuable)) {}
|
||||||
|
|
||||||
|
auto const& peek() const {
|
||||||
|
return continuable_;
|
||||||
}
|
}
|
||||||
|
|
||||||
continuable_base<Data, hints::signature_hint_tag<First>>&& fetch() {
|
auto&& fetch() {
|
||||||
return std::move(continuable_);
|
return std::move(continuable_);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -119,27 +125,27 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto unbox() && {
|
auto unbox() && {
|
||||||
return unpack_lazy(std::move(first_));
|
return unpack_lazy(std::is_default_constructible<First>{},
|
||||||
|
std::move(first_));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
template <typename Data, typename First, typename Second, typename... Rest>
|
template <typename Data, typename First, typename Second, typename... Rest>
|
||||||
class continuable_box<
|
class continuable_box<
|
||||||
continuable_base<Data, hints::signature_hint_tag<First, Second, Rest...>>> {
|
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_;
|
|
||||||
lazy_value_t<std::tuple<First, Second, Rest...>> args_;
|
lazy_value_t<std::tuple<First, Second, Rest...>> args_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit continuable_box(
|
explicit continuable_box(
|
||||||
continuable_base<Data,
|
continuable_base<Data, identity<First, Second, Rest...>>&& continuable)
|
||||||
hints::signature_hint_tag<First, Second, Rest...>>&&
|
: continuable_(std::move(continuable)) {}
|
||||||
continuable)
|
|
||||||
: continuable_(std::move(continuable)) {
|
auto const& peek() const {
|
||||||
|
return continuable_;
|
||||||
}
|
}
|
||||||
|
|
||||||
continuable_base<Data, hints::signature_hint_tag<First, Second, Rest...>>&&
|
auto&& fetch() {
|
||||||
fetch() {
|
|
||||||
return std::move(continuable_);
|
return std::move(continuable_);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -149,9 +155,13 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto unbox() && {
|
auto unbox() && {
|
||||||
return traits::unpack(unpack_lazy(std::move(args_)), [](auto&&... args) {
|
return traits::unpack(
|
||||||
|
[](auto&&... args) {
|
||||||
return spread_this(std::forward<decltype(args)>(args)...);
|
return spread_this(std::forward<decltype(args)>(args)...);
|
||||||
});
|
},
|
||||||
|
unpack_lazy(
|
||||||
|
std::is_default_constructible<std::tuple<First, Second, Rest...>>{},
|
||||||
|
std::move(args_)));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -200,21 +210,20 @@ constexpr auto unbox_continuables(Args&&... args) {
|
|||||||
|
|
||||||
namespace detail {
|
namespace detail {
|
||||||
template <typename Callback, typename Data>
|
template <typename Callback, typename Data>
|
||||||
constexpr auto finalize_impl(traits::identity<void>, Callback&& callback,
|
constexpr auto finalize_impl(identity<void>, Callback&& callback, Data&&) {
|
||||||
Data&&) {
|
|
||||||
return std::forward<Callback>(callback)();
|
return std::forward<Callback>(callback)();
|
||||||
}
|
}
|
||||||
template <typename... Args, typename Callback, typename Data>
|
template <typename... Args, typename Callback, typename Data>
|
||||||
constexpr auto finalize_impl(traits::identity<std::tuple<Args...>>,
|
constexpr auto finalize_impl(identity<std::tuple<Args...>>, Callback&& callback,
|
||||||
Callback&& callback, Data&& data) {
|
Data&& data) {
|
||||||
// Call the final callback with the cleaned result
|
// Call the final callback with the cleaned result
|
||||||
return traits::unpack(unbox_continuables(std::forward<Data>(data)),
|
return traits::unpack(std::forward<Callback>(callback),
|
||||||
std::forward<Callback>(callback));
|
unbox_continuables(std::forward<Data>(data)));
|
||||||
}
|
}
|
||||||
|
|
||||||
struct hint_mapper {
|
struct hint_mapper {
|
||||||
template <typename... T>
|
template <typename... T>
|
||||||
constexpr auto operator()(T...) -> hints::signature_hint_tag<T...> {
|
constexpr auto operator()(T...) -> identity<T...> {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -224,7 +233,7 @@ template <typename Callback, typename Data>
|
|||||||
constexpr auto finalize_data(Callback&& callback, Data&& data) {
|
constexpr auto finalize_data(Callback&& callback, Data&& data) {
|
||||||
using result_t = decltype(unbox_continuables(std::forward<Data>(data)));
|
using result_t = decltype(unbox_continuables(std::forward<Data>(data)));
|
||||||
// Guard the final result against void
|
// Guard the final result against void
|
||||||
return detail::finalize_impl(traits::identity<std::decay_t<result_t>>{},
|
return detail::finalize_impl(identity<std::decay_t<result_t>>{},
|
||||||
std::forward<Callback>(callback),
|
std::forward<Callback>(callback),
|
||||||
std::forward<Data>(data));
|
std::forward<Data>(data));
|
||||||
}
|
}
|
||||||
@ -5,9 +5,9 @@
|
|||||||
\_,(_)| | | || ||_|(_||_)|(/_
|
\_,(_)| | | || ||_|(_||_)|(/_
|
||||||
|
|
||||||
https://github.com/Naios/continuable
|
https://github.com/Naios/continuable
|
||||||
v3.0.0
|
v4.2.0
|
||||||
|
|
||||||
Copyright(c) 2015 - 2018 Denis Blank <denis.blank at outlook dot com>
|
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
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files(the "Software"), to deal
|
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
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
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
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
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
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
@ -37,13 +37,13 @@
|
|||||||
#include <tuple>
|
#include <tuple>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
#include <continuable/continuable-primitives.hpp>
|
||||||
#include <continuable/detail/base.hpp>
|
#include <continuable/detail/connection/connection-aggregated.hpp>
|
||||||
#include <continuable/detail/connection-aggregated.hpp>
|
#include <continuable/detail/connection/connection.hpp>
|
||||||
#include <continuable/detail/connection.hpp>
|
#include <continuable/detail/core/annotation.hpp>
|
||||||
#include <continuable/detail/hints.hpp>
|
#include <continuable/detail/core/base.hpp>
|
||||||
#include <continuable/detail/traits.hpp>
|
#include <continuable/detail/core/types.hpp>
|
||||||
#include <continuable/detail/types.hpp>
|
#include <continuable/detail/utility/traits.hpp>
|
||||||
|
|
||||||
namespace cti {
|
namespace cti {
|
||||||
namespace detail {
|
namespace detail {
|
||||||
@ -99,11 +99,11 @@ class result_submitter
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename... PartialArgs>
|
template <typename... PartialArgs>
|
||||||
void operator()(types::dispatch_error_tag tag, types::error_type error) && {
|
void operator()(exception_arg_t tag, exception_t exception) && {
|
||||||
// We never complete the connection, but we forward the first error
|
// We never complete the connection, but we forward the first error
|
||||||
// which was raised.
|
// which was raised.
|
||||||
std::call_once(me->flag_, std::move(me->callback_), tag,
|
std::call_once(me->flag_, std::move(me->callback_), tag,
|
||||||
std::move(error));
|
std::move(exception));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -157,22 +157,21 @@ struct connection_finalizer<connection_strategy_all_tag> {
|
|||||||
template <typename Connection>
|
template <typename Connection>
|
||||||
static auto finalize(Connection&& connection, util::ownership ownership) {
|
static auto finalize(Connection&& connection, util::ownership ownership) {
|
||||||
// Create the target result from the connection
|
// Create the target result from the connection
|
||||||
auto result =
|
auto res =
|
||||||
aggregated::box_continuables(std::forward<Connection>(connection));
|
aggregated::box_continuables(std::forward<Connection>(connection));
|
||||||
|
|
||||||
auto signature = aggregated::hint_of_data<decltype(result)>();
|
auto signature = aggregated::hint_of_data<decltype(res)>();
|
||||||
|
|
||||||
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 =
|
using submitter_t =
|
||||||
all::result_submitter<std::decay_t<decltype(callback)>,
|
all::result_submitter<std::decay_t<decltype(callback)>,
|
||||||
std::decay_t<decltype(result)>>;
|
std::decay_t<decltype(res)>>;
|
||||||
|
|
||||||
// Create the shared state which holds the result and the final
|
// Create the shared state which holds the result
|
||||||
// callback
|
// and the final callback
|
||||||
auto state = std::make_shared<submitter_t>(
|
auto state = std::make_shared<submitter_t>(
|
||||||
std::forward<decltype(callback)>(callback), std::move(result));
|
std::forward<decltype(callback)>(callback), std::move(res));
|
||||||
|
|
||||||
// Dispatch the continuables and store its partial result
|
// Dispatch the continuables and store its partial result
|
||||||
// in the whole result
|
// in the whole result
|
||||||
@ -186,6 +185,13 @@ struct connection_finalizer<connection_strategy_all_tag> {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
} // namespace connection
|
} // 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 detail
|
||||||
} // namespace cti
|
} // namespace cti
|
||||||
|
|
||||||
@ -5,9 +5,9 @@
|
|||||||
\_,(_)| | | || ||_|(_||_)|(/_
|
\_,(_)| | | || ||_|(_||_)|(/_
|
||||||
|
|
||||||
https://github.com/Naios/continuable
|
https://github.com/Naios/continuable
|
||||||
v3.0.0
|
v4.2.0
|
||||||
|
|
||||||
Copyright(c) 2015 - 2018 Denis Blank <denis.blank at outlook dot com>
|
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
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files(the "Software"), to deal
|
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
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
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
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
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
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
@ -37,14 +37,14 @@
|
|||||||
#include <tuple>
|
#include <tuple>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
#include <continuable/continuable-primitives.hpp>
|
||||||
#include <continuable/continuable-promise-base.hpp>
|
#include <continuable/continuable-promise-base.hpp>
|
||||||
#include <continuable/continuable-traverse.hpp>
|
#include <continuable/continuable-traverse.hpp>
|
||||||
#include <continuable/detail/base.hpp>
|
#include <continuable/detail/core/annotation.hpp>
|
||||||
#include <continuable/detail/container-category.hpp>
|
#include <continuable/detail/core/base.hpp>
|
||||||
#include <continuable/detail/hints.hpp>
|
#include <continuable/detail/core/types.hpp>
|
||||||
#include <continuable/detail/traits.hpp>
|
#include <continuable/detail/traversal/container-category.hpp>
|
||||||
#include <continuable/detail/types.hpp>
|
#include <continuable/detail/utility/traits.hpp>
|
||||||
|
|
||||||
namespace cti {
|
namespace cti {
|
||||||
namespace detail {
|
namespace detail {
|
||||||
@ -88,30 +88,30 @@ private:
|
|||||||
|
|
||||||
struct result_deducer {
|
struct result_deducer {
|
||||||
template <typename T>
|
template <typename T>
|
||||||
static auto deduce_one(std::false_type, traits::identity<T>) {
|
static auto deduce_one(std::false_type, identity<T>) {
|
||||||
static_assert(traits::fail<T>::value,
|
static_assert(traits::fail<T>::value,
|
||||||
"Non continuable types except tuple like and homogeneous "
|
"Non continuable types except tuple like and homogeneous "
|
||||||
"containers aren't allowed inside an any expression!");
|
"containers aren't allowed inside an any expression!");
|
||||||
}
|
}
|
||||||
template <typename T>
|
template <typename T>
|
||||||
static auto deduce_one(std::true_type, traits::identity<T> id) {
|
static auto deduce_one(std::true_type, identity<T> id) {
|
||||||
return hints::hint_of(id);
|
return base::annotation_of(id);
|
||||||
}
|
}
|
||||||
template <typename T>
|
template <typename T>
|
||||||
static auto deduce(traversal::container_category_tag<false, false>,
|
static auto deduce(traversal::container_category_tag<false, false>,
|
||||||
traits::identity<T> id) {
|
identity<T> id) {
|
||||||
return deduce_one<T>(base::is_continuable<T>{}, id);
|
return deduce_one<T>(base::is_continuable<T>{}, id);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Deduce a homogeneous container
|
/// Deduce a homogeneous container
|
||||||
template <bool IsTupleLike, typename T>
|
template <bool IsTupleLike, typename T>
|
||||||
static auto deduce(traversal::container_category_tag<true, IsTupleLike>,
|
static auto deduce(traversal::container_category_tag<true, IsTupleLike>,
|
||||||
traits::identity<T>) {
|
identity<T>) {
|
||||||
|
|
||||||
// Deduce the containing type
|
// Deduce the containing type
|
||||||
using element_t = std::decay_t<decltype(*std::declval<T>().begin())>;
|
using element_t = std::decay_t<decltype(*std::declval<T>().begin())>;
|
||||||
return deduce(traversal::container_category_of_t<element_t>{},
|
return deduce(traversal::container_category_of_t<element_t>{},
|
||||||
traits::identity<element_t>{});
|
identity<element_t>{});
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename First, typename... T>
|
template <typename First, typename... T>
|
||||||
@ -125,19 +125,18 @@ struct result_deducer {
|
|||||||
|
|
||||||
template <std::size_t... I, typename T>
|
template <std::size_t... I, typename T>
|
||||||
static auto deduce_tuple_like(std::integer_sequence<std::size_t, I...>,
|
static auto deduce_tuple_like(std::integer_sequence<std::size_t, I...>,
|
||||||
traits::identity<T>) {
|
identity<T>) {
|
||||||
|
|
||||||
return deduce_same_hints(deduce(
|
return deduce_same_hints(deduce(
|
||||||
traversal::container_category_of_t<
|
traversal::container_category_of_t<
|
||||||
std::decay_t<decltype(std::get<I>(std::declval<T>()))>>{},
|
std::decay_t<decltype(std::get<I>(std::declval<T>()))>>{},
|
||||||
traits::identity<
|
identity<std::decay_t<decltype(std::get<I>(std::declval<T>()))>>{})...);
|
||||||
std::decay_t<decltype(std::get<I>(std::declval<T>()))>>{})...);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Traverse tuple like container
|
/// Traverse tuple like container
|
||||||
template <typename T>
|
template <typename T>
|
||||||
static auto deduce(traversal::container_category_tag<false, true>,
|
static auto deduce(traversal::container_category_tag<false, true>,
|
||||||
traits::identity<T> id) {
|
identity<T> id) {
|
||||||
|
|
||||||
constexpr auto const size = std::tuple_size<T>::value;
|
constexpr auto const size = std::tuple_size<T>::value;
|
||||||
return deduce_tuple_like(std::make_index_sequence<size>{}, id);
|
return deduce_tuple_like(std::make_index_sequence<size>{}, id);
|
||||||
@ -172,12 +171,11 @@ struct connection_finalizer<connection_strategy_any_tag> {
|
|||||||
static auto finalize(Connection&& connection, util::ownership ownership) {
|
static auto finalize(Connection&& connection, util::ownership ownership) {
|
||||||
constexpr auto const signature = decltype(any::result_deducer::deduce(
|
constexpr auto const signature = decltype(any::result_deducer::deduce(
|
||||||
traversal::container_category_of_t<std::decay_t<Connection>>{},
|
traversal::container_category_of_t<std::decay_t<Connection>>{},
|
||||||
traits::identity<std::decay_t<Connection>>{})){};
|
identity<std::decay_t<Connection>>{})){};
|
||||||
|
|
||||||
return base::attorney::create(
|
return base::attorney::create_from(
|
||||||
[connection =
|
[connection =
|
||||||
std::forward<Connection>(connection)](auto&& callback) mutable {
|
std::forward<Connection>(connection)](auto&& callback) mutable {
|
||||||
|
|
||||||
using submitter_t =
|
using submitter_t =
|
||||||
any::any_result_submitter<std::decay_t<decltype(callback)>>;
|
any::any_result_submitter<std::decay_t<decltype(callback)>>;
|
||||||
|
|
||||||
@ -193,6 +191,13 @@ struct connection_finalizer<connection_strategy_any_tag> {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
} // namespace connection
|
} // 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 detail
|
||||||
} // namespace cti
|
} // namespace cti
|
||||||
|
|
||||||
@ -5,9 +5,9 @@
|
|||||||
\_,(_)| | | || ||_|(_||_)|(/_
|
\_,(_)| | | || ||_|(_||_)|(/_
|
||||||
|
|
||||||
https://github.com/Naios/continuable
|
https://github.com/Naios/continuable
|
||||||
v3.0.0
|
v4.2.0
|
||||||
|
|
||||||
Copyright(c) 2015 - 2018 Denis Blank <denis.blank at outlook dot com>
|
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
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files(the "Software"), to deal
|
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
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
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
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
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
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
@ -36,12 +36,12 @@
|
|||||||
#include <tuple>
|
#include <tuple>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
#include <continuable/continuable-primitives.hpp>
|
||||||
#include <continuable/continuable-traverse-async.hpp>
|
#include <continuable/continuable-traverse-async.hpp>
|
||||||
#include <continuable/detail/base.hpp>
|
#include <continuable/detail/connection/connection-aggregated.hpp>
|
||||||
#include <continuable/detail/connection-aggregated.hpp>
|
#include <continuable/detail/core/base.hpp>
|
||||||
#include <continuable/detail/traits.hpp>
|
#include <continuable/detail/utility/traits.hpp>
|
||||||
#include <continuable/detail/util.hpp>
|
#include <continuable/detail/utility/util.hpp>
|
||||||
|
|
||||||
namespace cti {
|
namespace cti {
|
||||||
namespace detail {
|
namespace detail {
|
||||||
@ -56,12 +56,12 @@ auto sequential_connect(Left&& left, Right&& right) {
|
|||||||
left.freeze(right.is_frozen());
|
left.freeze(right.is_frozen());
|
||||||
right.freeze();
|
right.freeze();
|
||||||
|
|
||||||
return std::forward<Left>(left).then([right = std::forward<Right>(right)](
|
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 {
|
auto&&... args) mutable {
|
||||||
return std::move(right).then([previous = std::make_tuple(
|
return std::tuple_cat(
|
||||||
std::forward<decltype(args)>(args)...)](
|
|
||||||
auto&&... args) mutable {
|
|
||||||
return traits::merge(
|
|
||||||
std::move(previous),
|
std::move(previous),
|
||||||
std::make_tuple(std::forward<decltype(args)>(args)...));
|
std::make_tuple(std::forward<decltype(args)>(args)...));
|
||||||
});
|
});
|
||||||
@ -94,25 +94,34 @@ public:
|
|||||||
|
|
||||||
template <typename Box, std::enable_if_t<aggregated::is_continuable_box<
|
template <typename Box, std::enable_if_t<aggregated::is_continuable_box<
|
||||||
std::decay_t<Box>>::value>* = nullptr>
|
std::decay_t<Box>>::value>* = nullptr>
|
||||||
bool operator()(async_traverse_visit_tag, Box&& /*box*/) {
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
template <typename Box, typename N>
|
template <typename Box, typename N>
|
||||||
void operator()(async_traverse_detach_tag, Box&& box, N&& next) {
|
void operator()(async_traverse_detach_tag, Box&& box, N&& next) {
|
||||||
box.fetch()
|
box.fetch()
|
||||||
.then([ box = std::addressof(box),
|
.then([box = std::addressof(box),
|
||||||
next = std::forward<N>(next) ](auto&&... args) mutable {
|
next = std::forward<N>(next)](auto&&... args) mutable {
|
||||||
|
|
||||||
// Assign the result to the target
|
// Assign the result to the target
|
||||||
box->assign(std::forward<decltype(args)>(args)...);
|
box->assign(std::forward<decltype(args)>(args)...);
|
||||||
|
|
||||||
// Continue the asynchronous sequential traversal
|
// Continue the asynchronous sequential traversal
|
||||||
next();
|
next();
|
||||||
})
|
})
|
||||||
.fail([me = this->shared_from_this()](types::error_type exception) {
|
.fail([me = this->shared_from_this()](exception_t exception) {
|
||||||
// Abort the traversal when an error occurred
|
// Abort the traversal when an error occurred
|
||||||
std::move(me->data_.callback)(types::dispatch_error_tag{},
|
std::move(me->data_.callback)(exception_arg_t{},
|
||||||
std::move(exception));
|
std::move(exception));
|
||||||
})
|
})
|
||||||
.done();
|
.done();
|
||||||
@ -138,30 +147,36 @@ struct connection_finalizer<connection_strategy_seq_tag> {
|
|||||||
template <typename Connection>
|
template <typename Connection>
|
||||||
static auto finalize(Connection&& connection, util::ownership ownership) {
|
static auto finalize(Connection&& connection, util::ownership ownership) {
|
||||||
|
|
||||||
auto result =
|
auto res =
|
||||||
aggregated::box_continuables(std::forward<Connection>(connection));
|
aggregated::box_continuables(std::forward<Connection>(connection));
|
||||||
|
|
||||||
auto signature = aggregated::hint_of_data<decltype(result)>();
|
auto signature = aggregated::hint_of_data<decltype(res)>();
|
||||||
|
|
||||||
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
|
// The data from which the visitor is constructed in-place
|
||||||
using data_t =
|
using data_t =
|
||||||
seq::sequential_dispatch_data<std::decay_t<decltype(callback)>,
|
seq::sequential_dispatch_data<std::decay_t<decltype(callback)>,
|
||||||
std::decay_t<decltype(result)>>;
|
std::decay_t<decltype(res)>>;
|
||||||
|
|
||||||
// The visitor type
|
// The visitor type
|
||||||
using visitor_t = seq::sequential_dispatch_visitor<data_t>;
|
using visitor_t = seq::sequential_dispatch_visitor<data_t>;
|
||||||
|
|
||||||
traverse_pack_async(async_traverse_in_place_tag<visitor_t>{},
|
traverse_pack_async(async_traverse_in_place_tag<visitor_t>{},
|
||||||
data_t{std::forward<decltype(callback)>(callback),
|
data_t{std::forward<decltype(callback)>(callback),
|
||||||
std::move(result)});
|
std::move(res)});
|
||||||
},
|
},
|
||||||
signature, std::move(ownership));
|
signature, std::move(ownership));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
} // namespace connection
|
} // 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 detail
|
||||||
} // namespace cti
|
} // namespace cti
|
||||||
|
|
||||||
@ -5,9 +5,9 @@
|
|||||||
\_,(_)| | | || ||_|(_||_)|(/_
|
\_,(_)| | | || ||_|(_||_)|(/_
|
||||||
|
|
||||||
https://github.com/Naios/continuable
|
https://github.com/Naios/continuable
|
||||||
v3.0.0
|
v4.2.0
|
||||||
|
|
||||||
Copyright(c) 2015 - 2018 Denis Blank <denis.blank at outlook dot com>
|
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
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files(the "Software"), to deal
|
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
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
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
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
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
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
@ -35,12 +35,11 @@
|
|||||||
#include <tuple>
|
#include <tuple>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
#include <continuable/continuable-traverse.hpp>
|
#include <continuable/continuable-traverse.hpp>
|
||||||
#include <continuable/detail/base.hpp>
|
#include <continuable/detail/core/base.hpp>
|
||||||
#include <continuable/detail/traits.hpp>
|
#include <continuable/detail/core/types.hpp>
|
||||||
#include <continuable/detail/types.hpp>
|
#include <continuable/detail/utility/traits.hpp>
|
||||||
#include <continuable/detail/util.hpp>
|
#include <continuable/detail/utility/util.hpp>
|
||||||
|
|
||||||
namespace cti {
|
namespace cti {
|
||||||
namespace detail {
|
namespace detail {
|
||||||
@ -56,7 +55,7 @@ template <typename... LeftArgs, typename... RightArgs>
|
|||||||
auto chain_connection(std::tuple<LeftArgs...> leftPack,
|
auto chain_connection(std::tuple<LeftArgs...> leftPack,
|
||||||
std::tuple<RightArgs...> rightPack) {
|
std::tuple<RightArgs...> rightPack) {
|
||||||
|
|
||||||
return traits::merge(std::move(leftPack), std::move(rightPack));
|
return std::tuple_cat(std::move(leftPack), std::move(rightPack));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Normalizes a continuation to a tuple holding an arbitrary count of
|
/// Normalizes a continuation to a tuple holding an arbitrary count of
|
||||||
@ -84,7 +83,7 @@ auto normalize(Strategy /*strategy*/,
|
|||||||
|
|
||||||
// If the right continuation is a different strategy materialize it
|
// If the right continuation is a different strategy materialize it
|
||||||
// in order to keep the precedence in cases where: `c1 && (c2 || c3)`.
|
// in order to keep the precedence in cases where: `c1 && (c2 || c3)`.
|
||||||
return std::make_tuple(base::attorney::materialize(std::move(continuation)));
|
return std::make_tuple(std::move(continuation).finish());
|
||||||
}
|
}
|
||||||
/// - The continuable is inside the current strategy state:
|
/// - The continuable is inside the current strategy state:
|
||||||
/// -> return the data of the tuple
|
/// -> return the data of the tuple
|
||||||
@ -93,7 +92,7 @@ auto normalize(Strategy /*strategy*/,
|
|||||||
continuable_base<Data, Strategy>&& continuation) {
|
continuable_base<Data, Strategy>&& continuation) {
|
||||||
|
|
||||||
// If we are in the given strategy we can just use the data of the continuable
|
// If we are in the given strategy we can just use the data of the continuable
|
||||||
return base::attorney::consume_data(std::move(continuation));
|
return base::attorney::consume(std::move(continuation));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Entry function for connecting two continuables with a given strategy.
|
/// Entry function for connecting two continuables with a given strategy.
|
||||||
@ -115,7 +114,7 @@ auto connect(Strategy strategy, continuable_base<LData, LAnnotation>&& left,
|
|||||||
|
|
||||||
// Return a new continuable containing the tuple and holding
|
// Return a new continuable containing the tuple and holding
|
||||||
// the current strategy as annotation.
|
// the current strategy as annotation.
|
||||||
return base::attorney::create(std::move(data), strategy, ownership_);
|
return base::attorney::create_from_raw(std::move(data), strategy, ownership_);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// All strategies should specialize this class in order to provide:
|
/// All strategies should specialize this class in order to provide:
|
||||||
@ -125,32 +124,24 @@ auto connect(Strategy strategy, continuable_base<LData, LAnnotation>&& left,
|
|||||||
template <typename Strategy>
|
template <typename Strategy>
|
||||||
struct connection_finalizer;
|
struct connection_finalizer;
|
||||||
|
|
||||||
/// Finalizes the connection logic of a given connection
|
template <typename Strategy>
|
||||||
template <typename Data, typename Strategy>
|
struct connection_annotation_trait {
|
||||||
auto finalize_connection(continuable_base<Data, Strategy>&& continuation) {
|
/// Finalizes the connection logic of a given connection
|
||||||
|
template <typename Continuable>
|
||||||
|
static auto finish(Continuable&& continuable) {
|
||||||
using finalizer = connection_finalizer<Strategy>;
|
using finalizer = connection_finalizer<Strategy>;
|
||||||
|
|
||||||
util::ownership ownership = base::attorney::ownership_of(continuation);
|
util::ownership ownership = base::attorney::ownership_of(continuable);
|
||||||
auto connection = base::attorney::consume_data(std::move(continuation));
|
auto connection =
|
||||||
|
base::attorney::consume(std::forward<Continuable>(continuable));
|
||||||
|
|
||||||
// Return a new continuable which
|
// Return a new continuable which
|
||||||
return finalizer::finalize(std::move(connection), std::move(ownership));
|
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>> {
|
|
||||||
|
|
||||||
static constexpr auto apply(continuable_base<Data, Strategy>&& continuable) {
|
template <typename Continuable>
|
||||||
return finalize_connection(std::move(continuable));
|
static bool is_ready(Continuable const& /*continuable*/) noexcept {
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -180,7 +171,7 @@ public:
|
|||||||
|
|
||||||
// Materialize every continuable
|
// Materialize every continuable
|
||||||
// TODO Actually we would just need to consume the data here
|
// TODO Actually we would just need to consume the data here
|
||||||
return base::attorney::materialize(std::forward<Continuable>(continuable));
|
return std::forward<Continuable>(continuable).finish();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -5,9 +5,9 @@
|
|||||||
\_,(_)| | | || ||_|(_||_)|(/_
|
\_,(_)| | | || ||_|(_||_)|(/_
|
||||||
|
|
||||||
https://github.com/Naios/continuable
|
https://github.com/Naios/continuable
|
||||||
v3.0.0
|
v4.2.0
|
||||||
|
|
||||||
Copyright(c) 2015 - 2018 Denis Blank <denis.blank at outlook dot com>
|
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
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files(the "Software"), to deal
|
of this software and associated documentation files(the "Software"), to deal
|
||||||
@ -21,51 +21,33 @@
|
|||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
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
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
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
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
SOFTWARE.
|
SOFTWARE.
|
||||||
**/
|
**/
|
||||||
|
|
||||||
#ifndef CONTINUABLE_DETAIL_HINTS_HPP_INCLUDED
|
#ifndef CONTINUABLE_DETAIL_ANNOTATION_HPP_INCLUDED
|
||||||
#define CONTINUABLE_DETAIL_HINTS_HPP_INCLUDED
|
#define CONTINUABLE_DETAIL_ANNOTATION_HPP_INCLUDED
|
||||||
|
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
#include <continuable/detail/core/types.hpp>
|
||||||
#include <continuable/detail/traits.hpp>
|
#include <continuable/detail/utility/traits.hpp>
|
||||||
#include <continuable/detail/types.hpp>
|
|
||||||
|
|
||||||
namespace cti {
|
namespace cti {
|
||||||
namespace detail {
|
namespace detail {
|
||||||
namespace hints {
|
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
|
/// Extracts the signature we pass to the internal continuable
|
||||||
/// from an argument pack as specified by make_continuable.
|
/// from an argument pack as specified by make_continuable.
|
||||||
///
|
///
|
||||||
/// This is the overload taking an arbitrary amount of args
|
/// This is the overload taking an arbitrary amount of args
|
||||||
template <typename... HintArgs>
|
template <typename... HintArgs>
|
||||||
constexpr auto extract(traits::identity<HintArgs...> hint) {
|
struct from_args : std::common_type<signature_arg_t<HintArgs...>> {};
|
||||||
return hint;
|
template <>
|
||||||
}
|
struct from_args<void> : std::common_type<signature_arg_t<>> {};
|
||||||
/// \copybrief extract
|
|
||||||
///
|
|
||||||
/// This is the overload taking a void arg.
|
|
||||||
constexpr auto extract(traits::identity<void> /*hint*/) {
|
|
||||||
return traits::identity<>{};
|
|
||||||
}
|
|
||||||
} // namespace hints
|
} // namespace hints
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
} // namespace cti
|
} // namespace cti
|
||||||
|
|
||||||
#endif // CONTINUABLE_DETAIL_HINTS_HPP_INCLUDED
|
#endif // CONTINUABLE_DETAIL_ANNOTATION_HPP_INCLUDED
|
||||||
1093
include/continuable/detail/core/base.hpp
Normal file
1093
include/continuable/detail/core/base.hpp
Normal file
File diff suppressed because it is too large
Load Diff
@ -5,9 +5,9 @@
|
|||||||
\_,(_)| | | || ||_|(_||_)|(/_
|
\_,(_)| | | || ||_|(_||_)|(/_
|
||||||
|
|
||||||
https://github.com/Naios/continuable
|
https://github.com/Naios/continuable
|
||||||
v3.0.0
|
v4.2.0
|
||||||
|
|
||||||
Copyright(c) 2015 - 2018 Denis Blank <denis.blank at outlook dot com>
|
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
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files(the "Software"), to deal
|
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
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
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
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
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
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
@ -31,9 +31,10 @@
|
|||||||
#ifndef CONTINUABLE_DETAIL_TYPES_HPP_INCLUDED
|
#ifndef CONTINUABLE_DETAIL_TYPES_HPP_INCLUDED
|
||||||
#define CONTINUABLE_DETAIL_TYPES_HPP_INCLUDED
|
#define CONTINUABLE_DETAIL_TYPES_HPP_INCLUDED
|
||||||
|
|
||||||
|
#include <type_traits>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
#include <continuable/detail/features.hpp>
|
#include <continuable/detail/features.hpp>
|
||||||
|
#include <continuable/detail/utility/identity.hpp>
|
||||||
|
|
||||||
#ifndef CONTINUABLE_WITH_CUSTOM_ERROR_TYPE
|
#ifndef CONTINUABLE_WITH_CUSTOM_ERROR_TYPE
|
||||||
#ifndef CONTINUABLE_WITH_NO_EXCEPTIONS
|
#ifndef CONTINUABLE_WITH_NO_EXCEPTIONS
|
||||||
@ -51,32 +52,37 @@ namespace detail {
|
|||||||
/// Contains types used globally across the library
|
/// Contains types used globally across the library
|
||||||
namespace types {
|
namespace types {
|
||||||
#ifdef CONTINUABLE_WITH_CUSTOM_ERROR_TYPE
|
#ifdef CONTINUABLE_WITH_CUSTOM_ERROR_TYPE
|
||||||
using error_type = CONTINUABLE_WITH_CUSTOM_ERROR_TYPE;
|
using exception_t = CONTINUABLE_WITH_CUSTOM_ERROR_TYPE;
|
||||||
#else // CONTINUABLE_WITH_CUSTOM_ERROR_TYPE
|
#else // CONTINUABLE_WITH_CUSTOM_ERROR_TYPE
|
||||||
#ifndef CONTINUABLE_WITH_NO_EXCEPTIONS
|
#ifndef CONTINUABLE_WITH_NO_EXCEPTIONS
|
||||||
/// Represents the error type when exceptions are enabled
|
/// Represents the exception type when exceptions are enabled
|
||||||
using error_type = std::exception_ptr;
|
using exception_t = std::exception_ptr;
|
||||||
#else // CONTINUABLE_WITH_NO_EXCEPTIONS
|
#else // CONTINUABLE_WITH_NO_EXCEPTIONS
|
||||||
/// Represents the error type when exceptions are disabled
|
/// Represents the error type when exceptions are disabled
|
||||||
using error_type = std::error_condition;
|
using exception_t = std::error_condition;
|
||||||
#endif // CONTINUABLE_WITH_NO_EXCEPTIONS
|
#endif // CONTINUABLE_WITH_NO_EXCEPTIONS
|
||||||
#endif // CONTINUABLE_WITH_CUSTOM_ERROR_TYPE
|
#endif // CONTINUABLE_WITH_CUSTOM_ERROR_TYPE
|
||||||
|
|
||||||
/// A tag which is used to execute the continuation inside the current thread
|
/// A tag which is used to execute the continuation inside the current thread
|
||||||
struct this_thread_executor_tag {};
|
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
|
/// Marks a given callable object as transformation
|
||||||
template <typename T>
|
template <typename T>
|
||||||
class transform : T {
|
class plain_tag {
|
||||||
|
T value_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit transform(T callable) : T(std::move(callable)) {
|
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)) {
|
||||||
}
|
}
|
||||||
|
|
||||||
using T::operator();
|
T&& consume() && {
|
||||||
|
return std::move(value_);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace types
|
} // namespace types
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
} // namespace cti
|
} // namespace cti
|
||||||
@ -1,164 +0,0 @@
|
|||||||
|
|
||||||
/*
|
|
||||||
|
|
||||||
/~` _ _ _|_. _ _ |_ | _
|
|
||||||
\_,(_)| | | || ||_|(_||_)|(/_
|
|
||||||
|
|
||||||
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
Normal file
242
include/continuable/detail/external/asio.hpp
vendored
Normal file
@ -0,0 +1,242 @@
|
|||||||
|
/*
|
||||||
|
|
||||||
|
/~` _ _ _|_. _ _ |_ | _
|
||||||
|
\_,(_)| | | || ||_|(_||_)|(/_
|
||||||
|
|
||||||
|
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
|
https://github.com/Naios/continuable
|
||||||
v3.0.0
|
v4.2.0
|
||||||
|
|
||||||
Copyright(c) 2015 - 2018 Denis Blank <denis.blank at outlook dot com>
|
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
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files(the "Software"), to deal
|
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
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
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
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
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
|
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
|
// Defines CONTINUABLE_WITH_NO_EXCEPTIONS when exception support is disabled
|
||||||
#ifndef CONTINUABLE_WITH_NO_EXCEPTIONS
|
#ifndef CONTINUABLE_WITH_NO_EXCEPTIONS
|
||||||
#if defined(_MSC_VER)
|
# if defined(_MSC_VER)
|
||||||
#if !defined(_HAS_EXCEPTIONS) || (_HAS_EXCEPTIONS == 0)
|
# if !defined(_HAS_EXCEPTIONS) || (_HAS_EXCEPTIONS == 0)
|
||||||
#define CONTINUABLE_WITH_NO_EXCEPTIONS
|
# define CONTINUABLE_WITH_NO_EXCEPTIONS
|
||||||
#endif
|
# endif
|
||||||
#elif defined(__clang__)
|
# elif defined(__clang__)
|
||||||
#if !(__EXCEPTIONS && __has_feature(cxx_exceptions))
|
# if !(__EXCEPTIONS && __has_feature(cxx_exceptions))
|
||||||
#define CONTINUABLE_WITH_NO_EXCEPTIONS
|
# define CONTINUABLE_WITH_NO_EXCEPTIONS
|
||||||
#endif
|
# endif
|
||||||
#elif defined(__GNUC__)
|
# elif defined(__GNUC__)
|
||||||
#if !__EXCEPTIONS
|
# if !__EXCEPTIONS
|
||||||
#define CONTINUABLE_WITH_NO_EXCEPTIONS
|
# define CONTINUABLE_WITH_NO_EXCEPTIONS
|
||||||
#endif
|
# endif
|
||||||
#endif
|
# endif
|
||||||
#endif // CONTINUABLE_WITH_NO_EXCEPTIONS
|
#endif // CONTINUABLE_WITH_NO_EXCEPTIONS
|
||||||
|
|
||||||
// clang-format off
|
// clang-format off
|
||||||
@ -55,8 +55,11 @@
|
|||||||
#define CONTINUABLE_HAS_CXX17_CONSTEXPR_IF
|
#define CONTINUABLE_HAS_CXX17_CONSTEXPR_IF
|
||||||
#define CONTINUABLE_HAS_CXX17_DISJUNCTION
|
#define CONTINUABLE_HAS_CXX17_DISJUNCTION
|
||||||
#define CONTINUABLE_HAS_CXX17_CONJUNCTION
|
#define CONTINUABLE_HAS_CXX17_CONJUNCTION
|
||||||
|
#define CONTINUABLE_HAS_CXX17_VOID_T
|
||||||
#else
|
#else
|
||||||
// Generic feature detection based on __has_feature
|
// 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(__has_feature)
|
||||||
#if !defined(CONTINUABLE_HAS_CXX17_CONSTEXPR_IF) && \
|
#if !defined(CONTINUABLE_HAS_CXX17_CONSTEXPR_IF) && \
|
||||||
__has_feature(cxx_if_constexpr)
|
__has_feature(cxx_if_constexpr)
|
||||||
@ -75,19 +78,49 @@
|
|||||||
(__cpp_lib_experimental_logical_traits >= 201511)
|
(__cpp_lib_experimental_logical_traits >= 201511)
|
||||||
#define CONTINUABLE_HAS_CXX17_CONJUNCTION
|
#define CONTINUABLE_HAS_CXX17_CONJUNCTION
|
||||||
#endif
|
#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
|
#endif
|
||||||
|
|
||||||
/// Usually this is enabled by the CMake project
|
// Automatically detects support for coroutines.
|
||||||
#if !defined(CONTINUABLE_HAS_EXPERIMENTAL_COROUTINE) && \
|
// Parts of this detection mechanism were adapted from boost::asio,
|
||||||
defined(__cpp_coroutines) && (__cpp_coroutines >= 201707)
|
// with support added for experimental coroutines.
|
||||||
#define CONTINUABLE_HAS_EXPERIMENTAL_COROUTINE
|
#if !defined(CONTINUABLE_HAS_DISABLED_COROUTINE) \
|
||||||
#endif
|
&& !defined(CONTINUABLE_HAS_COROUTINE)
|
||||||
|
/// Define CONTINUABLE_HAS_EXPERIMENTAL_COROUTINE when
|
||||||
/// Define CONTINUABLE_HAS_EXPERIMENTAL_COROUTINE when
|
/// CONTINUABLE_WITH_EXPERIMENTAL_COROUTINE is defined.
|
||||||
/// CONTINUABLE_WITH_EXPERIMENTAL_COROUTINE is defined.
|
#if defined(CONTINUABLE_WITH_EXPERIMENTAL_COROUTINE)
|
||||||
#if !defined(CONTINUABLE_HAS_EXPERIMENTAL_COROUTINE) && \
|
#define CONTINUABLE_HAS_COROUTINE 1
|
||||||
defined(CONTINUABLE_WITH_EXPERIMENTAL_COROUTINE)
|
#elif defined(CONTINUABLE_WITH_COROUTINE)
|
||||||
#define CONTINUABLE_HAS_EXPERIMENTAL_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
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/// Define CONTINUABLE_HAS_EXCEPTIONS when exceptions are used
|
/// Define CONTINUABLE_HAS_EXCEPTIONS when exceptions are used
|
||||||
@ -97,6 +130,18 @@
|
|||||||
#else
|
#else
|
||||||
#undef CONTINUABLE_HAS_EXCEPTIONS
|
#undef CONTINUABLE_HAS_EXCEPTIONS
|
||||||
#endif
|
#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
|
// clang-format on
|
||||||
|
|
||||||
#endif // CONTINUABLE_DETAIL_FEATURES_HPP_INCLUDED
|
#endif // CONTINUABLE_DETAIL_FEATURES_HPP_INCLUDED
|
||||||
|
|||||||
@ -1,357 +0,0 @@
|
|||||||
|
|
||||||
/*
|
|
||||||
|
|
||||||
/~` _ _ _|_. _ _ |_ | _
|
|
||||||
\_,(_)| | | || ||_|(_||_)|(/_
|
|
||||||
|
|
||||||
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
|
|
||||||
80
include/continuable/detail/operations/async.hpp
Normal file
80
include/continuable/detail/operations/async.hpp
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
/~` _ _ _|_. _ _ |_ | _
|
||||||
|
\_,(_)| | | || ||_|(_||_)|(/_
|
||||||
|
|
||||||
|
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
|
||||||
180
include/continuable/detail/operations/loop.hpp
Normal file
180
include/continuable/detail/operations/loop.hpp
Normal file
@ -0,0 +1,180 @@
|
|||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
/~` _ _ _|_. _ _ |_ | _
|
||||||
|
\_,(_)| | | || ||_|(_||_)|(/_
|
||||||
|
|
||||||
|
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
|
||||||
118
include/continuable/detail/operations/split.hpp
Normal file
118
include/continuable/detail/operations/split.hpp
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
/~` _ _ _|_. _ _ |_ | _
|
||||||
|
\_,(_)| | | || ||_|(_||_)|(/_
|
||||||
|
|
||||||
|
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
|
||||||
273
include/continuable/detail/other/coroutines.hpp
Normal file
273
include/continuable/detail/other/coroutines.hpp
Normal file
@ -0,0 +1,273 @@
|
|||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
/~` _ _ _|_. _ _ |_ | _
|
||||||
|
\_,(_)| | | || ||_|(_||_)|(/_
|
||||||
|
|
||||||
|
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
|
||||||
241
include/continuable/detail/other/erasure.hpp
Normal file
241
include/continuable/detail/other/erasure.hpp
Normal file
@ -0,0 +1,241 @@
|
|||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
/~` _ _ _|_. _ _ |_ | _
|
||||||
|
\_,(_)| | | || ||_|(_||_)|(/_
|
||||||
|
|
||||||
|
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
|
||||||
97
include/continuable/detail/other/promisify.hpp
Normal file
97
include/continuable/detail/other/promisify.hpp
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
/~` _ _ _|_. _ _ |_ | _
|
||||||
|
\_,(_)| | | || ||_|(_||_)|(/_
|
||||||
|
|
||||||
|
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
|
||||||
@ -5,9 +5,9 @@
|
|||||||
\_,(_)| | | || ||_|(_||_)|(/_
|
\_,(_)| | | || ||_|(_||_)|(/_
|
||||||
|
|
||||||
https://github.com/Naios/continuable
|
https://github.com/Naios/continuable
|
||||||
v3.0.0
|
v4.2.0
|
||||||
|
|
||||||
Copyright(c) 2015 - 2018 Denis Blank <denis.blank at outlook dot com>
|
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
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files(the "Software"), to deal
|
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
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
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
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
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
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
@ -33,13 +33,12 @@
|
|||||||
|
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
#include <gtest/gtest.h>
|
#include <gtest/gtest.h>
|
||||||
|
#include <continuable/continuable-primitives.hpp>
|
||||||
|
#include <continuable/detail/core/types.hpp>
|
||||||
#include <continuable/detail/features.hpp>
|
#include <continuable/detail/features.hpp>
|
||||||
#include <continuable/detail/traits.hpp>
|
#include <continuable/detail/utility/traits.hpp>
|
||||||
#include <continuable/detail/types.hpp>
|
#include <continuable/detail/utility/util.hpp>
|
||||||
#include <continuable/detail/util.hpp>
|
|
||||||
|
|
||||||
namespace cti {
|
namespace cti {
|
||||||
namespace detail {
|
namespace detail {
|
||||||
@ -55,7 +54,7 @@ void assert_async_completion(C&& continuable) {
|
|||||||
// Workaround for our known GCC bug.
|
// Workaround for our known GCC bug.
|
||||||
util::unused(std::forward<decltype(args)>(args)...);
|
util::unused(std::forward<decltype(args)>(args)...);
|
||||||
})
|
})
|
||||||
.fail([](cti::error_type /*error*/) {
|
.fail([](cti::exception_t /*error*/) {
|
||||||
// ...
|
// ...
|
||||||
FAIL();
|
FAIL();
|
||||||
});
|
});
|
||||||
@ -74,7 +73,28 @@ void assert_async_exception_completion(C&& continuable) {
|
|||||||
// ...
|
// ...
|
||||||
FAIL();
|
FAIL();
|
||||||
})
|
})
|
||||||
.fail([called](cti::error_type /*error*/) {
|
.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));
|
||||||
ASSERT_FALSE(*called);
|
ASSERT_FALSE(*called);
|
||||||
*called = true;
|
*called = true;
|
||||||
});
|
});
|
||||||
@ -91,7 +111,7 @@ void assert_async_never_completed(C&& continuable) {
|
|||||||
|
|
||||||
FAIL();
|
FAIL();
|
||||||
})
|
})
|
||||||
.fail([](cti::error_type /*error*/) {
|
.fail([](cti::exception_t) {
|
||||||
// ...
|
// ...
|
||||||
FAIL();
|
FAIL();
|
||||||
});
|
});
|
||||||
@ -101,9 +121,8 @@ template <typename C, typename V>
|
|||||||
void assert_async_validation(C&& continuable, V&& validator) {
|
void assert_async_validation(C&& continuable, V&& validator) {
|
||||||
assert_async_completion(
|
assert_async_completion(
|
||||||
std::forward<C>(continuable)
|
std::forward<C>(continuable)
|
||||||
.then([validator =
|
.then(
|
||||||
std::forward<V>(validator)](auto&&... args) mutable {
|
[validator = std::forward<V>(validator)](auto&&... args) mutable {
|
||||||
|
|
||||||
validator(std::forward<decltype(args)>(args)...);
|
validator(std::forward<decltype(args)>(args)...);
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
@ -115,11 +134,10 @@ void assert_async_binary_validation(V&& validator, C&& continuable,
|
|||||||
|
|
||||||
using size = std::integral_constant<std::size_t, sizeof...(expected)>;
|
using size = std::integral_constant<std::size_t, sizeof...(expected)>;
|
||||||
|
|
||||||
assert_async_validation(std::forward<C>(continuable), [
|
assert_async_validation(
|
||||||
expected_pack = std::make_tuple(std::forward<Args>(expected)...),
|
std::forward<C>(continuable),
|
||||||
validator = std::forward<V>(validator)
|
[expected_pack = std::make_tuple(std::forward<Args>(expected)...),
|
||||||
](auto&&... args) mutable {
|
validator = std::forward<V>(validator)](auto&&... args) mutable {
|
||||||
|
|
||||||
static_assert(size::value == sizeof...(args),
|
static_assert(size::value == sizeof...(args),
|
||||||
"Async completion handler called with a different count "
|
"Async completion handler called with a different count "
|
||||||
"of arguments!");
|
"of arguments!");
|
||||||
@ -139,20 +157,19 @@ void assert_async_binary_exception_validation(V&& validator, C&& continuable,
|
|||||||
// Workaround for our known GCC bug.
|
// Workaround for our known GCC bug.
|
||||||
util::unused(std::forward<decltype(args)>(args)...);
|
util::unused(std::forward<decltype(args)>(args)...);
|
||||||
|
|
||||||
// ...
|
// The exception was not thrown!
|
||||||
FAIL();
|
FAIL();
|
||||||
})
|
})
|
||||||
.fail([
|
.fail([called, validator = std::forward<decltype(validator)>(validator),
|
||||||
called, validator = std::forward<decltype(validator)>(validator),
|
expected = std::forward<decltype(expected)>(expected)](
|
||||||
expected = std::forward<decltype(expected)>(expected)
|
exception_t error) {
|
||||||
](types::error_type error) {
|
|
||||||
ASSERT_FALSE(*called);
|
ASSERT_FALSE(*called);
|
||||||
*called = true;
|
*called = true;
|
||||||
|
|
||||||
#if defined(CONTINUABLE_HAS_EXCEPTIONS)
|
#if defined(CONTINUABLE_HAS_EXCEPTIONS)
|
||||||
try {
|
try {
|
||||||
std::rethrow_exception(error);
|
std::rethrow_exception(error);
|
||||||
} catch (std::decay_t<decltype(expected)>& exception) {
|
} catch (std::decay_t<decltype(expected)> const& exception) {
|
||||||
validator(exception, expected);
|
validator(exception, expected);
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
FAIL();
|
FAIL();
|
||||||
@ -183,15 +200,14 @@ template <typename... Expected>
|
|||||||
struct assert_async_types_validator {
|
struct assert_async_types_validator {
|
||||||
template <typename... Actual>
|
template <typename... Actual>
|
||||||
void operator()(Actual...) {
|
void operator()(Actual...) {
|
||||||
static_assert(std::is_same<traits::identity<Actual...>,
|
static_assert(
|
||||||
traits::identity<Expected...>>::value,
|
std::is_same<identity<Actual...>, identity<Expected...>>::value,
|
||||||
"The called arguments don't match with the expected ones!");
|
"The called arguments don't match with the expected ones!");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename C, typename... Args>
|
template <typename C, typename... Args>
|
||||||
void assert_async_types(C&& continuable,
|
void assert_async_types(C&& continuable, identity<Args...> /*expected*/) {
|
||||||
traits::identity<Args...> /*expected*/) {
|
|
||||||
assert_async_validation(std::forward<C>(continuable),
|
assert_async_validation(std::forward<C>(continuable),
|
||||||
assert_async_types_validator<Args...>{});
|
assert_async_types_validator<Args...>{});
|
||||||
}
|
}
|
||||||
@ -1,95 +0,0 @@
|
|||||||
|
|
||||||
/*
|
|
||||||
|
|
||||||
/~` _ _ _|_. _ _ |_ | _
|
|
||||||
\_,(_)| | | || ||_|(_||_)|(/_
|
|
||||||
|
|
||||||
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
|
|
||||||
@ -1,358 +0,0 @@
|
|||||||
|
|
||||||
/*
|
|
||||||
|
|
||||||
/~` _ _ _|_. _ _ |_ | _
|
|
||||||
\_,(_)| | | || ||_|(_||_)|(/_
|
|
||||||
|
|
||||||
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
|
https://github.com/Naios/continuable
|
||||||
v3.0.0
|
v4.2.0
|
||||||
|
|
||||||
Copyright(c) 2015 - 2018 Denis Blank <denis.blank at outlook dot com>
|
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
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files(the "Software"), to deal
|
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
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
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
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
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
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
SOFTWARE.
|
SOFTWARE.
|
||||||
**/
|
**/
|
||||||
|
|
||||||
#ifndef CONTINUABLE_DETAIL_TRANSFORMS_HPP_INCLUDED
|
#ifndef CONTINUABLE_DETAIL_TRANSFORMS_FUTURE_HPP_INCLUDED
|
||||||
#define CONTINUABLE_DETAIL_TRANSFORMS_HPP_INCLUDED
|
#define CONTINUABLE_DETAIL_TRANSFORMS_FUTURE_HPP_INCLUDED
|
||||||
|
|
||||||
#include <future>
|
#include <future>
|
||||||
|
#include <continuable/continuable-primitives.hpp>
|
||||||
#include <continuable/detail/base.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/features.hpp>
|
||||||
#include <continuable/detail/hints.hpp>
|
#include <continuable/detail/utility/util.hpp>
|
||||||
#include <continuable/detail/types.hpp>
|
|
||||||
#include <continuable/detail/util.hpp>
|
|
||||||
|
|
||||||
namespace cti {
|
namespace cti {
|
||||||
namespace detail {
|
namespace detail {
|
||||||
@ -77,8 +77,7 @@ template <typename Hint>
|
|||||||
class promise_callback;
|
class promise_callback;
|
||||||
|
|
||||||
template <typename... Args>
|
template <typename... Args>
|
||||||
class promise_callback<hints::signature_hint_tag<Args...>>
|
class promise_callback<identity<Args...>> : public future_trait<Args...> {
|
||||||
: public future_trait<Args...> {
|
|
||||||
|
|
||||||
typename future_trait<Args...>::promise_t promise_;
|
typename future_trait<Args...>::promise_t promise_;
|
||||||
|
|
||||||
@ -95,7 +94,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Resolves the promise through the exception
|
/// Resolves the promise through the exception
|
||||||
void operator()(types::dispatch_error_tag, types::error_type error) {
|
void operator()(exception_arg_t, exception_t error) {
|
||||||
#if defined(CONTINUABLE_HAS_EXCEPTIONS)
|
#if defined(CONTINUABLE_HAS_EXCEPTIONS)
|
||||||
promise_.set_exception(error);
|
promise_.set_exception(error);
|
||||||
#else
|
#else
|
||||||
@ -104,7 +103,7 @@ public:
|
|||||||
// Can't forward a std::error_condition or custom error type
|
// Can't forward a std::error_condition or custom error type
|
||||||
// to a std::promise. Handle the error first in order
|
// to a std::promise. Handle the error first in order
|
||||||
// to prevent this trap!
|
// to prevent this trap!
|
||||||
util::trap();
|
CTI_DETAIL_TRAP();
|
||||||
#endif // CONTINUABLE_HAS_EXCEPTIONS
|
#endif // CONTINUABLE_HAS_EXCEPTIONS
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -116,10 +115,10 @@ public:
|
|||||||
|
|
||||||
/// Transforms the continuation to a future
|
/// Transforms the continuation to a future
|
||||||
template <typename Data, typename Annotation>
|
template <typename Data, typename Annotation>
|
||||||
auto as_future(continuable_base<Data, Annotation>&& continuable) {
|
auto to_future(continuable_base<Data, Annotation>&& continuable) {
|
||||||
// Create the promise which is able to supply the current arguments
|
// Create the promise which is able to supply the current arguments
|
||||||
constexpr auto const hint =
|
constexpr auto const hint =
|
||||||
hints::hint_of(traits::identify<decltype(continuable)>{});
|
base::annotation_of(identify<decltype(continuable)>{});
|
||||||
|
|
||||||
promise_callback<std::decay_t<decltype(hint)>> callback;
|
promise_callback<std::decay_t<decltype(hint)>> callback;
|
||||||
(void)hint;
|
(void)hint;
|
||||||
@ -136,4 +135,4 @@ auto as_future(continuable_base<Data, Annotation>&& continuable) {
|
|||||||
} // namespace detail
|
} // namespace detail
|
||||||
} // namespace cti
|
} // namespace cti
|
||||||
|
|
||||||
#endif // CONTINUABLE_DETAIL_TRANSFORMS_HPP_INCLUDED
|
#endif // CONTINUABLE_DETAIL_TRANSFORMS_FUTURE_HPP_INCLUDED
|
||||||
264
include/continuable/detail/transforms/wait.hpp
Normal file
264
include/continuable/detail/transforms/wait.hpp
Normal file
@ -0,0 +1,264 @@
|
|||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
/~` _ _ _|_. _ _ |_ | _
|
||||||
|
\_,(_)| | | || ||_|(_||_)|(/_
|
||||||
|
|
||||||
|
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
|
https://github.com/Naios/continuable
|
||||||
v3.0.0
|
v4.2.0
|
||||||
|
|
||||||
Copyright(c) 2015 - 2018 Denis Blank <denis.blank at outlook dot com>
|
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
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files(the "Software"), to deal
|
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
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
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
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
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
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
@ -33,8 +33,7 @@
|
|||||||
|
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
#include <continuable/detail/utility/traits.hpp>
|
||||||
#include <continuable/detail/traits.hpp>
|
|
||||||
|
|
||||||
namespace cti {
|
namespace cti {
|
||||||
namespace detail {
|
namespace detail {
|
||||||
@ -5,9 +5,9 @@
|
|||||||
\_,(_)| | | || ||_|(_||_)|(/_
|
\_,(_)| | | || ||_|(_||_)|(/_
|
||||||
|
|
||||||
https://github.com/Naios/continuable
|
https://github.com/Naios/continuable
|
||||||
v3.0.0
|
v4.2.0
|
||||||
|
|
||||||
Copyright(c) 2015 - 2018 Denis Blank <denis.blank at outlook dot com>
|
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
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files(the "Software"), to deal
|
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
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
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
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
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
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
@ -35,8 +35,7 @@
|
|||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <continuable/detail/utility/traits.hpp>
|
||||||
#include <continuable/detail/traits.hpp>
|
|
||||||
|
|
||||||
namespace cti {
|
namespace cti {
|
||||||
namespace detail {
|
namespace detail {
|
||||||
@ -5,9 +5,9 @@
|
|||||||
\_,(_)| | | || ||_|(_||_)|(/_
|
\_,(_)| | | || ||_|(_||_)|(/_
|
||||||
|
|
||||||
https://github.com/Naios/continuable
|
https://github.com/Naios/continuable
|
||||||
v3.0.0
|
v4.2.0
|
||||||
|
|
||||||
Copyright(c) 2015 - 2018 Denis Blank <denis.blank at outlook dot com>
|
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
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files(the "Software"), to deal
|
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
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
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
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
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
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
@ -39,9 +39,8 @@
|
|||||||
#include <tuple>
|
#include <tuple>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
#include <continuable/detail/traversal/container-category.hpp>
|
||||||
#include <continuable/detail/container-category.hpp>
|
#include <continuable/detail/utility/traits.hpp>
|
||||||
#include <continuable/detail/traits.hpp>
|
|
||||||
|
|
||||||
namespace cti {
|
namespace cti {
|
||||||
namespace detail {
|
namespace detail {
|
||||||
@ -98,10 +97,8 @@ public:
|
|||||||
/// given iterator tuple.
|
/// given iterator tuple.
|
||||||
template <typename Frame, typename State>
|
template <typename Frame, typename State>
|
||||||
auto make_resume_traversal_callable(Frame&& frame, State&& state)
|
auto make_resume_traversal_callable(Frame&& frame, State&& state)
|
||||||
-> resume_traversal_callable<typename std::decay<Frame>::type,
|
-> resume_traversal_callable<std::decay_t<Frame>, std::decay_t<State>> {
|
||||||
typename std::decay<State>::type> {
|
return resume_traversal_callable<std::decay_t<Frame>, std::decay_t<State>>(
|
||||||
return resume_traversal_callable<typename std::decay<Frame>::type,
|
|
||||||
typename std::decay<State>::type>(
|
|
||||||
std::forward<Frame>(frame), std::forward<State>(state));
|
std::forward<Frame>(frame), std::forward<State>(state));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -231,7 +228,8 @@ struct static_async_range {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <std::size_t Position>
|
template <std::size_t Position>
|
||||||
constexpr auto relocate() const noexcept {
|
constexpr auto relocate(std::integral_constant<std::size_t, Position>) const
|
||||||
|
noexcept {
|
||||||
return static_async_range<Target, Position, End>{target_};
|
return static_async_range<Target, Position, End>{target_};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -291,9 +289,9 @@ struct dynamic_async_range {
|
|||||||
};
|
};
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
using dynamic_async_range_of_t = dynamic_async_range<
|
using dynamic_async_range_of_t =
|
||||||
typename std::decay<decltype(std::begin(std::declval<T>()))>::type,
|
dynamic_async_range<std::decay_t<decltype(std::begin(std::declval<T>()))>,
|
||||||
typename std::decay<decltype(std::end(std::declval<T>()))>::type>;
|
std::decay_t<decltype(std::end(std::declval<T>()))>>;
|
||||||
|
|
||||||
/// Returns a dynamic range for the given type
|
/// Returns a dynamic range for the given type
|
||||||
template <typename T>
|
template <typename T>
|
||||||
@ -337,9 +335,8 @@ public:
|
|||||||
auto hierarchy = std::tuple_cat(
|
auto hierarchy = std::tuple_cat(
|
||||||
std::make_tuple(std::forward<Parent>(parent)), hierarchy_);
|
std::make_tuple(std::forward<Parent>(parent)), hierarchy_);
|
||||||
|
|
||||||
return async_traversal_point<Frame, typename std::decay<Parent>::type,
|
return async_traversal_point<Frame, std::decay_t<Parent>, Hierarchy...>(
|
||||||
Hierarchy...>(frame_, std::move(hierarchy),
|
frame_, std::move(hierarchy), detached_);
|
||||||
detached_);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Forks the current traversal point and continues the child
|
/// Forks the current traversal point and continues the child
|
||||||
@ -405,7 +402,7 @@ public:
|
|||||||
/// Async traverse the current iterator
|
/// Async traverse the current iterator
|
||||||
template <typename Current>
|
template <typename Current>
|
||||||
void async_traverse_one(Current&& current) {
|
void async_traverse_one(Current&& current) {
|
||||||
using ElementType = typename std::decay<decltype(*current)>::type;
|
using ElementType = std::decay_t<decltype(*current)>;
|
||||||
return async_traverse_one_impl(container_category_of_t<ElementType>{},
|
return async_traverse_one_impl(container_category_of_t<ElementType>{},
|
||||||
std::forward<Current>(current));
|
std::forward<Current>(current));
|
||||||
}
|
}
|
||||||
@ -422,8 +419,8 @@ public:
|
|||||||
template <std::size_t... Sequence, typename Current>
|
template <std::size_t... Sequence, typename Current>
|
||||||
void async_traverse_static_async_range(
|
void async_traverse_static_async_range(
|
||||||
std::integer_sequence<std::size_t, Sequence...>, Current&& current) {
|
std::integer_sequence<std::size_t, Sequence...>, Current&& current) {
|
||||||
int dummy[] = {0, ((void)async_traverse_one_checked(
|
int dummy[] = {0, (async_traverse_one_checked(current.relocate(
|
||||||
current.template relocate<Sequence>()),
|
std::integral_constant<std::size_t, Sequence>{})),
|
||||||
0)...};
|
0)...};
|
||||||
(void)dummy;
|
(void)dummy;
|
||||||
(void)current;
|
(void)current;
|
||||||
@ -453,8 +450,7 @@ public:
|
|||||||
/// given frame and hierarchy
|
/// given frame and hierarchy
|
||||||
template <typename Frame, typename... Hierarchy>
|
template <typename Frame, typename... Hierarchy>
|
||||||
using traversal_point_of_t =
|
using traversal_point_of_t =
|
||||||
async_traversal_point<typename std::decay<Frame>::type,
|
async_traversal_point<std::decay_t<Frame>, std::decay_t<Hierarchy>...>;
|
||||||
typename std::decay<Hierarchy>::type...>;
|
|
||||||
|
|
||||||
/// A callable object which is capable of resuming an asynchronous
|
/// A callable object which is capable of resuming an asynchronous
|
||||||
/// pack traversal.
|
/// pack traversal.
|
||||||
@ -520,7 +516,7 @@ struct resume_state_callable {
|
|||||||
template <typename Frame, typename State>
|
template <typename Frame, typename State>
|
||||||
void resume_traversal_callable<Frame, State>::operator()() {
|
void resume_traversal_callable<Frame, State>::operator()() {
|
||||||
auto hierarchy = std::tuple_cat(std::make_tuple(frame_), state_);
|
auto hierarchy = std::tuple_cat(std::make_tuple(frame_), state_);
|
||||||
traits::unpack(std::move(hierarchy), resume_state_callable{});
|
traits::unpack(resume_state_callable{}, std::move(hierarchy));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gives access to types related to the traversal frame
|
/// Gives access to types related to the traversal frame
|
||||||
@ -528,8 +524,8 @@ template <typename Visitor, typename... Args>
|
|||||||
struct async_traversal_types {
|
struct async_traversal_types {
|
||||||
/// Deduces to the async traversal frame type of the given
|
/// Deduces to the async traversal frame type of the given
|
||||||
/// traversal arguments and mapper
|
/// traversal arguments and mapper
|
||||||
using frame_t = async_traversal_frame<typename std::decay<Visitor>::type,
|
using frame_t =
|
||||||
typename std::decay<Args>::type...>;
|
async_traversal_frame<std::decay_t<Visitor>, std::decay_t<Args>...>;
|
||||||
|
|
||||||
/// The type of the demoted visitor type
|
/// The type of the demoted visitor type
|
||||||
using visitor_t = Visitor;
|
using visitor_t = Visitor;
|
||||||
@ -5,9 +5,9 @@
|
|||||||
\_,(_)| | | || ||_|(_||_)|(/_
|
\_,(_)| | | || ||_|(_||_)|(/_
|
||||||
|
|
||||||
https://github.com/Naios/continuable
|
https://github.com/Naios/continuable
|
||||||
v3.0.0
|
v4.2.0
|
||||||
|
|
||||||
Copyright(c) 2015 - 2018 Denis Blank <denis.blank at outlook dot com>
|
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
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files(the "Software"), to deal
|
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
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
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
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
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
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
@ -37,9 +37,8 @@
|
|||||||
#include <tuple>
|
#include <tuple>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
#include <continuable/detail/traversal/container-category.hpp>
|
||||||
#include <continuable/detail/container-category.hpp>
|
#include <continuable/detail/utility/traits.hpp>
|
||||||
#include <continuable/detail/traits.hpp>
|
|
||||||
|
|
||||||
namespace cti {
|
namespace cti {
|
||||||
namespace detail {
|
namespace detail {
|
||||||
@ -170,8 +169,7 @@ struct flat_arraylizer {
|
|||||||
/// Deduces to the array type when the array is instantiated
|
/// Deduces to the array type when the array is instantiated
|
||||||
/// with the given arguments.
|
/// with the given arguments.
|
||||||
template <typename First, typename... Rest>
|
template <typename First, typename... Rest>
|
||||||
using array_type_of_t =
|
using array_type_of_t = Type<std::decay_t<First>, 1 + sizeof...(Rest)>;
|
||||||
Type<typename std::decay<First>::type, 1 + sizeof...(Rest)>;
|
|
||||||
|
|
||||||
// We overload with one argument here so Clang and GCC don't
|
// We overload with one argument here so Clang and GCC don't
|
||||||
// have any issues with overloading against zero arguments.
|
// have any issues with overloading against zero arguments.
|
||||||
@ -192,10 +190,10 @@ struct flat_arraylizer {
|
|||||||
template <typename C, typename... T>
|
template <typename C, typename... T>
|
||||||
constexpr auto apply_spread_impl(std::true_type, C&& callable, T&&... args)
|
constexpr auto apply_spread_impl(std::true_type, C&& callable, T&&... args)
|
||||||
-> decltype(
|
-> decltype(
|
||||||
traits::unpack(std::tuple_cat(undecorate(std::forward<T>(args))...),
|
traits::unpack(std::forward<C>(callable),
|
||||||
std::forward<C>(callable))) {
|
std::tuple_cat(undecorate(std::forward<T>(args))...))) {
|
||||||
return traits::unpack(std::tuple_cat(undecorate(std::forward<T>(args))...),
|
return traits::unpack(std::forward<C>(callable),
|
||||||
std::forward<C>(callable));
|
std::tuple_cat(undecorate(std::forward<T>(args))...));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Use the linear instantiation for variadic packs which don't
|
/// Use the linear instantiation for variadic packs which don't
|
||||||
@ -408,9 +406,8 @@ using element_of_t = typename std::conditional<
|
|||||||
/// Removes all qualifier and references from the given type
|
/// Removes all qualifier and references from the given type
|
||||||
/// if the type is a l-value or r-value reference.
|
/// if the type is a l-value or r-value reference.
|
||||||
template <typename T>
|
template <typename T>
|
||||||
using dereferenced_of_t =
|
using dereferenced_of_t = typename std::conditional<std::is_reference<T>::value,
|
||||||
typename std::conditional<std::is_reference<T>::value,
|
std::decay_t<T>, T>::type;
|
||||||
typename std::decay<T>::type, T>::type;
|
|
||||||
|
|
||||||
/// Returns the type which is resulting if the mapping is applied to
|
/// Returns the type which is resulting if the mapping is applied to
|
||||||
/// an element in the container.
|
/// an element in the container.
|
||||||
@ -424,8 +421,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.
|
/// Deduces to a true_type if the mapping maps to zero elements.
|
||||||
template <typename T, typename M>
|
template <typename T, typename M>
|
||||||
using is_empty_mapped = spreading::is_empty_spread<typename std::decay<decltype(
|
using is_empty_mapped = spreading::is_empty_spread<
|
||||||
std::declval<M>()(std::declval<element_of_t<T>>()))>::type>;
|
std::decay_t<decltype(std::declval<M>()(std::declval<element_of_t<T>>()))>>;
|
||||||
|
|
||||||
/// We are allowed to reuse the container if we map to the same
|
/// We are allowed to reuse the container if we map to the same
|
||||||
/// type we are accepting and when we have
|
/// type we are accepting and when we have
|
||||||
@ -473,8 +470,7 @@ template <typename M, typename T>
|
|||||||
auto remap_container(container_mapping_tag<false, false>, M&& mapper,
|
auto remap_container(container_mapping_tag<false, false>, M&& mapper,
|
||||||
T&& container)
|
T&& container)
|
||||||
-> decltype(rebind_container<mapped_type_from_t<T, M>>(container)) {
|
-> decltype(rebind_container<mapped_type_from_t<T, M>>(container)) {
|
||||||
static_assert(
|
static_assert(has_push_back<std::decay_t<T>, element_of_t<T>>::value,
|
||||||
has_push_back<typename std::decay<T>::type, element_of_t<T>>::value,
|
|
||||||
"Can only remap containers that provide a push_back "
|
"Can only remap containers that provide a push_back "
|
||||||
"method!");
|
"method!");
|
||||||
|
|
||||||
@ -504,7 +500,7 @@ auto remap_container(container_mapping_tag<false, false>, M&& mapper,
|
|||||||
/// type we accepted such as int -> int.
|
/// type we accepted such as int -> int.
|
||||||
template <typename M, typename T>
|
template <typename M, typename T>
|
||||||
auto remap_container(container_mapping_tag<false, true>, M&& mapper,
|
auto remap_container(container_mapping_tag<false, true>, M&& mapper,
|
||||||
T&& container) -> typename std::decay<T>::type {
|
T&& container) -> std::decay_t<T> {
|
||||||
for (auto&& val : container_accessor_of(std::forward<T>(container))) {
|
for (auto&& val : container_accessor_of(std::forward<T>(container))) {
|
||||||
val = spreading::unpack(
|
val = spreading::unpack(
|
||||||
std::forward<M>(mapper)(std::forward<decltype(val)>(val)));
|
std::forward<M>(mapper)(std::forward<decltype(val)>(val)));
|
||||||
@ -630,14 +626,13 @@ struct tuple_like_remapper<
|
|||||||
/// different types.
|
/// different types.
|
||||||
template <typename Strategy, typename T, typename M>
|
template <typename Strategy, typename T, typename M>
|
||||||
auto remap(Strategy, T&& container, M&& mapper) -> decltype(traits::unpack(
|
auto remap(Strategy, T&& container, M&& mapper) -> decltype(traits::unpack(
|
||||||
std::forward<T>(container),
|
std::declval<
|
||||||
std::declval<tuple_like_remapper<Strategy, typename std::decay<M>::type,
|
tuple_like_remapper<Strategy, std::decay_t<M>, std::decay_t<T>>>(),
|
||||||
typename std::decay<T>::type>>())) {
|
std::forward<T>(container))) {
|
||||||
return traits::unpack(
|
return traits::unpack(
|
||||||
std::forward<T>(container),
|
tuple_like_remapper<Strategy, std::decay_t<M>, std::decay_t<T>>{
|
||||||
tuple_like_remapper<Strategy, typename std::decay<M>::type,
|
std::forward<M>(mapper)},
|
||||||
typename std::decay<T>::type>{
|
std::forward<T>(container));
|
||||||
std::forward<M>(mapper)});
|
|
||||||
}
|
}
|
||||||
} // end namespace tuple_like_remapping
|
} // end namespace tuple_like_remapping
|
||||||
|
|
||||||
@ -646,7 +641,7 @@ auto remap(Strategy, T&& container, M&& mapper) -> decltype(traits::unpack(
|
|||||||
template <typename Strategy>
|
template <typename Strategy>
|
||||||
struct mapping_strategy_base {
|
struct mapping_strategy_base {
|
||||||
template <typename T>
|
template <typename T>
|
||||||
auto may_void(T&& element) const -> typename std::decay<T>::type {
|
auto may_void(T&& element) const -> std::decay_t<T> {
|
||||||
return std::forward<T>(element);
|
return std::forward<T>(element);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -804,19 +799,19 @@ class mapping_helper : protected mapping_strategy_base<Strategy> {
|
|||||||
template <typename T>
|
template <typename T>
|
||||||
auto traverse(Strategy, T&& element)
|
auto traverse(Strategy, T&& element)
|
||||||
-> decltype(std::declval<mapping_helper>().match(
|
-> decltype(std::declval<mapping_helper>().match(
|
||||||
std::declval<container_category_of_t<typename std::decay<T>::type>>(),
|
std::declval<container_category_of_t<std::decay_t<T>>>(),
|
||||||
std::declval<T>()));
|
std::declval<T>()));
|
||||||
|
|
||||||
/// \copybrief traverse
|
/// \copybrief traverse
|
||||||
template <typename T>
|
template <typename T>
|
||||||
auto try_traverse(Strategy, T&& element)
|
auto try_traverse(Strategy, T&& element)
|
||||||
-> decltype(std::declval<mapping_helper>().try_match(
|
-> decltype(std::declval<mapping_helper>().try_match(
|
||||||
std::declval<container_category_of_t<typename std::decay<T>::type>>(),
|
std::declval<container_category_of_t<std::decay_t<T>>>(),
|
||||||
std::declval<T>())) {
|
std::declval<T>())) {
|
||||||
// We use tag dispatching here, to categorize the type T whether
|
// We use tag dispatching here, to categorize the type T whether
|
||||||
// it satisfies the container or tuple like requirements.
|
// it satisfies the container or tuple like requirements.
|
||||||
// Then we can choose the underlying implementation accordingly.
|
// Then we can choose the underlying implementation accordingly.
|
||||||
return try_match(container_category_of_t<typename std::decay<T>::type>{},
|
return try_match(container_category_of_t<std::decay_t<T>>{},
|
||||||
std::forward<T>(element));
|
std::forward<T>(element));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -862,7 +857,7 @@ public:
|
|||||||
/// Traverses the given pack with the given mapper and strategy
|
/// Traverses the given pack with the given mapper and strategy
|
||||||
template <typename Strategy, typename Mapper, typename... T>
|
template <typename Strategy, typename Mapper, typename... T>
|
||||||
decltype(auto) transform(Strategy strategy, Mapper&& mapper, T&&... pack) {
|
decltype(auto) transform(Strategy strategy, Mapper&& mapper, T&&... pack) {
|
||||||
mapping_helper<Strategy, typename std::decay<Mapper>::type> helper(
|
mapping_helper<Strategy, std::decay_t<Mapper>> helper(
|
||||||
std::forward<Mapper>(mapper));
|
std::forward<Mapper>(mapper));
|
||||||
return helper.init_traverse(strategy, std::forward<T>(pack)...);
|
return helper.init_traverse(strategy, std::forward<T>(pack)...);
|
||||||
}
|
}
|
||||||
54
include/continuable/detail/utility/identity.hpp
Normal file
54
include/continuable/detail/utility/identity.hpp
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
/~` _ _ _|_. _ _ |_ | _
|
||||||
|
\_,(_)| | | || ||_|(_||_)|(/_
|
||||||
|
|
||||||
|
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
|
||||||
101
include/continuable/detail/utility/result-trait.hpp
Normal file
101
include/continuable/detail/utility/result-trait.hpp
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
/~` _ _ _|_. _ _ |_ | _
|
||||||
|
\_,(_)| | | || ||_|(_||_)|(/_
|
||||||
|
|
||||||
|
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
|
||||||
217
include/continuable/detail/utility/result-variant.hpp
Normal file
217
include/continuable/detail/utility/result-variant.hpp
Normal file
@ -0,0 +1,217 @@
|
|||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
/~` _ _ _|_. _ _ |_ | _
|
||||||
|
\_,(_)| | | || ||_|(_||_)|(/_
|
||||||
|
|
||||||
|
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
|
||||||
192
include/continuable/detail/utility/traits.hpp
Normal file
192
include/continuable/detail/utility/traits.hpp
Normal file
@ -0,0 +1,192 @@
|
|||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
/~` _ _ _|_. _ _ |_ | _
|
||||||
|
\_,(_)| | | || ||_|(_||_)|(/_
|
||||||
|
|
||||||
|
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
|
||||||
@ -5,9 +5,9 @@
|
|||||||
\_,(_)| | | || ||_|(_||_)|(/_
|
\_,(_)| | | || ||_|(_||_)|(/_
|
||||||
|
|
||||||
https://github.com/Naios/continuable
|
https://github.com/Naios/continuable
|
||||||
v3.0.0
|
v4.2.0
|
||||||
|
|
||||||
Copyright(c) 2015 - 2018 Denis Blank <denis.blank at outlook dot com>
|
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
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files(the "Software"), to deal
|
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
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
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
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
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
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
@ -32,50 +32,118 @@
|
|||||||
#define CONTINUABLE_DETAIL_UTIL_HPP_INCLUDED
|
#define CONTINUABLE_DETAIL_UTIL_HPP_INCLUDED
|
||||||
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
#include <cstdlib>
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
#include <continuable/detail/features.hpp>
|
#include <continuable/detail/features.hpp>
|
||||||
#include <continuable/detail/traits.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
|
||||||
|
|
||||||
namespace cti {
|
namespace cti {
|
||||||
namespace detail {
|
namespace detail {
|
||||||
/// Utility namespace which provides useful meta-programming support
|
/// Utility namespace which provides useful meta-programming support
|
||||||
namespace util {
|
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
|
/// Helper to trick compilers about that a parameter pack is used
|
||||||
template <typename... T>
|
template <typename... T>
|
||||||
constexpr void unused(T&&...) noexcept {
|
constexpr void unused(T&&...) noexcept {
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace detail {
|
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
|
/// Forwards every element in the tuple except the last one
|
||||||
template <typename T>
|
template <typename T>
|
||||||
auto forward_except_last(T&& sequenceable) {
|
auto forward_except_last(T&& sequenceable) {
|
||||||
constexpr auto const size = pack_size_of(traits::identify<T>()) - 1U;
|
static_assert(
|
||||||
constexpr auto const sequence = std::make_index_sequence<size>();
|
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!");
|
||||||
|
|
||||||
return traits::unpack(std::forward<T>(sequenceable),
|
constexpr auto size = std::tuple_size<std::decay_t<T>>::value;
|
||||||
[](auto&&... args) {
|
constexpr auto sequence = make_decreased_index_sequence(
|
||||||
return std::forward_as_tuple(
|
std::integral_constant<std::size_t, size>{});
|
||||||
std::forward<decltype(args)>(args)...);
|
|
||||||
},
|
return forward_except_last_impl(std::forward<T>(sequenceable), sequence);
|
||||||
sequence);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// We are able to call the callable with the arguments given in the tuple
|
template <std::size_t Keep>
|
||||||
template <typename T, typename... Args>
|
struct invocation_env {
|
||||||
auto partial_invoke_impl(std::true_type, T&& callable,
|
/// 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) {
|
std::tuple<Args...> args) {
|
||||||
return traits::unpack(std::move(args), [&](auto&&... arg) {
|
return traits::unpack(std::forward<T>(callable), std::move(args));
|
||||||
return std::forward<T>(callable)(std::forward<decltype(arg)>(arg)...);
|
}
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/// We were unable to call the callable with the arguments in the tuple.
|
/// We were unable to call the callable with the arguments in the tuple.
|
||||||
/// Remove the last argument from the tuple and try it again.
|
/// Remove the last argument from the tuple and try it again.
|
||||||
template <typename T, typename... Args>
|
template <typename T, typename... Args>
|
||||||
auto partial_invoke_impl(std::false_type, T&& callable,
|
static auto partial_invoke_impl(std::false_type, T&& callable,
|
||||||
std::tuple<Args...> args) {
|
std::tuple<Args...> args) {
|
||||||
|
|
||||||
// If you are encountering this assertion you tried to attach a callback
|
// If you are encountering this assertion you tried to attach a callback
|
||||||
@ -86,54 +154,62 @@ auto partial_invoke_impl(std::false_type, T&& callable,
|
|||||||
// std::move(c).then([](std::vector<int> v) { /*...*/ })
|
// std::move(c).then([](std::vector<int> v) { /*...*/ })
|
||||||
// ```
|
// ```
|
||||||
static_assert(
|
static_assert(
|
||||||
sizeof...(Args) > 0,
|
sizeof...(Args) > Keep,
|
||||||
"There is no way to call the given object with these arguments!");
|
"There is no way to call the given object with these arguments!");
|
||||||
|
|
||||||
// Remove the last argument from the tuple
|
// Remove the last argument from the tuple
|
||||||
auto next = forward_except_last(std::move(args));
|
auto next = forward_except_last(std::move(args));
|
||||||
|
|
||||||
// Test whether we are able to call the function with the given tuple
|
// Test whether we are able to call the function with the given tuple
|
||||||
traits::is_invokable_from_tuple<decltype(callable), decltype(next)>
|
constexpr std::integral_constant<
|
||||||
is_invokable;
|
bool, traits::is_invocable_from_tuple<decltype(callable),
|
||||||
|
decltype(next)>::value ||
|
||||||
|
(sizeof...(Args) <= Keep)>
|
||||||
|
is_callable;
|
||||||
|
|
||||||
return partial_invoke_impl(is_invokable, std::forward<T>(callable),
|
return partial_invoke_impl(is_callable, std::forward<T>(callable),
|
||||||
std::move(next));
|
std::move(next));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Shortcut - we can call the callable directly
|
/// Shortcut - we can call the callable directly
|
||||||
template <typename T, typename... Args>
|
template <typename T, typename... Args>
|
||||||
auto partial_invoke_impl_shortcut(std::true_type, T&& callable,
|
static auto partial_invoke_impl_shortcut(std::true_type, T&& callable,
|
||||||
Args&&... args) {
|
Args&&... args) {
|
||||||
return std::forward<T>(callable)(std::forward<Args>(args)...);
|
return std::forward<T>(callable)(std::forward<Args>(args)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Failed shortcut - we were unable to invoke the callable with the
|
/// Failed shortcut - we were unable to invoke the callable with the
|
||||||
/// original arguments.
|
/// original arguments.
|
||||||
template <typename T, typename... Args>
|
template <typename T, typename... Args>
|
||||||
auto partial_invoke_impl_shortcut(std::false_type failed, T&& callable,
|
static auto partial_invoke_impl_shortcut(std::false_type failed, T&& callable,
|
||||||
Args&&... args) {
|
Args&&... args) {
|
||||||
|
|
||||||
// Our shortcut failed, convert the arguments into a forwarding tuple
|
// Our shortcut failed, convert the arguments into a forwarding tuple
|
||||||
return partial_invoke_impl(
|
return partial_invoke_impl(
|
||||||
failed, std::forward<T>(callable),
|
failed, std::forward<T>(callable),
|
||||||
std::forward_as_tuple(std::forward<Args>(args)...));
|
std::forward_as_tuple(std::forward<Args>(args)...));
|
||||||
}
|
}
|
||||||
|
};
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
|
|
||||||
/// Partially invokes the given callable with the given arguments.
|
/// Partially invokes the given callable with the given arguments.
|
||||||
///
|
///
|
||||||
/// \note This function will assert statically if there is no way to call the
|
/// \note This function will assert statically if there is no way to call the
|
||||||
/// given object with less arguments.
|
/// given object with less arguments.
|
||||||
template <typename T, typename... Args>
|
template <std::size_t KeepArgs, typename T, typename... Args>
|
||||||
/*keep this inline*/ inline auto partial_invoke(T&& callable, Args&&... args) {
|
/*keep this inline*/ inline auto
|
||||||
|
partial_invoke(std::integral_constant<std::size_t, KeepArgs>, T&& callable,
|
||||||
|
Args&&... args) {
|
||||||
// Test whether we are able to call the function with the given arguments.
|
// Test whether we are able to call the function with the given arguments.
|
||||||
traits::is_invokable_from_tuple<decltype(callable), std::tuple<Args...>>
|
constexpr traits::is_invocable_from_tuple<decltype(callable),
|
||||||
is_invokable;
|
std::tuple<Args...>>
|
||||||
|
is_invocable;
|
||||||
|
|
||||||
// The implementation is done in a shortcut way so there are less
|
// The implementation is done in a shortcut way so there are less
|
||||||
// type instantiations needed to call the callable with its full signature.
|
// type instantiations needed to call the callable with its full signature.
|
||||||
return detail::partial_invoke_impl_shortcut(
|
using env = detail::invocation_env<KeepArgs>;
|
||||||
is_invokable, std::forward<T>(callable), std::forward<Args>(args)...);
|
return env::partial_invoke_impl_shortcut(
|
||||||
|
is_invocable, std::forward<T>(callable), std::forward<Args>(args)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Invokes the given callable object with the given arguments
|
/// Invokes the given callable object with the given arguments
|
||||||
@ -161,6 +237,12 @@ constexpr auto invoke(Type T::*member, Self&& self, Args&&... args) noexcept(
|
|||||||
return (std::forward<Self>(self)->*member)(std::forward<Args>(args)...);
|
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
|
// Class for making child classes non copyable
|
||||||
struct non_copyable {
|
struct non_copyable {
|
||||||
constexpr non_copyable() = default;
|
constexpr non_copyable() = default;
|
||||||
@ -237,39 +319,8 @@ private:
|
|||||||
/// Is true when the automatic invocation on destruction is disabled
|
/// Is true when the automatic invocation on destruction is disabled
|
||||||
bool frozen_ : 1;
|
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 util
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
} // namespace cti
|
} // 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
|
#endif // CONTINUABLE_DETAIL_UTIL_HPP_INCLUDED
|
||||||
183
include/continuable/external/asio.hpp
vendored
Normal file
183
include/continuable/external/asio.hpp
vendored
Normal file
@ -0,0 +1,183 @@
|
|||||||
|
/*
|
||||||
|
|
||||||
|
/~` _ _ _|_. _ _ |_ | _
|
||||||
|
\_,(_)| | | || ||_|(_||_)|(/_
|
||||||
|
|
||||||
|
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
|
||||||
@ -5,9 +5,9 @@
|
|||||||
\_,(_)| | | || ||_|(_||_)|(/_
|
\_,(_)| | | || ||_|(_||_)|(/_
|
||||||
|
|
||||||
https://github.com/Naios/continuable
|
https://github.com/Naios/continuable
|
||||||
v3.0.0
|
v4.2.0
|
||||||
|
|
||||||
Copyright(c) 2015 - 2018 Denis Blank <denis.blank at outlook dot com>
|
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
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files(the "Software"), to deal
|
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
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
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
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
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
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
SOFTWARE.
|
SOFTWARE.
|
||||||
**/
|
**/
|
||||||
|
|
||||||
#ifndef CONTINUABLE_TESTING_HPP_INCLUDED
|
#ifndef CONTINUABLE_EXTERNAL_GTEST_HPP_INCLUDED
|
||||||
#define CONTINUABLE_TESTING_HPP_INCLUDED
|
#define CONTINUABLE_EXTERNAL_GTEST_HPP_INCLUDED
|
||||||
|
|
||||||
#include <continuable/detail/testing.hpp>
|
#include <continuable/detail/other/testing.hpp>
|
||||||
#include <continuable/detail/traits.hpp>
|
#include <continuable/detail/utility/traits.hpp>
|
||||||
|
|
||||||
/// \defgroup Testing Testing
|
/// \defgroup Testing Testing
|
||||||
/// provides macro shortcuts for testing asynchronous continuations through
|
/// provides macro shortcuts for testing asynchronous continuations through
|
||||||
@ -53,6 +53,14 @@
|
|||||||
#define ASSERT_ASYNC_EXCEPTION_COMPLETION(CONTINUABLE) \
|
#define ASSERT_ASYNC_EXCEPTION_COMPLETION(CONTINUABLE) \
|
||||||
cti::detail::testing::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
|
/// Asserts that the final callback of the given continuable is never called
|
||||||
/// with any result.
|
/// with any result.
|
||||||
///
|
///
|
||||||
@ -158,7 +166,7 @@
|
|||||||
/// \since 1.0.0
|
/// \since 1.0.0
|
||||||
#define ASSERT_ASYNC_TYPES(CONTINUABLE, ...) \
|
#define ASSERT_ASYNC_TYPES(CONTINUABLE, ...) \
|
||||||
cti::detail::testing::assert_async_types( \
|
cti::detail::testing::assert_async_types( \
|
||||||
CONTINUABLE, cti::detail::traits::identity<__VA_ARGS__>{})
|
CONTINUABLE, cti::detail::identity<__VA_ARGS__>{})
|
||||||
|
|
||||||
/// Asserts that the continuable is finished with the given exception
|
/// Asserts that the continuable is finished with the given exception
|
||||||
///
|
///
|
||||||
@ -169,4 +177,4 @@
|
|||||||
|
|
||||||
/// \}
|
/// \}
|
||||||
|
|
||||||
#endif // CONTINUABLE_TESTING_HPP_INCLUDED
|
#endif // CONTINUABLE_EXTERNAL_GTEST_HPP_INCLUDED
|
||||||
116
include/continuable/operations/async.hpp
Normal file
116
include/continuable/operations/async.hpp
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
/~` _ _ _|_. _ _ |_ | _
|
||||||
|
\_,(_)| | | || ||_|(_||_)|(/_
|
||||||
|
|
||||||
|
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
|
||||||
141
include/continuable/operations/loop.hpp
Normal file
141
include/continuable/operations/loop.hpp
Normal file
@ -0,0 +1,141 @@
|
|||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
/~` _ _ _|_. _ _ |_ | _
|
||||||
|
\_,(_)| | | || ||_|(_||_)|(/_
|
||||||
|
|
||||||
|
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
|
||||||
96
include/continuable/operations/split.hpp
Normal file
96
include/continuable/operations/split.hpp
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
/~` _ _ _|_. _ _ |_ | _
|
||||||
|
\_,(_)| | | || ||_|(_||_)|(/_
|
||||||
|
|
||||||
|
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