diff --git a/include/continuable/continuable-base.hpp b/include/continuable/continuable-base.hpp index 3ff5be4..5ea75b0 100644 --- a/include/continuable/continuable-base.hpp +++ b/include/continuable/continuable-base.hpp @@ -436,14 +436,15 @@ public: return std::move(*this).then(detail::base::convert_to{}); } - /// A method which allows to apply this continuable to the given callable. + /// A method which allows to apply a callable object to this continuable. /// - /// \param transform A transform which shall accept 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 /// continuable is passed into it. /// - /// \since 2.0.0 + /// \since 4.0.0 template auto apply(T&& transform) && { return std::forward(transform)(std::move(*this).finish()); @@ -462,22 +463,6 @@ public: return std::move(*this).then(std::forward(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 - auto operator|(detail::types::transform transform) && { - return std::move(*this).apply(std::move(transform)); - } - /// Invokes both continuable_base objects parallel and calls the /// callback with the result of both continuable_base objects. /// diff --git a/include/continuable/continuable-transforms.hpp b/include/continuable/continuable-transforms.hpp index 5ec48d7..0d2561c 100644 --- a/include/continuable/continuable-transforms.hpp +++ b/include/continuable/continuable-transforms.hpp @@ -31,8 +31,8 @@ #ifndef CONTINUABLE_TRANSFORMS_HPP_INCLUDED #define CONTINUABLE_TRANSFORMS_HPP_INCLUDED -#include -#include +#include +#include namespace cti { /// \defgroup Transforms Transforms @@ -41,70 +41,12 @@ namespace cti { /// types such as (`std::future`). /// \{ -/// A callable tag object which marks a wrapped callable object -/// as continuable transformation which enables some useful overloads. -/// -/// \since 3.0.0 -template -using transform = detail::types::transform; - -/// Wraps the given callable object into a transform class. -/// -/// \since 3.0.0 -template -auto make_transform(T&& callable) { - return transform>(std::forward(callable)); -} - /// The namespace transforms declares callable objects that transform /// any continuable_base to an object or to a continuable_base itself. /// /// Transforms can be applied to continuables through using /// the cti::continuable_base::apply method accordingly. -namespace transforms { -/// 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` | -/// | `continuable_base with ` | `std::future` | -/// | `continuable_base with ` | `std::future>` | -/// -/// \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(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(continuable).fail([](auto&&) {}); - }); -} -/// \} -} // namespace transforms +namespace transforms {} } // namespace cti #endif // CONTINUABLE_TRANSFORMS_HPP_INCLUDED diff --git a/include/continuable/continuable.hpp b/include/continuable/continuable.hpp index cbbc43a..ad932ed 100644 --- a/include/continuable/continuable.hpp +++ b/include/continuable/continuable.hpp @@ -53,7 +53,6 @@ namespace cti {} #include #include #include -#include #include #include #include diff --git a/include/continuable/detail/core/types.hpp b/include/continuable/detail/core/types.hpp index f0c1de9..a47dd1a 100644 --- a/include/continuable/detail/core/types.hpp +++ b/include/continuable/detail/core/types.hpp @@ -66,16 +66,6 @@ using exception_t = std::error_condition; /// A tag which is used to execute the continuation inside the current thread struct this_thread_executor_tag {}; -/// Marks a given callable object as transformation -template -class transform : T { -public: - explicit transform(T callable) : T(std::move(callable)) { - } - - using T::operator(); -}; - /// Marks a given callable object as transformation template class plain_tag { diff --git a/include/continuable/detail/other/transforms.hpp b/include/continuable/detail/transforms/future.hpp similarity index 94% rename from include/continuable/detail/other/transforms.hpp rename to include/continuable/detail/transforms/future.hpp index 95bd748..ffccdf4 100644 --- a/include/continuable/detail/other/transforms.hpp +++ b/include/continuable/detail/transforms/future.hpp @@ -28,8 +28,8 @@ SOFTWARE. **/ -#ifndef CONTINUABLE_DETAIL_TRANSFORMS_HPP_INCLUDED -#define CONTINUABLE_DETAIL_TRANSFORMS_HPP_INCLUDED +#ifndef CONTINUABLE_DETAIL_TRANSFORMS_FUTURE_HPP_INCLUDED +#define CONTINUABLE_DETAIL_TRANSFORMS_FUTURE_HPP_INCLUDED #include #include @@ -115,7 +115,7 @@ public: /// Transforms the continuation to a future template -auto as_future(continuable_base&& continuable) { +auto to_future(continuable_base&& continuable) { // Create the promise which is able to supply the current arguments constexpr auto const hint = base::annotation_of(identify{}); @@ -135,4 +135,4 @@ auto as_future(continuable_base&& continuable) { } // namespace detail } // namespace cti -#endif // CONTINUABLE_DETAIL_TRANSFORMS_HPP_INCLUDED +#endif // CONTINUABLE_DETAIL_TRANSFORMS_FUTURE_HPP_INCLUDED diff --git a/include/continuable/detail/transforms/wait.hpp b/include/continuable/detail/transforms/wait.hpp new file mode 100644 index 0000000..1235c04 --- /dev/null +++ b/include/continuable/detail/transforms/wait.hpp @@ -0,0 +1,134 @@ + +/* + + /~` _ _ _|_. _ _ |_ | _ + \_,(_)| | | || ||_|(_||_)|(/_ + + 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_DETAIL_TRANSFORMS_WAIT_HPP_INCLUDED +#define CONTINUABLE_DETAIL_TRANSFORMS_WAIT_HPP_INCLUDED + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(CONTINUABLE_HAS_EXCEPTIONS) +# include +#endif + +namespace cti { +namespace detail { +namespace transforms { + +/* +template +struct sync_trait { + /// The promise type used to create the future + using promise_t = std::tuple; + /// Boxes the argument pack into a tuple + static void resolve(promise_t& promise, Args... args) { + promise.set_value(std::make_tuple(std::move(args)...)); + } +}; +template <> +struct sync_trait<> { + /// The promise type used to create the future + using promise_t = result; + /// Boxes the argument pack into void + static void resolve(promise_t& promise) { + promise.set_value(); + } +}; +template +struct sync_trait { + /// The promise type used to create the future + using promise_t = std::promise; + /// Boxes the argument pack into nothing + static void resolve(promise_t& promise, First first) { + promise.set_value(std::move(first)); + } +}; +*/ + +template +struct sync_trait; +template +struct sync_trait> { + using result_t = result; +}; + +/// Transforms the continuation to sync execution +template +auto wait(continuable_base&& continuable) { + constexpr auto hint = base::annotation_of(identify{}); + using result_t = typename sync_trait>::result_t; + (void)hint; + + std::recursive_mutex mutex; + std::condition_variable_any cv; + std::atomic_bool ready{false}; + result_t sync_result; + + std::move(continuable) + .next([&](auto&&... args) { + sync_result = result_t::from(std::forward(args)...); + + ready.store(true, std::memory_order_release); + cv.notify_all(); + }) + .done(); + + if (!ready.load(std::memory_order_acquire)) { + std::unique_lock lock(mutex); + cv.wait(lock, [&] { + return ready.load(std::memory_order_acquire); + }); + } + +#if defined(CONTINUABLE_HAS_EXCEPTIONS) + if (sync_result.is_value()) { + return std::move(sync_result).get_value(); + } else { + assert(sync_result.is_exception()); + std::rethrow_exception(sync_result.get_exception()); + } +#else + return sync_result; +#endif // CONTINUABLE_HAS_EXCEPTIONS +} +} // namespace transforms +} // namespace detail +} // namespace cti + +#endif // CONTINUABLE_DETAIL_TRANSFORMS_WAIT_HPP_INCLUDED diff --git a/include/continuable/transforms/future.hpp b/include/continuable/transforms/future.hpp new file mode 100644 index 0000000..2b6da08 --- /dev/null +++ b/include/continuable/transforms/future.hpp @@ -0,0 +1,72 @@ + +/* + + /~` _ _ _|_. _ _ |_ | _ + \_,(_)| | | || ||_|(_||_)|(/_ + + 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_TRANSFORMS_FUTURE_HPP_INCLUDED +#define CONTINUABLE_TRANSFORMS_FUTURE_HPP_INCLUDED + +#include +#include + +namespace cti { +/// \ingroup 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` | +/// | `continuable_base with ` | `std::future` | +/// | `continuable_base with ` | `std::future>` | +/// +/// \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 to_future() { + return [](auto&& continuable) { + return detail::transforms::to_future( + std::forward(continuable)); + }; +} +} // namespace transforms +/// \} +} // namespace cti + +#endif // CONTINUABLE_OPERATIONS_SPLIT_HPP_INCLUDED diff --git a/include/continuable/transforms/wait.hpp b/include/continuable/transforms/wait.hpp new file mode 100644 index 0000000..4ae8914 --- /dev/null +++ b/include/continuable/transforms/wait.hpp @@ -0,0 +1,68 @@ + +/* + + /~` _ _ _|_. _ _ |_ | _ + \_,(_)| | | || ||_|(_||_)|(/_ + + 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_TRANSFORMS_WAIT_HPP_INCLUDED +#define CONTINUABLE_TRANSFORMS_WAIT_HPP_INCLUDED + +#include +#include + +namespace cti { +/// \ingroup Transforms +/// \{ + +namespace transforms { +/// Returns a transform that if applied to a continuable, +/// it will start the continuation chain and returns the result synchronously. +/// The current thread is blocked until the continuation chain is finished. +/// +/// \returns Returns a value that is available immediately. +/// The signature of the future depends on the result type: +/// | Continuation type | Return type | +/// | : ------------------------------- | : -------------------------------- | +/// | `continuable_base with <>` | `void` | +/// | `continuable_base with ` | `Arg` | +/// | `continuable_base with ` | `std::tuple` | +/// +/// \attention If exceptions are used, exceptions that are thrown, are rethrown +/// synchronously. +/// +/// \since 4.0.0 +inline auto wait() { + return [](auto&& continuable) { + return detail::transforms::wait( + std::forward(continuable)); + }; +} +} // namespace transforms +/// \} +} // namespace cti + +#endif // CONTINUABLE_TRANSFORMS_WAIT_HPP_INCLUDED diff --git a/test/playground/test-playground.cpp b/test/playground/test-playground.cpp index 997e85c..a413533 100644 --- a/test/playground/test-playground.cpp +++ b/test/playground/test-playground.cpp @@ -20,9 +20,37 @@ SOFTWARE. **/ +#include +#include +#include #include +#include +#include using namespace cti; +using namespace std::chrono_literals; int main(int, char**) { + asio::io_context ioc(1); + asio::steady_timer t(ioc); + auto work = std::make_shared(ioc); + + t.expires_after(1s); + + std::thread th([&] { + ioc.run(); + puts("io_context finished"); + }); + + int res = t.async_wait(cti::use_continuable) + .then([] { + return 1; + }) + .apply(transforms::wait()); + + puts("async_wait finished"); + work.reset(); + + th.join(); + return 0; } diff --git a/test/unit-test/multi/test-continuable-transforms.cpp b/test/unit-test/multi/test-continuable-transforms.cpp index 36e20ec..de323da 100644 --- a/test/unit-test/multi/test-continuable-transforms.cpp +++ b/test/unit-test/multi/test-continuable-transforms.cpp @@ -21,22 +21,27 @@ SOFTWARE. **/ +#include +#include +#include + #include #include using namespace cti; using namespace cti::detail; +using namespace std::chrono_literals; template bool is_ready(T& future) { // Check that the future is ready - return future.wait_for(std::chrono::seconds(0)) == std::future_status::ready; + return future.wait_for(0s) == std::future_status::ready; } -TYPED_TEST(single_dimension_tests, are_convertible_to_futures) { +TYPED_TEST(single_dimension_tests, to_future_test) { { - auto future = this->supply().apply(cti::transforms::futurize()); + auto future = this->supply().apply(cti::transforms::to_future()); ASSERT_TRUE(is_ready(future)); future.get(); } @@ -47,7 +52,7 @@ TYPED_TEST(single_dimension_tests, are_convertible_to_futures) { // ... return 0xFD; }) - .apply(cti::transforms::futurize()); + .apply(cti::transforms::to_future()); ASSERT_TRUE(is_ready(future)); EXPECT_EQ(future.get(), 0xFD); @@ -56,19 +61,20 @@ TYPED_TEST(single_dimension_tests, are_convertible_to_futures) { { auto canary = std::make_tuple(0xFD, 0xF5); - auto future = this->supply().then([&] { - // ... - return canary; - }) | cti::transforms::futurize(); + auto future = this->supply() + .then([&] { + // ... + return canary; + }) + .apply(cti::transforms::to_future()); ASSERT_TRUE(is_ready(future)); EXPECT_EQ(future.get(), canary); } } -TYPED_TEST(single_dimension_tests, are_flattable) { - auto continuation = this->supply_exception(supply_test_exception()) - .apply(cti::transforms::flatten()); - - ASSERT_ASYNC_INCOMPLETION(std::move(continuation)); +TYPED_TEST(single_dimension_tests, to_wait_test) { + { + this->supply().apply(cti::transforms::wait()); // + } }