| @@ -12,61 +12,84 @@ namespace asyncpp | |||||
| { | { | ||||
| template< | template< | ||||
| typename T_object, | |||||
| typename T_impl> | |||||
| struct future | |||||
| typename T_value, | |||||
| typename T_derived> | |||||
| struct base_future | |||||
| : public tag_future | |||||
| { | { | ||||
| using object_type = T_object; | |||||
| using clean_object_type = std::decay_t<object_type>; | |||||
| 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; | |||||
| public: | |||||
| using value_type = T_value; | |||||
| using result_type = future_result<value_type>; | |||||
| using derived_type = T_derived; | |||||
| using this_type = base_future<value_type, derived_type>; | |||||
| public: | |||||
| /** | /** | ||||
| * @brief Value constructor. | |||||
| * @brief Transform the result of this future. | |||||
| */ | */ | ||||
| template<typename X_object> | |||||
| inline future(X_object&& p_ref); | |||||
| template<typename X_lambda> | |||||
| inline auto map(X_lambda&& p_lambda) const &; | |||||
| /** | /** | ||||
| * @brief Function that will be called repeatedly to check if the future is ready. | |||||
| * @brief Transform the result of this future. | |||||
| */ | */ | ||||
| inline result_type poll(); | |||||
| template<typename X_lambda> | |||||
| inline auto map(X_lambda&& p_lambda) &; | |||||
| /** | /** | ||||
| * @brief Transform the result of this future. | * @brief Transform the result of this future. | ||||
| */ | */ | ||||
| template<typename X_lambda> | template<typename X_lambda> | ||||
| inline auto map(X_lambda&& p_lambda); | |||||
| inline auto map(X_lambda&& p_lambda) &&; | |||||
| public: | |||||
| /** | |||||
| * @brief Execute the given lambda after the future is finished and | |||||
| * wait for the future returned by the lambda. | |||||
| */ | |||||
| template<typename X_lambda> | |||||
| inline auto and_then(X_lambda&& p_lambda) const &; | |||||
| /** | /** | ||||
| * @brief Execute the given lambda after the future is finished and | * @brief Execute the given lambda after the future is finished and | ||||
| * wait for the future returned by the lambda. | * wait for the future returned by the lambda. | ||||
| */ | */ | ||||
| template<typename X_lambda> | template<typename X_lambda> | ||||
| inline auto and_then(X_lambda&& p_lambda); | |||||
| inline auto and_then(X_lambda&& p_lambda) &; | |||||
| #ifdef asyncpp_timing | |||||
| /** | |||||
| * @brief Execute the given lambda after the future is finished and | |||||
| * wait for the future returned by the lambda. | |||||
| */ | |||||
| template<typename X_lambda> | |||||
| inline auto and_then(X_lambda&& p_lambda) &&; | |||||
| #ifdef asyncpp_timing | |||||
| public: | |||||
| /** | /** | ||||
| * @brief Throw an execption if the timeout has passed. | * @brief Throw an execption if the timeout has passed. | ||||
| * | * | ||||
| * This method is only enabled if timer.h is included before. | * This method is only enabled if timer.h is included before. | ||||
| */ | */ | ||||
| template<typename X_base, typename X_ratio> | template<typename X_base, typename X_ratio> | ||||
| inline auto timeout(const duration<X_base, X_ratio>& p_timeout); | |||||
| #endif | |||||
| inline auto timeout(const duration<X_base, X_ratio>& p_timeout) const &; | |||||
| public: | |||||
| inline pointer operator->(); | |||||
| inline reference operator*(); | |||||
| inline const_pointer operator->() const; | |||||
| inline const_reference operator*() const; | |||||
| /** | |||||
| * @brief Throw an execption if the timeout has passed. | |||||
| * | |||||
| * This method is only enabled if timer.h is included before. | |||||
| */ | |||||
| template<typename X_base, typename X_ratio> | |||||
| inline auto timeout(const duration<X_base, X_ratio>& p_timeout) &; | |||||
| /** | |||||
| * @brief Throw an execption if the timeout has passed. | |||||
| * | |||||
| * This method is only enabled if timer.h is included before. | |||||
| */ | |||||
| template<typename X_base, typename X_ratio> | |||||
| inline auto timeout(const duration<X_base, X_ratio>& p_timeout) &&; | |||||
| #endif | |||||
| }; | }; | ||||
| } | } | ||||
| @@ -12,143 +12,174 @@ | |||||
| namespace asyncpp | namespace asyncpp | ||||
| { | { | ||||
| /* future_base */ | |||||
| /* future::map */ | |||||
| template<typename T_impl> | |||||
| template<typename X_future, typename X_lambda> | |||||
| auto future_base<T_impl> | |||||
| ::map(X_future&& self, X_lambda&& p_lambda) | |||||
| template< | |||||
| typename T_value, | |||||
| typename T_derived> | |||||
| template< | |||||
| typename X_lambda> | |||||
| auto base_future<T_value, T_derived> | |||||
| ::map(X_lambda&& p_lambda) const & | |||||
| { | { | ||||
| using future_type = X_future; | |||||
| using lambda_type = X_lambda; | |||||
| using map_type = __future::map_impl<future_type, lambda_type>; | |||||
| using lambda_type = X_lambda; | |||||
| using map_type = __future::map_impl<derived_type, lambda_type>; | |||||
| auto& self = static_cast<derived_type const &>(*this); | |||||
| return as_future(map_type( | |||||
| std::forward<X_future>(self), | |||||
| std::forward<X_lambda>(p_lambda))); | |||||
| return map_type( | |||||
| std::forward<derived_type const>(self), | |||||
| std::forward<X_lambda>(p_lambda)); | |||||
| } | } | ||||
| template<typename T_impl> | |||||
| template<typename X_future, typename X_lambda> | |||||
| auto future_base<T_impl> | |||||
| ::and_then(X_future&& self, X_lambda&& p_lambda) | |||||
| template< | |||||
| typename T_value, | |||||
| typename T_derived> | |||||
| template< | |||||
| typename X_lambda> | |||||
| auto base_future<T_value, T_derived> | |||||
| ::map(X_lambda&& p_lambda) & | |||||
| { | { | ||||
| using future_type = X_future; | |||||
| using lambda_type = X_lambda; | |||||
| using and_then_type = __future::and_then_impl<future_type, lambda_type>; | |||||
| using lambda_type = X_lambda; | |||||
| using map_type = __future::map_impl<derived_type&, lambda_type>; | |||||
| auto& self = static_cast<derived_type &>(*this); | |||||
| return as_future(and_then_type( | |||||
| std::forward<X_future>(self), | |||||
| std::forward<X_lambda>(p_lambda))); | |||||
| return map_type( | |||||
| std::forward<derived_type &>(self), | |||||
| std::forward<X_lambda>(p_lambda)); | |||||
| } | } | ||||
| #ifdef asyncpp_timing | |||||
| template<typename T_impl> | |||||
| template<typename X_future, typename X_base, typename X_ratio> | |||||
| auto future_base<T_impl> | |||||
| ::timeout(X_future&& self, const duration<X_base, X_ratio>& p_timeout) | |||||
| template< | |||||
| typename T_value, | |||||
| typename T_derived> | |||||
| template< | |||||
| typename X_lambda> | |||||
| auto base_future<T_value, T_derived> | |||||
| ::map(X_lambda&& p_lambda) && | |||||
| { | { | ||||
| using future_type = X_future; | |||||
| using timeout_type = timing::timeout<future_type>; | |||||
| using lambda_type = X_lambda; | |||||
| using map_type = __future::map_impl<derived_type, lambda_type>; | |||||
| return as_future(timeout_type( | |||||
| std::forward<X_future>(self), | |||||
| p_timeout)); | |||||
| auto& self = static_cast<derived_type &>(*this); | |||||
| return map_type( | |||||
| std::forward<derived_type &&>(self), | |||||
| std::forward<X_lambda>(p_lambda)); | |||||
| } | } | ||||
| #endif | |||||
| /* future */ | |||||
| /* future::and_then */ | |||||
| template< | template< | ||||
| typename T_value, | typename T_value, | ||||
| typename T_impl> | |||||
| typename T_derived> | |||||
| template< | template< | ||||
| typename X_object> | |||||
| future<T_value, T_impl> | |||||
| ::future(X_object&& p_ref) | |||||
| : ref(std::forward<X_object>(p_ref)) | |||||
| { } | |||||
| typename X_lambda> | |||||
| auto base_future<T_value, T_derived> | |||||
| ::and_then(X_lambda&& p_lambda) const & | |||||
| { | |||||
| using lambda_type = X_lambda; | |||||
| using and_then_type = __future::and_then_impl<derived_type, lambda_type>; | |||||
| template< | |||||
| typename T_value, | |||||
| typename T_impl> | |||||
| typename future<T_value, T_impl>::result_type | |||||
| future<T_value, T_impl> | |||||
| ::poll() | |||||
| { return trait_type::poll(*this); } | |||||
| auto& self = static_cast<derived_type const &>(*this); | |||||
| return and_then_type( | |||||
| std::forward<derived_type const>(self), | |||||
| std::forward<X_lambda>(p_lambda)); | |||||
| } | |||||
| template< | template< | ||||
| typename T_value, | typename T_value, | ||||
| typename T_impl> | |||||
| typename T_derived> | |||||
| template< | template< | ||||
| typename X_lambda> | typename X_lambda> | ||||
| auto future<T_value, T_impl> | |||||
| ::map(X_lambda&& p_lambda) | |||||
| { return trait_type::map(std::move(*this), std::forward<X_lambda>(p_lambda)); } | |||||
| auto base_future<T_value, T_derived> | |||||
| ::and_then(X_lambda&& p_lambda) & | |||||
| { | |||||
| using lambda_type = X_lambda; | |||||
| using and_then_type = __future::and_then_impl<derived_type&, lambda_type>; | |||||
| auto& self = static_cast<derived_type &>(*this); | |||||
| return and_then_type( | |||||
| std::forward<derived_type &>(self), | |||||
| std::forward<X_lambda>(p_lambda)); | |||||
| } | |||||
| template< | template< | ||||
| typename T_value, | typename T_value, | ||||
| typename T_impl> | |||||
| typename T_derived> | |||||
| template< | template< | ||||
| typename X_lambda> | typename X_lambda> | ||||
| auto future<T_value, T_impl> | |||||
| ::and_then(X_lambda&& p_lambda) | |||||
| { return trait_type::and_then(std::move(*this), std::forward<X_lambda>(p_lambda)); } | |||||
| auto base_future<T_value, T_derived> | |||||
| ::and_then(X_lambda&& p_lambda) && | |||||
| { | |||||
| using lambda_type = X_lambda; | |||||
| using and_then_type = __future::and_then_impl<derived_type, lambda_type>; | |||||
| auto& self = static_cast<derived_type &>(*this); | |||||
| return and_then_type( | |||||
| std::forward<derived_type &&>(self), | |||||
| std::forward<X_lambda>(p_lambda)); | |||||
| } | |||||
| /* future::timeout */ | |||||
| #ifdef asyncpp_timing | #ifdef asyncpp_timing | ||||
| template< | template< | ||||
| typename T_value, | typename T_value, | ||||
| typename T_impl> | |||||
| typename T_derived> | |||||
| template< | template< | ||||
| typename X_base, | typename X_base, | ||||
| typename X_ratio> | typename X_ratio> | ||||
| auto future<T_value, T_impl> | |||||
| ::timeout(const duration<X_base, X_ratio>& p_timeout) | |||||
| { return trait_type::timeout(std::move(*this), p_timeout); } | |||||
| #endif | |||||
| auto base_future<T_value, T_derived> | |||||
| ::timeout(const duration<X_base, X_ratio>& p_timeout) const & | |||||
| { | |||||
| using timeout_type = timing::timeout<derived_type>; | |||||
| template< | |||||
| typename T_value, | |||||
| typename T_impl> | |||||
| typename future<T_value, T_impl>::pointer | |||||
| future<T_value, T_impl>::operator->() | |||||
| { return &ref; } | |||||
| auto& self = static_cast<derived_type const &>(*this); | |||||
| template< | |||||
| typename T_value, | |||||
| typename T_impl> | |||||
| typename future<T_value, T_impl>::reference | |||||
| future<T_value, T_impl>::operator*() | |||||
| { return ref; } | |||||
| return timeout_type( | |||||
| std::forward<derived_type const>(self), | |||||
| p_timeout); | |||||
| } | |||||
| template< | template< | ||||
| typename T_value, | typename T_value, | ||||
| typename T_impl> | |||||
| typename future<T_value, T_impl>::const_pointer | |||||
| future<T_value, T_impl>::operator->() const | |||||
| { return &ref; } | |||||
| typename T_derived> | |||||
| template< | template< | ||||
| typename T_value, | |||||
| typename T_impl> | |||||
| typename future<T_value, T_impl>::const_reference | |||||
| future<T_value, T_impl>::operator*() const | |||||
| { return ref; } | |||||
| typename X_base, | |||||
| typename X_ratio> | |||||
| auto base_future<T_value, T_derived> | |||||
| ::timeout(const duration<X_base, X_ratio>& p_timeout) & | |||||
| { | |||||
| using timeout_type = timing::timeout<derived_type&>; | |||||
| /* misc */ | |||||
| auto& self = static_cast<derived_type &>(*this); | |||||
| template<typename X_value> | |||||
| constexpr future<X_value> as_future(X_value&& value) | |||||
| return timeout_type( | |||||
| std::forward<derived_type &>(self), | |||||
| p_timeout); | |||||
| } | |||||
| template< | |||||
| typename T_value, | |||||
| typename T_derived> | |||||
| template< | |||||
| typename X_base, | |||||
| typename X_ratio> | |||||
| auto base_future<T_value, T_derived> | |||||
| ::timeout(const duration<X_base, X_ratio>& p_timeout) && | |||||
| { | { | ||||
| using value_type = X_value; | |||||
| using future_type = future<value_type>; | |||||
| using timeout_type = timing::timeout<derived_type>; | |||||
| return future_type(std::forward<X_value>(value)); | |||||
| } | |||||
| auto& self = static_cast<derived_type &>(*this); | |||||
| template<typename T> | |||||
| struct is_future<future<T>, void> | |||||
| : public std::true_type | |||||
| { }; | |||||
| return timeout_type( | |||||
| std::forward<derived_type &&>(self), | |||||
| p_timeout); | |||||
| } | |||||
| #endif | |||||
| } | } | ||||
| @@ -5,48 +5,20 @@ | |||||
| namespace asyncpp | namespace asyncpp | ||||
| { | { | ||||
| template<typename T_impl> | |||||
| struct future_base | |||||
| { | |||||
| public: | |||||
| using impl_type = T_impl; | |||||
| public: | |||||
| template<typename X_future> | |||||
| static inline auto poll(X_future& self) = delete; | |||||
| 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); | |||||
| #ifdef asyncpp_timing | |||||
| template<typename X_future, typename X_base, typename X_ratio> | |||||
| static inline auto timeout(X_future&& self, const duration<X_base, X_ratio>& p_timeout); | |||||
| #endif | |||||
| }; | |||||
| template<typename T, typename = void> | |||||
| struct future_trait; | |||||
| struct tag_future | |||||
| { }; | |||||
| template< | template< | ||||
| typename T_object, | |||||
| typename T_impl = future_trait<std::decay_t<T_object>>> | |||||
| struct future; | |||||
| typename T_value, | |||||
| typename T_derived> | |||||
| struct base_future; | |||||
| template<typename T, typename = void> | |||||
| template<typename T> | |||||
| struct is_future | struct is_future | ||||
| : public std::false_type | |||||
| : public std::is_base_of<tag_future, T> | |||||
| { }; | { }; | ||||
| template<typename T> | template<typename T> | ||||
| constexpr decltype(auto) is_future_v = is_future<T>::value; | constexpr decltype(auto) is_future_v = is_future<T>::value; | ||||
| /** | |||||
| * @brief Construct a future from the given value. | |||||
| */ | |||||
| template<typename X_value> | |||||
| constexpr future<X_value> as_future(X_value&& value); | |||||
| } | } | ||||
| @@ -2,7 +2,7 @@ | |||||
| #include <memory> | #include <memory> | ||||
| #include <asyncpp/core/future.pre.h> | |||||
| #include "../future.pre.h" | |||||
| namespace asyncpp { | namespace asyncpp { | ||||
| namespace __future { | namespace __future { | ||||
| @@ -10,14 +10,22 @@ namespace __future { | |||||
| template< | template< | ||||
| typename T_future, | typename T_future, | ||||
| typename T_lambda> | typename T_lambda> | ||||
| struct and_then_impl | |||||
| struct and_then_impl final : | |||||
| public base_future< | |||||
| decltype(std::declval<T_lambda>()(std::declval<typename std::decay_t<T_future>::value_type>())), | |||||
| and_then_impl<T_future, T_lambda> | |||||
| > | |||||
| { | { | ||||
| public: | public: | ||||
| using lambda_type = T_lambda; | using lambda_type = T_lambda; | ||||
| using first_future_type = T_future; | 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 first_value_type = typename std::decay_t<first_future_type>::value_type; | |||||
| using second_future_type = decltype(std::declval<lambda_type>()(std::declval<first_value_type>())); | |||||
| using second_future_type_ptr = std::unique_ptr<second_future_type>; | using second_future_type_ptr = std::unique_ptr<second_future_type>; | ||||
| using value_type = typename second_future_type::value_type; | |||||
| using this_type = and_then_impl<value_type, lambda_type>; | |||||
| using base_future_type = base_future<value_type, this_type>; | |||||
| using result_type = typename base_future_type::result_type; | |||||
| public: | public: | ||||
| lambda_type lambda; | lambda_type lambda; | ||||
| @@ -34,28 +42,12 @@ namespace __future { | |||||
| inline and_then_impl( | inline and_then_impl( | ||||
| X_future&& p_outer, | X_future&& p_outer, | ||||
| X_lambda&& p_lambda); | X_lambda&& p_lambda); | ||||
| }; | |||||
| } } | |||||
| 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); | |||||
| public: /* future */ | |||||
| /** | |||||
| * @brief Poll the result from the future. | |||||
| */ | |||||
| inline result_type poll(); | |||||
| }; | }; | ||||
| } | |||||
| } } | |||||
| @@ -21,36 +21,28 @@ namespace __future { | |||||
| , lambda(std::forward<X_lambda>(p_lambda)) | , lambda(std::forward<X_lambda>(p_lambda)) | ||||
| { } | { } | ||||
| } } | |||||
| namespace asyncpp | |||||
| { | |||||
| /* future_trait for ant_then_impl */ | |||||
| template< | template< | ||||
| typename T_future, | typename T_future, | ||||
| typename T_lambda> | typename T_lambda> | ||||
| template< | |||||
| typename X_future> | |||||
| auto future_trait<__future::and_then_impl<T_future, T_lambda>, void> | |||||
| ::poll(X_future& self) | |||||
| typename and_then_impl<T_future, T_lambda>::result_type | |||||
| and_then_impl<T_future, T_lambda> | |||||
| ::poll() | |||||
| { | { | ||||
| while (true) | while (true) | ||||
| { | { | ||||
| if (self->second) | |||||
| if (second) | |||||
| { | { | ||||
| return self->second->poll(); | |||||
| return second->poll(); | |||||
| } | } | ||||
| else | else | ||||
| { | { | ||||
| auto r = self->first.poll(); | |||||
| auto r = first.poll(); | |||||
| if (!r) | if (!r) | ||||
| return result_type::not_ready(); | return result_type::not_ready(); | ||||
| self->second = std::make_unique<second_future_type>(as_future(r.call(self->lambda))); | |||||
| second = std::make_unique<second_future_type>(r.call(lambda)); | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | |||||
| } } | |||||
| @@ -1,16 +1,27 @@ | |||||
| #pragma once | #pragma once | ||||
| #include "../future.pre.h" | |||||
| namespace asyncpp { | namespace asyncpp { | ||||
| namespace __future { | namespace __future { | ||||
| template< | template< | ||||
| typename T_future, | typename T_future, | ||||
| typename T_lambda> | typename T_lambda> | ||||
| struct map_impl | |||||
| struct map_impl final : | |||||
| public base_future< | |||||
| typename std::decay_t<T_future>::value_type, | |||||
| map_impl<T_future, T_lambda> | |||||
| > | |||||
| { | { | ||||
| public: | public: | ||||
| using future_type = T_future; | |||||
| using lambda_type = T_lambda; | |||||
| using future_type = T_future; | |||||
| using lambda_type = T_lambda; | |||||
| using future_value_type = typename std::decay_t<future_type>::value_type; | |||||
| using value_type = decltype(std::declval<lambda_type>()(std::declval<future_value_type>())); | |||||
| using this_type = map_impl<future_type, lambda_type>; | |||||
| using base_future_type = base_future<value_type, this_type>; | |||||
| using result_type = typename base_future_type::result_type; | |||||
| public: | public: | ||||
| future_type future; | future_type future; | ||||
| @@ -26,29 +37,12 @@ namespace __future { | |||||
| inline map_impl( | inline map_impl( | ||||
| X_future&& p_future, | X_future&& p_future, | ||||
| X_lambda&& p_lambda); | X_lambda&& p_lambda); | ||||
| }; | |||||
| } } | |||||
| 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); | |||||
| public: /* future */ | |||||
| /** | |||||
| * @brief Poll the result from the future. | |||||
| */ | |||||
| inline result_type poll(); | |||||
| }; | }; | ||||
| } | |||||
| } } | |||||
| @@ -21,25 +21,17 @@ namespace __future { | |||||
| , lambda(std::forward<X_lambda>(p_lambda)) | , lambda(std::forward<X_lambda>(p_lambda)) | ||||
| { } | { } | ||||
| } } | |||||
| namespace asyncpp | |||||
| { | |||||
| /* future_trait for map_impl */ | |||||
| template< | template< | ||||
| typename T_future, | typename T_future, | ||||
| typename T_lambda> | typename T_lambda> | ||||
| template< | |||||
| typename X_future> | |||||
| auto future_trait<__future::map_impl<T_future, T_lambda>, void> | |||||
| ::poll(X_future& self) | |||||
| typename map_impl<T_future, T_lambda>::result_type | |||||
| map_impl<T_future, T_lambda> | |||||
| ::poll() | |||||
| { | { | ||||
| auto r = self->future.poll(); | |||||
| auto r = future.poll(); | |||||
| return r | return r | ||||
| ? result_type::ready(r.call(self->lambda)) | |||||
| ? result_type::ready(r.call(lambda)) | |||||
| : result_type::not_ready(); | : result_type::not_ready(); | ||||
| } | } | ||||
| } | |||||
| } } | |||||
| @@ -22,9 +22,9 @@ namespace asyncpp | |||||
| using lambda_type = X_lambda; | using lambda_type = X_lambda; | ||||
| using for_each_type = __stream::for_each_impl<stream_type, lambda_type>; | using for_each_type = __stream::for_each_impl<stream_type, lambda_type>; | ||||
| return as_future(for_each_type( | |||||
| return for_each_type( | |||||
| std::forward<X_stream>(self), | std::forward<X_stream>(self), | ||||
| std::forward<X_lambda>(p_lambda))); | |||||
| std::forward<X_lambda>(p_lambda)); | |||||
| } | } | ||||
| #ifdef asyncpp_timing | #ifdef asyncpp_timing | ||||
| @@ -8,11 +8,19 @@ namespace __stream { | |||||
| template< | template< | ||||
| typename T_stream, | typename T_stream, | ||||
| typename T_lambda> | typename T_lambda> | ||||
| struct for_each_impl | |||||
| struct for_each_impl final : | |||||
| public base_future< | |||||
| void, | |||||
| for_each_impl<T_stream, T_lambda> | |||||
| > | |||||
| { | { | ||||
| public: | public: | ||||
| using stream_type = T_stream; | |||||
| using lambda_type = T_lambda; | |||||
| using stream_type = T_stream; | |||||
| using lambda_type = T_lambda; | |||||
| using value_type = void; | |||||
| using this_type = for_each_impl<stream_type, lambda_type>; | |||||
| using base_future_type = base_future<value_type, this_type>; | |||||
| using result_type = typename base_future_type::result_type; | |||||
| public: | public: | ||||
| stream_type stream; | stream_type stream; | ||||
| @@ -28,30 +36,12 @@ namespace __stream { | |||||
| inline for_each_impl( | inline for_each_impl( | ||||
| X_stream&& p_stream, | X_stream&& p_stream, | ||||
| X_lambda&& p_lambda); | 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 inner_result_type = future_result<inner_value_type>; | |||||
| using lambda_type = T_lambda; | |||||
| using value_type = decltype(std::declval<inner_result_type>().call(std::declval<lambda_type>())); | |||||
| using result_type = future_result<value_type>; | |||||
| template<typename X_future> | |||||
| static inline auto poll(X_future& self); | |||||
| public: /* future */ | |||||
| /** | |||||
| * @brief Poll the result from the future. | |||||
| */ | |||||
| inline result_type poll(); | |||||
| }; | }; | ||||
| } | |||||
| } } | |||||
| @@ -21,32 +21,24 @@ namespace __stream { | |||||
| , lambda(std::forward<X_lambda>(p_lambda)) | , lambda(std::forward<X_lambda>(p_lambda)) | ||||
| { } | { } | ||||
| } } | |||||
| namespace asyncpp | |||||
| { | |||||
| /* future_trait for for_each_impl */ | |||||
| template< | template< | ||||
| typename T_stream, | typename T_stream, | ||||
| typename T_lambda> | typename T_lambda> | ||||
| template< | |||||
| typename X_stream> | |||||
| auto future_trait<__stream::for_each_impl<T_stream, T_lambda>, void> | |||||
| ::poll(X_stream& self) | |||||
| typename for_each_impl<T_stream, T_lambda>::result_type | |||||
| for_each_impl<T_stream, T_lambda> | |||||
| ::poll() | |||||
| { | { | ||||
| while (true) | while (true) | ||||
| { | { | ||||
| auto r = self->stream.poll(); | |||||
| auto r = stream.poll(); | |||||
| if (r.is_done()) | if (r.is_done()) | ||||
| return result_type::ready(); | return result_type::ready(); | ||||
| if (r.is_not_ready()) | if (r.is_not_ready()) | ||||
| return result_type::not_ready(); | return result_type::not_ready(); | ||||
| r.call(self->lambda); | |||||
| r.call(lambda); | |||||
| } | } | ||||
| } | } | ||||
| } | |||||
| } } | |||||
| @@ -9,10 +9,13 @@ | |||||
| namespace asyncpp { | namespace asyncpp { | ||||
| namespace timing { | namespace timing { | ||||
| struct delay | |||||
| struct delay final | |||||
| : public base_future<void, delay> | |||||
| { | { | ||||
| public: | public: | ||||
| friend struct future_trait<delay, void>; | |||||
| using value_type = void; | |||||
| using base_future_type = base_future<void, delay>; | |||||
| using result_type = typename base_future_type::result_type; | |||||
| private: | private: | ||||
| time_point _deadline; | time_point _deadline; | ||||
| @@ -50,24 +53,12 @@ namespace timing { | |||||
| */ | */ | ||||
| template<typename T_base, typename T_ratio> | template<typename T_base, typename T_ratio> | ||||
| inline void reset(const duration<T_base, T_ratio>& p_duration); | inline void reset(const duration<T_base, T_ratio>& p_duration); | ||||
| }; | |||||
| } } | |||||
| namespace asyncpp | |||||
| { | |||||
| /* future_impl for timing::delay */ | |||||
| template<> | |||||
| struct future_trait<timing::delay, void> | |||||
| : public future_base<future<timing::delay, void>> | |||||
| { | |||||
| using value_type = void; | |||||
| using result_type = future_result<value_type>; | |||||
| template<typename X_future> | |||||
| static inline auto poll(X_future& self); | |||||
| public: /* future */ | |||||
| /** | |||||
| * @brief Poll the result from the future. | |||||
| */ | |||||
| inline result_type poll(); | |||||
| }; | }; | ||||
| } | |||||
| } } | |||||
| @@ -43,26 +43,19 @@ namespace timing { | |||||
| _deadline = asyncpp::now() + p_duration; | _deadline = asyncpp::now() + p_duration; | ||||
| } | } | ||||
| } } | |||||
| namespace asyncpp | |||||
| { | |||||
| /* future_impl for timing::delay */ | |||||
| template<typename X_future> | |||||
| auto future_trait<timing::delay, void> | |||||
| ::poll(X_future& self) | |||||
| typename delay::result_type | |||||
| delay | |||||
| ::poll() | |||||
| { | { | ||||
| auto now = asyncpp::now(); | auto now = asyncpp::now(); | ||||
| if (self->_deadline <= now) | |||||
| if (_deadline <= now) | |||||
| return result_type::ready(); | return result_type::ready(); | ||||
| if (self->_registration.expired()) | |||||
| self->_registration = timing::__impl::timer_base::register_resource(self->_deadline); | |||||
| if (_registration.expired()) | |||||
| _registration = timing::__impl::timer_base::register_resource(_deadline); | |||||
| return result_type::not_ready(); | return result_type::not_ready(); | ||||
| } | } | ||||
| } | |||||
| } } | |||||
| @@ -9,16 +9,13 @@ | |||||
| namespace asyncpp { | namespace asyncpp { | ||||
| namespace timing { | namespace timing { | ||||
| struct interval | |||||
| struct interval final | |||||
| { | { | ||||
| public: | |||||
| using delay_future_type = future<delay>; | |||||
| public: | public: | ||||
| friend struct stream_trait<interval, void>; | friend struct stream_trait<interval, void>; | ||||
| private: | private: | ||||
| delay_future_type _delay; //!< Delay future | |||||
| delay _delay; //!< Delay future | |||||
| clock::duration _duration; //!< Interval duration. | clock::duration _duration; //!< Interval duration. | ||||
| time_point _deadline; //!< Deadline after the interval should end. | time_point _deadline; //!< Deadline after the interval should end. | ||||
| @@ -22,7 +22,7 @@ namespace timing { | |||||
| const time_point& p_at, | const time_point& p_at, | ||||
| const asyncpp::duration<T_base, T_ratio>& p_duration, | const asyncpp::duration<T_base, T_ratio>& p_duration, | ||||
| time_point p_deadline) | time_point p_deadline) | ||||
| : _delay (as_future(delay(p_at))) | |||||
| : _delay (p_at) | |||||
| , _duration(p_duration) | , _duration(p_duration) | ||||
| , _deadline(p_deadline) | , _deadline(p_deadline) | ||||
| { } | { } | ||||
| @@ -43,17 +43,17 @@ namespace asyncpp | |||||
| ::poll(X_stream& self) | ::poll(X_stream& self) | ||||
| { | { | ||||
| if ( self->_deadline.time_since_epoch().count() | if ( self->_deadline.time_since_epoch().count() | ||||
| && self->_delay->deadline() >= self->_deadline | |||||
| && asyncpp::now() >= self->_delay->deadline()) | |||||
| && self->_delay.deadline() >= self->_deadline | |||||
| && asyncpp::now() >= self->_delay.deadline()) | |||||
| return result_type::done(); | return result_type::done(); | ||||
| auto ret = self->_delay.poll(); | auto ret = self->_delay.poll(); | ||||
| if (ret.is_not_ready()) | if (ret.is_not_ready()) | ||||
| return result_type::not_ready(); | return result_type::not_ready(); | ||||
| auto now = self->_delay->deadline(); | |||||
| auto now = self->_delay.deadline(); | |||||
| auto new_deadline = now + self->_duration; | auto new_deadline = now + self->_duration; | ||||
| self->_delay->reset(new_deadline); | |||||
| self->_delay.reset(new_deadline); | |||||
| return result_type::ready(); | return result_type::ready(); | ||||
| } | } | ||||
| @@ -21,21 +21,27 @@ namespace timing { | |||||
| inline timeout_exception(); | inline timeout_exception(); | ||||
| }; | }; | ||||
| struct tag_timeout | |||||
| { }; | |||||
| template<typename T_inner> | template<typename T_inner> | ||||
| struct timeout | |||||
| struct timeout final | |||||
| : public std::conditional_t< | |||||
| is_future_v<T_inner>, | |||||
| base_future<typename std::decay_t<T_inner>::value_type, timeout<T_inner>>, | |||||
| tag_timeout> | |||||
| { | { | ||||
| public: | public: | ||||
| using inner_type = T_inner; | |||||
| using delay_future_type = future<delay>; | |||||
| using inner_type = T_inner; | |||||
| using value_type = typename std::decay_t<inner_type>::value_type; | |||||
| public: | public: | ||||
| friend struct stream_trait<timeout, void>; | friend struct stream_trait<timeout, void>; | ||||
| friend struct future_trait<timeout, void>; | |||||
| private: | private: | ||||
| inner_type _inner; //!< Inner future / stream. | |||||
| clock::duration _timeout; //!< Timeout. | |||||
| delay_future_type _delay; //!< Delay future. | |||||
| inner_type _inner; //!< Inner future / stream. | |||||
| clock::duration _timeout; //!< Timeout. | |||||
| delay _delay; //!< Delay future. | |||||
| public: | public: | ||||
| /** | /** | ||||
| @@ -52,6 +58,15 @@ namespace timing { | |||||
| template<typename X_base, typename X_ratio> | template<typename X_base, typename X_ratio> | ||||
| inline void reset( | inline void reset( | ||||
| const duration<X_base, X_ratio>& p_timeout); | const duration<X_base, X_ratio>& p_timeout); | ||||
| public: /* future */ | |||||
| /** | |||||
| * @brief Poll the result from the future. | |||||
| */ | |||||
| template< | |||||
| typename X = std::decay_t<inner_type>, | |||||
| typename = std::enable_if_t<is_future_v<X>>> | |||||
| inline auto poll(); | |||||
| }; | }; | ||||
| } } | } } | ||||
| @@ -59,24 +74,6 @@ namespace timing { | |||||
| namespace asyncpp | namespace asyncpp | ||||
| { | { | ||||
| /* future_trait for timing::timeout */ | |||||
| template<typename T_inner> | |||||
| struct future_trait< | |||||
| timing::timeout<T_inner>, | |||||
| std::enable_if_t<is_future_v<T_inner>> | |||||
| > | |||||
| : public future_base<future<timing::timeout<T_inner>, void>> | |||||
| { | |||||
| using inner_type = T_inner; | |||||
| using timeout_type = timing::timeout<inner_type>; | |||||
| using value_type = typename inner_type::value_type; | |||||
| using result_type = typename inner_type::result_type; | |||||
| template<typename X_future> | |||||
| static inline result_type poll(X_future& self); | |||||
| }; | |||||
| /* stream_trait for timing::timeout */ | /* stream_trait for timing::timeout */ | ||||
| template<typename T_inner> | template<typename T_inner> | ||||
| @@ -15,55 +15,59 @@ namespace timing { | |||||
| /* timer */ | /* timer */ | ||||
| template<typename T_inner> | |||||
| template<typename X_inner, typename X_base, typename X_ratio> | |||||
| template< | |||||
| typename T_inner> | |||||
| template< | |||||
| typename X_inner, | |||||
| typename X_base, | |||||
| typename X_ratio> | |||||
| timeout<T_inner> | timeout<T_inner> | ||||
| ::timeout( | ::timeout( | ||||
| X_inner&& p_inner, | X_inner&& p_inner, | ||||
| const duration<X_base, X_ratio>& p_duration) | const duration<X_base, X_ratio>& p_duration) | ||||
| : _inner (std::forward<X_inner>(p_inner)) | : _inner (std::forward<X_inner>(p_inner)) | ||||
| , _timeout (p_duration) | , _timeout (p_duration) | ||||
| , _delay (as_future(delay(asyncpp::now() + p_duration))) | |||||
| , _delay (asyncpp::now() + p_duration) | |||||
| { } | { } | ||||
| template<typename T_inner> | |||||
| template<typename X_base, typename X_ratio> | |||||
| template< | |||||
| typename T_inner> | |||||
| template< | |||||
| typename X_base, | |||||
| typename X_ratio> | |||||
| void timeout<T_inner> | void timeout<T_inner> | ||||
| ::reset(const duration<X_base, X_ratio>& p_duration) | ::reset(const duration<X_base, X_ratio>& p_duration) | ||||
| { | { | ||||
| _timeout = p_duration; | _timeout = p_duration; | ||||
| _delay->reset(asyncpp::now() + p_duration); | |||||
| _delay.reset(asyncpp::now() + p_duration); | |||||
| } | } | ||||
| } } | |||||
| namespace asyncpp | |||||
| { | |||||
| /* future_trait for timing::timeout */ | |||||
| template<typename T_inner> | |||||
| template<typename X_future> | |||||
| typename T_inner::result_type | |||||
| future_trait< | |||||
| timing::timeout<T_inner>, | |||||
| std::enable_if_t<is_future_v<T_inner>> | |||||
| > | |||||
| ::poll(X_future& self) | |||||
| template< | |||||
| typename T_inner> | |||||
| template< | |||||
| typename X, | |||||
| typename> | |||||
| auto timeout<T_inner> | |||||
| ::poll() | |||||
| { | { | ||||
| auto r = self->_inner.poll(); | |||||
| auto r = _inner.poll(); | |||||
| if ( r.is_not_ready() | if ( r.is_not_ready() | ||||
| && self->_delay.poll()) | |||||
| && _delay.poll()) | |||||
| { | { | ||||
| auto new_deadline = self->_delay->deadline() + self->_timeout; | |||||
| self->_delay->reset(new_deadline); | |||||
| auto new_deadline = _delay.deadline() + _timeout; | |||||
| _delay.reset(new_deadline); | |||||
| throw timing::timeout_exception(); | throw timing::timeout_exception(); | ||||
| } | } | ||||
| return r; | return r; | ||||
| } | } | ||||
| } } | |||||
| namespace asyncpp | |||||
| { | |||||
| /* stream_trait for timing::timeout */ | /* stream_trait for timing::timeout */ | ||||
| template<typename T_inner> | template<typename T_inner> | ||||
| @@ -81,13 +85,13 @@ namespace asyncpp | |||||
| { | { | ||||
| if (self->_delay.poll()) | if (self->_delay.poll()) | ||||
| { | { | ||||
| self->_delay->reset(self->_timeout); | |||||
| self->_delay.reset(self->_timeout); | |||||
| throw timing::timeout_exception(); | throw timing::timeout_exception(); | ||||
| } | } | ||||
| } | } | ||||
| else | else | ||||
| { | { | ||||
| self->_delay->reset(self->_timeout); | |||||
| self->_delay.reset(self->_timeout); | |||||
| } | } | ||||
| return r; | return r; | ||||
| @@ -2,43 +2,14 @@ | |||||
| #include <asyncpp.h> | #include <asyncpp.h> | ||||
| #include "../../helper/test_delay.h" | |||||
| using namespace ::testing; | using namespace ::testing; | ||||
| using namespace ::asyncpp; | 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->count >= self->delay) | |||||
| return result_type::ready(self->count); | |||||
| ++self->count; | |||||
| return result_type::not_ready(); | |||||
| } | |||||
| }; | |||||
| } | |||||
| TEST(future_tests, poll) | TEST(future_tests, poll) | ||||
| { | { | ||||
| delay d { 5, 0 }; | |||||
| auto f = as_future(d); | |||||
| test_delay f(5, 0); | |||||
| auto r0 = f.poll(); | auto r0 = f.poll(); | ||||
| ASSERT_FALSE(r0); | ASSERT_FALSE(r0); | ||||
| @@ -58,14 +29,14 @@ TEST(future_tests, poll) | |||||
| auto r = f.poll(); | auto r = f.poll(); | ||||
| ASSERT_TRUE (r); | ASSERT_TRUE (r); | ||||
| ASSERT_EQ (5, *r); | ASSERT_EQ (5, *r); | ||||
| ASSERT_EQ (5, d.count); | |||||
| ASSERT_EQ (&*r, &d.count); | |||||
| ASSERT_EQ (5, f._count); | |||||
| ASSERT_EQ (&*r, &f._count); | |||||
| } | } | ||||
| TEST(future_tests, map) | TEST(future_tests, map) | ||||
| { | { | ||||
| delay d { 1, 1 }; | |||||
| auto f = as_future(d) | |||||
| test_delay d(1, 1); | |||||
| auto f = d | |||||
| .map([](int& i){ | .map([](int& i){ | ||||
| return 10 + i; | return 10 + i; | ||||
| }); | }); | ||||
| @@ -77,10 +48,10 @@ TEST(future_tests, map) | |||||
| TEST(future_tests, and_then) | TEST(future_tests, and_then) | ||||
| { | { | ||||
| delay d { 2, 0 }; | |||||
| auto f = as_future(d) | |||||
| test_delay d(2, 0); | |||||
| auto f = d | |||||
| .and_then([](int& i){ | .and_then([](int& i){ | ||||
| return delay { 5, i }; | |||||
| return test_delay { 5, i }; | |||||
| }); | }); | ||||
| auto r0 = f.poll(); | auto r0 = f.poll(); | ||||
| @@ -101,5 +72,5 @@ TEST(future_tests, and_then) | |||||
| auto r = f.poll(); | auto r = f.poll(); | ||||
| ASSERT_TRUE(r); | ASSERT_TRUE(r); | ||||
| ASSERT_EQ (5, *r); | ASSERT_EQ (5, *r); | ||||
| ASSERT_EQ (2, d.count); | |||||
| ASSERT_EQ (2, f.first._count); | |||||
| } | } | ||||
| @@ -2,42 +2,14 @@ | |||||
| #include <asyncpp.h> | #include <asyncpp.h> | ||||
| #include "../../helper/test_delay.h" | |||||
| using namespace ::testing; | using namespace ::testing; | ||||
| using namespace ::asyncpp; | 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->count >= self->delay) | |||||
| return result_type::ready(self->count); | |||||
| ++self->count; | |||||
| return result_type::not_ready(); | |||||
| } | |||||
| }; | |||||
| } | |||||
| TEST(task_tests, poll) | TEST(task_tests, poll) | ||||
| { | { | ||||
| auto t = make_task(as_future(delay { 5, 0 })); | |||||
| auto t = make_task(test_delay { 5, 0 }); | |||||
| ASSERT_FALSE(t->poll()); | ASSERT_FALSE(t->poll()); | ||||
| ASSERT_FALSE(t->poll()); | ASSERT_FALSE(t->poll()); | ||||
| @@ -11,9 +11,29 @@ using namespace ::testing; | |||||
| using namespace ::asyncpp; | using namespace ::asyncpp; | ||||
| struct test | struct test | ||||
| : public base_future<void, test> | |||||
| { | { | ||||
| public: | |||||
| using value_type = void; | |||||
| using this_type = test; | |||||
| using base_future_type = base_future<void, this_type>; | |||||
| using result_type = typename base_future_type::result_type; | |||||
| public: | |||||
| bool done { false }; | bool done { false }; | ||||
| task_ptr_w task; | task_ptr_w task; | ||||
| public: | |||||
| inline test() = default; | |||||
| public: | |||||
| inline auto poll() | |||||
| { | |||||
| task = task::current(); | |||||
| return done | |||||
| ? result_type::ready() | |||||
| : result_type::not_ready(); | |||||
| } | |||||
| }; | }; | ||||
| struct mock | struct mock | ||||
| @@ -21,30 +41,8 @@ struct mock | |||||
| MOCK_METHOD0(call, void()); | MOCK_METHOD0(call, void()); | ||||
| }; | }; | ||||
| namespace asyncpp | |||||
| { | |||||
| template<> | |||||
| struct future_trait<test, void> | |||||
| : public future_base<future<test, void>> | |||||
| { | |||||
| using value_type = void; | |||||
| using result_type = future_result<value_type>; | |||||
| template<typename X_future> | |||||
| static inline auto poll(X_future& self) | |||||
| { | |||||
| self->task = task::current(); | |||||
| return self->done | |||||
| ? result_type::ready() | |||||
| : result_type::not_ready(); | |||||
| } | |||||
| }; | |||||
| } | |||||
| TEST(current_thread_tests, run) | TEST(current_thread_tests, run) | ||||
| {/* | |||||
| { | |||||
| Sequence s; | Sequence s; | ||||
| StrictMock<runtime_mock> m; | StrictMock<runtime_mock> m; | ||||
| executor::current_thread<StrictMock<runtime_mock>&> e(m); | executor::current_thread<StrictMock<runtime_mock>&> e(m); | ||||
| @@ -52,7 +50,6 @@ TEST(current_thread_tests, run) | |||||
| EXPECT_CALL(m, init_thread()); | EXPECT_CALL(m, init_thread()); | ||||
| test t; | test t; | ||||
| auto f = as_future(t); | |||||
| EXPECT_CALL(m, idle(nullptr)) | EXPECT_CALL(m, idle(nullptr)) | ||||
| .InSequence(s) | .InSequence(s) | ||||
| @@ -68,7 +65,7 @@ TEST(current_thread_tests, run) | |||||
| s->notify(); | s->notify(); | ||||
| }));; | }));; | ||||
| e.run(f); */ | |||||
| e.run(t); | |||||
| } | } | ||||
| TEST(current_thread_tests, interval) | TEST(current_thread_tests, interval) | ||||
| @@ -22,8 +22,7 @@ TEST(delay_tests, poll) | |||||
| t.make_current(); | t.make_current(); | ||||
| { | { | ||||
| delay d(time_point(std::chrono::seconds(1000))); | |||||
| auto f = as_future(d); | |||||
| delay f(time_point(std::chrono::seconds(1000))); | |||||
| EXPECT_EQ(0, t.resource_count()); | EXPECT_EQ(0, t.resource_count()); | ||||
| @@ -10,28 +10,31 @@ using namespace ::asyncpp; | |||||
| using namespace ::asyncpp::timing; | using namespace ::asyncpp::timing; | ||||
| struct test | struct test | ||||
| : public base_future<int, test> | |||||
| { | { | ||||
| public: | |||||
| using value_type = int; | |||||
| using this_type = test; | |||||
| using base_future_type = base_future<value_type, this_type>; | |||||
| public: | |||||
| int i; | int i; | ||||
| }; | |||||
| namespace asyncpp | |||||
| { | |||||
| inline test(int p_i) | |||||
| : i(p_i) | |||||
| { } | |||||
| template<> | |||||
| struct future_trait<test, void> | |||||
| : public future_base<future<test, void>> | |||||
| public: | |||||
| inline result_type poll() | |||||
| { | { | ||||
| using value_type = int; | |||||
| using result_type = future_result<value_type>; | |||||
| return i | |||||
| ? result_type::ready(i) | |||||
| : result_type::not_ready(); | |||||
| } | |||||
| }; | |||||
| template<typename X_future> | |||||
| static inline result_type poll(X_future& self) | |||||
| { | |||||
| return self->i | |||||
| ? result_type::ready(self->i) | |||||
| : result_type::not_ready(); | |||||
| } | |||||
| }; | |||||
| namespace asyncpp | |||||
| { | |||||
| template<> | template<> | ||||
| struct stream_trait<test, void> | struct stream_trait<test, void> | ||||
| @@ -62,8 +65,8 @@ TEST(timeout_tests, poll_future_no_timeout) | |||||
| EXPECT_CALL(m, now()) | EXPECT_CALL(m, now()) | ||||
| .WillOnce(Return(time_point(std::chrono::seconds(0)))); | .WillOnce(Return(time_point(std::chrono::seconds(0)))); | ||||
| auto t = test { 0 }; | |||||
| auto f = as_future(t) | |||||
| test t(0); | |||||
| auto f = t | |||||
| .timeout(std::chrono::seconds(5)); | .timeout(std::chrono::seconds(5)); | ||||
| EXPECT_CALL(m, now()) | EXPECT_CALL(m, now()) | ||||
| @@ -95,8 +98,7 @@ TEST(timeout_tests, poll_future_timeout) | |||||
| EXPECT_CALL(m, now()) | EXPECT_CALL(m, now()) | ||||
| .WillOnce(Return(time_point(std::chrono::seconds(0)))); | .WillOnce(Return(time_point(std::chrono::seconds(0)))); | ||||
| auto t = test { 0 }; | |||||
| auto f = as_future(t) | |||||
| auto f = test(0) | |||||
| .timeout(std::chrono::seconds(5)); | .timeout(std::chrono::seconds(5)); | ||||
| EXPECT_CALL(m, now()) | EXPECT_CALL(m, now()) | ||||
| @@ -38,14 +38,12 @@ TEST(timer_tests, resource_registration) | |||||
| EXPECT_CALL(m, now) | EXPECT_CALL(m, now) | ||||
| .WillRepeatedly(Return(time_point(std::chrono::seconds(0)))); | .WillRepeatedly(Return(time_point(std::chrono::seconds(0)))); | ||||
| using delay_future_type = decltype(as_future(timing::delay(std::chrono::seconds(10)))); | |||||
| timing::timer t; | timing::timer t; | ||||
| t.make_current(); | t.make_current(); | ||||
| auto f1 = std::make_unique<delay_future_type>(timing::delay(std::chrono::seconds(10))); | |||||
| auto f2 = std::make_unique<delay_future_type>(timing::delay(std::chrono::seconds(20))); | |||||
| auto f3 = std::make_unique<delay_future_type>(timing::delay(std::chrono::seconds(30))); | |||||
| auto f1 = std::make_unique<timing::delay>(std::chrono::seconds(10)); | |||||
| auto f2 = std::make_unique<timing::delay>(std::chrono::seconds(20)); | |||||
| auto f3 = std::make_unique<timing::delay>(std::chrono::seconds(30)); | |||||
| EXPECT_EQ(0, t.resource_count()); | EXPECT_EQ(0, t.resource_count()); | ||||
| @@ -80,8 +78,6 @@ TEST(timer_tests, resource_registration) | |||||
| TEST(timer_tests, idle) | TEST(timer_tests, idle) | ||||
| { | { | ||||
| using delay_future_type = decltype(as_future(std::declval<timing::delay>())); | |||||
| time_point x; | time_point x; | ||||
| InSequence seq; | InSequence seq; | ||||
| StrictMock<now_mock> nm; | StrictMock<now_mock> nm; | ||||
| @@ -102,7 +98,7 @@ TEST(timer_tests, idle) | |||||
| EXPECT_CALL(nm, now); | EXPECT_CALL(nm, now); | ||||
| auto f = std::make_unique<delay_future_type>(timing::delay(time_point(std::chrono::seconds(10)))); | |||||
| auto f = std::make_unique<timing::delay>(time_point(std::chrono::seconds(10))); | |||||
| f->poll(); | f->poll(); | ||||
| EXPECT_CALL(nm, now); | EXPECT_CALL(nm, now); | ||||
| @@ -0,0 +1,33 @@ | |||||
| #pragma once | |||||
| #include <asyncpp.h> | |||||
| struct test_delay final | |||||
| : public asyncpp::base_future<int&, test_delay> | |||||
| { | |||||
| public: | |||||
| using value_type = int&; | |||||
| using this_type = test_delay; | |||||
| using base_future_type = base_future<value_type, this_type>; | |||||
| using result_type = typename base_future_type::result_type; | |||||
| public: | |||||
| int const _delay { 5 }; | |||||
| int _count { 0 }; | |||||
| public: | |||||
| test_delay(int p_delay, int p_count) | |||||
| : _delay(p_delay) | |||||
| , _count(p_count) | |||||
| { } | |||||
| inline result_type poll() | |||||
| { | |||||
| if (_count >= _delay) | |||||
| return result_type::ready(_count); | |||||
| ++_count; | |||||
| return result_type::not_ready(); | |||||
| } | |||||
| }; | |||||