From a2fdfdfcebadb34ea5efbafe2f0bfaedf69573b9 Mon Sep 17 00:00:00 2001 From: Denis Blank Date: Mon, 2 Sep 2019 00:01:26 +0200 Subject: [PATCH] Use a promise<> for work rather than a dedicated work_base --- include/continuable/continuable-types.hpp | 11 +- include/continuable/continuable-work-base.hpp | 135 ------------------ include/continuable/continuable.hpp | 1 - include/continuable/detail/core/base.hpp | 14 +- .../continuable/detail/operations/split.hpp | 4 +- include/continuable/detail/other/erasure.hpp | 113 ++++++++------- .../multi/test-continuable-base-executors.cpp | 24 +++- 7 files changed, 99 insertions(+), 203 deletions(-) delete mode 100644 include/continuable/continuable-work-base.hpp diff --git a/include/continuable/continuable-types.hpp b/include/continuable/continuable-types.hpp index c83aee9..71d23fd 100644 --- a/include/continuable/continuable-types.hpp +++ b/include/continuable/continuable-types.hpp @@ -35,7 +35,6 @@ #include #include #include -#include #include namespace cti { @@ -83,8 +82,11 @@ using promise = promise_base, // signature_arg_t>; /// Defines a non-copyable type erasure which is capable of carrying -/// callable objects passed to executors. Additionally the outstanding work -/// can be resolved through an exception. +/// callable objects passed to executors. +/// +/// The work behaves like a `promise<>` but the work type erasure uses extra +/// stack space for small object optimization. +/// Additionally the outstanding work can be resolved through an exception. /// /// \note You can always define your own cancelable_work with a type erasure of /// choice, the type erasure wrapper just needs to accept a @@ -92,7 +94,8 @@ using promise = promise_base, // /// `void(exception_arg_t, exception_t)` signature. /// /// \since 4.0.0 -using work = work_base; +using work = promise_base>; /// \} } // namespace cti diff --git a/include/continuable/continuable-work-base.hpp b/include/continuable/continuable-work-base.hpp deleted file mode 100644 index 06f3aae..0000000 --- a/include/continuable/continuable-work-base.hpp +++ /dev/null @@ -1,135 +0,0 @@ - -/* - - /~` _ _ _|_. _ _ |_ | _ - \_,(_)| | | || ||_|(_||_)|(/_ - - https://github.com/Naios/continuable - v4.0.0 - - 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. -**/ - -#ifndef CONTINUABLE_WORK_BASE_HPP_INCLUDED -#define CONTINUABLE_WORK_BASE_HPP_INCLUDED - -#include -#include -#include -#include -#include -#include -#include -#include - -namespace cti { -/// \defgroup Base Base -/// provides classes and functions to create continuable_base objects. -/// \{ - -/// The work_base makes it possible to resolve an asynchronous -/// work on a different execution context than the current one. -/// -/// 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 -class work_base - /// \cond false - : detail::util::non_copyable -/// \endcond -{ // clang-format on - - /// \cond false - // The work type - Data data_; - /// \endcond - -public: - /// Constructor accepting the data object - explicit work_base(Data data) : data_(std::move(data)) { - } - - /// \cond false - work_base(work_base&&) = default; - work_base(work_base const&) = delete; - - work_base& operator=(work_base&&) = default; - work_base& operator=(work_base const&) = delete; - /// \endcond - - /// Constructor accepting any object convertible to the data object - template , Data>::value>* = nullptr> - /* implicit */ work_base(OData&& data) : data_(std::forward(data)) { - } - - /// Assignment operator accepting any object convertible to the data object - template , Data>::value>* = nullptr> - work_base& operator=(OData&& data) { - data_ = std::forward(data); - return *this; - } - - /// Invokes the underlying work - /// - /// \throws This method never throws an exception. - /// - /// \attention This method may only be called once! - /// - /// \since 4.0.0 - void set_value() noexcept { - std::move(data_)(); - data_ = nullptr; - } - - /// Passes an exception to the underlying work - /// - /// \throws This method never throws an exception. - /// - /// \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 - -#endif // CONTINUABLE_WORK_BASE_HPP_INCLUDED diff --git a/include/continuable/continuable.hpp b/include/continuable/continuable.hpp index c1564c7..cbbc43a 100644 --- a/include/continuable/continuable.hpp +++ b/include/continuable/continuable.hpp @@ -57,6 +57,5 @@ namespace cti {} #include #include #include -#include #endif // CONTINUABLE_HPP_INCLUDED diff --git a/include/continuable/detail/core/base.hpp b/include/continuable/detail/core/base.hpp index 2b8b475..e41c1d0 100644 --- a/include/continuable/detail/core/base.hpp +++ b/include/continuable/detail/core/base.hpp @@ -523,6 +523,10 @@ public: std::move(next_callback_)(exception_arg_t{}, std::move(exception)); } + explicit operator bool() const noexcept { + return true; + } + private: Invoker invoker_; Callback callback_; @@ -671,12 +675,12 @@ struct callback_base, HandleResults, HandleErrors, Callback, Executor, NextCallback>>::operator(); /// Resolves the continuation with the given values - void set_value(Args... args) { + void set_value(Args... args) noexcept { std::move (*this)(std::move(args)...); } /// Resolves the continuation with the given error variable. - void set_exception(exception_t error) { + void set_exception(exception_t error) noexcept { std::move (*this)(exception_arg_t{}, std::move(error)); } @@ -725,13 +729,13 @@ struct final_callback : util::non_copyable { #endif // CONTINUABLE_WITH_UNHANDLED_EXCEPTIONS } - void set_value(Args... args) { + void set_value(Args... args) noexcept { std::move (*this)(std::forward(args)...); } - void set_exception(exception_t error) { + void set_exception(exception_t exception) noexcept { // NOLINTNEXTLINE(hicpp-move-const-arg, performance-move-const-arg) - std::move (*this)(exception_arg_t{}, std::move(error)); + std::move (*this)(exception_arg_t{}, std::move(exception)); } explicit operator bool() const noexcept { diff --git a/include/continuable/detail/operations/split.hpp b/include/continuable/detail/operations/split.hpp index 1d29a95..229ed4a 100644 --- a/include/continuable/detail/operations/split.hpp +++ b/include/continuable/detail/operations/split.hpp @@ -85,11 +85,11 @@ public: } template - void set_value(Args... args) { + void set_value(Args... args) noexcept { std::move (*this)(std::move(args)...); } - void set_exception(exception_t error) { + void set_exception(exception_t error) noexcept { std::move (*this)(exception_arg_t{}, std::move(error)); } diff --git a/include/continuable/detail/other/erasure.hpp b/include/continuable/detail/other/erasure.hpp index c42b91c..b3b340e 100644 --- a/include/continuable/detail/other/erasure.hpp +++ b/include/continuable/detail/other/erasure.hpp @@ -87,11 +87,12 @@ public: return *this; } - void operator()(Args... args) && { + void operator()(Args... args) && noexcept { std::move(erasure_)(std::move(args)...); } - void operator()(exception_arg_t exception_arg, exception_t exception) && { + void operator()(exception_arg_t exception_arg, exception_t exception) && + noexcept { std::move(erasure_)(exception_arg, std::move(exception)); } @@ -101,6 +102,62 @@ public: }; #endif +using work_erasure_t = + fu2::function_base, true, false, + void()&&, void(exception_arg_t, exception_t) &&>; + +#ifdef CONTINUABLE_HAS_IMMEDIATE_TYPES +using work = work_erasure_t; +#else +class work; + +template +struct is_work : std::false_type {}; +template <> +struct is_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::value>* = nullptr, + std::enable_if_t>::value>* = nullptr> + /* implicit */ work(T&& callable) : erasure_(std::forward(callable)) { + } + + template < + typename T, + std::enable_if_t::value>* = nullptr, + std::enable_if_t>::value>* = nullptr> + work& operator=(T&& callable) { + erasure_ = std::forward(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 struct continuation_capacity { using type = union { @@ -177,58 +234,6 @@ public: } }; #endif - -using work_erasure_t = - fu2::function_base, true, false, - void()&&, void(exception_arg_t, exception_t) &&>; - -#ifdef CONTINUABLE_HAS_IMMEDIATE_TYPES -using work = work_erasure_t; -#else -class work; - -template -struct is_work : std::false_type {}; -template <> -struct is_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::value>* = nullptr, - std::enable_if_t>::value>* = nullptr> - /* implicit */ work(T&& callable) : erasure_(std::forward(callable)) { - } - - template < - typename T, - std::enable_if_t::value>* = nullptr, - std::enable_if_t>::value>* = nullptr> - work& operator=(T&& callable) { - erasure_ = std::forward(callable); - return *this; - } - - void operator()() && { - std::move(erasure_)(); - } - - void operator()(exception_arg_t, exception_t e) && { - std::move(erasure_)(exception_arg_t{}, std::move(e)); - } -}; -#endif } // namespace erasure } // namespace detail } // namespace cti diff --git a/test/unit-test/multi/test-continuable-base-executors.cpp b/test/unit-test/multi/test-continuable-base-executors.cpp index a424e0c..950b13f 100644 --- a/test/unit-test/multi/test-continuable-base-executors.cpp +++ b/test/unit-test/multi/test-continuable-base-executors.cpp @@ -48,8 +48,28 @@ TYPED_TEST(single_dimension_tests, are_executor_dispatchable) { } TYPED_TEST(single_dimension_tests, are_executor_exception_resolveable) { - auto executor = [&](work work) { - work.set_exception(supply_test_exception()); // + auto executor = [&](auto&& work) { + std::forward(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()); +} + +TYPED_TEST(single_dimension_tests, are_executor_exception_resolveable_erased) { + auto executor = [&](work work) { + std::move(work).set_exception(supply_test_exception()); // }; ASSERT_ASYNC_EXCEPTION_RESULT(async_on(