| @@ -3,7 +3,9 @@ | |||
| #include "core/future.h" | |||
| #include "core/result.h" | |||
| #include "core/stream.h" | |||
| #include "core/task.h" | |||
| #include "core/future.inl" | |||
| #include "core/result.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()); | |||
| } | |||