Compare commits

..

199 Commits

Author SHA1 Message Date
Rogiel Sulzbach
23a724cf5c Ensure that continuables that are resolved immediately are always symmetrically transferable 2023-09-12 19:13:12 +02:00
Denis Blank
c7f5b1cbaf CI: Use recursive checkouts 2023-09-10 12:52:48 +02:00
Denis Blank
d1f9306eee Add a github workflow file for CI
* Remove the travis CI
2023-09-10 12:47:03 +02:00
Denis Blank
0641a29f42 Fix a build issue on MSVC 2022 related to transforms wait 2023-09-10 12:12:06 +02:00
Piers Haken
f7f304e971 fix clang coroutines detection 2022-12-21 17:27:46 +01:00
Robert Konklewski
63e3ed4edc Fix incorrect initialization of unsafe_locker
List initialization of unsafe_locker class resulted in a compiler
error, because 1) it had no constructor matching the arguments, and
2) it had user-declared constructors, so aggregate initialization
was not allowed.

This change fixes the issue by adding an appropriate constructor.
2022-09-05 11:41:35 +02:00
Denis Blank
b51be39e71 Fix Stopping a continuable in a failure handler makes wait() hang forever
* Closes #46
* Closes #48
2022-06-02 01:01:26 +02:00
Denis Blank
ed8310e345 Year and version update 2022-01-20 08:41:32 +01:00
Denis Blank
01f9dbd1f4 Add support for stable coroutines (/await:strict and -fcoroutines)
* The definition CONTINUABLE_HAS_COROUTINE now indicates support for coroutines,
  while CONTINUABLE_HAS_EXPERIMENTAL_COROUTINE is added if the experimental version is used.
2022-01-20 08:41:32 +01:00
sTabishAzam
2fcc2bf281 Update connection-seq.hpp
This was causing error on usage of when seq :: "result is not a type name static or enumerator"
2021-11-14 21:35:58 +01:00
Denis Blank
ace3317f65 Minor improvement 2021-10-22 08:03:34 +02:00
Denis Blank
e6f817ca7b Add the void(...) asio handler overload to the use_continuable initiation token
* Makes it possible to use the initiation token with dispatch/post
* Ref #44
2021-10-22 07:57:20 +02:00
Denis Blank
e2b5fc36fe Add continuable::via to change the invocation chain to the given executor 2021-10-20 07:41:01 +02:00
Denis Blank
6bffb44d2b Fix a race condition in cti::transforms::wait()
* Thanks to p4654545 for reporting this issue and providing a reproducible example
* Closes #38
2020-11-03 17:28:24 +01:00
Denis Blank
48c6abf5f2 Ensure that the example given in #34 compiles in the CI
* Ref #34
2020-08-10 18:31:16 +02:00
Denis Blank
f57c5898eb Improve the documentation of the fail handler
* State that the exception of type exception_t can be passed
  with an initial state.
* Ref #32
2020-04-10 15:25:37 +02:00
Denis Blank
8187c16ede Improve the use_continuable_t asio completion tokens such that special mappings are aptable
* Also allow to ignore certain error types through use_continuable_ignoring
* Ref #32
2020-04-09 18:43:00 +02:00
Denis Blank
d80f5ef3ec Make the wait transform throw a wait_transform_canceled_exception on cancellation 2020-04-09 16:03:47 +02:00
Denis Blank
5f84de0e86 Handle the cancellation of continuables used in co_await expression correctly
* Throws a await_canceled_exception now which automatically gets
  converted to a default exception type again if it becomes unhandled in the handler.
* Ref #32
2020-04-09 15:34:11 +02:00
Denis Blank
8e63a45840 Increase the version to 4.1.0 2020-04-09 15:13:36 +02:00
Denis Blank
61826817c7 Add the 4.0.0 amalgamation to the documentation
* Closes #31
2020-04-07 22:31:32 +02:00
Denis Blank
735697026b Update the 4.0.0 changelog 2020-04-06 17:53:15 +02:00
Denis Blank
9593ba120c Add a quick tour to the readme 2020-04-06 17:36:42 +02:00
Denis Blank
33bfc490ef Rename cancel() to stop() and make cancel() return a cancellation result instead 2020-04-05 00:49:57 +02:00
Denis Blank
77faf3120f 4.0.0 estimated changelog 2020-04-05 00:15:35 +02:00
Denis Blank
26cd377831 4.0 version increase 2020-04-04 23:35:02 +02:00
Denis Blank
923843cd44 Update function2 2020-04-04 23:32:36 +02:00
Denis Blank
8c1a79d17b Update the copyright year 2020-04-04 23:31:20 +02:00
Denis Blank
5fbc9c4a59 Some doc fixes 2020-04-04 23:27:32 +02:00
Denis Blank
adc75655f4 Adapt the required boost versions for the async initiate
* Also respect asio and boost major versions
2020-04-04 23:08:04 +02:00
Denis Blank
1e39bd85dd Replace the result<...> implementation by a lighter one
* result<...> only moveable now, the conditional copy capabilities were removed
* If you require the optional copy capability use a std::variant implementation of your choice
* Closes #13
2020-04-04 22:26:09 +02:00
Denis Blank
5f8b2aa317 Fix example code in the tutorial documentation
* Closes #30
2020-04-04 21:57:38 +02:00
Denis Blank
37359dec0b Fix infinite recursion on Clang if the compiler attempts to continue on best effort
* The library triggers a static_assert correctly if a callable
  can't be called with a subset of its arguments but it seems like this is
  not enough to make the compiler stop causing the generation
  of a 0 - 1 -> std::size_t::max length index sequence which obviously
  causes infinite work.
* Reproducible with:
  ```
  cti::make_continuable<std::string>([](cti::promise<std::string> promise) {
    promise.set_value("hello");
  }).then([](int num) {
    //
  });
  ```
