| @@ -3,7 +3,9 @@ | |||||
| #include "core/future.h" | #include "core/future.h" | ||||
| #include "core/result.h" | #include "core/result.h" | ||||
| #include "core/stream.h" | #include "core/stream.h" | ||||
| #include "core/task.h" | |||||
| #include "core/future.inl" | #include "core/future.inl" | ||||
| #include "core/result.inl" | #include "core/result.inl" | ||||
| #include "core/stream.inl" | #include "core/stream.inl" | ||||
| #include "core/task.inl" | |||||
| @@ -0,0 +1,73 @@ | |||||
| #pragma once | |||||
| #include <memory> | |||||
| namespace asyncpp | |||||
| { | |||||
| struct task | |||||
| { | |||||
| public: | |||||
| /** | |||||
| * @brief Destructor. | |||||
| */ | |||||
| virtual ~task() = default; | |||||
| /** | |||||
| * @brief Poll the future stored in the task. | |||||
| * | |||||
| * @return TRUE if the task is finished, FALSE otherwise. | |||||
| */ | |||||
| bool poll(); | |||||
| private: | |||||
| /** | |||||
| * @brief Actual implementation of the poll function. | |||||
| */ | |||||
| virtual bool poll_impl() = 0; | |||||
| private: | |||||
| struct storage | |||||
| { | |||||
| task* current { nullptr }; | |||||
| }; | |||||
| /** | |||||
| * @brief Get the thread local storage. | |||||
| */ | |||||
| static inline storage& local_storage(); | |||||
| }; | |||||
| template<typename T_future> | |||||
| struct task_tpl | |||||
| : public task | |||||
| { | |||||
| public: | |||||
| using future_type = T_future; | |||||
| private: | |||||
| future_type _future; | |||||
| public: | |||||
| /** | |||||
| * @brief Constructor. | |||||
| */ | |||||
| template<typename X_future> | |||||
| inline task_tpl(X_future&& p_future); | |||||
| private: | |||||
| /** | |||||
| * @brief Actual implementation of the poll function. | |||||
| */ | |||||
| inline bool poll_impl() override; | |||||
| }; | |||||
| using task_ptr_s = std::shared_ptr<task>; | |||||
| /** | |||||
| * @brief Create a task from the passed future. | |||||
| */ | |||||
| template<typename X_future> | |||||
| inline task_ptr_s make_task(X_future&& p_future); | |||||
| } | |||||
| @@ -0,0 +1,66 @@ | |||||
| #pragma once | |||||
| namespace asyncpp | |||||
| { | |||||
| namespace __impl | |||||
| { | |||||
| struct current_lock | |||||
| { | |||||
| task* owner; | |||||
| task*& storage; | |||||
| current_lock( | |||||
| task* p_owner, | |||||
| task*& p_storage) | |||||
| : owner (p_owner) | |||||
| , storage (p_storage) | |||||
| { | |||||
| if (storage) | |||||
| throw std::runtime_error("Thread local task instance is already assigned!"); | |||||
| storage = owner; | |||||
| } | |||||
| ~current_lock() | |||||
| { storage = nullptr; } | |||||
| }; | |||||
| } | |||||
| /* task */ | |||||
| bool task::poll() | |||||
| { | |||||
| __impl::current_lock l(this, local_storage().current); | |||||
| return poll_impl(); | |||||
| } | |||||
| task::storage& task::local_storage() | |||||
| { | |||||
| thread_local storage value; | |||||
| return value; | |||||
| } | |||||
| /* task_tpl */ | |||||
| template<typename T_future> | |||||
| template<typename X_future> | |||||
| task_tpl<T_future>::task_tpl(X_future&& p_future) | |||||
| : _future(std::forward<X_future>(p_future)) | |||||
| { } | |||||
| template<typename T_future> | |||||
| bool task_tpl<T_future>::poll_impl() | |||||
| { return _future.poll().is_ready(); } | |||||
| /* misc */ | |||||
| template<typename X_future> | |||||
| task_ptr_s make_task(X_future&& p_future) | |||||
| { | |||||
| using task_type = task_tpl<X_future>; | |||||
| return std::make_shared<task_type>(std::forward<X_future>(p_future)); | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,48 @@ | |||||
| #include <gtest/gtest.h> | |||||
| #include <asyncpp.h> | |||||
| using namespace ::testing; | |||||
| using namespace ::asyncpp; | |||||
| struct delay | |||||
| { | |||||
| int const delay { 5 }; | |||||
| int count { 0 }; | |||||
| }; | |||||
| namespace asyncpp | |||||
| { | |||||
| template<> | |||||
| struct future_trait<delay, void> | |||||
| : public future_base<future<delay, void>> | |||||
| { | |||||
| using value_type = int&; | |||||
| template<typename T_future> | |||||
| static inline auto poll(T_future& self) | |||||
| { | |||||
| using result_type = future_result<value_type>; | |||||
| if (self.ref.count >= self.ref.delay) | |||||
| return result_type::ready(self.ref.count); | |||||
| ++self.ref.count; | |||||
| return result_type::not_ready(); | |||||
| } | |||||
| }; | |||||
| } | |||||
| TEST(task_tests, poll) | |||||
| { | |||||
| auto t = make_task(as_future(delay { 5, 0 })); | |||||
| ASSERT_FALSE(t->poll()); | |||||
| ASSERT_FALSE(t->poll()); | |||||
| ASSERT_FALSE(t->poll()); | |||||
| ASSERT_FALSE(t->poll()); | |||||
| ASSERT_FALSE(t->poll()); | |||||
| ASSERT_TRUE (t->poll()); | |||||
| } | |||||