1
0
Fork 0
mirror of https://gitlab.com/niansa/libasync.git synced 2025-03-06 20:53:29 +01:00
libasync/include/async/execution.hpp
2020-04-22 18:36:37 +02:00

85 lines
2.6 KiB
C++

#pragma once
#include <type_traits>
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;
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::move(s), std::move(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_cpo {
template<typename Operation>
auto operator() (Operation op) const {
if constexpr (has_start_member_v<Operation>)
return op.start();
else if constexpr (has_global_start_v<Operation>)
return start(std::move(op));
else
static_assert(dependent_false_t<Operation>,
"No start() customization defined for operation type");
}
};
}
namespace execution {
template<typename S, typename R>
using operation_t = std::invoke_result_t<cpo_types::connect_cpo, S, R>;
inline cpo_types::connect_cpo connect;
inline cpo_types::start_cpo start;
}
} // namespace async