* Closes #21
2020-04-04 19:41:57 +02:00
Denis Blank
2c76e6c367 Split the async tests into their own test case 2020-04-04 17:19:44 +02:00
Denis Blank
0fb66a7eec Fix the ci build when exceptions are disabled 2020-04-04 03:02:05 +02:00
Denis Blank
c69385be5f Implement the wait transforms tests 2020-04-04 01:51:02 +02:00
Denis Blank
ab9669fa2a Implement wait, wait_for and wait_until transforms properly
* wait is implemented by a atomic and default condition variable.
* wait_for and wait_until are expensive since we can't assume
  anything about the environment thus we have to allocate
  a persistent frame.
2020-04-04 01:11:27 +02:00
Denis Blank
df4d6ed971 Start to revise transforms 2020-04-04 00:04:51 +02:00
Denis Blank
957d3fa375 Align the cancel behaviour of result to the one used in the unhandled exception handler
* Introduce cancellation_result to represent a cancelled async task
* Add cancellation unit tests
* This doesn't allow cancellation of continuables, it is meant
  for treating the special state action canceled on the receiver side.
  Cancellation of a chain is still up to the user.
2020-04-03 22:34:08 +02:00
Denis Blank
c8c4325b5b Fix the unit tests by providing an ASSERT_ASYNC_CANCELLATION 2020-04-03 19:57:46 +02:00
Denis Blank
f1e9255eb9 Fix the test header includes 2020-04-03 19:47:42 +02:00
Denis Blank
85c0d76c7c Make make_cancelling_continuable throw an default constructed exception_t
* This behaviour now aligns on how cancellation is handled in the
  unhandled exception handler
2020-04-03 19:44:49 +02:00
Denis Blank
ca26bbbc87 Remap asio::error::basic_errors::operation_aborted to a default constructed exception_t
* Add a successful wait on the asio async timer
* Closes #27
* Closes #28
2020-04-03 19:38:13 +02:00
Denis Blank
564d134c75 Improve the clang-tidy and clang-format config 2020-04-03 18:13:41 +02:00
Denis Blank
f7e00bcc8d Store std::exception::what() automatically before calling TRAP on unhandled exceptions
* Makes it easier to inspect the message in debuggers
2020-04-03 17:44:40 +02:00
Denis Blank
89031d932c Rename cti::asio_token to cti::use_continuable
* support -> external
2020-04-03 17:25:52 +02:00
Christos Stratopoulos
1a1c7b68c6 Base implementation of an ASIO completion token integration
* Bump the asio version to 1.41
* Move headers that require an external dependency to include/continuable/support
* Ref #28
* Ref #27
2020-04-03 14:44:34 +02:00
Denis Blank
0b1b284e3a Add continuable_base::is_ready and continuable_base::unpack.
* Can be used to specialize the asynchronous control flow
  on immediate available asynchronous results mostly returned by:
    - make_ready_continuable
    - make_exceptional_continuable
* Usable to avoid longer unnecessary synchronous callback nestings.
* cti::query_arg_t was renamed into cti::unpack_arg_t.
* The continuation overload nowreturns result<Args...> rather
  than std::tuple<Args...>.
* Add is_ready optimizations to make_exceptional_continuable.
2019-12-26 10:13:20 +01:00
Denis Blank
117a716de1 Test the class which represents exception_t against true before running unhandled exception handlers.
* This allows cheap cancellation of the control flow by passing
  a default constructed `exception_t` object to `set_exception`.
* Since possible representatives like
    - `std::exception_ptr`
    - `std::error_code`
    - `std::error_condition`
  can be default constructed we have to test them anyway before possibly
  rethrowing them.
2019-11-16 17:13:23 +01:00
Denis Blank
cacb84371a Add MSVC 16 to the CI 2019-09-28 17:37:01 +02:00
Denis Blank
92d8bbad36 Fix the MSVC 16 build 2019-09-28 17:29:30 +02:00
Denis Blank
0afdbec2cc Upgrade the dependencies 2019-09-28 16:25:09 +02:00
Denis Blank
ffb3db7089 Fix the asio example
* Attempt to fix the GCC warning in a different way
2019-09-02 01:03:28 +02:00
Denis Blank
7aff2c0d9b Show the submodule revisions in Travis CI 2019-09-02 00:52:30 +02:00
Denis Blank
959f059a25 Fix a build error 2019-09-02 00:45:53 +02:00
Denis Blank
91d51e6543 Attempt to fix the clang/GCC build 2019-09-02 00:37:37 +02:00
Denis Blank
5e8bbe7c72 Use TYPED_TEST_SUITE instead of deprecated GTest TYPED_TEST_CASE 2019-09-02 00:24:07 +02:00
Denis Blank
dce0fbcffe Clean the playground since the test was moved into the unit tests 2019-09-02 00:17:17 +02:00
Denis Blank
a2fdfdfceb Use a promise<> for work rather than a dedicated work_base 2019-09-02 00:01:26 +02:00
Denis Blank
389002e918 Improve the work wrapper 2019-09-01 23:47:59 +02:00
Denis Blank
92368bccb7 Update submodules 2019-08-31 03:31:25 +02:00
Denis Blank
e09d26f3c6 First work on passing an exception to the executable work
* Make work r-value callable only by default
2019-08-31 03:30:03 +02:00
Denis Blank
422b6138cd Lift control flow compiler intrinsics into the used scope
* Also make UNREACHABLE trap in debug mode
2019-08-27 04:01:37 +02:00
Bogdan Vaneev
42af23fa03 Remove ccache
Signed-off-by: Bogdan Vaneev <warchantua@gmail.com>
2019-05-24 17:39:48 +02:00
Bogdan Vaneev
bcf55e88dd Add ccache
Signed-off-by: Bogdan Vaneev <warchantua@gmail.com>
2019-05-24 17:39:48 +02:00
Bogdan Vaneev
88fbcdbc17 Add ccache, add travis cache
Signed-off-by: Bogdan Vaneev <warchantua@gmail.com>
2019-05-24 17:39:48 +02:00
Bogdan Vaneev
c9d0e871cd Bump asio to 1.13.0
Signed-off-by: Bogdan Vaneev <warchantua@gmail.com>
2019-05-24 02:33:31 +02:00
Bogdan Vaneev
4cc7523380 Add regex to match AppleClang compiler
Signed-off-by: Bogdan Vaneev <warchantua@gmail.com>
2019-05-24 02:33:14 +02:00
Denis Blank
d842c14268 Re-enable the converting constructor of continuable_base
* Probably a forgotten leftover from debugging
  mainly responsible for more efficient conversions only.
