Bläddra i källkod

* refactored/simplified 'future' class

master
bergmann 6 år sedan
förälder
incheckning
8289b4b235
23 ändrade filer med 433 tillägg och 503 borttagningar
  1. +52
    -29
      include/asyncpp/core/future.h
  2. +123
    -92
      include/asyncpp/core/future.inl
  3. +7
    -35
      include/asyncpp/core/future.pre.h
  4. +18
    -26
      include/asyncpp/core/future/and_then.h
  5. +8
    -16
      include/asyncpp/core/future/and_then.inl
  6. +20
    -26
      include/asyncpp/core/future/map.h
  7. +6
    -14
      include/asyncpp/core/future/map.inl
  8. +2
    -2
      include/asyncpp/core/stream.inl
  9. +17
    -27
      include/asyncpp/core/stream/for_each.h
  10. +6
    -14
      include/asyncpp/core/stream/for_each.inl
  11. +11
    -20
      include/asyncpp/timing/delay.h
  12. +7
    -14
      include/asyncpp/timing/delay.inl
  13. +2
    -5
      include/asyncpp/timing/interval.h
  14. +5
    -5
      include/asyncpp/timing/interval.inl
  15. +22
    -25
      include/asyncpp/timing/timeout.h
  16. +31
    -27
      include/asyncpp/timing/timeout.inl
  17. +11
    -40
      test/asyncpp/core/future_tests.cpp
  18. +3
    -31
      test/asyncpp/core/task_tests.cpp
  19. +22
    -25
      test/asyncpp/executor/current_thread_tests.cpp
  20. +1
    -2
      test/asyncpp/timing/delay_tests.cpp
  21. +22
    -20
      test/asyncpp/timing/timeout_tests.cpp
  22. +4
    -8
      test/asyncpp/timing/timer_tests.cpp
  23. +33
    -0
      test/helper/test_delay.h

+ 52
- 29
include/asyncpp/core/future.h Visa fil

@@ -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
}; };


} }

+ 123
- 92
include/asyncpp/core/future.inl Visa fil

@@ -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


} }

+ 7
- 35
include/asyncpp/core/future.pre.h Visa fil

@@ -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);

} }

+ 18
- 26
include/asyncpp/core/future/and_then.h Visa fil

@@ -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();
}; };


}
} }

+ 8
- 16
include/asyncpp/core/future/and_then.inl Visa fil

@@ -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));
} }
} }
} }


}
} }

+ 20
- 26
include/asyncpp/core/future/map.h Visa fil

@@ -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();
}; };


}
} }

+ 6
- 14
include/asyncpp/core/future/map.inl Visa fil

@@ -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();
} }


}
} }

+ 2
- 2
include/asyncpp/core/stream.inl Visa fil

@@ -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


+ 17
- 27
include/asyncpp/core/stream/for_each.h Visa fil

@@ -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();
}; };


}
} }

+ 6
- 14
include/asyncpp/core/stream/for_each.inl Visa fil

@@ -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);
} }
} }


}
} }

+ 11
- 20
include/asyncpp/timing/delay.h Visa fil

@@ -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();
}; };


}
} }

+ 7
- 14
include/asyncpp/timing/delay.inl Visa fil

@@ -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();
} }


}
} }

+ 2
- 5
include/asyncpp/timing/interval.h Visa fil

@@ -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.




+ 5
- 5
include/asyncpp/timing/interval.inl Visa fil

@@ -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();
} }


+ 22
- 25
include/asyncpp/timing/timeout.h Visa fil

@@ -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>


+ 31
- 27
include/asyncpp/timing/timeout.inl Visa fil

@@ -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;


+ 11
- 40
test/asyncpp/core/future_tests.cpp Visa fil

@@ -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);
} }

+ 3
- 31
test/asyncpp/core/task_tests.cpp Visa fil

@@ -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());


+ 22
- 25
test/asyncpp/executor/current_thread_tests.cpp Visa fil

@@ -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)


+ 1
- 2
test/asyncpp/timing/delay_tests.cpp Visa fil

@@ -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());




+ 22
- 20
test/asyncpp/timing/timeout_tests.cpp Visa fil

@@ -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())


+ 4
- 8
test/asyncpp/timing/timer_tests.cpp Visa fil

@@ -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);


+ 33
- 0
test/helper/test_delay.h Visa fil

@@ -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();
}
};

Laddar…
Avbryt
Spara