Skip to content

Commit

Permalink
*: rewrite to concepts
Browse files Browse the repository at this point in the history
  • Loading branch information
ArsenArsen committed Sep 6, 2022
1 parent 4da44b4 commit 3628ce0
Show file tree
Hide file tree
Showing 3 changed files with 144 additions and 164 deletions.
5 changes: 3 additions & 2 deletions include/async/algorithm.hpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#pragma once

#include <algorithm>
#include <concepts>

#include <async/basic.hpp>
#include <async/cancellation.hpp>
Expand Down Expand Up @@ -141,7 +142,7 @@ template<typename Sender, typename F>
struct [[nodiscard]] transform_sender;

template<typename Sender, typename F>
requires (!std::is_same_v<typename Sender::value_type, void>)
requires (!std::same_as<typename Sender::value_type, void>)
struct [[nodiscard]] transform_sender<Sender, F> {
using value_type = std::invoke_result_t<F, typename Sender::value_type>;

Expand All @@ -160,7 +161,7 @@ struct [[nodiscard]] transform_sender<Sender, F> {
};

template<typename Sender, typename F>
requires std::is_same_v<typename Sender::value_type, void>
requires std::same_as<typename Sender::value_type, void>
struct [[nodiscard]] transform_sender<Sender, F> {
using value_type = std::invoke_result_t<F>;

Expand Down
46 changes: 27 additions & 19 deletions include/async/basic.hpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#pragma once

#include <atomic>
#include <concepts>
#include <type_traits>

#include <async/execution.hpp>
#include <frg/list.hpp>
Expand Down Expand Up @@ -140,11 +142,12 @@ struct [[nodiscard]] sender_awaiter<S, void> {
template<typename T>
struct any_receiver {
template<typename R>
requires (
std::is_trivially_copyable_v<R>
&& sizeof(R) <= sizeof(void *)
&& alignof(R) <= alignof(void *)
)
any_receiver(R receiver) {
static_assert(std::is_trivially_copyable_v<R>);
static_assert(sizeof(R) <= sizeof(void *));
static_assert(alignof(R) <= alignof(void *));

new (stor_) R(receiver);
set_value_fptr_ = [] (void *p, T value) {
auto *rp = static_cast<R *>(p);
Expand All @@ -168,8 +171,12 @@ struct any_receiver {
template<>
struct any_receiver<void> {
template<typename R>
requires (
std::is_trivially_copyable_v<R>
&& sizeof(R) <= sizeof(void *)
&& alignof(R) <= alignof(void *)
)
any_receiver(R receiver) {
static_assert(std::is_trivially_copyable_v<R>);
new (stor_) R(receiver);
set_value_fptr_ = [] (void *p) {
auto *rp = static_cast<R *>(p);
Expand Down Expand Up @@ -211,10 +218,13 @@ struct callback<R(Args...)> {
callback()
: _function(nullptr) { }

template<typename F, typename = std::enable_if_t<
sizeof(F) == sizeof(void *) && alignof(F) == alignof(void *)
&& std::is_trivially_copy_constructible<F>::value
&& std::is_trivially_destructible<F>::value>>
template<typename F>
requires (
sizeof(F) <= sizeof(void*)
&& alignof(F) <= alignof(void*)
&& std::is_trivially_copy_constructible_v<F>
&& std::is_trivially_destructible_v<F>
)
callback(F functor)
: _function(&invoke<F>) {
new (&_object) F{std::move(functor)};
Expand Down Expand Up @@ -307,8 +317,8 @@ void run_forever(IoService ios) {
}

template<typename Sender>
std::enable_if_t<std::is_same_v<typename Sender::value_type, void>, void>
run(Sender s) {
requires std::same_as<typename Sender::value_type, void>
void run(Sender s) {
struct receiver {
void set_value_inline() { }

Expand All @@ -323,9 +333,8 @@ run(Sender s) {
}

template<typename Sender>
std::enable_if_t<!std::is_same_v<typename Sender::value_type, void>,
typename Sender::value_type>
run(Sender s) {
requires (!std::same_as<typename Sender::value_type, void>)
typename Sender::value_type run(Sender s) {
struct state {
frg::optional<typename Sender::value_type> value;
};
Expand Down Expand Up @@ -356,8 +365,8 @@ run(Sender s) {
}

template<typename Sender, typename IoService>
std::enable_if_t<std::is_same_v<typename Sender::value_type, void>, void>
run(Sender s, IoService ios) {
requires std::same_as<typename Sender::value_type, void>
void run(Sender s, IoService ios) {
struct state {
bool done = false;
};
Expand Down Expand Up @@ -390,9 +399,8 @@ run(Sender s, IoService ios) {
}

template<typename Sender, typename IoService>
std::enable_if_t<!std::is_same_v<typename Sender::value_type, void>,
typename Sender::value_type>
run(Sender s, IoService ios) {
requires (!std::same_as<typename Sender::value_type, void>)
typename Sender::value_type run(Sender s, IoService ios) {
struct state {
bool done = false;
frg::optional<typename Sender::value_type> value;
Expand Down
257 changes: 114 additions & 143 deletions include/async/execution.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,154 +2,125 @@

#include <type_traits>
#include <utility>
#include <concepts>

namespace async {

// Detection pattern boilerplate.

template<typename... Ts>
using void_t = void;

template<typename... Ts>
constexpr bool dependent_false_t = false;

template <template <typename...> typename Trait, typename Void, typename... Args>
struct is_detected_helper : std::false_type { };

template <template <typename...> typename Trait, typename... Args>
struct is_detected_helper<Trait, void_t<Trait<Args...>>, Args...> : std::true_type { };

template <template <typename...> typename Trait, typename... Args>
constexpr bool is_detected_v = is_detected_helper<Trait, void, Args...>::value;
#include <frg/detection.hpp>

namespace async {
namespace cpo_types {
// TODO: Rewrite this using concepts.
template<typename S, typename R>
using connect_member_t = decltype(std::declval<S>().connect(std::declval<R>()));

template<typename S, typename R>
constexpr bool has_connect_member_v = is_detected_v<connect_member_t, S, R>;

template<typename S, typename R>
using global_connect_t = decltype(connect(std::declval<S>(), std::declval<R>()));

template<typename S, typename R>
constexpr bool has_global_connect_v = is_detected_v<global_connect_t, S, R>;

struct connect_cpo {
template<typename Sender, typename Receiver>
auto operator() (Sender &&s, Receiver &&r) const {
if constexpr (has_connect_member_v<Sender, Receiver>)
return s.connect(r);
else if constexpr (has_global_connect_v<Sender, Receiver>)
return connect(std::forward<Sender>(s), std::forward<Receiver>(r));
else
static_assert(dependent_false_t<Sender, Receiver>,
"No connect() customization defined for sender type");
}
};

template<typename Op>
using start_member_t = decltype(std::declval<Op>().start());

template<typename Op>
constexpr bool has_start_member_v = is_detected_v<start_member_t, Op>;

template<typename Op>
using global_start_t = decltype(start(std::declval<Op>()));

template<typename Op>
constexpr bool has_global_start_v = is_detected_v<global_start_t, Op>;

struct start_inline_cpo {
template<typename Operation>
bool operator() (Operation &&op) const {
if constexpr (requires { op.start_inline(); }) {
return op.start_inline();
}else if constexpr (has_start_member_v<Operation>) {
op.start();
return false;
}else if constexpr (has_global_start_v<Operation>) {
start(std::forward<Operation>(op));
return false;
}else{
static_assert(dependent_false_t<Operation>,
"No start() customization defined for operation type");
}
}
};

struct set_value_cpo {
template<typename Receiver, typename T>
requires
requires(Receiver &&r, T &&value) { r.set_value_noinline(std::forward<T>(value)); }
void operator() (Receiver &&r, T &&value) {
if constexpr (requires { r.set_value_noinline(std::forward<T>(value)); })
r.set_value_noinline(std::forward<T>(value));
else
// This should have been caught by the concept.
static_assert(dependent_false_t<Receiver>);
}

template<typename Receiver>
requires
requires(Receiver &&r) { r.set_value_noinline(); }
void operator() (Receiver &&r) {
if constexpr (requires { r.set_value_noinline(); })
r.set_value_noinline();
else
// This should have been caught by the concept.
static_assert(dependent_false_t<Receiver>);
}
};

struct set_value_inline_cpo {
template<typename Receiver, typename T>
requires
requires(Receiver &&r, T &&value) { r.set_value_inline(std::forward<T>(value)); }
void operator() (Receiver &&r, T &&value) {
if constexpr (requires { r.set_value_inline(std::forward<T>(value)); })
r.set_value_inline(std::forward<T>(value));
else
// This should have been caught by the concept.
static_assert(dependent_false_t<Receiver>);
}

template<typename Receiver>
requires
requires(Receiver &&r) { r.set_value_inline(); }
void operator() (Receiver &&r) {
if constexpr (requires { r.set_value_inline(); })
r.set_value_inline();
else
// This should have been caught by the concept.
static_assert(dependent_false_t<Receiver>);
}
};

struct set_value_noinline_cpo {
template<typename Receiver, typename T>
requires
requires(Receiver &&r, T &&value) { r.set_value_noinline(std::forward<T>(value)); }
void operator() (Receiver &&r, T &&value) {
if constexpr (requires { r.set_value_noinline(std::forward<T>(value)); })
r.set_value_noinline(std::forward<T>(value));
else
// This should have been caught by the concept.
static_assert(dependent_false_t<Receiver>);
template<typename Sender, typename Receiver>
concept member_connect = requires (Sender &&s, Receiver &&r) {
std::forward<Sender>(s).connect(std::forward<Receiver>(r));
};

template<typename Sender, typename Receiver>
concept global_connect = requires (Sender &&s, Receiver &&r) {
connect(std::forward<Sender>(s), std::forward<Receiver>(r));
};

struct connect_cpo {
template<typename Sender, typename Receiver>
auto operator() (Sender &&s, Receiver &&r) const {
if constexpr (member_connect<Sender, Receiver>) {
return std::forward<Sender>(s).connect(std::forward<Receiver>(r));
} else if constexpr (global_connect<Sender, Receiver>) {
return connect(
std::forward<Sender>(s),
std::forward<Receiver>(r)
);
} else {
static_assert(frg::dependent_false_t<Sender, Receiver>,
"No connect() customization defined for S,R");
}

template<typename Receiver>
requires
requires(Receiver &&r) { r.set_value_noinline(); }
void operator() (Receiver &&r) {
if constexpr (requires { r.set_value_noinline(); })
r.set_value_noinline();
else
// This should have been caught by the concept.
static_assert(dependent_false_t<Receiver>);
}
};

template<typename Operation>
concept inline_startable_operation = requires (Operation &&op) {
{ std::forward<Operation>(op).start_inline() } -> std::convertible_to<bool>;
};

template<typename Operation>
concept member_start = requires (Operation &&op) {
std::forward<Operation>(op).start();
};

template<typename Operation>
concept global_start = requires (Operation &&op) {
start(std::forward<Operation>(op));
};

struct start_inline_cpo {
template<typename Operation>
bool operator() (Operation &&op) const {
if constexpr (inline_startable_operation<Operation>) {
return op.start_inline();
}else if constexpr (member_start<Operation>) {
std::forward<Operation>(op).start();
return false;
}else if constexpr (global_start<Operation>) {
start(std::forward<Operation>(op));
return false;
}else{
static_assert(frg::dependent_false_t<Operation>,
"No start() customization defined for operation type");
}
};
}
};

struct set_value_cpo {
template<typename Receiver, typename T>
requires requires(Receiver &&r, T &&value) {
std::forward<Receiver>(r).set_value_noinline(std::forward<T>(value));
}
void operator() (Receiver &&r, T &&value) {
std::forward<Receiver>(r).set_value_noinline(std::forward<T>(value));
}

template<typename Receiver>
requires requires(Receiver &&r) {
std::forward<Receiver>(r).set_value_noinline();
}
void operator() (Receiver &&r) {
std::forward<Receiver>(r).set_value_noinline();
}
};

struct set_value_inline_cpo {
template<typename Receiver, typename T>
requires requires(Receiver &&r, T &&value) {
std::forward<Receiver>(r).set_value_inline(std::forward<T>(value));
}
void operator() (Receiver &&r, T &&value) {
std::forward<Receiver>(r).set_value_inline(std::forward<T>(value));
}

template<typename Receiver>
requires requires(Receiver &&r) {
std::forward<Receiver>(r).set_value_inline();
}
void operator() (Receiver &&r) {
std::forward<Receiver>(r).set_value_inline();
}
};

struct set_value_noinline_cpo {
template<typename Receiver, typename T>
requires requires(Receiver &&r, T &&value) {
std::forward<Receiver>(r).set_value_noinline(std::forward<T>(value));
}
void operator() (Receiver &&r, T &&value) {
std::forward<Receiver>(r).set_value_noinline(std::forward<T>(value));
}

template<typename Receiver>
requires requires(Receiver &&r) {
std::forward<Receiver>(r).set_value_noinline();
}
void operator() (Receiver &&r) {
std::forward<Receiver>(r).set_value_noinline();
}
};
}

namespace execution {
Expand Down

0 comments on commit 3628ce0

Please sign in to comment.