2019-03-19 17:06:58 +01:00
Denis Blank
e9be3eb8c3 Improved the coroutine support auto detection on MSVC
* Based on _RESUMABLE_FUNCTIONS_SUPPORTED inspired from asio.
2019-03-15 17:11:38 +01:00
Denis Blank
67d77808dc Fix the GCC build after bc4d69735 2019-03-12 14:44:15 +01:00
Denis Blank
03ae1b5c45 Update function2 to Naios/function2@e3695b4 2019-03-12 14:43:50 +01:00
Denis Blank
bc4d69735c Improve cti::split and make it workable with plain callbacks 2019-03-11 16:39:35 +01:00
Denis Blank
daa2fdd686 Implement cti::split which makes it possible to resolve multiple
asynchronous control flows from a single promise.
2019-03-08 22:06:44 +01:00
Denis Blank
41f3429c85 Remove some using expressions
* Those caused issues in namespaces where symbols were preloaded
* Formatting fixes
2019-03-08 20:18:26 +01:00
Denis Blank
6b4f6de10f Use the work erased type directly in release builds
* So this behaviour aligns to the one used in continuable_base and promise_base.
2019-03-08 18:27:57 +01:00
Denis Blank
fdd9a061c4 Make promise_base default constructible
* This makes it possible to use promise_base for optional
  promises directly rather than wrapping it as optional<promise_base<...>>.
* Invalidate the promise_base after its first usage.
* Expose an `operator bool()` to make the validility accessible.
* Remove the no longer needed private promise_no_init_arg_t tag.
2019-03-08 18:13:40 +01:00
Denis Blank
2bc448b905 Link the MeetingC++ talk in the readme 2019-02-26 16:01:20 +01:00
Denis Blank
e23e363b03 Add a conanfile
* Closes #12
2019-01-29 20:28:09 +01:00
Denis Blank
d72e1bfb86 Implement async_on for asynchronous execution on a specific executor
* Makes it possible to specify an executor in addition to
  the arguments passed to async.
* The reason why async should not support this directly is
  that it should be closely modelled to std::async.
2019-01-26 03:46:39 +01:00
Denis Blank
fa589a1e95 Document range_loop 2019-01-14 23:14:29 +01:00
Denis Blank
20cd0191fc For loops provide loop_result loop_break and loop_continue for better readability 2019-01-14 23:13:23 +01:00
Denis Blank
76ecc3d26d Attempt to fix the build 2019-01-14 21:10:25 +01:00
Denis Blank
7491022d0f Implement make_plain to make it possible to not handle special objects in handlers 2019-01-14 21:02:22 +01:00
Denis Blank
4c807aec75 Update a deprecation message 2019-01-14 18:13:22 +01:00
Denis Blank
60b75a6134 Finish the async implementation 2019-01-14 18:07:37 +01:00
Denis Blank
b86fe7a255 Additional work on async 2019-01-13 19:10:55 +01:00
Denis Blank
a4da3e84ef Fix the range_loop build 2019-01-13 18:52:13 +01:00
Denis Blank
ac175b4e57 Start to implement the unit tests for loop and add range_loop 2019-01-13 18:19:49 +01:00
Denis Blank
135ebfccf3 Start to implement loop and async 2019-01-13 17:05:28 +01:00
Denis Blank
5c1cd87739 Doc improvement 2019-01-06 14:05:54 +01:00
Denis Blank
20e8c7d3e3 Reflow the license text
* For some reason some spaces were removed,
  the license text and content stays the same.
2019-01-04 13:39:46 +01:00
Denis Blank
a3a9695174 Happy new year! 2019-01-04 13:35:44 +01:00
Denis Blank
c066940d8d Use new types instead of aliases for type erasures
* Makes compiler output much more readable
  This is configurateable through CONTINUABLE_WITH_IMMEDIATE_TYPES,
  and automatically enabled for debug builds but disabled
  for release builds.
* Remove the old continuable-trait.hpp header
* Make the signature of continuable not dependent anymore
  on any size of the arguments which fixes the compilation
  with forward declared types.
  Thanks Rogiel for the correspoding bug report.
  Closes #11
2019-01-04 13:12:48 +01:00
Denis Blank
2d5aa36b67 Update function2 to Naios/function2@d2acdb6 2019-01-04 12:59:25 +01:00
Denis Blank
3bd4dd40de Fixate the args of the final callback
* Also allow to customize it through the
  CONTINUABLE_WITH_CUSTOM_FINAL_CALLBACK define.
  This can be used to implement custom unhandled
  exception handlers and more.
