| @@ -6,7 +6,13 @@ | |||||
| #include "core/stream.h" | #include "core/stream.h" | ||||
| #include "core/task.h" | #include "core/task.h" | ||||
| #include "core/future.inl" | |||||
| #include "core/misc.inl" | |||||
| #include "core/result.inl" | #include "core/result.inl" | ||||
| #include "core/stream.inl" | #include "core/stream.inl" | ||||
| #include "core/future/map.inl" | |||||
| #include "core/future/lazy.inl" | |||||
| #include "core/future/and_then.inl" | |||||
| #ifdef asyncpp_timing | |||||
| #include "core/future/timeout.inl" | |||||
| #endif | |||||
| @@ -2,6 +2,7 @@ | |||||
| #include <type_traits> | #include <type_traits> | ||||
| #include "misc.h" | |||||
| #include "result.h" | #include "result.h" | ||||
| #include "future.pre.h" | #include "future.pre.h" | ||||
| @@ -28,19 +29,17 @@ namespace asyncpp | |||||
| /** | /** | ||||
| * @brief Transform the result of this future. | * @brief Transform the result of this future. | ||||
| */ | */ | ||||
| template<typename X_lambda> | |||||
| inline auto map(X_lambda&& p_lambda) const &; | |||||
| /** | |||||
| * @brief Transform the result of this future. | |||||
| */ | |||||
| template<typename X_lambda> | |||||
| template< | |||||
| chaining_mode X_mode = copy, | |||||
| typename X_lambda> | |||||
| inline auto map(X_lambda&& p_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< | |||||
| chaining_mode X_mode = move, | |||||
| typename X_lambda> | |||||
| inline auto map(X_lambda&& p_lambda) &&; | inline auto map(X_lambda&& p_lambda) &&; | ||||
| public: | public: | ||||
| @@ -48,21 +47,18 @@ namespace asyncpp | |||||
| * @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> | |||||
| 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> | |||||
| template< | |||||
| chaining_mode X_mode = copy, | |||||
| typename X_lambda> | |||||
| inline auto and_then(X_lambda&& p_lambda) &; | inline auto and_then(X_lambda&& p_lambda) &; | ||||
| /** | /** | ||||
| * @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< | |||||
| chaining_mode X_mode = move, | |||||
| typename X_lambda> | |||||
| inline auto and_then(X_lambda&& p_lambda) &&; | inline auto and_then(X_lambda&& p_lambda) &&; | ||||
| #ifdef asyncpp_timing | #ifdef asyncpp_timing | ||||
| @@ -72,15 +68,10 @@ namespace asyncpp | |||||
| * | * | ||||
| * 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> | |||||
| inline auto timeout(const duration<X_base, X_ratio>& p_timeout) 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> | |||||
| template< | |||||
| chaining_mode X_mode = copy, | |||||
| typename X_base, | |||||
| typename X_ratio> | |||||
| inline auto timeout(const duration<X_base, X_ratio>& p_timeout) &; | inline auto timeout(const duration<X_base, X_ratio>& p_timeout) &; | ||||
| /** | /** | ||||
| @@ -88,7 +79,10 @@ namespace asyncpp | |||||
| * | * | ||||
| * 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< | |||||
| chaining_mode X_mode = move, | |||||
| typename X_base, | |||||
| typename X_ratio> | |||||
| inline auto timeout(const duration<X_base, X_ratio>& p_timeout) &&; | inline auto timeout(const duration<X_base, X_ratio>& p_timeout) &&; | ||||
| #endif | #endif | ||||
| }; | }; | ||||
| @@ -1,186 +0,0 @@ | |||||
| #pragma once | |||||
| #include "future.h" | |||||
| #include "future/map.inl" | |||||
| #include "future/lazy.inl" | |||||
| #include "future/and_then.inl" | |||||
| #ifdef asyncpp_timing | |||||
| #include <asyncpp/timing/timeout.inl> | |||||
| #endif | |||||
| namespace asyncpp | |||||
| { | |||||
| /* base_future::map */ | |||||
| 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 lambda_type = X_lambda; | |||||
| using map_type = __future::map_impl<derived_type, lambda_type>; | |||||
| auto& self = static_cast<derived_type const &>(*this); | |||||
| return map_type( | |||||
| std::forward<derived_type const>(self), | |||||
| std::forward<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 lambda_type = X_lambda; | |||||
| using map_type = __future::map_impl<derived_type&, lambda_type>; | |||||
| auto& self = static_cast<derived_type &>(*this); | |||||
| return map_type( | |||||
| std::forward<derived_type &>(self), | |||||
| std::forward<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 lambda_type = X_lambda; | |||||
| using map_type = __future::map_impl<derived_type, lambda_type>; | |||||
| auto& self = static_cast<derived_type &>(*this); | |||||
| return map_type( | |||||
| std::forward<derived_type &&>(self), | |||||
| std::forward<X_lambda>(p_lambda)); | |||||
| } | |||||
| /* base_future::and_then */ | |||||
| template< | |||||
| typename T_value, | |||||
| typename T_derived> | |||||
| template< | |||||
| 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>; | |||||
| 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_derived> | |||||
| template< | |||||
| typename X_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_derived> | |||||
| template< | |||||
| typename X_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)); | |||||
| } | |||||
| /* base_future::timeout */ | |||||
| #ifdef asyncpp_timing | |||||
| 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) const & | |||||
| { | |||||
| using timeout_type = timing::timeout<derived_type>; | |||||
| auto& self = static_cast<derived_type const &>(*this); | |||||
| return timeout_type( | |||||
| std::forward<derived_type const>(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 timeout_type = timing::timeout<derived_type&>; | |||||
| auto& self = static_cast<derived_type &>(*this); | |||||
| 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 timeout_type = timing::timeout<derived_type>; | |||||
| auto& self = static_cast<derived_type &>(*this); | |||||
| return timeout_type( | |||||
| std::forward<derived_type &&>(self), | |||||
| p_timeout); | |||||
| } | |||||
| #endif | |||||
| } | |||||
| @@ -10,10 +10,10 @@ namespace __future { | |||||
| template< | template< | ||||
| typename T_future, | typename T_future, | ||||
| typename T_lambda> | typename T_lambda> | ||||
| struct and_then_impl final : | |||||
| struct and_then_future final : | |||||
| public base_future< | public base_future< | ||||
| decltype(std::declval<T_lambda>()(std::declval<typename std::decay_t<T_future>::value_type>())), | decltype(std::declval<T_lambda>()(std::declval<typename std::decay_t<T_future>::value_type>())), | ||||
| and_then_impl<T_future, T_lambda> | |||||
| and_then_future<T_future, T_lambda> | |||||
| > | > | ||||
| { | { | ||||
| public: | public: | ||||
| @@ -23,7 +23,7 @@ namespace __future { | |||||
| using second_future_type = decltype(std::declval<lambda_type>()(std::declval<first_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 value_type = typename second_future_type::value_type; | ||||
| using this_type = and_then_impl<value_type, lambda_type>; | |||||
| using this_type = and_then_future<value_type, lambda_type>; | |||||
| using base_future_type = base_future<value_type, this_type>; | using base_future_type = base_future<value_type, this_type>; | ||||
| using result_type = typename base_future_type::result_type; | using result_type = typename base_future_type::result_type; | ||||
| @@ -39,10 +39,13 @@ namespace __future { | |||||
| template< | template< | ||||
| typename X_future, | typename X_future, | ||||
| typename X_lambda> | typename X_lambda> | ||||
| inline and_then_impl( | |||||
| inline and_then_future( | |||||
| X_future&& p_outer, | X_future&& p_outer, | ||||
| X_lambda&& p_lambda); | X_lambda&& p_lambda); | ||||
| inline and_then_future(and_then_future &&) = default; | |||||
| inline and_then_future(and_then_future const &) = default; | |||||
| public: /* future */ | public: /* future */ | ||||
| /** | /** | ||||
| * @brief Poll the result from the future. | * @brief Poll the result from the future. | ||||
| @@ -1,11 +1,12 @@ | |||||
| #pragma once | #pragma once | ||||
| #include "map.h" | |||||
| #include "and_then.h" | |||||
| #include "../future.h" | |||||
| namespace asyncpp { | namespace asyncpp { | ||||
| namespace __future { | namespace __future { | ||||
| /* and_then_impl */ | |||||
| /* and_then_future */ | |||||
| template< | template< | ||||
| typename T_future, | typename T_future, | ||||
| @@ -13,8 +14,8 @@ namespace __future { | |||||
| template< | template< | ||||
| typename X_future, | typename X_future, | ||||
| typename X_lambda> | typename X_lambda> | ||||
| and_then_impl<T_future, T_lambda> | |||||
| ::and_then_impl( | |||||
| and_then_future<T_future, T_lambda> | |||||
| ::and_then_future( | |||||
| X_future&& p_first, | X_future&& p_first, | ||||
| X_lambda&& p_lambda) | X_lambda&& p_lambda) | ||||
| : _first (std::forward<X_future>(p_first)) | : _first (std::forward<X_future>(p_first)) | ||||
| @@ -24,8 +25,8 @@ namespace __future { | |||||
| template< | template< | ||||
| typename T_future, | typename T_future, | ||||
| typename T_lambda> | typename T_lambda> | ||||
| typename and_then_impl<T_future, T_lambda>::result_type | |||||
| and_then_impl<T_future, T_lambda> | |||||
| typename and_then_future<T_future, T_lambda>::result_type | |||||
| and_then_future<T_future, T_lambda> | |||||
| ::poll() | ::poll() | ||||
| { | { | ||||
| while (true) | while (true) | ||||
| @@ -45,4 +46,61 @@ namespace __future { | |||||
| } | } | ||||
| } | } | ||||
| /* and_then_impl */ | |||||
| template< | |||||
| chaining_mode X_mode, | |||||
| typename X_self, | |||||
| typename X_lambda> | |||||
| auto and_then_impl(X_self&& p_self, X_lambda&& p_lambda) | |||||
| { | |||||
| using lambda_type = X_lambda; | |||||
| using self_type = X_self; | |||||
| using derived_type = typename std::decay_t<self_type>::derived_type; | |||||
| using derived_storage_type = storage_type_t<X_mode, derived_type>; | |||||
| using derived_ref_type = std::conditional_t< | |||||
| std::is_const_v<std::remove_reference_t<self_type>>, | |||||
| derived_type const &, | |||||
| derived_type &>; | |||||
| using derived_forward_type = forward_type_t<X_mode, derived_ref_type>; | |||||
| using and_then_future_type = __future::and_then_future<derived_storage_type, lambda_type>; | |||||
| static_assert( | |||||
| X_mode != ref || !std::is_rvalue_reference_v<self_type>, | |||||
| "Can not store rvalue reference as lvalue reference!"); | |||||
| auto& self = static_cast<derived_ref_type>(p_self); | |||||
| return and_then_future_type( | |||||
| std::forward<derived_forward_type>(self), | |||||
| std::forward<X_lambda> (p_lambda)); | |||||
| } | |||||
| } } | } } | ||||
| namespace asyncpp | |||||
| { | |||||
| /* future_base::and_then */ | |||||
| template< | |||||
| typename T_value, | |||||
| typename T_derived> | |||||
| template< | |||||
| chaining_mode X_mode, | |||||
| typename X_lambda> | |||||
| auto base_future<T_value, T_derived> | |||||
| ::and_then(X_lambda&& p_lambda) & | |||||
| { return __future::and_then_impl<X_mode>(*this, std::forward<X_lambda>(p_lambda)); } | |||||
| template< | |||||
| typename T_value, | |||||
| typename T_derived> | |||||
| template< | |||||
| chaining_mode X_mode, | |||||
| typename X_lambda> | |||||
| auto base_future<T_value, T_derived> | |||||
| ::and_then(X_lambda&& p_lambda) && | |||||
| { return __future::and_then_impl<X_mode>(std::move(*this), std::forward<X_lambda>(p_lambda)); } | |||||
| } | |||||
| @@ -9,16 +9,16 @@ namespace asyncpp | |||||
| { | { | ||||
| template<typename T_lambda> | template<typename T_lambda> | ||||
| struct lazy_impl final : | |||||
| struct lazy_future final : | |||||
| public base_future< | public base_future< | ||||
| decltype(std::declval<T_lambda>()()), | decltype(std::declval<T_lambda>()()), | ||||
| lazy_impl<T_lambda> | |||||
| lazy_future<T_lambda> | |||||
| > | > | ||||
| { | { | ||||
| public: | public: | ||||
| using lambda_type = T_lambda; | using lambda_type = T_lambda; | ||||
| using value_type = decltype(std::declval<lambda_type>()()); | using value_type = decltype(std::declval<lambda_type>()()); | ||||
| using this_type = lazy_impl<lambda_type>; | |||||
| using this_type = lazy_future<lambda_type>; | |||||
| using base_future_type = base_future<value_type, this_type>; | using base_future_type = base_future<value_type, this_type>; | ||||
| using result_type = typename base_future_type::result_type; | using result_type = typename base_future_type::result_type; | ||||
| @@ -30,9 +30,12 @@ namespace asyncpp | |||||
| * @brief Constructor. | * @brief Constructor. | ||||
| */ | */ | ||||
| template<typename X_lambda> | template<typename X_lambda> | ||||
| inline lazy_impl( | |||||
| inline lazy_future( | |||||
| X_lambda&& p_lambda); | X_lambda&& p_lambda); | ||||
| inline lazy_future(lazy_future &&) = default; | |||||
| inline lazy_future(lazy_future const &) = default; | |||||
| public: /* future */ | public: /* future */ | ||||
| /** | /** | ||||
| * @brief Poll the result from the future. | * @brief Poll the result from the future. | ||||
| @@ -8,18 +8,18 @@ namespace asyncpp | |||||
| namespace __future | namespace __future | ||||
| { | { | ||||
| /* lazy_impl */ | |||||
| /* lazy_future */ | |||||
| template<typename T_lambda> | template<typename T_lambda> | ||||
| template<typename X_lambda> | template<typename X_lambda> | ||||
| lazy_impl<T_lambda>::lazy_impl( | |||||
| lazy_future<T_lambda>::lazy_future( | |||||
| X_lambda&& p_lambda) | X_lambda&& p_lambda) | ||||
| : _lambda(std::forward<X_lambda>(p_lambda)) | : _lambda(std::forward<X_lambda>(p_lambda)) | ||||
| { } | { } | ||||
| template<typename T_lambda> | template<typename T_lambda> | ||||
| template<typename X> | template<typename X> | ||||
| inline auto lazy_impl<T_lambda> | |||||
| inline auto lazy_future<T_lambda> | |||||
| ::poll() | ::poll() | ||||
| -> std::enable_if_t< | -> std::enable_if_t< | ||||
| std::is_void_v<X>, | std::is_void_v<X>, | ||||
| @@ -31,7 +31,7 @@ namespace asyncpp | |||||
| template<typename T_lambda> | template<typename T_lambda> | ||||
| template<typename X> | template<typename X> | ||||
| inline auto lazy_impl<T_lambda> | |||||
| inline auto lazy_future<T_lambda> | |||||
| ::poll() | ::poll() | ||||
| -> std::enable_if_t< | -> std::enable_if_t< | ||||
| !std::is_void_v<X>, | !std::is_void_v<X>, | ||||
| @@ -45,7 +45,7 @@ namespace asyncpp | |||||
| inline auto lazy(X_lambda&& p_lambda) | inline auto lazy(X_lambda&& p_lambda) | ||||
| { | { | ||||
| using lambda_type = X_lambda; | using lambda_type = X_lambda; | ||||
| using lazy_type = __future::lazy_impl<lambda_type>; | |||||
| using lazy_type = __future::lazy_future<lambda_type>; | |||||
| return lazy_type(std::forward<X_lambda>(p_lambda)); | return lazy_type(std::forward<X_lambda>(p_lambda)); | ||||
| } | } | ||||
| @@ -8,10 +8,10 @@ namespace __future { | |||||
| template< | template< | ||||
| typename T_future, | typename T_future, | ||||
| typename T_lambda> | typename T_lambda> | ||||
| struct map_impl final : | |||||
| struct map_future final : | |||||
| public base_future< | public base_future< | ||||
| typename std::decay_t<T_future>::value_type, | typename std::decay_t<T_future>::value_type, | ||||
| map_impl<T_future, T_lambda> | |||||
| map_future<T_future, T_lambda> | |||||
| > | > | ||||
| { | { | ||||
| public: | public: | ||||
| @@ -19,7 +19,7 @@ namespace __future { | |||||
| using lambda_type = T_lambda; | using lambda_type = T_lambda; | ||||
| using future_value_type = typename std::decay_t<future_type>::value_type; | 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 value_type = decltype(std::declval<lambda_type>()(std::declval<future_value_type>())); | ||||
| using this_type = map_impl<future_type, lambda_type>; | |||||
| using this_type = map_future<future_type, lambda_type>; | |||||
| using base_future_type = base_future<value_type, this_type>; | using base_future_type = base_future<value_type, this_type>; | ||||
| using result_type = typename base_future_type::result_type; | using result_type = typename base_future_type::result_type; | ||||
| @@ -34,10 +34,13 @@ namespace __future { | |||||
| template< | template< | ||||
| typename X_future, | typename X_future, | ||||
| typename X_lambda> | typename X_lambda> | ||||
| inline map_impl( | |||||
| inline map_future( | |||||
| X_future&& p_future, | X_future&& p_future, | ||||
| X_lambda&& p_lambda); | X_lambda&& p_lambda); | ||||
| inline map_future(map_future &&) = default; | |||||
| inline map_future(map_future const &) = default; | |||||
| public: /* future */ | public: /* future */ | ||||
| /** | /** | ||||
| * @brief Poll the result from the future. | * @brief Poll the result from the future. | ||||
| @@ -5,7 +5,7 @@ | |||||
| namespace asyncpp { | namespace asyncpp { | ||||
| namespace __future { | namespace __future { | ||||
| /* map_impl */ | |||||
| /* map_future */ | |||||
| template< | template< | ||||
| typename T_future, | typename T_future, | ||||
| @@ -13,8 +13,8 @@ namespace __future { | |||||
| template< | template< | ||||
| typename X_future, | typename X_future, | ||||
| typename X_lambda> | typename X_lambda> | ||||
| map_impl<T_future, T_lambda> | |||||
| ::map_impl( | |||||
| map_future<T_future, T_lambda> | |||||
| ::map_future( | |||||
| X_future&& p_future, | X_future&& p_future, | ||||
| X_lambda&& p_lambda) | X_lambda&& p_lambda) | ||||
| : _future(std::forward<X_future>(p_future)) | : _future(std::forward<X_future>(p_future)) | ||||
| @@ -24,8 +24,8 @@ namespace __future { | |||||
| template< | template< | ||||
| typename T_future, | typename T_future, | ||||
| typename T_lambda> | typename T_lambda> | ||||
| typename map_impl<T_future, T_lambda>::result_type | |||||
| map_impl<T_future, T_lambda> | |||||
| typename map_future<T_future, T_lambda>::result_type | |||||
| map_future<T_future, T_lambda> | |||||
| ::poll() | ::poll() | ||||
| { | { | ||||
| auto r = _future.poll(); | auto r = _future.poll(); | ||||
| @@ -34,4 +34,61 @@ namespace __future { | |||||
| : result_type::not_ready(); | : result_type::not_ready(); | ||||
| } | } | ||||
| /* map_impl */ | |||||
| template< | |||||
| chaining_mode X_mode, | |||||
| typename X_self, | |||||
| typename X_lambda> | |||||
| auto map_impl(X_self&& p_self, X_lambda&& p_lambda) | |||||
| { | |||||
| using lambda_type = X_lambda; | |||||
| using self_type = X_self; | |||||
| using derived_type = typename std::decay_t<self_type>::derived_type; | |||||
| using derived_storage_type = storage_type_t<X_mode, derived_type>; | |||||
| using derived_ref_type = std::conditional_t< | |||||
| std::is_const_v<std::remove_reference_t<self_type>>, | |||||
| derived_type const &, | |||||
| derived_type &>; | |||||
| using derived_forward_type = forward_type_t<X_mode, derived_ref_type>; | |||||
| using map_future_type = __future::map_future<derived_storage_type, lambda_type>; | |||||
| static_assert( | |||||
| X_mode != ref || !std::is_rvalue_reference_v<self_type>, | |||||
| "Can not store rvalue reference as lvalue reference!"); | |||||
| auto& self = static_cast<derived_ref_type>(p_self); | |||||
| return map_future_type( | |||||
| std::forward<derived_forward_type>(self), | |||||
| std::forward<X_lambda> (p_lambda)); | |||||
| } | |||||
| } } | } } | ||||
| namespace asyncpp | |||||
| { | |||||
| /* future_base::map */ | |||||
| template< | |||||
| typename T_value, | |||||
| typename T_derived> | |||||
| template< | |||||
| chaining_mode X_mode, | |||||
| typename X_lambda> | |||||
| auto base_future<T_value, T_derived> | |||||
| ::map(X_lambda&& p_lambda) & | |||||
| { return __future::map_impl<X_mode>(*this, std::forward<X_lambda>(p_lambda)); } | |||||
| template< | |||||
| typename T_value, | |||||
| typename T_derived> | |||||
| template< | |||||
| chaining_mode X_mode, | |||||
| typename X_lambda> | |||||
| auto base_future<T_value, T_derived> | |||||
| ::map(X_lambda&& p_lambda) && | |||||
| { return __future::map_impl<X_mode>(std::move(*this), std::forward<X_lambda>(p_lambda)); } | |||||
| } | |||||
| @@ -0,0 +1,63 @@ | |||||
| #pragma once | |||||
| #include "../future.h" | |||||
| namespace asyncpp { | |||||
| namespace __future { | |||||
| template< | |||||
| chaining_mode X_mode, | |||||
| typename X_self, | |||||
| typename X_base, | |||||
| typename X_ratio> | |||||
| auto helper_timeout( | |||||
| X_self&& p_self, | |||||
| const duration<X_base, X_ratio>& p_timeout) | |||||
| { | |||||
| using self_type = X_self; | |||||
| using derived_type = typename std::decay_t<self_type>::derived_type; | |||||
| using derived_storage_type = storage_type_t<X_mode, derived_type>; | |||||
| using derived_ref_type = std::conditional_t< | |||||
| std::is_const_v<std::remove_reference_t<self_type>>, | |||||
| derived_type const &, | |||||
| derived_type &>; | |||||
| using derived_forward_type = forward_type_t<X_mode, derived_ref_type>; | |||||
| using timeout_type = timing::timeout<derived_storage_type>; | |||||
| auto& self = static_cast<derived_ref_type>(p_self); | |||||
| return timeout_type( | |||||
| std::forward<derived_forward_type>(self), | |||||
| p_timeout); | |||||
| } | |||||
| } } | |||||
| namespace asyncpp | |||||
| { | |||||
| /* future_base::timeout */ | |||||
| template< | |||||
| typename T_value, | |||||
| typename T_derived> | |||||
| template< | |||||
| chaining_mode X_mode, | |||||
| typename X_base, | |||||
| typename X_ratio> | |||||
| auto base_future<T_value, T_derived> | |||||
| ::timeout(const duration<X_base, X_ratio>& p_timeout) & | |||||
| { return __future::helper_timeout<X_mode>(*this, p_timeout); } | |||||
| template< | |||||
| typename T_value, | |||||
| typename T_derived> | |||||
| template< | |||||
| chaining_mode X_mode, | |||||
| typename X_base, | |||||
| typename X_ratio> | |||||
| auto base_future<T_value, T_derived> | |||||
| ::timeout(const duration<X_base, X_ratio>& p_timeout) && | |||||
| { return __future::helper_timeout<X_mode>(std::move(*this), p_timeout); } | |||||
| } | |||||
| @@ -1,28 +1,7 @@ | |||||
| #pragma once | |||||
| #pragma | |||||
| #include <chrono> | |||||
| #include "misc/chaining.h" | |||||
| #include "misc/timing.h" | |||||
| namespace asyncpp | |||||
| { | |||||
| using clock = std::chrono::steady_clock; | |||||
| using time_point = clock::time_point; | |||||
| template<typename T_base, typename T_ratio> | |||||
| using duration = std::chrono::duration<T_base ,T_ratio>; | |||||
| /** | |||||
| * @brief Get the current time point. | |||||
| */ | |||||
| 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); | |||||
| } | |||||
| #include "misc/chaining.inl" | |||||
| #include "misc/timing.inl" | |||||
| @@ -0,0 +1,39 @@ | |||||
| #pragma once | |||||
| namespace asyncpp | |||||
| { | |||||
| enum chaining_mode | |||||
| { | |||||
| move, | |||||
| copy, | |||||
| ref, | |||||
| }; | |||||
| /** | |||||
| * @brief Get the storage type of the passed type for the passed mode. | |||||
| * | |||||
| * move: T | |||||
| * copy: T | |||||
| * ref T & | |||||
| */ | |||||
| template<chaining_mode X_mode, typename X_type, typename = void> | |||||
| struct storage_type; | |||||
| /** | |||||
| * @brief Get the forward type of the passed type for the passed mode. | |||||
| * | |||||
| * move: T && | |||||
| * copy: T const & | |||||
| * ref T & | |||||
| */ | |||||
| template<chaining_mode X_mode, typename X_type, typename = void> | |||||
| struct forward_type; | |||||
| template<chaining_mode X_mode, typename X_type> | |||||
| using storage_type_t = typename storage_type<X_mode, X_type>::type; | |||||
| template<chaining_mode X_mode, typename X_type> | |||||
| using forward_type_t = typename forward_type<X_mode, X_type>::type; | |||||
| } | |||||
| @@ -0,0 +1,34 @@ | |||||
| #pragma once | |||||
| namespace asyncpp | |||||
| { | |||||
| /* storage_type */ | |||||
| template<typename X_type> | |||||
| struct storage_type<move, X_type, void> | |||||
| { using type = X_type; }; | |||||
| template<typename X_type> | |||||
| struct storage_type<copy, X_type, void> | |||||
| { using type = X_type; }; | |||||
| template<typename X_type> | |||||
| struct storage_type<ref, X_type, void> | |||||
| { using type = X_type&; }; | |||||
| /* forward_type */ | |||||
| template<typename X_type> | |||||
| struct forward_type<move, X_type, void> | |||||
| { using type = std::decay_t<X_type> &&; }; | |||||
| template<typename X_type> | |||||
| struct forward_type<copy, X_type, void> | |||||
| { using type = std::decay_t<X_type> const &; }; | |||||
| template<typename X_type> | |||||
| struct forward_type<ref, X_type, void> | |||||
| { using type = std::remove_reference_t<X_type> &; }; | |||||
| } | |||||
| @@ -0,0 +1,28 @@ | |||||
| #pragma once | |||||
| #include <chrono> | |||||
| namespace asyncpp | |||||
| { | |||||
| using clock = std::chrono::steady_clock; | |||||
| using time_point = clock::time_point; | |||||
| template<typename T_base, typename T_ratio> | |||||
| using duration = std::chrono::duration<T_base ,T_ratio>; | |||||
| /** | |||||
| * @brief Get the current time point. | |||||
| */ | |||||
| 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); | |||||
| } | |||||
| @@ -1,11 +1,11 @@ | |||||
| #pragma once | #pragma once | ||||
| #include "misc.h" | |||||
| #include "timing.h" | |||||
| namespace asyncpp | namespace asyncpp | ||||
| { | { | ||||
| #ifndef __asyncpp_has_impl_timer_now | |||||
| #ifndef __asyncpp_has_impl_timer_now | |||||
| time_point now() | time_point now() | ||||
| { return clock::now(); } | { return clock::now(); } | ||||
| #endif | #endif | ||||
| @@ -80,7 +80,7 @@ namespace asyncpp | |||||
| ::map(X_lambda&& p_lambda) const & | ::map(X_lambda&& p_lambda) const & | ||||
| { | { | ||||
| using lambda_type = X_lambda; | using lambda_type = X_lambda; | ||||
| using map_type = __stream::map_impl<derived_type, lambda_type>; | |||||
| using map_type = __stream::map_future<derived_type, lambda_type>; | |||||
| auto& self = static_cast<derived_type const &>(*this); | auto& self = static_cast<derived_type const &>(*this); | ||||
| @@ -98,7 +98,7 @@ namespace asyncpp | |||||
| ::map(X_lambda&& p_lambda) & | ::map(X_lambda&& p_lambda) & | ||||
| { | { | ||||
| using lambda_type = X_lambda; | using lambda_type = X_lambda; | ||||
| using map_type = __stream::map_impl<derived_type, lambda_type>; | |||||
| using map_type = __stream::map_future<derived_type, lambda_type>; | |||||
| auto& self = static_cast<derived_type &>(*this); | auto& self = static_cast<derived_type &>(*this); | ||||
| @@ -116,7 +116,7 @@ namespace asyncpp | |||||
| ::map(X_lambda&& p_lambda) && | ::map(X_lambda&& p_lambda) && | ||||
| { | { | ||||
| using lambda_type = X_lambda; | using lambda_type = X_lambda; | ||||
| using map_type = __stream::map_impl<derived_type, lambda_type>; | |||||
| using map_type = __stream::map_future<derived_type, lambda_type>; | |||||
| auto& self = static_cast<derived_type &>(*this); | auto& self = static_cast<derived_type &>(*this); | ||||
| @@ -8,10 +8,10 @@ namespace __stream { | |||||
| template< | template< | ||||
| typename T_stream, | typename T_stream, | ||||
| typename T_lambda> | typename T_lambda> | ||||
| struct map_impl final : | |||||
| struct map_future final : | |||||
| public base_stream< | public base_stream< | ||||
| decltype(std::declval<T_lambda>()(std::declval<typename T_stream::value_type>())), | decltype(std::declval<T_lambda>()(std::declval<typename T_stream::value_type>())), | ||||
| map_impl<T_stream, T_lambda> | |||||
| map_future<T_stream, T_lambda> | |||||
| > | > | ||||
| { | { | ||||
| public: | public: | ||||
| @@ -19,7 +19,7 @@ namespace __stream { | |||||
| using lambda_type = T_lambda; | using lambda_type = T_lambda; | ||||
| using inner_value_type = typename stream_type::value_type; | using inner_value_type = typename stream_type::value_type; | ||||
| using value_type = decltype(std::declval<lambda_type>()(std::declval<inner_value_type>())); | using value_type = decltype(std::declval<lambda_type>()(std::declval<inner_value_type>())); | ||||
| using this_type = map_impl<stream_type, lambda_type>; | |||||
| using this_type = map_future<stream_type, lambda_type>; | |||||
| using base_stream_type = base_stream<value_type, this_type>; | using base_stream_type = base_stream<value_type, this_type>; | ||||
| using result_type = typename base_stream_type::result_type; | using result_type = typename base_stream_type::result_type; | ||||
| @@ -34,7 +34,7 @@ namespace __stream { | |||||
| template< | template< | ||||
| typename X_stream, | typename X_stream, | ||||
| typename X_lambda> | typename X_lambda> | ||||
| inline map_impl( | |||||
| inline map_future( | |||||
| X_stream&& p_stream, | X_stream&& p_stream, | ||||
| X_lambda&& p_lambda); | X_lambda&& p_lambda); | ||||
| @@ -5,7 +5,7 @@ | |||||
| namespace asyncpp { | namespace asyncpp { | ||||
| namespace __stream { | namespace __stream { | ||||
| /* map_impl */ | |||||
| /* map_future */ | |||||
| template< | template< | ||||
| typename T_stream, | typename T_stream, | ||||
| @@ -13,7 +13,7 @@ namespace __stream { | |||||
| template< | template< | ||||
| typename X_stream, | typename X_stream, | ||||
| typename X_lambda> | typename X_lambda> | ||||
| map_impl<T_stream, T_lambda>::map_impl( | |||||
| map_future<T_stream, T_lambda>::map_future( | |||||
| X_stream&& p_stream, | X_stream&& p_stream, | ||||
| X_lambda&& p_lambda) | X_lambda&& p_lambda) | ||||
| : _stream(std::forward<X_stream>(p_stream)) | : _stream(std::forward<X_stream>(p_stream)) | ||||
| @@ -23,8 +23,8 @@ namespace __stream { | |||||
| template< | template< | ||||
| typename T_stream, | typename T_stream, | ||||
| typename T_lambda> | typename T_lambda> | ||||
| typename map_impl<T_stream, T_lambda>::result_type | |||||
| map_impl<T_stream, T_lambda> | |||||
| typename map_future<T_stream, T_lambda>::result_type | |||||
| map_future<T_stream, T_lambda> | |||||
| ::poll() | ::poll() | ||||
| { | { | ||||
| auto r = _stream.poll(); | auto r = _stream.poll(); | ||||
| @@ -42,7 +42,7 @@ namespace timing { | |||||
| X_args&&... p_args); | X_args&&... p_args); | ||||
| inline void idle( | inline void idle( | ||||
| const asyncpp::time_point * p_deadline); | |||||
| const time_point * p_deadline); | |||||
| inline thread_lock_ptr_u init_thread(); | inline thread_lock_ptr_u init_thread(); | ||||
| }; | }; | ||||
| @@ -70,7 +70,7 @@ namespace timing { | |||||
| owner_type& p_owner); | owner_type& p_owner); | ||||
| inline void idle( | inline void idle( | ||||
| const asyncpp::time_point * p_deadline); | |||||
| const time_point * p_deadline); | |||||
| inline thread_lock_ptr_u init_thread(); | inline thread_lock_ptr_u init_thread(); | ||||
| }; | }; | ||||
| @@ -30,7 +30,7 @@ namespace __impl { | |||||
| { } | { } | ||||
| template<typename T_inner> | template<typename T_inner> | ||||
| void timer_impl<T_inner>::idle(const asyncpp::time_point * p_deadline) | |||||
| void timer_impl<T_inner>::idle(const time_point * p_deadline) | |||||
| { | { | ||||
| { | { | ||||
| auto r = owner._registrations.lock(); | auto r = owner._registrations.lock(); | ||||
| @@ -63,7 +63,7 @@ namespace __impl { | |||||
| { } | { } | ||||
| void timer_impl<void>::idle( | void timer_impl<void>::idle( | ||||
| const asyncpp::time_point * p_deadline) | |||||
| const time_point * p_deadline) | |||||
| { } | { } | ||||
| timer_impl<void>::thread_lock_ptr_u | timer_impl<void>::thread_lock_ptr_u | ||||
| @@ -1,9 +1,8 @@ | |||||
| #pragma once | #pragma once | ||||
| #include <asyncpp/core/future.inl> | |||||
| #include "interval.h" | |||||
| #include "delay.inl" | #include "delay.inl" | ||||
| #include "interval.h" | |||||
| namespace asyncpp { | namespace asyncpp { | ||||
| namespace timing { | namespace timing { | ||||
| @@ -12,7 +11,7 @@ namespace timing { | |||||
| template<typename T_base, typename T_ratio> | template<typename T_base, typename T_ratio> | ||||
| interval::interval( | interval::interval( | ||||
| 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) | ||||
| : interval(asyncpp::now() + p_duration, p_duration, p_deadline) | : interval(asyncpp::now() + p_duration, p_duration, p_deadline) | ||||
| { } | { } | ||||
| @@ -20,7 +19,7 @@ namespace timing { | |||||
| template<typename T_base, typename T_ratio> | template<typename T_base, typename T_ratio> | ||||
| interval::interval( | interval::interval( | ||||
| 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 (p_at) | : _delay (p_at) | ||||
| , _duration(p_duration) | , _duration(p_duration) | ||||
| @@ -36,7 +35,7 @@ namespace timing { | |||||
| { | { | ||||
| if ( _deadline.time_since_epoch().count() | if ( _deadline.time_since_epoch().count() | ||||
| && _delay.deadline() >= _deadline | && _delay.deadline() >= _deadline | ||||
| && asyncpp::now() >= _delay.deadline()) | |||||
| && asyncpp::now() >= _delay.deadline()) | |||||
| return result_type::done(); | return result_type::done(); | ||||
| auto ret = _delay.poll(); | auto ret = _delay.poll(); | ||||
| @@ -68,7 +68,7 @@ namespace timing { | |||||
| template<typename T_inner> | template<typename T_inner> | ||||
| struct timeout final | struct timeout final | ||||
| : public __impl::timeout_impl<timeout<T_inner>> | |||||
| : public __impl::timeout_impl<timeout<T_inner>> | |||||
| { | { | ||||
| public: | public: | ||||
| using inner_type = T_inner; | using inner_type = T_inner; | ||||
| @@ -1,7 +1,5 @@ | |||||
| #pragma once | #pragma once | ||||
| #include <asyncpp/core/misc.inl> | |||||
| #include "timeout.h" | #include "timeout.h" | ||||
| namespace asyncpp { | namespace asyncpp { | ||||
| @@ -39,7 +39,7 @@ namespace timing { | |||||
| * This method is called as soon as the runtime has nothing to do. | * This method is called as soon as the runtime has nothing to do. | ||||
| * The passed deadline 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(const asyncpp::time_point * p_deadline); | |||||
| inline void idle(const time_point * p_deadline); | |||||
| /** | /** | ||||
| * @brief This method is calld by the executor when a new thread needs to be initialized. | * @brief This method is calld by the executor when a new thread needs to be initialized. | ||||
| @@ -1,7 +1,5 @@ | |||||
| #pragma once | #pragma once | ||||
| #include <asyncpp/core/misc.inl> | |||||
| #include "timer.h" | #include "timer.h" | ||||
| #include "delay.inl" | #include "delay.inl" | ||||
| @@ -21,7 +19,7 @@ namespace timing { | |||||
| { } | { } | ||||
| template<typename T_inner> | template<typename T_inner> | ||||
| void timer<T_inner>::idle(const asyncpp::time_point * p_deadline) | |||||
| void timer<T_inner>::idle(const time_point * p_deadline) | |||||
| { | { | ||||
| auto now = asyncpp::now(); | auto now = asyncpp::now(); | ||||
| @@ -33,6 +33,12 @@ public: | |||||
| } | } | ||||
| }; | }; | ||||
| auto make_test_future(int i) | |||||
| { | |||||
| test_future ret(i); | |||||
| return ret; | |||||
| } | |||||
| struct test_stream | struct test_stream | ||||
| : public base_stream<int, test_stream> | : public base_stream<int, test_stream> | ||||
| { | { | ||||
| @@ -70,7 +76,7 @@ TEST(timeout_tests, poll_future_no_timeout) | |||||
| test_future t(0); | test_future t(0); | ||||
| auto f = t | auto f = t | ||||
| .timeout(std::chrono::seconds(5)); | |||||
| .timeout<ref>(std::chrono::seconds(5)); | |||||
| EXPECT_CALL(m, now()) | EXPECT_CALL(m, now()) | ||||
| .WillOnce(Return(time_point(std::chrono::seconds(0)))); | .WillOnce(Return(time_point(std::chrono::seconds(0)))); | ||||