diff --git a/include/continuable/continuable-work-base.hpp b/include/continuable/continuable-work-base.hpp index e8cf847..06f3aae 100644 --- a/include/continuable/continuable-work-base.hpp +++ b/include/continuable/continuable-work-base.hpp @@ -46,16 +46,10 @@ namespace cti { /// \{ /// The work_base makes it possible to resolve an asynchronous -/// continuable through it's result or through an error type. +/// work on a different execution context than the current one. /// -/// Use the work type defined in `continuable/continuable_types.hpp`, -/// in order to use this class. -/// -/// If we want to resolve the work_base trough the call operator, -/// and we want to resolve it through an exception, we must call it with a -/// exception_arg_t as first and the exception as second argument. -/// Additionally the work is resolveable only through its call -/// operator when invoked as an r-value. +/// A work compatible object is passed to any executor that is passed to +/// \see continuable_base::then or \see async_on. /// /// \since 4.0.0 template @@ -71,8 +65,6 @@ class work_base /// \endcond public: - /// Constructor for constructing an empty work - explicit work_base() = default; /// Constructor accepting the data object explicit work_base(Data data) : data_(std::move(data)) { } @@ -101,52 +93,11 @@ public: return *this; } - /// Resolves the continuation with the given values. + /// Invokes the underlying work /// /// \throws This method never throws an exception. /// - /// \attention This method may only be called once, - /// when the work is valid operator bool() returns true. - /// Calling this method will invalidate the work such that - /// subsequent calls to operator bool() will return false. - /// This behaviour is only consistent in work_base and - /// non type erased promises may behave differently. - /// Invoking an invalid work_base is undefined! - /// - /// \since 4.0.0 - void operator()() && noexcept { - std::move(data_)(); - data_ = nullptr; - } - /// Resolves the continuation with the given exception. - /// - /// \throws This method never throws an exception. - /// - /// \attention This method may only be called once, - /// when the work is valid operator bool() returns true. - /// Calling this method will invalidate the work such that - /// subsequent calls to operator bool() will return false. - /// This behaviour is only consistent in work_base and - /// non type erased promises may behave differently. - /// Invoking an invalid work_base is undefined! - /// - /// \since 4.0.0 - void operator()(exception_arg_t tag, exception_t exception) && noexcept { - std::move(data_)(tag, std::move(exception)); - data_ = nullptr; - } - - /// Resolves the continuation with the given values. - /// - /// \throws This method never throws an exception. - /// - /// \attention This method may only be called once, - /// when the work is valid operator bool() returns true. - /// Calling this method will invalidate the work such that - /// subsequent calls to operator bool() will return false. - /// This behaviour is only consistent in work_base and - /// non type erased promises may behave differently. - /// Invoking an invalid work_base is undefined! + /// \attention This method may only be called once! /// /// \since 4.0.0 void set_value() noexcept { @@ -154,23 +105,29 @@ public: data_ = nullptr; } - /// Resolves the continuation with the given exception. + /// Passes an exception to the underlying work /// /// \throws This method never throws an exception. /// - /// \attention This method may only be called once, - /// when the work is valid operator bool() returns true. - /// Calling this method will invalidate the work such that - /// subsequent calls to operator bool() will return false. - /// This behaviour is only consistent in work_base and - /// non type erased promises may behave differently. - /// Invoking an invalid work_base is undefined! + /// \attention This method may only be called once! /// /// \since 4.0.0 void set_exception(exception_t exception) noexcept { std::move(data_)(exception_arg_t{}, std::move(exception)); data_ = nullptr; } + + /// \copydoc set_value + void operator()() && noexcept { + std::move(data_)(); + data_ = nullptr; + } + + /// \copydoc set_exception + void operator()(exception_arg_t tag, exception_t exception) && noexcept { + std::move(data_)(tag, std::move(exception)); + data_ = nullptr; + } }; /// \} } // namespace cti diff --git a/include/continuable/detail/core/base.hpp b/include/continuable/detail/core/base.hpp index 0fa2a5d..2b8b475 100644 --- a/include/continuable/detail/core/base.hpp +++ b/include/continuable/detail/core/base.hpp @@ -499,7 +499,7 @@ public: work_proxy& operator=(work_proxy&&) = default; work_proxy& operator=(work_proxy const&) = delete; - void operator()() && { + void set_value() noexcept { traits::unpack( [&](auto&&... captured_args) { // Just use the packed dispatch method which dispatches the work_proxy @@ -511,7 +511,11 @@ public: std::move(args_)); } - void operator()(exception_arg_t, exception_t exception) && { + void operator()() && noexcept { + std::move(*this).set_value(); + } + + void operator()(exception_arg_t, exception_t exception) && noexcept { std::move(next_callback_)(exception_arg_t{}, std::move(exception)); } diff --git a/test/unit-test/CMakeLists.txt b/test/unit-test/CMakeLists.txt index 68f92f8..f8c9dda 100644 --- a/test/unit-test/CMakeLists.txt +++ b/test/unit-test/CMakeLists.txt @@ -51,6 +51,7 @@ set(TEST_SOURCES ${CMAKE_CURRENT_LIST_DIR}/multi/test-continuable-base-errors.cpp ${CMAKE_CURRENT_LIST_DIR}/multi/test-continuable-base-partial.cpp ${CMAKE_CURRENT_LIST_DIR}/multi/test-continuable-base-multipath.cpp + ${CMAKE_CURRENT_LIST_DIR}/multi/test-continuable-base-executors.cpp ${CMAKE_CURRENT_LIST_DIR}/multi/test-continuable-connection-all-seq-ag-1.cpp ${CMAKE_CURRENT_LIST_DIR}/multi/test-continuable-connection-all-seq-ag-2.cpp ${CMAKE_CURRENT_LIST_DIR}/multi/test-continuable-connection-all-seq-op.cpp diff --git a/test/unit-test/multi/test-continuable-base-executors.cpp b/test/unit-test/multi/test-continuable-base-executors.cpp new file mode 100644 index 0000000..a424e0c --- /dev/null +++ b/test/unit-test/multi/test-continuable-base-executors.cpp @@ -0,0 +1,68 @@ + +/* + Copyright(c) 2015 - 2019 Denis Blank + + 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 + +using namespace cti; +using namespace cti::detail; + +TYPED_TEST(single_dimension_tests, are_executor_dispatchable) { + bool invoked = false; + auto executor = [&](auto&& work) { + // We can move the worker object + auto local = std::forward(work); + ASSERT_FALSE(invoked); + // We can invoke the worker object + std::move(local)(); + ASSERT_TRUE(invoked); + }; + + auto chain = this->supply().then( + [&] { + ASSERT_FALSE(invoked); + invoked = true; + }, + executor); + + ASSERT_ASYNC_COMPLETION(std::move(chain)); +} + +TYPED_TEST(single_dimension_tests, are_executor_exception_resolveable) { + auto executor = [&](work work) { + work.set_exception(supply_test_exception()); // + }; + + ASSERT_ASYNC_EXCEPTION_RESULT(async_on( + [] { + FAIL(); // + }, + executor), + get_test_exception_proto()); + + ASSERT_ASYNC_EXCEPTION_RESULT(this->supply().then( + [] { + FAIL(); // + }, + executor), + get_test_exception_proto()); +} diff --git a/test/unit-test/multi/test-continuable-base-partial.cpp b/test/unit-test/multi/test-continuable-base-partial.cpp index ebcc58b..b952c25 100644 --- a/test/unit-test/multi/test-continuable-base-partial.cpp +++ b/test/unit-test/multi/test-continuable-base-partial.cpp @@ -36,24 +36,3 @@ TYPED_TEST(single_dimension_tests, are_partial_callable) { EXPECT_EQ(b, 0xDD); })); } - -TYPED_TEST(single_dimension_tests, are_dispatchable) { - bool invoked = false; - auto executor = [&](auto&& work) { - // We can move the worker object - auto local = std::forward(work); - ASSERT_FALSE(invoked); - // We can invoke the worker object - std::move(local)(); - ASSERT_TRUE(invoked); - }; - - auto chain = this->supply().then( - [&] { - ASSERT_FALSE(invoked); - invoked = true; - }, - executor); - - ASSERT_ASYNC_COMPLETION(std::move(chain)); -}