2018-12-29 06:25:49 +01:00
Denis Blank
a099c504e1 Workaround for a MSVC required symbol link bug 2018-12-26 06:20:48 +01:00
Denis Blank
7a10363dce Implement continuable_base<...>::as
* Can convert continuables to other compatible signatures
2018-12-26 05:38:10 +01:00
Denis Blank
30f0dca27f Fix a unit test introduced in 4127c02c3f6d 2018-12-25 11:15:06 +01:00
Denis Blank
d4cb7dd7b3 Only disable specific top level project settings
* When being not being inside in a top level project
2018-12-25 09:35:20 +01:00
Denis Blank
f469b7058a Implement make_cancelling_continuable()
* Can be used to cancel the chain when being inside a handler
2018-12-25 09:30:23 +01:00
Denis Blank
4127c02c3f Add an overload to make_result which accepts a exception_arg_t and exception_t
* Can be used to forward the result correctly from next handlers
2018-12-25 09:05:51 +01:00
Denis Blank
d052a02595 Remove a bad GCC diagnostic pop when using result<...> and GCC 2018-12-25 08:42:42 +01:00
Denis Blank
7dbc95c4b3 Implement zero cost ready continuables for await expressions 2018-12-16 04:25:56 +01:00
Denis Blank
fcf9a76029 Set the minimum required CMake version to 3.11
* Make travis-ci install a recent CMake version
* Update function2
2018-12-12 17:46:16 +01:00
Denis Blank
49e3a659ad Rework the find_package() support
* It is now possible to include the repository correctly
  through add_subdirectory
* find_package(continuable) was improved to work when
  only the path of the repository was added to the module path.
