| @@ -12,61 +12,84 @@ namespace asyncpp | |||
| { | |||
| 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. | |||
| */ | |||
| 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 | |||
| * wait for the future returned by the 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. | |||
| * | |||
| * 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 | |||
| 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 | |||
| { | |||
| /* 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< | |||
| typename T_value, | |||
| typename T_impl> | |||
| typename T_derived> | |||
| 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< | |||
| typename T_value, | |||
| typename T_impl> | |||
| typename T_derived> | |||
| template< | |||
| 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< | |||
| typename T_value, | |||
| typename T_impl> | |||
| typename T_derived> | |||
| template< | |||
| 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 | |||
| template< | |||
| typename T_value, | |||
| typename T_impl> | |||
| typename T_derived> | |||
| template< | |||
| typename X_base, | |||
| 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< | |||
| 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< | |||
| 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 | |||
| { | |||
| 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< | |||
| 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 | |||
| : public std::false_type | |||
| : public std::is_base_of<tag_future, T> | |||
| { }; | |||
| template<typename T> | |||
| 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 <asyncpp/core/future.pre.h> | |||
| #include "../future.pre.h" | |||
| namespace asyncpp { | |||
| namespace __future { | |||
| @@ -10,14 +10,22 @@ namespace __future { | |||
| template< | |||
| typename T_future, | |||
| 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: | |||
| 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 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 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: | |||
| lambda_type lambda; | |||
| @@ -34,28 +42,12 @@ namespace __future { | |||
| inline and_then_impl( | |||
| X_future&& p_outer, | |||
| 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)) | |||
| { } | |||
| } } | |||
| 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) | |||
| typename and_then_impl<T_future, T_lambda>::result_type | |||
| and_then_impl<T_future, T_lambda> | |||
| ::poll() | |||
| { | |||
| while (true) | |||
| { | |||
| if (self->second) | |||
| if (second) | |||
| { | |||
| return self->second->poll(); | |||
| return second->poll(); | |||
| } | |||
| else | |||
| { | |||
| auto r = self->first.poll(); | |||
| auto r = first.poll(); | |||
| if (!r) | |||
| 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 | |||
| #include "../future.pre.h" | |||
| namespace asyncpp { | |||
| namespace __future { | |||
| template< | |||
| typename T_future, | |||
| 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: | |||
| 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: | |||
| future_type future; | |||
| @@ -26,29 +37,12 @@ namespace __future { | |||
| inline map_impl( | |||
| X_future&& p_future, | |||
| 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)) | |||
| { } | |||
| } } | |||
| 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) | |||
| 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 | |||
| ? result_type::ready(r.call(self->lambda)) | |||
| ? result_type::ready(r.call(lambda)) | |||
| : result_type::not_ready(); | |||
| } | |||
| } | |||
| } } | |||
| @@ -22,9 +22,9 @@ namespace asyncpp | |||
| using lambda_type = X_lambda; | |||
| 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_lambda>(p_lambda))); | |||
| std::forward<X_lambda>(p_lambda)); | |||
| } | |||
| #ifdef asyncpp_timing | |||
| @@ -8,11 +8,19 @@ namespace __stream { | |||
| template< | |||
| typename T_stream, | |||
| typename T_lambda> | |||
| struct for_each_impl | |||
| struct for_each_impl final : | |||
| public base_future< | |||
| void, | |||
| for_each_impl<T_stream, T_lambda> | |||
| > | |||
| { | |||
| 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: | |||
| stream_type stream; | |||
| @@ -28,30 +36,12 @@ namespace __stream { | |||
| 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 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)) | |||
| { } | |||
| } } | |||
| 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) | |||
| typename for_each_impl<T_stream, T_lambda>::result_type | |||
| for_each_impl<T_stream, T_lambda> | |||
| ::poll() | |||
| { | |||
| while (true) | |||
| { | |||
| auto r = self->stream.poll(); | |||
| auto r = stream.poll(); | |||
| if (r.is_done()) | |||
| return result_type::ready(); | |||
| if (r.is_not_ready()) | |||
| return result_type::not_ready(); | |||
| r.call(self->lambda); | |||
| r.call(lambda); | |||
| } | |||
| } | |||
| } | |||
| } } | |||
| @@ -9,10 +9,13 @@ | |||
| namespace asyncpp { | |||
| namespace timing { | |||
| struct delay | |||
| struct delay final | |||
| : public base_future<void, delay> | |||
| { | |||
| 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: | |||
| time_point _deadline; | |||
| @@ -50,24 +53,12 @@ namespace timing { | |||
| */ | |||
| template<typename T_base, typename T_ratio> | |||
| 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; | |||
| } | |||
| } } | |||
| 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(); | |||
| if (self->_deadline <= now) | |||
| if (_deadline <= now) | |||
| 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(); | |||
| } | |||
| } | |||
| } } | |||
| @@ -9,16 +9,13 @@ | |||
| namespace asyncpp { | |||
| namespace timing { | |||
| struct interval | |||
| struct interval final | |||
| { | |||
| public: | |||
| using delay_future_type = future<delay>; | |||
| public: | |||
| friend struct stream_trait<interval, void>; | |||
| private: | |||
| delay_future_type _delay; //!< Delay future | |||
| delay _delay; //!< Delay future | |||
| clock::duration _duration; //!< Interval duration. | |||
| time_point _deadline; //!< Deadline after the interval should end. | |||
| @@ -22,7 +22,7 @@ namespace timing { | |||
| const time_point& p_at, | |||
| const asyncpp::duration<T_base, T_ratio>& p_duration, | |||
| time_point p_deadline) | |||
| : _delay (as_future(delay(p_at))) | |||
| : _delay (p_at) | |||
| , _duration(p_duration) | |||
| , _deadline(p_deadline) | |||
| { } | |||
| @@ -43,17 +43,17 @@ namespace asyncpp | |||
| ::poll(X_stream& self) | |||
| { | |||
| 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(); | |||
| auto ret = self->_delay.poll(); | |||
| if (ret.is_not_ready()) | |||
| return result_type::not_ready(); | |||
| auto now = self->_delay->deadline(); | |||
| auto now = self->_delay.deadline(); | |||
| auto new_deadline = now + self->_duration; | |||
| self->_delay->reset(new_deadline); | |||
| self->_delay.reset(new_deadline); | |||
| return result_type::ready(); | |||
| } | |||
| @@ -21,21 +21,27 @@ namespace timing { | |||
| inline timeout_exception(); | |||
| }; | |||
| struct tag_timeout | |||
| { }; | |||
| 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: | |||
| 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: | |||
| friend struct stream_trait<timeout, void>; | |||
| friend struct future_trait<timeout, void>; | |||
| 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: | |||
| /** | |||
| @@ -52,6 +58,15 @@ namespace timing { | |||
| template<typename X_base, typename X_ratio> | |||
| inline void reset( | |||
| 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 | |||
| { | |||
| /* 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 */ | |||
| template<typename T_inner> | |||
| @@ -15,55 +15,59 @@ namespace timing { | |||
| /* 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( | |||
| X_inner&& p_inner, | |||
| const duration<X_base, X_ratio>& p_duration) | |||
| : _inner (std::forward<X_inner>(p_inner)) | |||
| , _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> | |||
| ::reset(const duration<X_base, X_ratio>& 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() | |||
| && 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(); | |||
| } | |||
| return r; | |||
| } | |||
| } } | |||
| namespace asyncpp | |||
| { | |||
| /* stream_trait for timing::timeout */ | |||
| template<typename T_inner> | |||
| @@ -81,13 +85,13 @@ namespace asyncpp | |||
| { | |||
| if (self->_delay.poll()) | |||
| { | |||
| self->_delay->reset(self->_timeout); | |||
| self->_delay.reset(self->_timeout); | |||
| throw timing::timeout_exception(); | |||
| } | |||
| } | |||
| else | |||
| { | |||
| self->_delay->reset(self->_timeout); | |||
| self->_delay.reset(self->_timeout); | |||
| } | |||
| return r; | |||
| @@ -2,43 +2,14 @@ | |||
| #include <asyncpp.h> | |||
| #include "../../helper/test_delay.h" | |||
| using namespace ::testing; | |||
| using namespace ::asyncpp; | |||
| struct delay | |||
| { | |||
| int const delay { 5 }; | |||
| int count { 0 }; | |||
| }; | |||
| namespace asyncpp | |||
| { | |||
| template<> | |||
| struct future_trait<delay, void> | |||
| : public future_base<future<delay, void>> | |||
| { | |||
| using value_type = int&; | |||
| template<typename T_future> | |||
| static inline auto poll(T_future& self) | |||
| { | |||
| using result_type = future_result<value_type>; | |||
| if (self->count >= self->delay) | |||
| return result_type::ready(self->count); | |||
| ++self->count; | |||
| return result_type::not_ready(); | |||
| } | |||
| }; | |||
| } | |||
| TEST(future_tests, poll) | |||
| { | |||
| delay d { 5, 0 }; | |||
| auto f = as_future(d); | |||
| test_delay f(5, 0); | |||
| auto r0 = f.poll(); | |||
| ASSERT_FALSE(r0); | |||
| @@ -58,14 +29,14 @@ TEST(future_tests, poll) | |||
| auto r = f.poll(); | |||
| ASSERT_TRUE (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) | |||
| { | |||
| delay d { 1, 1 }; | |||
| auto f = as_future(d) | |||
| test_delay d(1, 1); | |||
| auto f = d | |||
| .map([](int& i){ | |||
| return 10 + i; | |||
| }); | |||
| @@ -77,10 +48,10 @@ TEST(future_tests, map) | |||
| 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){ | |||
| return delay { 5, i }; | |||
| return test_delay { 5, i }; | |||
| }); | |||
| auto r0 = f.poll(); | |||
| @@ -101,5 +72,5 @@ TEST(future_tests, and_then) | |||
| auto r = f.poll(); | |||
| ASSERT_TRUE(r); | |||
| ASSERT_EQ (5, *r); | |||
| ASSERT_EQ (2, d.count); | |||
| ASSERT_EQ (2, f.first._count); | |||
| } | |||
| @@ -2,42 +2,14 @@ | |||
| #include <asyncpp.h> | |||
| #include "../../helper/test_delay.h" | |||
| using namespace ::testing; | |||
| using namespace ::asyncpp; | |||
| struct delay | |||
| { | |||
| int const delay { 5 }; | |||
| int count { 0 }; | |||
| }; | |||
| namespace asyncpp | |||
| { | |||
| template<> | |||
| struct future_trait<delay, void> | |||
| : public future_base<future<delay, void>> | |||
| { | |||
| using value_type = int&; | |||
| template<typename T_future> | |||
| static inline auto poll(T_future& self) | |||
| { | |||
| using result_type = future_result<value_type>; | |||
| if (self->count >= self->delay) | |||
| return result_type::ready(self->count); | |||
| ++self->count; | |||
| return result_type::not_ready(); | |||
| } | |||
| }; | |||
| } | |||
| 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()); | |||
| @@ -11,9 +11,29 @@ using namespace ::testing; | |||
| using namespace ::asyncpp; | |||
| 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 }; | |||
| 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 | |||
| @@ -21,30 +41,8 @@ struct mock | |||
| 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) | |||
| {/* | |||
| { | |||
| Sequence s; | |||
| StrictMock<runtime_mock> m; | |||
| executor::current_thread<StrictMock<runtime_mock>&> e(m); | |||
| @@ -52,7 +50,6 @@ TEST(current_thread_tests, run) | |||
| EXPECT_CALL(m, init_thread()); | |||
| test t; | |||
| auto f = as_future(t); | |||
| EXPECT_CALL(m, idle(nullptr)) | |||
| .InSequence(s) | |||
| @@ -68,7 +65,7 @@ TEST(current_thread_tests, run) | |||
| s->notify(); | |||
| }));; | |||
| e.run(f); */ | |||
| e.run(t); | |||
| } | |||
| TEST(current_thread_tests, interval) | |||
| @@ -22,8 +22,7 @@ TEST(delay_tests, poll) | |||
| 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()); | |||
| @@ -10,28 +10,31 @@ using namespace ::asyncpp; | |||
| using namespace ::asyncpp::timing; | |||
| 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; | |||
| }; | |||
| 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<> | |||
| struct stream_trait<test, void> | |||
| @@ -62,8 +65,8 @@ TEST(timeout_tests, poll_future_no_timeout) | |||
| EXPECT_CALL(m, now()) | |||
| .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)); | |||
| EXPECT_CALL(m, now()) | |||
| @@ -95,8 +98,7 @@ TEST(timeout_tests, poll_future_timeout) | |||
| EXPECT_CALL(m, now()) | |||
| .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)); | |||
| EXPECT_CALL(m, now()) | |||
| @@ -38,14 +38,12 @@ TEST(timer_tests, resource_registration) | |||
| EXPECT_CALL(m, now) | |||
| .WillRepeatedly(Return(time_point(std::chrono::seconds(0)))); | |||
| using delay_future_type = decltype(as_future(timing::delay(std::chrono::seconds(10)))); | |||
| timing::timer t; | |||
| 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()); | |||
| @@ -80,8 +78,6 @@ TEST(timer_tests, resource_registration) | |||
| TEST(timer_tests, idle) | |||
| { | |||
| using delay_future_type = decltype(as_future(std::declval<timing::delay>())); | |||
| time_point x; | |||
| InSequence seq; | |||
| StrictMock<now_mock> nm; | |||
| @@ -102,7 +98,7 @@ TEST(timer_tests, idle) | |||
| 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(); | |||
| 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(); | |||
| } | |||
| }; | |||