Selaa lähdekoodia

* Splitted result into future_result and stream_result (because the future_result does not need a 'done' state)

* Refactored namespaces (trait classes are postfixed with '_trait'; internal namespaces are prefixed with __)
master
bergmann 4 vuotta sitten
vanhempi
commit
8f4d2f4608
11 muutettua tiedostoa jossa 405 lisäystä ja 366 poistoa
  1. +3
    -3
      include/asyncpp/future.h
  2. +28
    -31
      include/asyncpp/future.inl
  3. +12
    -17
      include/asyncpp/future.pre.h
  4. +1
    -1
      include/asyncpp/future/and_then.h
  5. +28
    -29
      include/asyncpp/future/and_then.inl
  6. +1
    -1
      include/asyncpp/future/map.h
  7. +23
    -24
      include/asyncpp/future/map.inl
  8. +104
    -86
      include/asyncpp/result.h
  9. +152
    -140
      include/asyncpp/result.inl
  10. +22
    -28
      test/asyncpp/future_tests.cpp
  11. +31
    -6
      test/asyncpp/result_tests.cpp

+ 3
- 3
include/asyncpp/future.h Näytä tiedosto

@@ -17,9 +17,9 @@ namespace asyncpp
{
using object_type = T_object;
using clean_object_type = std::decay_t<object_type>;
using impl_type = impl::future<clean_object_type>;
using value_type = typename impl_type::value_type;
using result_type = result<value_type>;
using trait_type = future_trait<clean_object_type>;
using value_type = typename trait_type::value_type;
using result_type = future_result<value_type>;

object_type ref;



+ 28
- 31
include/asyncpp/future.inl Näytä tiedosto

@@ -8,37 +8,34 @@
namespace asyncpp
{

namespace impl
/* future_base */

template<typename T_impl>
template<typename X_future, typename X_lambda>
auto future_base<T_impl>
::map(X_future&& self, X_lambda&& p_lambda)
{
using future_type = X_future;
using lambda_type = X_lambda;
using map_type = __future::map_impl<future_type, lambda_type>;

return as_future(map_type(
std::forward<X_future>(self),
std::forward<X_lambda>(p_lambda)));
}

template<typename T_impl>
template<typename X_future, typename X_lambda>
auto future_base<T_impl>
::map(X_future&& self, X_lambda&& p_lambda)
{
using future_type = X_future;
using lambda_type = X_lambda;
using map_type = future_impl::map_impl<future_type, lambda_type>;

return as_future(map_type(
std::forward<X_future>(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)
{
using future_type = X_future;
using lambda_type = X_lambda;
using and_then_type = future_impl::and_then_impl<future_type, lambda_type>;

return as_future(and_then_type(
std::forward<X_future>(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)
{
using future_type = X_future;
using lambda_type = X_lambda;
using and_then_type = __future::and_then_impl<future_type, lambda_type>;

return as_future(and_then_type(
std::forward<X_future>(self),
std::forward<X_lambda>(p_lambda)));
}

/* future */
@@ -59,7 +56,7 @@ namespace asyncpp
typename future<T_value, T_impl>::result_type
future<T_value, T_impl>
::poll()
{ return impl_type::poll(*this); }
{ return trait_type::poll(*this); }

template<
typename T_value,
@@ -68,7 +65,7 @@ namespace asyncpp
typename X_lambda>
auto future<T_value, T_impl>
::map(X_lambda&& p_lambda)
{ return impl_type::map(std::move(*this), std::forward<X_lambda>(p_lambda)); }
{ return trait_type::map(std::move(*this), std::forward<X_lambda>(p_lambda)); }

template<
typename T_value,
@@ -77,7 +74,7 @@ namespace asyncpp
typename X_lambda>
auto future<T_value, T_impl>
::and_then(X_lambda&& p_lambda)
{ return impl_type::and_then(std::move(*this), std::forward<X_lambda>(p_lambda)); }
{ return trait_type::and_then(std::move(*this), std::forward<X_lambda>(p_lambda)); }

/* misc */



+ 12
- 17
include/asyncpp/future.pre.h Näytä tiedosto

@@ -3,30 +3,25 @@
namespace asyncpp
{

namespace impl
template<typename T_impl>
struct future_base
{
template<typename T_future>
static inline auto poll(T_future& self) = delete;

template<typename T_impl>
struct future_base
{
template<typename T_future>
static inline auto poll(T_future& self) = delete;
template<typename T_future, typename T_lambda>
static inline auto map(T_future&& self, T_lambda&& p_lambda);

template<typename T_future, typename T_lambda>
static inline auto map(T_future&& self, T_lambda&& p_lambda);
template<typename T_future, typename T_lambda>
static inline auto and_then(T_future&& self, T_lambda&& p_lambda);
};

template<typename T_future, typename T_lambda>
static inline auto and_then(T_future&& self, T_lambda&& p_lambda);
};

template<typename T, typename = void>
struct future;

}
template<typename T, typename = void>
struct future_trait;

template<
typename T_object,
typename T_impl = impl::future<std::decay_t<T_object>>>
typename T_impl = future_trait<std::decay_t<T_object>>>
struct future;

/**


+ 1
- 1
include/asyncpp/future/and_then.h Näytä tiedosto

@@ -3,7 +3,7 @@
#include <memory>

namespace asyncpp {
namespace future_impl {
namespace __future {

template<
typename T_future,


+ 28
- 29
include/asyncpp/future/and_then.inl Näytä tiedosto

@@ -5,47 +5,46 @@
namespace asyncpp
{

namespace impl
/* future_trait for ant_then_impl */

template<
typename T_future,
typename T_lambda>
struct future_trait<__future::and_then_impl<T_future, T_lambda>, void>
: public future_base<future<__future::and_then_impl<T_future, T_lambda>, void>>
{
using and_then_type = __future::and_then_impl<T_future, T_lambda>;
using inner_future_type = typename and_then_type::inner_future_type;
using value_type = typename inner_future_type::value_type;
using result_type = typename inner_future_type::result_type;

template<
typename T_future,
typename T_lambda>
struct future<future_impl::and_then_impl<T_future, T_lambda>, void>
: public future_base<future<future_impl::and_then_impl<T_future, T_lambda>, void>>
template<typename X_future>
static inline auto poll(X_future& self)
{
using and_then_type = future_impl::and_then_impl<T_future, T_lambda>;
using inner_future_type = typename and_then_type::inner_future_type;
using value_type = typename inner_future_type::value_type;
using result_type = typename inner_future_type::result_type;

template<typename X_future>
static inline auto poll(X_future& self)
while (true)
{
while (true)
if (self.ref.inner)
{
if (self.ref.inner)
{
return self.ref.inner->poll();
}
else
{
auto r = self.ref.outer.poll();
if (!r)
return result_type::not_ready();
return self.ref.inner->poll();
}
else
{
auto r = self.ref.outer.poll();
if (!r)
return result_type::not_ready();

self.ref.inner = std::make_unique<inner_future_type>(as_future(self.ref.lambda(*r)));
}
self.ref.inner = std::make_unique<inner_future_type>(as_future(self.ref.lambda(*r)));
}
}
};

}
}
};

}

namespace asyncpp {
namespace future_impl {
namespace __future {

/* and_then_impl */

template<
typename T_future,


+ 1
- 1
include/asyncpp/future/map.h Näytä tiedosto

@@ -1,7 +1,7 @@
#pragma once

namespace asyncpp {
namespace future_impl {
namespace __future {

template<
typename T_future,


+ 23
- 24
include/asyncpp/future/map.inl Näytä tiedosto

@@ -5,38 +5,37 @@
namespace asyncpp
{

namespace impl
/* 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>()));

template<
typename T_future,
typename T_lambda>
struct future<future_impl::map_impl<T_future, T_lambda>, void>
: public future_base<future<future_impl::map_impl<T_future, T_lambda>, void>>
template<typename X_future>
static inline auto poll(X_future& self)
{
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)
{
using result_type = result<value_type>;

auto r = self.ref.future.poll();
return r
? result_type::ready(self.ref.lambda(*r))
: result_type::not_ready();
}
};

}
auto r = self.ref.future.poll();
return r
? result_type::ready(self.ref.lambda(*r))
: result_type::not_ready();
}
};

}

namespace asyncpp {
namespace future_impl {
namespace __future {

/* map_impl */

template<
typename T_future,


+ 104
- 86
include/asyncpp/result.h Näytä tiedosto

@@ -5,7 +5,15 @@
namespace asyncpp
{

namespace impl
enum class result_status
{
unknown = 0,
not_ready,
ready,
done,
};

namespace __impl
{

struct result_not_ready
@@ -25,94 +33,104 @@ namespace asyncpp
inline result_ready(T_args&&... p_args);
};

template<bool for_stream, typename T_value>
struct result
{
public:
using value_type = T_value;
using not_ready_type = result_not_ready;
using ready_type = result_ready<value_type>;
using done_type = result_done;
using storage_type = std::conditional_t<
for_stream,
std::variant<not_ready_type, ready_type, done_type>,
std::variant<not_ready_type, ready_type>>;
using clean_value_type = std::remove_reference_t<value_type>;
using pointer_type = clean_value_type*;
using reference_type = clean_value_type&;
using const_pointer_type = clean_value_type const *;
using const_reference_type = clean_value_type const &;

private:
storage_type _storage; //!< Stores the actual result.

private:
/**
* @brief Constructor.
*/
inline result(storage_type&& p_storage);

public:
/**
* @brief returns a result that is not ready.
*/
static inline auto& not_ready();

/**
* @brief returns a result that is not ready.
*/
template<typename... X_args>
static inline auto ready(X_args&&... p_args);

/**
* @brief returns a result that is not ready.
*/
template<
bool X = for_stream,
typename = std::enable_if_t<X>>
static inline auto& done();

public:
/**
* @brief Get the status of the result.
*/
template<
bool X = for_stream,
typename = std::enable_if_t<X>>
inline result_status status() const;

/**
* @brief Check if the result is not ready (is pending).
*/
inline bool is_not_ready() const;

/**
* @brief Check if the result is ready (has a value).
*/
inline bool is_ready() const;

/**
* @brief Check if the result is done (stream is finished).
*/
template<
bool X = for_stream,
typename = std::enable_if_t<X>>
inline bool is_done() const;

/**
* @brief Get the value of the result.
*/
inline reference_type value();

/**
* @brief Get the value of the result.
*/
inline const_reference_type value() const;

public:
inline operator bool() const;
inline pointer_type operator-> ();
inline reference_type operator* ();
inline const_pointer_type operator-> () const;
inline const_reference_type operator* () const;
};

}

enum class result_status
{
unknown = 0,
not_ready,
ready,
done,
};
template<typename T_value>
using future_result = __impl::result<false, T_value>;

template<typename T_value>
struct result
{
public:
using value_type = T_value;
using not_ready_type = impl::result_not_ready;
using ready_type = impl::result_ready<value_type>;
using done_type = impl::result_done;
using storage_type = std::variant<not_ready_type, ready_type, done_type>;
using clean_value_type = std::remove_reference_t<value_type>;
using pointer_type = clean_value_type*;
using reference_type = clean_value_type&;
using const_pointer_type = clean_value_type const *;
using const_reference_type = clean_value_type const &;

private:
storage_type _storage; //!< Stores the actual result.

private:
/**
* @brief Constructor.
*/
inline result(storage_type&& p_storage);

public:
/**
* @brief returns a result that is not ready.
*/
static inline auto& not_ready();

/**
* @brief returns a result that is not ready.
*/
template<typename... X_args>
static inline auto ready(X_args&&... p_args);

/**
* @brief returns a result that is not ready.
*/
static inline auto& done();

public:
/**
* @brief Get the status of the result.
*/
inline result_status status() const;

/**
* @brief Check if the result is not ready (is pending).
*/
inline bool is_not_ready() const;

/**
* @brief Check if the result is ready (has a value).
*/
inline bool is_ready() const;

/**
* @brief Check if the result is done (stream is finished).
*/
inline bool is_done() const;

/**
* @brief Get the value of the result.
*/
inline reference_type value();

/**
* @brief Get the value of the result.
*/
inline const_reference_type value() const;

public:
inline operator bool() const;
inline pointer_type operator-> ();
inline reference_type operator* ();
inline const_pointer_type operator-> () const;
inline const_reference_type operator* () const;
};
using stream_result = __impl::result<true, T_value>;

}

+ 152
- 140
include/asyncpp/result.inl Näytä tiedosto

@@ -5,7 +5,7 @@
namespace asyncpp
{

namespace impl
namespace __impl
{

/* result_ready */
@@ -17,163 +17,175 @@ namespace asyncpp
: value(std::forward<T_args>(p_args)...)
{ }

}

/* result */

template<typename T_value>
result<T_value>
::result(storage_type&& p_storage)
: _storage(std::move(p_storage))
{ }

template<typename T_value>
auto& result<T_value>
::not_ready()
{
static const result ret(storage_type(not_ready_type { }));
return ret;
}

template<typename T_value>
template<typename... X_args>
auto result<T_value>
::ready(X_args&&... p_args)
{ return result(storage_type(ready_type(std::forward<X_args>(p_args)...))); }

template<typename T_value>
auto& result<T_value>
::done()
{
static const result ret(storage_type(done_type { }));
return ret;
}

template<typename T_value>
result_status result<T_value>
::status() const
{
if (is_not_ready())
return result_status::not_ready;
else if (is_ready())
return result_status::ready;
else if (is_done())
return result_status::done;
else
return result_status::unknown;
}

template<typename T_value>
bool result<T_value>
::is_not_ready() const
{ return std::holds_alternative<not_ready_type>(_storage); }

template<typename T_value>
bool result<T_value>
::is_ready() const
{ return std::holds_alternative<ready_type>(_storage); }

template<typename T_value>
bool result<T_value>
::is_done() const
{ return std::holds_alternative<done_type>(_storage); }

template<typename T_value>
typename result<T_value>::reference_type
result<T_value>
::value()
{ return std::get<ready_type>(_storage).value; }

template<typename T_value>
typename result<T_value>::const_reference_type
result<T_value>
::value() const
{ return std::get<ready_type>(_storage).value; }

template<typename T_value>
result<T_value>
::operator bool() const
{ return is_ready(); }

template<typename T_value>
typename result<T_value>::pointer_type
result<T_value>
::operator-> ()
{ return &value(); }

template<typename T_value>
typename result<T_value>::reference_type
result<T_value>
::operator* ()
{ return value(); }

template<typename T_value>
typename result<T_value>::const_pointer_type
result<T_value>
::operator-> () const
{ return &value(); }

template<typename T_value>
typename result<T_value>::const_reference_type
result<T_value>
::operator* () const
{ return value(); }

template<>
struct result<void>
{
public:
using value_type = void;

private:
result_status _status;
/* result */

private:
inline result(result_status p_status)
: _status(p_status)
template<bool for_stream, typename T_value>
result<for_stream, T_value>
::result(storage_type&& p_storage)
: _storage(std::move(p_storage))
{ }

public:
static inline auto& not_ready()
template<bool for_stream, typename T_value>
auto& result<for_stream, T_value>
::not_ready()
{
static const result ret { result_status::not_ready };
static const result ret(storage_type(not_ready_type { }));
return ret;
}

template<bool for_stream, typename T_value>
template<typename... X_args>
static inline auto& ready(X_args&&... p_args)
auto result<for_stream, T_value>
::ready(X_args&&... p_args)
{ return result(storage_type(ready_type(std::forward<X_args>(p_args)...))); }

template<bool for_stream, typename T_value>
template<bool X, typename>
auto& result<for_stream, T_value>
::done()
{
static const result ret { result_status::ready };
static const result ret(storage_type(done_type { }));
return ret;
}

static inline auto& done()
template<bool for_stream, typename T_value>
template<bool X, typename>
result_status result<for_stream, T_value>
::status() const
{
static const result ret { result_status::done };
return ret;
if (is_not_ready())
return result_status::not_ready;
else if (is_ready())
return result_status::ready;
else if (is_done())
return result_status::done;
else
return result_status::unknown;
}

public:
inline result_status status() const
{ return _status; }

inline bool is_not_ready() const
{ return _status == result_status::not_ready; }

inline bool is_ready() const
{ return _status == result_status::ready; }
template<bool for_stream, typename T_value>
bool result<for_stream, T_value>
::is_not_ready() const
{ return std::holds_alternative<not_ready_type>(_storage); }

template<bool for_stream, typename T_value>
bool result<for_stream, T_value>
::is_ready() const
{ return std::holds_alternative<ready_type>(_storage); }

template<bool for_stream, typename T_value>
template<bool X, typename>
bool result<for_stream, T_value>
::is_done() const
{ return std::holds_alternative<done_type>(_storage); }

template<bool for_stream, typename T_value>
typename result<for_stream, T_value>::reference_type
result<for_stream, T_value>
::value()
{ return std::get<ready_type>(_storage).value; }

template<bool for_stream, typename T_value>
typename result<for_stream, T_value>::const_reference_type
result<for_stream, T_value>
::value() const
{ return std::get<ready_type>(_storage).value; }

template<bool for_stream, typename T_value>
result<for_stream, T_value>
::operator bool() const
{ return is_ready(); }

template<bool for_stream, typename T_value>
typename result<for_stream, T_value>::pointer_type
result<for_stream, T_value>
::operator-> ()
{ return &value(); }

template<bool for_stream, typename T_value>
typename result<for_stream, T_value>::reference_type
result<for_stream, T_value>
::operator* ()
{ return value(); }

template<bool for_stream, typename T_value>
typename result<for_stream, T_value>::const_pointer_type
result<for_stream, T_value>
::operator-> () const
{ return &value(); }

template<bool for_stream, typename T_value>
typename result<for_stream, T_value>::const_reference_type
result<for_stream, T_value>
::operator* () const
{ return value(); }

template<bool for_stream>
struct result<for_stream, void>
{
public:
using value_type = void;

inline bool is_done() const
{ return _status == result_status::done; }
private:
result_status _status;

inline void value()
{ throw std::runtime_error("'void' result does not store any value!"); }
private:
inline result(result_status p_status)
: _status(p_status)
{ }

inline operator bool() const
{ return _status == result_status::ready; }
public:
static inline auto& not_ready()
{
static const result ret { result_status::not_ready };
return ret;
}

template<typename... X_args>
static inline auto& ready(X_args&&... p_args)
{
static const result ret { result_status::ready };
return ret;
}

template<
bool X = for_stream,
typename = std::enable_if_t<X>>
static inline auto& done()
{
static const result ret { result_status::done };
return ret;
}

public:
template<
bool X = for_stream,
typename = std::enable_if_t<X>>
inline result_status status() const
{ return _status; }

inline bool is_not_ready() const
{ return _status == result_status::not_ready; }

inline bool is_ready() const
{ return _status == result_status::ready; }

template<
bool X = for_stream,
typename = std::enable_if_t<X>>
inline bool is_done() const
{ return _status == result_status::done; }

inline void value()
{ throw std::runtime_error("'void' result does not store any value!"); }

inline operator bool() const
{ return _status == result_status::ready; }

inline void operator* ()
{ value(); }
};

inline void operator* ()
{ value(); }
};
}

}

+ 22
- 28
test/asyncpp/future_tests.cpp Näytä tiedosto

@@ -14,29 +14,24 @@ struct delay
namespace asyncpp
{

namespace impl
template<>
struct future_trait<delay, void>
: public future_base<future<delay, void>>
{
using value_type = int&;

template<>
struct future<delay, void>
: public future_base<future<delay, void>>
template<typename T_future>
static inline auto poll(T_future& self)
{
using value_type = int&;
using result_type = future_result<value_type>;

template<typename T_future>
static inline auto poll(T_future& self)
{
using result_type = result<value_type>;
if (self.ref.count >= self.ref.delay)
return result_type::ready(self.ref.count);

if (self.ref.count >= self.ref.delay)
return result_type::ready(self.ref.count);

++self.ref.count;
return result_type::not_ready();
}
};

}
++self.ref.count;
return result_type::not_ready();
}
};

}

@@ -46,26 +41,25 @@ TEST(future_tests, poll)
auto f = as_future(d);

auto r0 = f.poll();
ASSERT_EQ(result_status::not_ready, r0.status());
ASSERT_FALSE(r0);

auto r1 = f.poll();
ASSERT_EQ(result_status::not_ready, r1.status());
ASSERT_FALSE(r1);

auto r2 = f.poll();
ASSERT_EQ(result_status::not_ready, r2.status());
ASSERT_FALSE(r2);

auto r3 = f.poll();
ASSERT_EQ(result_status::not_ready, r3.status());
ASSERT_FALSE(r3);

auto r4 = f.poll();
ASSERT_EQ(result_status::not_ready, r4.status());
ASSERT_FALSE(r4);

auto r = f.poll();
ASSERT_TRUE(r);
ASSERT_EQ (result_status::ready, r.status());
ASSERT_EQ (5, *r);
ASSERT_EQ (5, d.count);
ASSERT_EQ (&*r, &d.count);
ASSERT_TRUE (r);
ASSERT_EQ (5, *r);
ASSERT_EQ (5, d.count);
ASSERT_EQ (&*r, &d.count);
}

TEST(future_tests, map)


+ 31
- 6
test/asyncpp/result_tests.cpp Näytä tiedosto

@@ -5,9 +5,34 @@
using namespace ::testing;
using namespace ::asyncpp;

TEST(result_tests, not_ready)
TEST(result_tests, future_result___not_ready)
{
using result_type = result<int>;
using result_type = future_result<int>;

auto r = result_type::not_ready();

EXPECT_TRUE (r.is_not_ready());
EXPECT_FALSE (r.is_ready());
EXPECT_FALSE (r);
EXPECT_ANY_THROW(*r);
}

TEST(result_tests, future_result___ready)
{
using result_type = future_result<int&>;

int i;
auto r = result_type::ready(i);

EXPECT_FALSE (r.is_not_ready());
EXPECT_TRUE (r.is_ready());
EXPECT_TRUE (r);
EXPECT_EQ (&*r, &i);
}

TEST(result_tests, stream_result___not_ready)
{
using result_type = stream_result<int>;

auto r = result_type::not_ready();

@@ -19,9 +44,9 @@ TEST(result_tests, not_ready)
EXPECT_ANY_THROW(*r);
}

TEST(result_tests, ready)
TEST(result_tests, stream_result___ready)
{
using result_type = result<int&>;
using result_type = stream_result<int&>;

int i;
auto r = result_type::ready(i);
@@ -34,9 +59,9 @@ TEST(result_tests, ready)
EXPECT_EQ (&*r, &i);
}

TEST(result_tests, done)
TEST(result_tests, stream_result___done)
{
using result_type = result<void>;
using result_type = stream_result<void>;

auto r = result_type::done();



Ladataan…
Peruuta
Tallenna