2018-12-11 04:30:58 +01:00
Denis Blank
65916e29a8 Update function2 to Naios/function2@2b3bc42 2018-12-11 04:29:24 +01:00
Denis Blank
121265df71 Cleanup in result<> 2018-12-11 01:21:26 +01:00
Denis Blank
4c41995316 Document recover, rethrow and cancel
* Closes #9
2018-12-11 01:21:09 +01:00
Denis Blank
dd09c3d684 Bump the version to 4.0.0 2018-12-10 18:08:29 +01:00
Denis Blank
ff881091fc Update function2 to Naios/function2@1dd435d 2018-12-10 06:27:15 +01:00
Denis Blank
30d49141a8 Resolve ready continuables directly in sequential connections 2018-12-10 06:22:53 +01:00
Denis Blank
c7ef5c6f64 Adhust the SFO buffer size so it can contain a pointer at zero cost 2018-12-10 06:07:43 +01:00
Denis Blank
b2726982ac Fix the build when coroutines are enabled 2018-12-10 06:03:46 +01:00
Denis Blank
57bb43138b Fix a recursive template instantiation issue on clang and gcc 2018-12-10 05:08:39 +01:00
Denis Blank
1320c8eb63 Add a unit test which tests for ready continuables explicitly 2018-12-09 17:01:56 +01:00
Denis Blank
1bdee5b371 Remove an unused using 2018-12-09 16:49:03 +01:00
Denis Blank
bdada99096 Fix the immediate return type of chained continuables
* Statically resolve ready continuables
2018-12-09 16:48:08 +01:00
Denis Blank
7273891a4c Specialize the continuation chainer in case ready continuables are chained 2018-12-09 04:53:28 +01:00
Denis Blank
9ceee76647 Fix an issue with the is_ready overload 2018-12-08 17:52:22 +01:00
Denis Blank
4b1f6281fc Initial work on wrapping all continuations into the triple path schema 2018-12-08 05:53:44 +01:00
Denis Blank
cb6ce5b43b get_arg_t -> query_arg_t 2018-12-08 04:50:38 +01:00
Denis Blank
24158583b7 Provide the get_arg_t and is_ready_arg_t also from continuables created through make_* 2018-12-08 04:49:03 +01:00
Denis Blank
6947091a27 Preserve the ownership across chainings
* Fixes the unit tests
2018-12-08 04:31:32 +01:00
Denis Blank
bcafd1b333 Only consume the data when chaining continuations 2018-12-08 04:19:53 +01:00
Denis Blank
d416698758 Make the ready query stuff part of the private API 2018-12-08 04:11:40 +01:00
Denis Blank
b5f353222c Make it possible to add optional methods to continuable_base depending on the annotation 2018-12-08 03:28:33 +01:00
Denis Blank
f5dd02ef8b Some documentation fixes 2018-12-08 02:53:33 +01:00
Denis Blank
969445c8a0 Fix the build 2018-12-08 02:40:10 +01:00
Denis Blank
577b71b8ab Remove the template args from the void make_ready_continuable 2018-12-08 01:28:27 +01:00
Denis Blank
b293d9a342 Adapt the small functor capacity to hold a ready continuable at zero cost 2018-12-08 01:26:14 +01:00
Denis Blank
da8ec15c6f Some minor improvements 2018-12-07 04:46:18 +01:00
Denis Blank
62ca39e59c Some renaming 2018-12-07 04:40:03 +01:00
Denis Blank
f17cc4073c Add the is_ready proto 2018-11-30 03:05:18 +01:00
Denis Blank
7a5bde328c Unify the exception and result invoker 2018-11-30 03:04:55 +01:00
Denis Blank
7352cbf8a9 Make it possible to continue with a continuable from failure handlers 2018-11-30 02:10:05 +01:00
Denis Blank
4d58e3bded Attempt to fix the GCC build 2018-11-28 17:55:01 +01:00
Denis Blank
1edd1e633d Fix the unit tests 2018-11-28 17:00:35 +01:00
Denis Blank
70c716bb28 Make the failure handler partial applyable
* Make result C++17 destructible
* Add unit tests
2018-11-28 01:29:36 +01:00
Denis Blank
bb7112eec2 Fix the build 2018-11-27 16:38:24 +01:00
Denis Blank
f1f9d61952 Attempt to remove the plain handler 2018-11-27 02:39:41 +01:00
Denis Blank
b77e926c41 Fix the unit tests 2018-11-26 04:37:48 +01:00
Denis Blank
812420cf06 Unify the exception and result handler
* Make the failure handler partial applyable
2018-11-26 04:15:40 +01:00
Denis Blank
a9375c7f22 Implement the exception invokers which fully implements recover, rethrow and cancel now 2018-11-26 04:12:17 +01:00
Denis Blank
ca1c0bf1da Split the logic for exception forwarding 2018-11-26 03:27:35 +01:00
Denis Blank
82dd47b463 Cleanup the unit tests 2018-11-26 03:21:01 +01:00
Denis Blank
c5663bf1ad Add the unit tests for the failure handlers recovering and rethrowing 2018-11-26 03:02:49 +01:00
Denis Blank
afe1a3298e Make the current unit tests pass 2018-11-26 02:35:27 +01:00
Denis Blank
9955f9e469 Add the invoker for result<...> 2018-11-26 02:19:16 +01:00
Denis Blank
ba9ff9fce0 Initial work on routing the arguments correctly when using result<...> 2018-11-26 00:41:15 +01:00
Denis Blank
7767ce6fbb Only provide value_t from result 2018-11-25 21:31:08 +01:00
Denis Blank
67964b0793 Attempt to fix the clang build 2018-11-25 20:43:14 +01:00
Denis Blank
41da6ba293 Remove the is_result trait 2018-11-25 20:00:41 +01:00
Denis Blank
cd367b3d43 Make result<> return void when calling get_value() 2018-11-25 19:56:03 +01:00
Denis Blank
5354d3512e Fix the MSVC/Clang build even more 2018-11-25 18:01:15 +01:00
Denis Blank
2a80649084 Make exception and empty results returning a void hint 2018-11-25 17:14:23 +01:00
Denis Blank
782e1c6447 Fix the MSVC build 2018-11-25 17:08:01 +01:00
Denis Blank
f4268f60f9 initial work on the multipathing unit tests 2018-11-25 03:18:35 +01:00
Denis Blank
07c8ed0cf9 Add invoker for the result class and specialized ones 2018-11-25 02:54:35 +01:00
Denis Blank
ffa3b9ee1b Rename cti::expected -> cti::result 2018-11-25 02:23:08 +01:00
Denis Blank
93b1d27b07 Fix the build for the expected class 2018-11-25 02:13:01 +01:00
Denis Blank
867ab38b8e Rework the expected_trait
* Add tests for the new expected public interface
2018-11-25 00:29:00 +01:00
Denis Blank
c76fe9e973 Make the expected class part of the public interface
* Required for exception rethrowing and recovering
2018-11-24 22:57:18 +01:00
Denis Blank
3a70356f16 Move some methods out of the attorney
* Code cleanup
2018-11-24 15:02:23 +01:00
Denis Blank
6969a9e392 Expose finish() method in continuable_base which makes it possible
to materialize the continuable_base when using it as an expression template.
2018-11-24 14:26:51 +01:00
Denis Blank
0657445466 Re-enable the deprecation warnings
* Ref 815c3d71
2018-11-22 00:50:41 +01:00
Denis Blank
815c3d71b9 Make the old error and dispatch tag not throw deprecation warnings for now 2018-11-22 00:48:02 +01:00
Denis Blank
057fb37123 Introduce the continuable primitive header which supplies tags
* Adapts the new naming scheme from the "Unified Futures" proposal
* Provides new tags for the future inplace resolution
2018-11-19 23:59:01 +01:00
Denis Blank
2ff7bb9b8d Improve 4ae560156348 and allow it to be set as an option 2018-11-19 19:53:02 +01:00
Denis Blank
8e7af3a320 Add traits::unrefcv_t for later usage 2018-11-19 19:37:53 +01:00
Denis Blank
4ae5601563 Limit MSVC concurrent build tasks 2018-11-19 19:37:34 +01:00
Denis Blank
6cd39a2e54 Remove a useless unit test 2018-11-19 19:36:57 +01:00
Denis Blank
818b7a7314 Workaround for a regression introduced ~MSVC 15.8.1 2018-11-19 19:27:29 +01:00
Denis Blank
7cf7314486 Reformat the travis-ci shell script 2018-11-19 19:26:51 +01:00
Denis Blank
8f89835ca4 Add vscode files to gitignore 2018-11-19 19:26:30 +01:00
Denis Blank
646707e5dc Move from std::decay to std::decay_t
* Makes the transition to traits::unref easier later
2018-11-19 19:26:18 +01:00
Denis Blank
a9d4ee5ba8 Fix the single tests 2018-11-18 18:59:54 +01:00
Denis Blank
cc83fd5251 Rearrange the internal headers 2018-11-18 18:46:15 +01:00
Denis Blank
c1b8aa8694 Attempt to work around the failing MSVC CI build 2018-11-18 18:11:50 +01:00
Denis Blank
7b4ab90f9c Disable benchmarks by default 2018-11-18 17:46:25 +01:00
Denis Blank
fae030afa3 Fix a compilation error which is caused by regression in one of the MSVC 15.1 updates 2018-11-18 17:46:25 +01:00
Denis Blank
2cfbdaf673 Implement a benchmark against boost::future 2018-11-18 17:46:25 +01:00
Denis Blank
2b4f31c121 Initial work on benchmarking 2018-11-18 17:46:24 +01:00
Thomas James Passmore
ede7a4a72b Fix CMake scripts
cmake/configure_macros.cmake and cmake/configure_compiler.cmake
incorrectly reference CMAKE_SOURCE_DIR, occurences have been changed to
PROJECT_SOURCE_DIR

