* Implemented 'for_each' stream method * More refactoring and unit testsmaster
@@ -8,4 +8,3 @@ | |||
#include "core/future.inl" | |||
#include "core/result.inl" | |||
#include "core/stream.inl" | |||
#include "core/task.inl" |
@@ -4,6 +4,7 @@ | |||
#include "result.h" | |||
#include "future.pre.h" | |||
#include "future/map.h" | |||
#include "future/and_then.h" | |||
@@ -20,6 +21,10 @@ namespace asyncpp | |||
using trait_type = future_trait<clean_object_type>; | |||
using value_type = typename trait_type::value_type; | |||
using result_type = future_result<value_type>; | |||
using reference = clean_object_type&; | |||
using pointer = clean_object_type*; | |||
using const_reference = const clean_object_type&; | |||
using const_pointer = const clean_object_type*; | |||
object_type ref; | |||
@@ -46,6 +51,12 @@ namespace asyncpp | |||
*/ | |||
template<typename X_lambda> | |||
inline auto and_then(X_lambda&& p_lambda); | |||
public: | |||
inline pointer operator->(); | |||
inline reference operator*(); | |||
inline const_pointer operator->() const; | |||
inline const_reference operator*() const; | |||
}; | |||
} |
@@ -76,6 +76,34 @@ namespace asyncpp | |||
::and_then(X_lambda&& p_lambda) | |||
{ return trait_type::and_then(std::move(*this), std::forward<X_lambda>(p_lambda)); } | |||
template< | |||
typename T_value, | |||
typename T_impl> | |||
typename future<T_value, T_impl>::pointer | |||
future<T_value, T_impl>::operator->() | |||
{ return &ref; } | |||
template< | |||
typename T_value, | |||
typename T_impl> | |||
typename future<T_value, T_impl>::reference | |||
future<T_value, T_impl>::operator*() | |||
{ return ref; } | |||
template< | |||
typename T_value, | |||
typename T_impl> | |||
typename future<T_value, T_impl>::const_pointer | |||
future<T_value, T_impl>::operator->() const | |||
{ return &ref; } | |||
template< | |||
typename T_value, | |||
typename T_impl> | |||
typename future<T_value, T_impl>::const_reference | |||
future<T_value, T_impl>::operator*() const | |||
{ return ref; } | |||
/* misc */ | |||
template<typename X_value> | |||
@@ -6,14 +6,18 @@ namespace asyncpp | |||
template<typename T_impl> | |||
struct future_base | |||
{ | |||
template<typename T_future> | |||
static inline auto poll(T_future& self) = delete; | |||
public: | |||
using impl_type = T_impl; | |||
template<typename T_future, typename T_lambda> | |||
static inline auto map(T_future&& self, T_lambda&& p_lambda); | |||
public: | |||
template<typename X_future> | |||
static inline auto poll(X_future& self) = delete; | |||
template<typename T_future, typename T_lambda> | |||
static inline auto and_then(T_future&& self, T_lambda&& p_lambda); | |||
template<typename X_future, typename X_lambda> | |||
static inline auto map(X_future&& self, X_lambda&& p_lambda); | |||
template<typename X_future, typename X_lambda> | |||
static inline auto and_then(X_future&& self, X_lambda&& p_lambda); | |||
}; | |||
template<typename T, typename = void> | |||
@@ -2,6 +2,8 @@ | |||
#include <memory> | |||
#include <asyncpp/core/future.pre.h> | |||
namespace asyncpp { | |||
namespace __future { | |||
@@ -11,16 +13,16 @@ namespace __future { | |||
struct and_then_impl | |||
{ | |||
public: | |||
using lambda_type = T_lambda; | |||
using outer_future_type = T_future; | |||
using outer_value_type = typename outer_future_type::value_type; | |||
using inner_future_type = decltype(as_future(std::declval<lambda_type>()(std::declval<outer_value_type>()))); | |||
using inner_future_type_ptr = std::unique_ptr<inner_future_type>; | |||
using lambda_type = T_lambda; | |||
using first_future_type = T_future; | |||
using first_value_type = typename first_future_type::value_type; | |||
using second_future_type = decltype(as_future(std::declval<lambda_type>()(std::declval<first_value_type>()))); | |||
using second_future_type_ptr = std::unique_ptr<second_future_type>; | |||
public: | |||
lambda_type lambda; | |||
outer_future_type outer; | |||
inner_future_type_ptr inner; | |||
first_future_type first; | |||
second_future_type_ptr second; | |||
public: | |||
/** | |||
@@ -35,3 +37,25 @@ namespace __future { | |||
}; | |||
} } | |||
namespace asyncpp | |||
{ | |||
/* future_trait for and_then_impl */ | |||
template< | |||
typename T_future, | |||
typename T_lambda> | |||
struct future_trait<__future::and_then_impl<T_future, T_lambda>, void> | |||
: public future_base<future<__future::and_then_impl<T_future, T_lambda>, void>> | |||
{ | |||
using and_then_type = __future::and_then_impl<T_future, T_lambda>; | |||
using second_future_type = typename and_then_type::second_future_type; | |||
using value_type = typename second_future_type::value_type; | |||
using result_type = typename second_future_type::result_type; | |||
template<typename X_future> | |||
static inline auto poll(X_future& self); | |||
}; | |||
} |
@@ -2,45 +2,6 @@ | |||
#include "map.h" | |||
namespace asyncpp | |||
{ | |||
/* future_trait for ant_then_impl */ | |||
template< | |||
typename T_future, | |||
typename T_lambda> | |||
struct future_trait<__future::and_then_impl<T_future, T_lambda>, void> | |||
: public future_base<future<__future::and_then_impl<T_future, T_lambda>, void>> | |||
{ | |||
using and_then_type = __future::and_then_impl<T_future, T_lambda>; | |||
using inner_future_type = typename and_then_type::inner_future_type; | |||
using value_type = typename inner_future_type::value_type; | |||
using result_type = typename inner_future_type::result_type; | |||
template<typename X_future> | |||
static inline auto poll(X_future& self) | |||
{ | |||
while (true) | |||
{ | |||
if (self.ref.inner) | |||
{ | |||
return self.ref.inner->poll(); | |||
} | |||
else | |||
{ | |||
auto r = self.ref.outer.poll(); | |||
if (!r) | |||
return result_type::not_ready(); | |||
self.ref.inner = std::make_unique<inner_future_type>(as_future(self.ref.lambda(*r))); | |||
} | |||
} | |||
} | |||
}; | |||
} | |||
namespace asyncpp { | |||
namespace __future { | |||
@@ -54,10 +15,42 @@ namespace __future { | |||
typename X_lambda> | |||
and_then_impl<T_future, T_lambda> | |||
::and_then_impl( | |||
X_future&& p_outer, | |||
X_future&& p_first, | |||
X_lambda&& p_lambda) | |||
: outer (std::forward<X_future>(p_outer)) | |||
: first (std::forward<X_future>(p_first)) | |||
, lambda(std::forward<X_lambda>(p_lambda)) | |||
{ } | |||
} } | |||
namespace asyncpp | |||
{ | |||
/* future_trait for ant_then_impl */ | |||
template< | |||
typename T_future, | |||
typename T_lambda> | |||
template< | |||
typename X_future> | |||
auto future_trait<__future::and_then_impl<T_future, T_lambda>, void> | |||
::poll(X_future& self) | |||
{ | |||
while (true) | |||
{ | |||
if (self->second) | |||
{ | |||
return self->second->poll(); | |||
} | |||
else | |||
{ | |||
auto r = self->first.poll(); | |||
if (!r) | |||
return result_type::not_ready(); | |||
self->second = std::make_unique<second_future_type>(as_future(self->lambda(*r))); | |||
} | |||
} | |||
} | |||
} |
@@ -29,3 +29,26 @@ namespace __future { | |||
}; | |||
} } | |||
namespace asyncpp | |||
{ | |||
/* future_trait for map_impl */ | |||
template< | |||
typename T_future, | |||
typename T_lambda> | |||
struct future_trait<__future::map_impl<T_future, T_lambda>, void> | |||
: public future_base<future<__future::map_impl<T_future, T_lambda>, void>> | |||
{ | |||
using future_type = T_future; | |||
using inner_value_type = typename future_type::value_type; | |||
using lambda_type = T_lambda; | |||
using value_type = decltype(std::declval<lambda_type>()(std::declval<inner_value_type>())); | |||
using result_type = future_result<value_type>; | |||
template<typename X_future> | |||
static inline auto poll(X_future& self); | |||
}; | |||
} |
@@ -2,35 +2,6 @@ | |||
#include "map.h" | |||
namespace asyncpp | |||
{ | |||
/* future_trait for map_impl */ | |||
template< | |||
typename T_future, | |||
typename T_lambda> | |||
struct future_trait<__future::map_impl<T_future, T_lambda>, void> | |||
: public future_base<future<__future::map_impl<T_future, T_lambda>, void>> | |||
{ | |||
using future_type = T_future; | |||
using inner_value_type = typename future_type::value_type; | |||
using lambda_type = T_lambda; | |||
using value_type = decltype(std::declval<lambda_type>()(std::declval<inner_value_type>())); | |||
using result_type = future_result<value_type>; | |||
template<typename X_future> | |||
static inline auto poll(X_future& self) | |||
{ | |||
auto r = self.ref.future.poll(); | |||
return r | |||
? result_type::ready(self.ref.lambda(*r)) | |||
: result_type::not_ready(); | |||
} | |||
}; | |||
} | |||
namespace asyncpp { | |||
namespace __future { | |||
@@ -51,3 +22,24 @@ namespace __future { | |||
{ } | |||
} } | |||
namespace asyncpp | |||
{ | |||
/* future_trait for map_impl */ | |||
template< | |||
typename T_future, | |||
typename T_lambda> | |||
template< | |||
typename X_future> | |||
auto future_trait<__future::map_impl<T_future, T_lambda>, void> | |||
::poll(X_future& self) | |||
{ | |||
auto r = self->future.poll(); | |||
return r | |||
? result_type::ready(self->lambda(*r)) | |||
: result_type::not_ready(); | |||
} | |||
} |
@@ -17,4 +17,12 @@ namespace asyncpp | |||
*/ | |||
inline time_point now(); | |||
/** | |||
* @brief Returns the lowest of the two passed deadlines (if not null) | |||
* or nullptr if no deadline was passed. | |||
*/ | |||
inline const time_point * merge_deadlines( | |||
const time_point * p_deadline_0, | |||
const time_point * p_deadline_1); | |||
} |
@@ -10,4 +10,28 @@ namespace timer { | |||
{ return clock::now(); } | |||
#endif | |||
const time_point * merge_deadlines( | |||
const time_point * p_deadline_0, | |||
const time_point * p_deadline_1) | |||
{ | |||
if (p_deadline_0 && p_deadline_1) | |||
{ | |||
return *p_deadline_0 < *p_deadline_1 | |||
? p_deadline_0 | |||
: p_deadline_1; | |||
} | |||
else if (p_deadline_0) | |||
{ | |||
return p_deadline_0; | |||
} | |||
else if (p_deadline_1) | |||
{ | |||
return p_deadline_1; | |||
} | |||
else | |||
{ | |||
return nullptr; | |||
} | |||
} | |||
} } |
@@ -5,6 +5,8 @@ | |||
#include "result.h" | |||
#include "stream.pre.h" | |||
#include "stream/for_each.h" | |||
namespace asyncpp | |||
{ | |||
@@ -18,6 +20,10 @@ namespace asyncpp | |||
using trait_type = stream_trait<clean_object_type>; | |||
using value_type = typename trait_type::value_type; | |||
using result_type = stream_result<value_type>; | |||
using reference = clean_object_type&; | |||
using pointer = clean_object_type*; | |||
using const_reference = const clean_object_type&; | |||
using const_pointer = const clean_object_type*; | |||
object_type ref; | |||
@@ -31,6 +37,20 @@ namespace asyncpp | |||
* @brief Function that will be called repeatedly to check if the stream has values. | |||
*/ | |||
inline result_type poll(); | |||
/** | |||
* @brief Execute the given lambda for each element in the stream. | |||
* | |||
* @return Returns a future that completes once the stream is finished. | |||
*/ | |||
template<typename X_lambda> | |||
inline auto for_each(X_lambda&& p_lambda); | |||
public: | |||
inline pointer operator->(); | |||
inline reference operator*(); | |||
inline const_pointer operator->() const; | |||
inline const_reference operator*() const; | |||
}; | |||
} |
@@ -2,9 +2,27 @@ | |||
#include "stream.h" | |||
#include "stream/for_each.inl" | |||
namespace asyncpp | |||
{ | |||
/* stream_base */ | |||
template<typename T_impl> | |||
template<typename X_stream, typename X_lambda> | |||
auto stream_base<T_impl> | |||
::for_each(X_stream&& self, X_lambda&& p_lambda) | |||
{ | |||
using stream_type = X_stream; | |||
using lambda_type = X_lambda; | |||
using for_each_type = __stream::for_each_impl<stream_type, lambda_type>; | |||
return as_future(for_each_type( | |||
std::forward<X_stream>(self), | |||
std::forward<X_lambda>(p_lambda))); | |||
} | |||
/* stream */ | |||
template< | |||
@@ -25,6 +43,43 @@ namespace asyncpp | |||
::poll() | |||
{ return trait_type::poll(*this); } | |||
template< | |||
typename T_value, | |||
typename T_impl> | |||
template< | |||
typename X_lambda> | |||
auto stream<T_value, T_impl> | |||
::for_each(X_lambda&& p_lambda) | |||
{ return trait_type::for_each(std::move(*this), std::forward<X_lambda>(p_lambda)); } | |||
template< | |||
typename T_value, | |||
typename T_impl> | |||
typename stream<T_value, T_impl>::pointer | |||
stream<T_value, T_impl>::operator->() | |||
{ return &ref; } | |||
template< | |||
typename T_value, | |||
typename T_impl> | |||
typename stream<T_value, T_impl>::reference | |||
stream<T_value, T_impl>::operator*() | |||
{ return ref; } | |||
template< | |||
typename T_value, | |||
typename T_impl> | |||
typename stream<T_value, T_impl>::const_pointer | |||
stream<T_value, T_impl>::operator->() const | |||
{ return &ref; } | |||
template< | |||
typename T_value, | |||
typename T_impl> | |||
typename stream<T_value, T_impl>::const_reference | |||
stream<T_value, T_impl>::operator*() const | |||
{ return ref; } | |||
/* misc */ | |||
template<typename X_value> | |||
@@ -6,8 +6,15 @@ namespace asyncpp | |||
template<typename T_impl> | |||
struct stream_base | |||
{ | |||
template<typename T_stream> | |||
static inline auto poll(T_stream& self) = delete; | |||
public: | |||
using impl_type = T_impl; | |||
public: | |||
template<typename X_stream> | |||
static inline auto poll(X_stream& self) = delete; | |||
template<typename X_stream, typename X_lambda> | |||
static inline auto for_each(X_stream&& self, X_lambda&& p_lambda); | |||
}; | |||
template<typename T, typename = void> | |||
@@ -0,0 +1,56 @@ | |||
#pragma once | |||
#include <asyncpp/core/future.pre.h> | |||
namespace asyncpp { | |||
namespace __stream { | |||
template< | |||
typename T_stream, | |||
typename T_lambda> | |||
struct for_each_impl | |||
{ | |||
public: | |||
using stream_type = T_stream; | |||
using lambda_type = T_lambda; | |||
public: | |||
stream_type stream; | |||
lambda_type lambda; | |||
public: | |||
/** | |||
* @brief Constructor. | |||
*/ | |||
template< | |||
typename X_stream, | |||
typename X_lambda> | |||
inline for_each_impl( | |||
X_stream&& p_stream, | |||
X_lambda&& p_lambda); | |||
}; | |||
} } | |||
namespace asyncpp | |||
{ | |||
/* future_trait for map_impl */ | |||
template< | |||
typename T_stream, | |||
typename T_lambda> | |||
struct future_trait<__stream::for_each_impl<T_stream, T_lambda>, void> | |||
: public future_base<future<__stream::for_each_impl<T_stream, T_lambda>, void>> | |||
{ | |||
using stream_type = T_stream; | |||
using inner_value_type = typename stream_type::value_type; | |||
using lambda_type = T_lambda; | |||
using value_type = decltype(std::declval<lambda_type>()(std::declval<inner_value_type>())); | |||
using result_type = future_result<value_type>; | |||
template<typename X_future> | |||
static inline auto poll(X_future& self); | |||
}; | |||
} |
@@ -0,0 +1,52 @@ | |||
#pragma once | |||
#include "for_each.h" | |||
namespace asyncpp { | |||
namespace __stream { | |||
/* for_each_impl */ | |||
template< | |||
typename T_stream, | |||
typename T_lambda> | |||
template< | |||
typename X_stream, | |||
typename X_lambda> | |||
for_each_impl<T_stream, T_lambda> | |||
::for_each_impl( | |||
X_stream&& p_stream, | |||
X_lambda&& p_lambda) | |||
: stream(std::forward<X_stream>(p_stream)) | |||
, lambda(std::forward<X_lambda>(p_lambda)) | |||
{ } | |||
} } | |||
namespace asyncpp | |||
{ | |||
/* future_trait for for_each_impl */ | |||
template< | |||
typename T_stream, | |||
typename T_lambda> | |||
template< | |||
typename X_stream> | |||
auto future_trait<__stream::for_each_impl<T_stream, T_lambda>, void> | |||
::poll(X_stream& self) | |||
{ | |||
while (true) | |||
{ | |||
auto r = self->stream.poll(); | |||
if (r.is_done()) | |||
return result_type::ready(); | |||
if (r.is_not_ready()) | |||
return result_type::not_ready(); | |||
self->lambda(*r); | |||
} | |||
} | |||
} |
@@ -1,88 +1,9 @@ | |||
#pragma once | |||
#include <vector> | |||
#include <memory> | |||
#include <functional> | |||
#include "task/task.h" | |||
#include "task/task_tpl.h" | |||
#include "task/current_task_lock.h" | |||
namespace asyncpp | |||
{ | |||
struct task | |||
{ | |||
public: | |||
using notify_handler = std::function<void (task&)>; | |||
using notify_handler_vector = std::vector<notify_handler>; | |||
private: | |||
bool _notified; | |||
notify_handler_vector _notify_handlers; | |||
public: | |||
/** | |||
* @brief Destructor. | |||
*/ | |||
virtual ~task() = default; | |||
/** | |||
* @brief Check if the task is notified. | |||
*/ | |||
inline bool notified() const; | |||
/** | |||
* @brief Notify the task that a resource that the task is interested in, is ready to be polled. | |||
*/ | |||
inline void notify(); | |||
/** | |||
* @brief Poll the future stored in the task. | |||
* | |||
* @return TRUE if the task is finished, FALSE otherwise. | |||
*/ | |||
inline bool poll(); | |||
/** | |||
* @brief Add a callback to execute when the task is notified. | |||
*/ | |||
inline void add_notify_handler(notify_handler p_handler); | |||
private: | |||
/** | |||
* @brief Actual implementation of the poll function. | |||
*/ | |||
virtual bool poll_impl() = 0; | |||
}; | |||
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_w = std::weak_ptr<task>; | |||
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); | |||
} | |||
#include "task/task.inl" | |||
#include "task/task_tpl.inl" | |||
#include "task/current_task_lock.inl" |
@@ -0,0 +1,23 @@ | |||
#pragma once | |||
#include "task.h" | |||
#include "current_task_lock.pre.h" | |||
namespace asyncpp | |||
{ | |||
struct current_task_lock | |||
{ | |||
public: | |||
/** | |||
* @brief Constructor. | |||
*/ | |||
current_task_lock(const task_ptr_s& p_task); | |||
/** | |||
* @brief Destructor. | |||
*/ | |||
~current_task_lock(); | |||
}; | |||
} |
@@ -0,0 +1,16 @@ | |||
#pragma once | |||
#include "current_task_lock.h" | |||
namespace asyncpp | |||
{ | |||
/* current_task_lock */ | |||
current_task_lock::current_task_lock(const task_ptr_s& p_task) | |||
{ task::local_storage().current = p_task; } | |||
current_task_lock::~current_task_lock() | |||
{ task::local_storage().current.reset(); } | |||
} |
@@ -0,0 +1,8 @@ | |||
#pragma once | |||
namespace asyncpp | |||
{ | |||
struct current_task_lock; | |||
} |
@@ -0,0 +1,76 @@ | |||
#pragma once | |||
#include <vector> | |||
#include <functional> | |||
#include "task.pre.h" | |||
#include "current_task_lock.pre.h" | |||
namespace asyncpp | |||
{ | |||
struct task | |||
{ | |||
public: | |||
friend current_task_lock; | |||
using notify_handler = std::function<void (task&)>; | |||
using notify_handler_vector = std::vector<notify_handler>; | |||
private: | |||
bool _notified; | |||
notify_handler_vector _notify_handlers; | |||
public: | |||
/** | |||
* @brief Destructor. | |||
*/ | |||
virtual ~task() = default; | |||
/** | |||
* @brief Check if the task is notified. | |||
*/ | |||
inline bool notified() const; | |||
/** | |||
* @brief Notify the task that a resource that the task is interested in, is ready to be polled. | |||
*/ | |||
inline void notify(); | |||
/** | |||
* @brief Poll the future stored in the task. | |||
* | |||
* @return TRUE if the task is finished, FALSE otherwise. | |||
*/ | |||
inline bool poll(); | |||
/** | |||
* @brief Add a callback to execute when the task is notified. | |||
*/ | |||
inline void add_notify_handler(notify_handler p_handler); | |||
public: | |||
/** | |||
* @brief Get reference of the current task. | |||
*/ | |||
static inline const task_ptr_w& current(); | |||
private: | |||
/** | |||
* @brief Actual implementation of the poll function. | |||
*/ | |||
virtual bool poll_impl() = 0; | |||
private: | |||
struct storage | |||
{ | |||
task_ptr_w current; | |||
}; | |||
/** | |||
* @brief Get the thread local storage. | |||
*/ | |||
static storage& local_storage(); | |||
}; | |||
} |
@@ -0,0 +1,37 @@ | |||
#pragma once | |||
namespace asyncpp | |||
{ | |||
/* task */ | |||
bool task::poll() | |||
{ | |||
_notified = false; | |||
return poll_impl(); | |||
} | |||
bool task::notified() const | |||
{ return _notified; } | |||
void task::notify() | |||
{ | |||
_notified = true; | |||
for (auto& h : _notify_handlers) | |||
h(*this); | |||
} | |||
void task::add_notify_handler(notify_handler p_handler) | |||
{ _notify_handlers.emplace_back(p_handler); } | |||
const task_ptr_w& task::current() | |||
{ return local_storage().current; } | |||
task::storage& task::local_storage() | |||
{ | |||
thread_local storage value { }; | |||
return value; | |||
} | |||
} |
@@ -0,0 +1,13 @@ | |||
#pragma once | |||
#include <memory> | |||
namespace asyncpp | |||
{ | |||
struct task; | |||
using task_ptr_w = std::weak_ptr<task>; | |||
using task_ptr_s = std::shared_ptr<task>; | |||
} |
@@ -0,0 +1,32 @@ | |||
#pragma once | |||
#include "task.h" | |||
namespace asyncpp | |||
{ | |||
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; | |||
}; | |||
} |
@@ -1,30 +1,10 @@ | |||
#pragma once | |||
#include "task_tpl.h" | |||
namespace asyncpp | |||
{ | |||
/* task */ | |||
bool task::poll() | |||
{ | |||
_notified = false; | |||
return poll_impl(); | |||
} | |||
bool task::notified() const | |||
{ return _notified; } | |||
void task::notify() | |||
{ | |||
_notified = true; | |||
for (auto& h : _notify_handlers) | |||
h(*this); | |||
} | |||
void task::add_notify_handler(notify_handler p_handler) | |||
{ _notify_handlers.emplace_back(p_handler); } | |||
/* task_tpl */ | |||
template<typename T_future> |
@@ -8,24 +8,6 @@ namespace executor { | |||
namespace __impl | |||
{ | |||
struct current_task_lock | |||
{ | |||
private: | |||
executor::storage& _storage; | |||
public: | |||
current_task_lock( | |||
executor::storage& p_storage, | |||
const task_ptr_s& p_task) | |||
: _storage (p_storage) | |||
{ | |||
_storage.current_task = p_task; | |||
} | |||
~current_task_lock() | |||
{ _storage.current_task.reset(); } | |||
}; | |||
struct current_executor_lock | |||
{ | |||
private: | |||
@@ -37,11 +19,11 @@ namespace executor { | |||
executor& p_executor) | |||
: _storage (p_storage) | |||
{ | |||
_storage.current_executor = &p_executor; | |||
_storage.current = &p_executor; | |||
} | |||
~current_executor_lock() | |||
{ _storage.current_executor = nullptr; } | |||
{ _storage.current = nullptr; } | |||
}; | |||
} | |||
@@ -100,7 +82,7 @@ namespace executor { | |||
void current_thread<T_runtime> | |||
::poll_task(task_ptr_s p_task) | |||
{ | |||
__impl::current_task_lock l(executor::local_storage(), p_task); | |||
current_task_lock l(p_task); | |||
// TODO execption handling | |||
@@ -10,16 +10,10 @@ namespace executor { | |||
public: | |||
struct storage | |||
{ | |||
task_ptr_w current_task; | |||
executor * current_executor; | |||
executor * current; | |||
}; | |||
public: | |||
/** | |||
* @brief Get reference of the current task. | |||
*/ | |||
static inline const task_ptr_w& current_task(); | |||
/** | |||
* @brief Spawn a new task. | |||
*/ | |||
@@ -7,13 +7,10 @@ namespace executor { | |||
/* executor */ | |||
const task_ptr_w& executor::current_task() | |||
{ return local_storage().current_task; } | |||
template<typename X_future> | |||
void executor::spawn(X_future&& p_future) | |||
{ | |||
auto exec = local_storage().current_executor; | |||
auto exec = local_storage().current; | |||
if (!exec) | |||
throw std::runtime_error("Thread local executor instance is not assigned!"); | |||
exec->spawn_impl(make_task(std::forward<X_future>(p_future))); | |||
@@ -1,7 +1,9 @@ | |||
#pragma once | |||
#include "timer/delay.h" | |||
#include "timer/interval.h" | |||
#include "timer/timer.h" | |||
#include "timer/delay.inl" | |||
#include "timer/interval.inl" | |||
#include "timer/timer.inl" |
@@ -14,14 +14,14 @@ namespace timer { | |||
friend struct future_trait<delay, void>; | |||
private: | |||
time_point _timeout; | |||
__impl::registration _registration; | |||
time_point _deadline; | |||
__impl::registration_ptr_w _registration; | |||
public: | |||
/** | |||
* @brief Constructor. Create a delay at the given timeout. | |||
* @brief Constructor. Create a delay at the given deadline. | |||
*/ | |||
inline delay(const time_point& p_timeout); | |||
inline delay(const time_point& p_deadline); | |||
/** | |||
* @brief Constructor. Create a delay with the given duration. | |||
@@ -35,14 +35,14 @@ namespace timer { | |||
inline ~delay(); | |||
/** | |||
* @brief Get the current timeout of the delay. | |||
* @brief Get the current deadline of the delay. | |||
*/ | |||
inline time_point timeout() const; | |||
inline time_point deadline() const; | |||
/** | |||
* @brief Reset the delay to a new time point. | |||
*/ | |||
inline void reset(const time_point& p_timeout); | |||
inline void reset(const time_point& p_deadline); | |||
/** | |||
* @brief Reset the delay to the given duration. | |||
@@ -52,3 +52,21 @@ namespace timer { | |||
}; | |||
} } | |||
namespace asyncpp | |||
{ | |||
/* future_impl for timer::delay */ | |||
template<> | |||
struct future_trait<timer::delay, void> | |||
: public future_base<future<timer::delay, void>> | |||
{ | |||
using value_type = void; | |||
using result_type = future_result<value_type>; | |||
template<typename X_future> | |||
static inline auto poll(X_future& self); | |||
}; | |||
} |
@@ -12,34 +12,34 @@ namespace timer { | |||
/* delay */ | |||
delay::delay(const time_point& p_timeout) | |||
: _timeout (p_timeout) | |||
, _registration (*this) | |||
delay::delay(const time_point& p_deadline) | |||
: _deadline (p_deadline) | |||
, _registration () | |||
{ } | |||
template<typename T_base, typename T_ratio> | |||
delay::delay(const duration<T_base, T_ratio>& p_duration) | |||
: _timeout (clock::now() + p_duration) | |||
, _registration (*this) | |||
: _deadline (clock::now() + p_duration) | |||
, _registration () | |||
{ } | |||
inline delay::~delay() | |||
{ __impl::timer_base::unregister_resource(_registration); } | |||
time_point delay::timeout() const | |||
{ return _timeout; } | |||
time_point delay::deadline() const | |||
{ return _deadline; } | |||
void delay::reset(const time_point& p_timeout) | |||
void delay::reset(const time_point& p_deadline) | |||
{ | |||
__impl::timer_base::unregister_resource(_registration); | |||
_timeout = p_timeout; | |||
_deadline = p_deadline; | |||
} | |||
template<typename T_base, typename T_ratio> | |||
void delay::reset(const duration<T_base, T_ratio>& p_duration) | |||
{ | |||
__impl::timer_base::unregister_resource(_registration); | |||
_timeout = now() + p_duration; | |||
_deadline = now() + p_duration; | |||
} | |||
} } | |||
@@ -49,25 +49,19 @@ namespace asyncpp | |||
/* future_impl for timer::delay */ | |||
template<> | |||
struct future_trait<timer::delay, void> | |||
: public future_base<future<timer::delay, void>> | |||
template<typename X_future> | |||
auto future_trait<timer::delay, void> | |||
::poll(X_future& self) | |||
{ | |||
using value_type = void; | |||
using result_type = future_result<value_type>; | |||
auto now = timer::now(); | |||
template<typename X_future> | |||
static inline auto poll(X_future& self) | |||
{ | |||
auto now = timer::now(); | |||
if (self->_deadline <= now) | |||
return result_type::ready(); | |||
if (self.ref._timeout <= now) | |||
return result_type::ready(); | |||
if (self->_registration.expired()) | |||
self->_registration = timer::__impl::timer_base::register_resource(self->_deadline); | |||
timer::__impl::timer_base::register_resource(self.ref._registration); | |||
return result_type::not_ready(); | |||
} | |||
}; | |||
return result_type::not_ready(); | |||
} | |||
} |
@@ -3,9 +3,9 @@ | |||
#include <memory> | |||
#include <asyncpp/core/misc.h> | |||
#include <asyncpp/core/task.h> | |||
#include "timer_base.pre.h" | |||
#include "../delay.pre.h" | |||
namespace asyncpp { | |||
namespace timer { | |||
@@ -14,27 +14,20 @@ namespace __impl { | |||
struct registration | |||
{ | |||
public: | |||
struct inner | |||
{ | |||
timer_base& owner; | |||
time_point timeout; | |||
/** | |||
* @brief Constructor. | |||
*/ | |||
inline inner(timer_base& p_owner, time_point p_timeout); | |||
}; | |||
using inner_ptr_w = std::weak_ptr<inner>; | |||
public: | |||
delay& owner; | |||
inner_ptr_w ptr; | |||
timer_base& owner; | |||
const time_point deadline; | |||
const task_ptr_w task; | |||
/** | |||
* @brief Constructor. | |||
*/ | |||
inline registration(delay& p_owner); | |||
inline registration( | |||
timer_base& p_owner, | |||
const time_point& p_deadline, | |||
const task_ptr_w& p_task); | |||
}; | |||
using registration_ptr_w = std::weak_ptr<registration>; | |||
using registration_ptr_s = std::shared_ptr<registration>; | |||
} } } |
@@ -6,18 +6,15 @@ namespace asyncpp { | |||
namespace timer { | |||
namespace __impl { | |||
/* registration::inner */ | |||
registration::inner::inner(timer_base& p_owner, time_point p_timeout) | |||
: owner (p_owner) | |||
, timeout (p_timeout) | |||
{ } | |||
/* registration */ | |||
registration::registration(delay& p_owner) | |||
: owner(p_owner) | |||
, ptr () | |||
registration::registration( | |||
timer_base& p_owner, | |||
const time_point& p_deadline, | |||
const task_ptr_w& p_task) | |||
: owner (p_owner) | |||
, deadline (p_deadline) | |||
, task (p_task) | |||
{ } | |||
} } } |
@@ -1,9 +0,0 @@ | |||
#pragma once | |||
namespace asyncpp { | |||
namespace timer { | |||
namespace __impl { | |||
struct registration; | |||
} } } |
@@ -17,15 +17,17 @@ namespace __impl { | |||
struct timer_base | |||
{ | |||
private: | |||
using inner_ptr_s = std::shared_ptr<registration::inner>; | |||
struct inner_less_compare | |||
{ constexpr bool operator()(const inner_ptr_s& lhs, const inner_ptr_s& rhs) const; }; | |||
struct registration_less_compare | |||
{ | |||
constexpr bool operator()( | |||
const registration_ptr_s& lhs, | |||
const registration_ptr_s& rhs) const; | |||
}; | |||
using inner_set = std::set<inner_ptr_s, inner_less_compare>; | |||
using registration_set = std::set<registration_ptr_s, registration_less_compare>; | |||
protected: | |||
cppcore::locked<inner_set> _registrations; | |||
cppcore::locked<registration_set> _registrations; | |||
public: | |||
/** | |||
@@ -58,18 +60,18 @@ namespace __impl { | |||
/** | |||
* @brief Register a new resource within this timer_base. | |||
*/ | |||
static inline void register_resource(registration& p_value); | |||
static inline registration_ptr_w register_resource(const time_point& p_deadline); | |||
/** | |||
* @brief Register a new resource within this timer_base. | |||
*/ | |||
static inline void unregister_resource(registration& p_value); | |||
static inline void unregister_resource(registration_ptr_w& p_value); | |||
private: | |||
/** | |||
* @brief Add a new resource to the timer_base. | |||
* @brief Create registration for a new resource. | |||
*/ | |||
inline inner_ptr_s make_inner(registration& p_value); | |||
registration_ptr_w create_registration(const time_point& p_deadline); | |||
private: | |||
struct storage | |||
@@ -8,13 +8,15 @@ namespace __impl { | |||
/* timer_base::inner_less_compare */ | |||
constexpr bool timer_base::inner_less_compare::operator()(const inner_ptr_s& lhs, const inner_ptr_s& rhs) const | |||
constexpr bool timer_base::registration_less_compare::operator()( | |||
const registration_ptr_s& lhs, | |||
const registration_ptr_s& rhs) const | |||
{ | |||
return (lhs->timeout < rhs->timeout) | |||
return (lhs->deadline < rhs->deadline) | |||
? true | |||
: | |||
(lhs->timeout == rhs->timeout) | |||
&& (lhs.get() < rhs.get()) | |||
(lhs->deadline == rhs->deadline) | |||
&& (lhs.get() < rhs.get()) | |||
? true | |||
: false; | |||
} | |||
@@ -50,42 +52,36 @@ namespace __impl { | |||
timer_base* timer_base::current() | |||
{ return local_storage().current; } | |||
void timer_base::register_resource(registration& p_value) | |||
registration_ptr_w timer_base::register_resource(const time_point& p_deadline) | |||
{ | |||
auto s = p_value.ptr.lock(); | |||
auto t = current(); | |||
if (s && s->timeout != p_value.owner.timeout()) | |||
{ | |||
unregister_resource(p_value); | |||
s.reset(); | |||
} | |||
if (!t) | |||
throw std::runtime_error("Thread local timer_base instance is not assigned!"); | |||
if (!s) | |||
{ | |||
auto t = current(); | |||
return t->create_registration(p_deadline); | |||
} | |||
registration_ptr_w timer_base::create_registration(const time_point& p_deadline) | |||
{ | |||
auto r = std::make_shared<registration>( | |||
*this, | |||
p_deadline, | |||
task::current()); | |||
if (!t) | |||
throw std::runtime_error("Thread local timer_base instance is not assigned!"); | |||
_registrations.lock()->insert(r); | |||
p_value.ptr = t->make_inner(p_value); | |||
} | |||
return r; | |||
} | |||
void timer_base::unregister_resource(registration& p_value) | |||
void timer_base::unregister_resource(registration_ptr_w& p_value) | |||
{ | |||
auto s = p_value.ptr.lock(); | |||
p_value.ptr.reset(); | |||
auto s = p_value.lock(); | |||
p_value.reset(); | |||
if (s) | |||
s->owner._registrations.lock()->erase(s); | |||
} | |||
inline timer_base::inner_ptr_s timer_base::make_inner(registration& p_value) | |||
{ | |||
auto s = std::make_shared<registration::inner>(*this, p_value.owner.timeout()); | |||
_registrations.lock()->insert(s); | |||
return s; | |||
} | |||
timer_base::storage& timer_base::local_storage() | |||
{ | |||
thread_local storage value; | |||
@@ -0,0 +1,67 @@ | |||
#pragma once | |||
#include <asyncpp/core/misc.h> | |||
#include <asyncpp/core/future.h> | |||
#include <asyncpp/core/stream.h> | |||
#include "delay.h" | |||
namespace asyncpp { | |||
namespace timer { | |||
struct interval | |||
{ | |||
public: | |||
using delay_future_type = future<delay>; | |||
public: | |||
friend struct stream_trait<interval, void>; | |||
private: | |||
delay_future_type _delay; //!< Delay future | |||
clock::duration _duration; //!< Interval duration. | |||
time_point _deadline; //!< Deadline after the interval should end. | |||
public: | |||
/** | |||
* @brief Constructor. | |||
*/ | |||
template<typename T_base, typename T_ratio> | |||
inline interval( | |||
const duration<T_base, T_ratio>& p_duration, | |||
time_point p_deadline = time_point()); | |||
/** | |||
* @brief Constructor. | |||
*/ | |||
template<typename T_base, typename T_ratio> | |||
inline interval( | |||
const time_point& p_at, | |||
const duration<T_base, T_ratio>& p_duration, | |||
time_point p_deadline = time_point()); | |||
/** | |||
* @brief Get the duration of the interval. | |||
*/ | |||
inline const clock::duration& duration() const; | |||
}; | |||
} } | |||
namespace asyncpp | |||
{ | |||
/* stream_trait for timer::interval */ | |||
template<> | |||
struct stream_trait<timer::interval, void> | |||
: public stream_base<stream<timer::interval, void>> | |||
{ | |||
using value_type = void; | |||
using result_type = stream_result<value_type>; | |||
template<typename X_stream> | |||
static inline result_type poll(X_stream& self); | |||
}; | |||
} |
@@ -0,0 +1,60 @@ | |||
#pragma once | |||
#include <asyncpp/core/future.inl> | |||
#include "delay.inl" | |||
#include "interval.h" | |||
namespace asyncpp { | |||
namespace timer { | |||
/* interval */ | |||
template<typename T_base, typename T_ratio> | |||
interval::interval( | |||
const asyncpp::duration<T_base, T_ratio>& p_duration, | |||
time_point p_deadline) | |||
: interval(clock::now() + p_duration, p_duration, p_deadline) | |||
{ } | |||
template<typename T_base, typename T_ratio> | |||
interval::interval( | |||
const time_point& p_at, | |||
const asyncpp::duration<T_base, T_ratio>& p_duration, | |||
time_point p_deadline) | |||
: _delay (as_future(delay(p_at))) | |||
, _duration(p_duration) | |||
, _deadline(p_deadline) | |||
{ } | |||
const clock::duration& interval::duration() const | |||
{ return _duration; } | |||
} } | |||
namespace asyncpp | |||
{ | |||
/* stream_trait for timer::interval */ | |||
template<typename X_stream> | |||
typename stream_trait<timer::interval, void>::result_type | |||
stream_trait<timer::interval, void> | |||
::poll(X_stream& self) | |||
{ | |||
auto ret = self->_delay.poll(); | |||
if (ret.is_not_ready()) | |||
return result_type::not_ready(); | |||
auto now = self->_delay->deadline(); | |||
auto new_deadline = now + self->_duration; | |||
if ( self->_deadline.time_since_epoch().count() | |||
&& new_deadline >= self->_deadline) | |||
return result_type::done(); | |||
self->_delay->reset(new_deadline); | |||
return result_type::ready(); | |||
} | |||
} |
@@ -49,23 +49,23 @@ namespace timer { | |||
* @brief Handle idle of the runtime. | |||
* | |||
* This method is called as soon as the runtime has nothing to do. | |||
* The passed timeout is the timepoint the method should return (or null if not set). | |||
* The passed deadline is the timepoint the method should return (or null if not set). | |||
*/ | |||
inline void idle(asyncpp::time_point* p_timeout); | |||
inline void idle(const asyncpp::time_point * p_deadline); | |||
private: | |||
/** | |||
* @brief Call the idle method of the inner runtime. | |||
*/ | |||
template<typename X = inner_type> | |||
inline auto inner_idle(asyncpp::time_point* p_timeout) | |||
inline auto inner_idle(const asyncpp::time_point * p_deadline) | |||
-> std::enable_if_t<std::is_same_v<X, void>>; | |||
/** | |||
* @brief Call the idle method of the inner runtime. | |||
*/ | |||
template<typename X = inner_type> | |||
inline auto inner_idle(asyncpp::time_point* p_timeout) | |||
inline auto inner_idle(const asyncpp::time_point * p_deadline) | |||
-> std::enable_if_t<!std::is_same_v<X, void>>; | |||
}; | |||
@@ -1,5 +1,7 @@ | |||
#pragma once | |||
#include <asyncpp/core/misc.inl> | |||
#include "timer.h" | |||
#include "delay.inl" | |||
@@ -37,40 +39,29 @@ namespace timer { | |||
{ } | |||
template<typename T_inner> | |||
void timer<T_inner>::idle(asyncpp::time_point* p_timeout) | |||
void timer<T_inner>::idle(const asyncpp::time_point * p_deadline) | |||
{ | |||
bool has_timeout = false; | |||
asyncpp::time_point timeout; | |||
if (p_timeout) | |||
{ | |||
timeout = *p_timeout; | |||
has_timeout = true; | |||
} | |||
auto now = clock::now(); | |||
{ | |||
auto r = _registrations.lock(); | |||
if (!r->empty()) | |||
auto it = r->begin(); | |||
while (it != r->end() && now >= (**it).deadline) | |||
{ | |||
auto t = (*r->begin())->timeout; | |||
if (!has_timeout) | |||
timeout = t; | |||
else if (t < timeout) | |||
timeout = t; | |||
auto t = (**it).task.lock(); | |||
if (t) | |||
t->notify(); | |||
has_timeout = true; | |||
++it; | |||
} | |||
} | |||
inner_idle(has_timeout | |||
? &timeout | |||
: nullptr); | |||
inner_idle(p_deadline); | |||
} | |||
template<typename T_inner> | |||
template<typename X> | |||
auto timer<T_inner>::inner_idle(asyncpp::time_point* p_timeout) | |||
auto timer<T_inner>::inner_idle(const asyncpp::time_point * p_deadline) | |||
-> std::enable_if_t<std::is_same_v<X, void>> | |||
{ | |||
/* no-op */ | |||
@@ -78,10 +69,18 @@ namespace timer { | |||
template<typename T_inner> | |||
template<typename X> | |||
auto timer<T_inner>::inner_idle(asyncpp::time_point* p_timeout) | |||
auto timer<T_inner>::inner_idle(const asyncpp::time_point * p_deadline) | |||
-> std::enable_if_t<!std::is_same_v<X, void>> | |||
{ | |||
_storage.inner.idle(p_timeout); | |||
{ | |||
auto r = _registrations.lock(); | |||
if (!r->empty()) | |||
{ | |||
p_deadline = merge_deadlines(p_deadline, &(*r->begin())->deadline); | |||
} | |||
} | |||
_storage.inner.idle(p_deadline); | |||
} | |||
} } |
@@ -25,10 +25,10 @@ namespace asyncpp | |||
{ | |||
using result_type = future_result<value_type>; | |||
if (self.ref.count >= self.ref.delay) | |||
return result_type::ready(self.ref.count); | |||
if (self->count >= self->delay) | |||
return result_type::ready(self->count); | |||
++self.ref.count; | |||
++self->count; | |||
return result_type::not_ready(); | |||
} | |||
}; | |||
@@ -17,23 +17,23 @@ namespace asyncpp | |||
template<> | |||
struct stream_trait<delay, void> | |||
: public future_base<future<delay, void>> | |||
: public stream_base<stream<delay, void>> | |||
{ | |||
using value_type = int; | |||
template<typename T_future> | |||
static inline auto poll(T_future& self) | |||
template<typename X_stream> | |||
static inline auto poll(X_stream& self) | |||
{ | |||
using result_type = stream_result<value_type>; | |||
if (self.ref.count >= self.ref.delay) | |||
if (self->count >= self->delay) | |||
return result_type::done(); | |||
++self.ref.count; | |||
++self->count; | |||
return self.ref.count <= self.ref.threshold | |||
return self->count <= self->threshold | |||
? result_type::not_ready() | |||
: result_type::ready(self.ref.count); | |||
: result_type::ready(self->count); | |||
} | |||
}; | |||
@@ -66,3 +66,17 @@ TEST(stream_tests, poll) | |||
ASSERT_FALSE(r); | |||
ASSERT_TRUE (r.is_done()); | |||
} | |||
TEST(stream_tests, for_each) | |||
{ | |||
int i = 0; | |||
delay d { 5, 0, 0 }; | |||
auto f = as_stream(d) | |||
.for_each([&i](int x) { | |||
++i; | |||
EXPECT_EQ(i, x); | |||
}); | |||
auto r = f.poll(); | |||
ASSERT_TRUE(r); | |||
} |
@@ -25,10 +25,10 @@ namespace asyncpp | |||
{ | |||
using result_type = future_result<value_type>; | |||
if (self.ref.count >= self.ref.delay) | |||
return result_type::ready(self.ref.count); | |||
if (self->count >= self->delay) | |||
return result_type::ready(self->count); | |||
++self.ref.count; | |||
++self->count; | |||
return result_type::not_ready(); | |||
} | |||
}; | |||
@@ -27,8 +27,8 @@ namespace asyncpp | |||
template<typename X_future> | |||
static inline auto poll(X_future& self) | |||
{ | |||
self.ref.task = executor::executor::current_task(); | |||
return self.ref.done | |||
self->task = task::current(); | |||
return self->done | |||
? result_type::ready() | |||
: result_type::not_ready(); | |||
} | |||
@@ -0,0 +1,72 @@ | |||
#include <gtest/gtest.h> | |||
#include "../../helper/now_mock.h" | |||
#include <asyncpp.h> | |||
#include <asyncpp/timer.h> | |||
using namespace ::testing; | |||
using namespace ::asyncpp; | |||
using namespace ::asyncpp::timer; | |||
TEST(interval_tests, poll) | |||
{ | |||
InSequence seq; | |||
StrictMock<now_mock> m; | |||
asyncpp::timer::timer t; | |||
interval i( | |||
time_point(std::chrono::seconds(10)), | |||
std::chrono::seconds(5), | |||
time_point(std::chrono::seconds(30))); | |||
// 30 - 10 = 20 | |||
// 20 / 5 = 4 | |||
// 4 - 1 = 3 | |||
// 3 x Ready | |||
t.make_current(); | |||
auto s = as_stream(i); | |||
EXPECT_CALL(m, now) | |||
.WillOnce(Return(time_point(std::chrono::seconds(0)))); | |||
auto r0 = s.poll(); | |||
ASSERT_EQ(result_status::not_ready, r0.status()); | |||
EXPECT_CALL(m, now) | |||
.WillOnce(Return(time_point(std::chrono::seconds(9)))); | |||
auto r1 = s.poll(); | |||
ASSERT_EQ(result_status::not_ready, r1.status()); | |||
EXPECT_CALL(m, now) | |||
.WillOnce(Return(time_point(std::chrono::seconds(10)))); | |||
auto r2 = s.poll(); | |||
ASSERT_EQ(result_status::ready, r2.status()); | |||
EXPECT_CALL(m, now) | |||
.WillOnce(Return(time_point(std::chrono::seconds(11)))); | |||
auto r3 = s.poll(); | |||
ASSERT_EQ(result_status::not_ready, r3.status()); | |||
EXPECT_CALL(m, now) | |||
.WillOnce(Return(time_point(std::chrono::seconds(30)))); | |||
auto r4 = s.poll(); | |||
ASSERT_EQ(result_status::ready, r4.status()); | |||
EXPECT_CALL(m, now) | |||
.WillOnce(Return(time_point(std::chrono::seconds(30)))); | |||
auto r5 = s.poll(); | |||
ASSERT_EQ(result_status::ready, r5.status()); | |||
EXPECT_CALL(m, now) | |||
.WillOnce(Return(time_point(std::chrono::seconds(30)))); | |||
auto r6 = s.poll(); | |||
ASSERT_EQ(result_status::done, r6.status()); | |||
} |
@@ -8,5 +8,5 @@ | |||
struct runtime_mock | |||
{ | |||
public: | |||
MOCK_METHOD1(idle, void (asyncpp::time_point* p_timeout)); | |||
MOCK_METHOD1(idle, void (const asyncpp::time_point * p_deadline)); | |||
}; |