closes #7
2018-11-17 12:10:01 +01:00
Denis Blank
9247e7b85f Silence a warning when using CONTINUABLE_WITH_UNHANDLED_EXCEPTIONS
* Ref e59e6ae8b9
2018-03-19 09:07:34 +01:00
Denis Blank
e59e6ae8b9 Make it easier to inspect unhandled asynchronous exceptions in debuggers 2018-03-17 14:23:19 +01:00
Denis Blank
7dbf22a2d2 Make it possible to remap the result from promisified expressions 2018-03-17 13:24:57 +01:00
Denis Blank
b68cd1b43a Set the CMake project version to 3.0.0 2018-03-14 10:29:45 +01:00
Denis Blank
be6571091b Implement continuables as return types for coroutines
* Closes #4
2018-03-14 10:29:45 +01:00
Denis Blank
358e13e06e Remove unused size traits 2018-03-14 10:29:45 +01:00
Denis Blank
3a5cea7779 std::size_t is part of cstddef not cstdint 2018-03-14 10:29:45 +01:00
Denis Blank
139f7d39de Remove unused static_if 2018-03-14 10:29:45 +01:00
Denis Blank
65e41a2cbd Remove unused identity utilities 2018-03-14 10:29:45 +01:00
Denis Blank
83f736a93f Move the arguments out of a ready continuable with multiple arguments 2018-03-14 10:29:44 +01:00
Denis Blank
f091cbb079 Use a std::apply style unpack
* Some cleanup
2018-03-14 10:29:44 +01:00
Denis Blank
41c7cb008a Add an alias for type erased work objects 2018-03-14 10:29:44 +01:00
Denis Blank
084937e192 Use std::void_t when available 2018-03-12 16:34:55 +01:00
Denis Blank
0e4b299b45 Provide tools for creating an amalgamation header 2018-03-12 16:34:18 +01:00
Denis Blank
977feb3825 Update the online compilers 2018-03-12 16:32:28 +01:00
150 changed files with 9038 additions and 3406 deletions

View File

@ -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

View File

@ -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
View 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
View File

@ -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

22
.gitmodules vendored
View File

@ -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

View File

@ -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

View File

@ -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,139 +7,215 @@
# 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
cxx_decltype_auto cxx_decltype_auto
cxx_final cxx_final
cxx_lambdas cxx_lambdas
cxx_generic_lambdas cxx_generic_lambdas
cxx_variadic_templates cxx_variadic_templates
cxx_defaulted_functions cxx_defaulted_functions
cxx_nullptr cxx_nullptr
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
$<$<CXX_COMPILER_ID:MSVC>:/await>
$<$<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_COROUTINE)
target_compile_definitions(continuable-base if(NOT CTI_CONTINUABLE_WITH_CPP_LATEST)
INTERFACE message(FATAL_ERROR "CTI_CONTINUABLE_WITH_COROUTINE requires "
-DCONTINUABLE_WITH_UNHANDLED_EXCEPTIONS) "CTI_CONTINUABLE_WITH_CPP_LATEST!")
endif()
target_compile_options(
continuable-base
INTERFACE $<$<CXX_COMPILER_ID:MSVC>:/await:strict>
$<$<CXX_COMPILER_ID:Clang>:-fcoroutines-ts>
$<$<CXX_COMPILER_ID:GNU>:-fcoroutines>)
elseif(CTI_CONTINUABLE_WITH_EXPERIMENTAL_COROUTINE)
target_compile_options(
continuable-base INTERFACE $<$<CXX_COMPILER_ID:MSVC>:/await>
$<$<CXX_COMPILER_ID:Clang>:-fcoroutines-ts>)
endif()
if(CTI_CONTINUABLE_WITH_UNHANDLED_EXCEPTIONS)
target_compile_definitions(continuable-base
INTERFACE CONTINUABLE_WITH_UNHANDLED_EXCEPTIONS)
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
View 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")

View File

@ -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
View File

@ -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)] |
.

View File

@ -1,17 +1,17 @@
image: image:
- Visual Studio 2017 - Visual Studio 2017
- Visual Studio 2019
environment: environment:
matrix: matrix:
- WITH_NO_EXCEPTIONS: OFF - WITH_NO_EXCEPTIONS: OFF
WITH_CPP_LATEST: OFF WITH_CPP_LATEST: OFF
- WITH_NO_EXCEPTIONS: ON - WITH_NO_EXCEPTIONS: ON
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
@ -24,18 +24,20 @@ clone_script:
before_build: before_build:
- cmd: > - cmd: >
cmake -H. -Bbuild -A%PLATFORM% cmake -H. -Bbuild -A%PLATFORM%
-DCTI_CONTINUABLE_WITH_NO_EXCEPTIONS=%WITH_NO_EXCEPTIONS% -DCTI_CONTINUABLE_WITH_NO_EXCEPTIONS=%WITH_NO_EXCEPTIONS%
-DCTI_CONTINUABLE_WITH_EXPERIMENTAL_COROUTINE=ON -DCTI_CONTINUABLE_WITH_EXPERIMENTAL_COROUTINE=ON
-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'

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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
View 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@)

View File

@ -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()

View File

@ -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)

View File

@ -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,46 +13,48 @@
# #
# 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 "")
# Include all header and c files foreach(dir ${ARGN})
file(GLOB_RECURSE elements RELATIVE ${dir} *.h *.hpp *.inl *.inc *.c *.cpp *.cc) # Include all header and c files
file(GLOB_RECURSE elements RELATIVE ${dir} ${dir}/*)
foreach(element ${elements}) foreach(element ${elements})
# Extract filename and directory # Extract filename and directory
get_filename_component(element_name ${element} NAME) get_filename_component(element_name ${element} NAME)
get_filename_component(element_dir ${element} DIRECTORY) get_filename_component(element_dir ${element} DIRECTORY)
if (NOT ${element_dir} STREQUAL "") if (NOT ${element_dir} STREQUAL "")
# If the file is in a subdirectory use it as source group. # If the file is in a subdirectory use it as source group.
if (${WITH_SOURCE_TREE} STREQUAL "flat") if (${WITH_SOURCE_TREE} STREQUAL "flat")
# Build flat structure by using only the first subdirectory. # Build flat structure by using only the first subdirectory.
string(FIND ${element_dir} "/" delemiter_pos) string(FIND ${element_dir} "/" delemiter_pos)
if (NOT ${delemiter_pos} EQUAL -1) if (NOT ${delemiter_pos} EQUAL -1)
string(SUBSTRING ${element_dir} 0 ${delemiter_pos} group_name) string(SUBSTRING ${element_dir} 0 ${delemiter_pos} group_name)
source_group("${group_name}" FILES ${dir}/${element}) source_group("${group_name}" FILES ${dir}/${element})
else()
# Build hierarchical structure.
# File is in root directory.
source_group("${element_dir}" FILES ${dir}/${element})
endif()
else() else()
# Build hierarchical structure. # Use the full hierarchical structure to build source_groups.
# File is in root directory. string(REPLACE "/" "\\" group_name ${element_dir})
source_group("${element_dir}" FILES ${dir}/${element}) source_group("${group_name}" FILES ${dir}/${element})
endif() endif()
else() else()
# Use the full hierarchical structure to build source_groups. # If the file is in the root directory, place it in the root source_group.
string(REPLACE "/" "\\" group_name ${element_dir}) source_group("\\" FILES ${dir}/${element})
source_group("${group_name}" FILES ${dir}/${element})
endif() endif()
else() endforeach()
# If the file is in the root directory, place it in the root source_group.
source_group("\\" FILES ${dir}/${element})
endif()
endforeach() endforeach()
endif() endif()
endmacro() endmacro()

37
conanfile.py Normal file
View 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")

View File

@ -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()

View File

@ -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

View 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

View 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)

@ -0,0 +1 @@
Subproject commit b874e72208b6e21b62287942e5e3b11f6630107f

43
dep/boost/CMakeLists.txt Normal file
View 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

View File

@ -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

View File

@ -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

View File

@ -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.

View File

@ -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,9 +30,11 @@ in order to change the libraries behaviour:
| Preprocessor definition | Consequence | | Preprocessor definition | Consequence |
| ----------------------------------------- | --------------- | | ----------------------------------------- | --------------- |
| `CONTINUABLE_WITH_NO_EXCEPTIONS` | Exceptions are disabled and `std::error_condition` is used as \ref error_type . See \ref tutorial-chaining-continuables-fail for details. | | `CONTINUABLE_WITH_NO_EXCEPTIONS` | Exceptions are disabled and `std::error_condition` is used as \ref error_type . See \ref tutorial-chaining-continuables-fail for details. |
| `CONTINUABLE_WITH_CUSTOM_ERROR_TYPE` | Exceptions are disabled and the type defined by `CONTINUABLE_WITH_CUSTOM_ERROR_TYPE` is used as \ref error_type . See \ref tutorial-chaining-continuables-fail for details. | | `CONTINUABLE_WITH_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. |
*/ */

View File

@ -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,13 +70,13 @@ your personal experience in using the library to improve it.
\note If you are using the library in your open-source or commercial project \note If you are using the library in your open-source or commercial project
I would highly appreciate if you could give me a short notice so I can I would highly appreciate if you could give me a short notice so I can
add you to a list of projects and companies using this library. add you to a list of projects and companies using this library.
\section mainpage-license License \section mainpage-license License
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

View File

@ -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
@ -44,12 +44,12 @@ versions might work.
\section installation-dependencies Dependencies \section installation-dependencies Dependencies
Continuable is a header-only library with one required header-only dependency: Continuable is a header-only library with one required header-only dependency:
- [Naios/function2](https://github.com/Naios/function2) is used as type - [Naios/function2](https://github.com/Naios/function2) is used as type
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

View File

@ -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
*/ */
} }

View File

@ -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

View File

@ -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
@ -201,8 +201,8 @@ for (int i = 2; i < 5; ++i) {
// to the container afterwards // to the container afterwards
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) {
// ... // ...
}); });

View File

@ -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

View File

@ -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
@ -50,7 +50,7 @@ The default callback style is something like
Continuable offers the \ref promisify::from method for such callback styles. Continuable offers the \ref promisify::from method for such callback styles.
See an example of how to promisify boost asio's `async_resolve` below: See an example of how to promisify boost asio's `async_resolve` below:
\code{.cpp} \code{.cpp}
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>::from(
@ -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
*/ */
} }

View File

@ -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
*/ */
} }

View File

@ -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

View File

@ -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

View File

@ -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)

View 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();
}

View File

@ -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*/) {
// ... // ...
}); });

View File

@ -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

View File

@ -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,12 +317,18 @@ 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) {
/// // Handle the error here /// // Check whether the exception_ptr is valid (not default constructed)
/// try { /// // if bool(ep) == false this means that the operation was cancelled
/// std::rethrow_exception(ptr); /// // by the user or application (promise.set_canceled() or
/// } catch (std::exception& e) { /// // make_cancelling_continuable()).
/// e.what(); // Handle the exception /// if (ep) {
/// // Handle the error here
/// try {
/// std::rethrow_exception(ep);
/// } catch (std::exception& e) {
/// e.what(); // Handle the exception
/// }
/// } /// }
/// }); /// });
/// ``` /// ```
@ -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

View File

@ -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

View 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

View 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

View 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

View File

@ -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_);
} }
}; };
/// \} /// \}

View File

@ -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)...);
} }
}; };
/// \} /// \}

View 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

View File

@ -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

View File

@ -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

View File

@ -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) {

View File

@ -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

View File

@ -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

View File

@ -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>

View File

@ -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

View File

@ -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

View File

@ -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(
return spread_this(std::forward<decltype(args)>(args)...); [](auto&&... 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));
} }

View File

@ -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

View File

@ -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

View File

@ -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,16 +56,16 @@ 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(
auto&&... args) mutable { [right = std::forward<Right>(right)](auto&&... args) mutable {
return std::move(right).then([previous = std::make_tuple( return std::move(right).then(
std::forward<decltype(args)>(args)...)]( [previous = std::make_tuple(std::forward<decltype(args)>(args)...)](
auto&&... args) mutable { auto&&... args) mutable {
return traits::merge( return std::tuple_cat(
std::move(previous), std::move(previous),
std::make_tuple(std::forward<decltype(args)>(args)...)); std::make_tuple(std::forward<decltype(args)>(args)...));
}); });
}); });
} }
template <typename Callback, typename Box> template <typename Callback, typename Box>
@ -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) {
return false; 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;
}
} }
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

View File

@ -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
using finalizer = connection_finalizer<Strategy>; template <typename Continuable>
static auto finish(Continuable&& continuable) {
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();
} }
}; };

View File

@ -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

File diff suppressed because it is too large Load Diff

View File

@ -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

View File

@ -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

View 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

View File

@ -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

View File

@ -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

View 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

View 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

View 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

View 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

View 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

View 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

View File

@ -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,11 +121,10 @@ 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)...); }));
}));
} }
/// Expects that the continuable is finished with the given arguments /// Expects that the continuable is finished with the given arguments
@ -115,18 +134,17 @@ 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),
"Async completion handler called with a different count "
"of arguments!");
static_assert(size::value == sizeof...(args), validator(std::make_tuple(std::forward<decltype(args)>(args)...),
"Async completion handler called with a different count " expected_pack);
"of arguments!"); });
validator(std::make_tuple(std::forward<decltype(args)>(args)...),
expected_pack);
});
} }
/// Expects that the continuable is finished with the given arguments /// Expects that the continuable is finished with the given 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...>{});
} }

View File

@ -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

View File

@ -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

View File

@ -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

View 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

View File

@ -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 {

View File

@ -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 {

View File

@ -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;

View File

@ -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,10 +470,9 @@ 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!");
// Create the new container, which is capable of holding // Create the new container, which is capable of holding
// the remappped types. // the remappped types.
@ -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)...);
} }

View 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

View 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

View 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

View 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

View File

@ -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,108 +32,184 @@
#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;
constexpr auto const sequence = std::make_index_sequence<size>();
return traits::unpack(std::forward<T>(sequenceable),
[](auto&&... args) {
return std::forward_as_tuple(
std::forward<decltype(args)>(args)...);
},
sequence);
}
/// We are able to call the callable with the arguments given in the tuple
template <typename T, typename... Args>
auto partial_invoke_impl(std::true_type, T&& callable,
std::tuple<Args...> args) {
return traits::unpack(std::move(args), [&](auto&&... arg) {
return std::forward<T>(callable)(std::forward<decltype(arg)>(arg)...);
});
}
/// We were unable to call the callable with the arguments in the tuple.
/// Remove the last argument from the tuple and try it again.
template <typename T, typename... Args>
auto partial_invoke_impl(std::false_type, T&& callable,
std::tuple<Args...> args) {
// If you are encountering this assertion you tried to attach a callback
// which can't accept the arguments of the continuation.
//
// ```cpp
// continuable<int, int> c;
// std::move(c).then([](std::vector<int> v) { /*...*/ })
// ```
static_assert( static_assert(
sizeof...(Args) > 0, std::tuple_size<std::decay_t<T>>::value > 0U,
"There is no way to call the given object with these arguments!"); "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!");
// Remove the last argument from the tuple constexpr auto size = std::tuple_size<std::decay_t<T>>::value;
auto next = forward_except_last(std::move(args)); constexpr auto sequence = make_decreased_index_sequence(
std::integral_constant<std::size_t, size>{});
// Test whether we are able to call the function with the given tuple return forward_except_last_impl(std::forward<T>(sequenceable), sequence);
traits::is_invokable_from_tuple<decltype(callable), decltype(next)>
is_invokable;
return partial_invoke_impl(is_invokable, std::forward<T>(callable),
std::move(next));
} }
/// Shortcut - we can call the callable directly template <std::size_t Keep>
template <typename T, typename... Args> struct invocation_env {
auto partial_invoke_impl_shortcut(std::true_type, T&& callable, /// We are able to call the callable with the arguments given in the tuple
Args&&... args) { template <typename T, typename... Args>
return std::forward<T>(callable)(std::forward<Args>(args)...); static auto partial_invoke_impl(std::true_type, T&& callable,
} std::tuple<Args...> args) {
return traits::unpack(std::forward<T>(callable), std::move(args));
}
/// Failed shortcut - we were unable to invoke the callable with the /// We were unable to call the callable with the arguments in the tuple.
/// original arguments. /// 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_shortcut(std::false_type failed, T&& callable, static auto partial_invoke_impl(std::false_type, T&& callable,
Args&&... args) { std::tuple<Args...> args) {
// Our shortcut failed, convert the arguments into a forwarding tuple // If you are encountering this assertion you tried to attach a callback
return partial_invoke_impl( // which can't accept the arguments of the continuation.
failed, std::forward<T>(callable), //
std::forward_as_tuple(std::forward<Args>(args)...)); // ```cpp
} // continuable<int, int> c;
// std::move(c).then([](std::vector<int> v) { /*...*/ })
// ```
static_assert(
sizeof...(Args) > Keep,
"There is no way to call the given object with these arguments!");
// Remove the last argument from the tuple
auto next = forward_except_last(std::move(args));
// Test whether we are able to call the function with the given tuple
constexpr std::integral_constant<
bool, traits::is_invocable_from_tuple<decltype(callable),
decltype(next)>::value ||
(sizeof...(Args) <= Keep)>
is_callable;
return partial_invoke_impl(is_callable, std::forward<T>(callable),
std::move(next));
}
/// Shortcut - we can call the callable directly
template <typename T, typename... Args>
static auto partial_invoke_impl_shortcut(std::true_type, T&& callable,
Args&&... args) {
return std::forward<T>(callable)(std::forward<Args>(args)...);
}
/// Failed shortcut - we were unable to invoke the callable with the
/// original arguments.
template <typename T, typename... Args>
static auto partial_invoke_impl_shortcut(std::false_type failed, T&& callable,
Args&&... args) {
// Our shortcut failed, convert the arguments into a forwarding tuple
return partial_invoke_impl(
failed, std::forward<T>(callable),
std::forward_as_tuple(std::forward<Args>(args)...));
}
};
} // namespace detail } // 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
View 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

View File

@ -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

View 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

View 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

View 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