Created
April 6, 2020 18:58
-
-
Save qookei/3b9289690e3869042b705cdc64fba2c7 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <iostream> | |
#include <tuple> | |
#include <array> | |
namespace details { | |
template<typename... Ts> | |
struct concat_size; | |
template<typename... Ts> | |
inline constexpr size_t concat_size_v = concat_size<Ts...>::value; | |
template<typename T, typename... Ts> | |
struct concat_size<T, Ts...> | |
: std::integral_constant<size_t, std::tuple_size_v<T> + concat_size_v<Ts...>> { }; | |
template<> | |
struct concat_size<> | |
: std::integral_constant<size_t, 0> { }; | |
template<typename X, size_t N> | |
constexpr void concat_insert(std::array<X, N> &, size_t) { } | |
template<typename X, size_t N, typename T, typename... Ts> | |
constexpr void concat_insert(std::array<X, N> &res, size_t at, const T &other, const Ts &... tail) { | |
size_t n = std::tuple_size_v<T>; | |
for(size_t i = 0; i < n; ++i) | |
res[at + i] = other[i]; | |
concat_insert(res, at + n, tail...); | |
} | |
template<typename X, typename... Ts> | |
constexpr auto array_concat(const Ts &... arrays) { | |
std::array<X, concat_size_v<Ts...>> res{}; | |
concat_insert(res, 0, arrays...); | |
return res; | |
} | |
} // namespace details | |
struct HelAction { int i; bool chain; bool ancilary; }; | |
struct RecvBufferResult { auto error() { return "RecvBufferResult"; } void parse(void *&) { } }; | |
struct SendBufferResult { auto error() { return "SendBufferResult"; } void parse(void *&) { } }; | |
struct OfferResult { auto error() { return "OfferResult"; } void parse(void *&) { } }; | |
struct RecvBuffer{ }; | |
struct SendBuffer{ }; | |
template <typename ...T> | |
struct Offer{ std::tuple<T...> nested_actions; }; | |
template <typename ...T> | |
auto offer(T &&...args) { | |
return Offer<T...>{std::make_tuple(args...)}; | |
} | |
struct TransmissionError { int i; }; | |
struct { | |
template <typename T, typename ...Ts> | |
auto operator() (T &&arg, Ts &&...args) { | |
return details::array_concat<HelAction>( | |
createActionsArrayFor(true, std::forward<T>(arg)), | |
this->operator()<Ts...>(std::forward<Ts>(args)...) | |
); | |
} | |
template <typename T> | |
auto operator() (T &&arg) { | |
return createActionsArrayFor(false, std::forward<T>(arg)); | |
} | |
} createMultipleActionsArray; | |
template <typename ...T> | |
auto createActionsArrayFor(bool chain, const Offer<T...> &o) { | |
return details::array_concat<HelAction>( | |
std::array<HelAction, 1>{ | |
3, chain, | |
std::tuple_size_v<decltype(o.nested_actions)> > 0 | |
}, | |
std::apply(createMultipleActionsArray, o.nested_actions) | |
); | |
} | |
auto createActionsArrayFor(bool chain, const RecvBuffer &) { | |
return std::array<HelAction, 1>{1, chain, false}; | |
} | |
auto createActionsArrayFor(bool chain, const SendBuffer &) { | |
return std::array<HelAction, 1>{2, chain, false}; | |
} | |
auto resultTypeTuple(RecvBuffer arg) { | |
return std::tuple<RecvBufferResult>{}; | |
} | |
auto resultTypeTuple(SendBuffer arg) { | |
return std::tuple<SendBufferResult>{}; | |
} | |
template <typename ...T> | |
auto resultTypeTuple(Offer<T...> arg) { | |
return std::tuple_cat(std::tuple<OfferResult>{}, resultTypeTuple(T{})...); | |
} | |
template <typename ...T> | |
auto createResultsTuple(T &&...args) { | |
return std::tuple_cat(resultTypeTuple(args)...); | |
} | |
template <typename Results, typename Actions> | |
struct Transmission { | |
Transmission(Results, Actions actions) { | |
static_assert(std::is_same_v<Actions, std::array<typename Actions::value_type, actions.size()>>, "Bad actions type"); | |
for (auto a : actions) { | |
constexpr const char *names[] = {"", "RecvBuffer", "SendBuffer", "Offer"}; | |
printf("%c%c - %s\n", a.chain ? 'c' : ' ', a.ancilary ? 'a' : ' ', names[a.i]); | |
} | |
// submit actions | |
// ... | |
complete(nullptr); | |
} | |
// replace with co_await stuff to return the values | |
auto operator *() { | |
return std::tuple_cat(std::make_tuple(TransmissionError{0}), _results); | |
} | |
private: | |
void complete(void *ptr) { | |
[&]<size_t ...p>(std::index_sequence<p...>) { | |
(std::get<p>(_results).parse(ptr), ...); | |
} (std::make_index_sequence<std::tuple_size<Results>::value>{}); | |
} | |
Results _results; | |
}; | |
template <typename ...Args> | |
auto asyncSubmit(Args &&...args) { | |
return Transmission{ | |
createResultsTuple(args...), | |
createMultipleActionsArray(args...) | |
}; | |
} | |
int main() { | |
auto [error, offer1, recv_resp1, send_req1, offer2, recv_resp2, send_req2] = *asyncSubmit( | |
offer( | |
RecvBuffer{}, | |
SendBuffer{} | |
), | |
offer( | |
RecvBuffer{}, | |
SendBuffer{} | |
) | |
); | |
std::cout << offer1.error() << " " << recv_resp1.error() << " " << send_req1.error() << "\n"; | |
std::cout << offer2.error() << " " << recv_resp2.error() << " " << send_req2.error() << "\n"; | |
static_assert(std::is_same_v<decltype(error), TransmissionError>, "Bad tranmission error type"); | |
static_assert(std::is_same_v<decltype(offer1), OfferResult>, "Bad first offer result type"); | |
static_assert(std::is_same_v<decltype(recv_resp1), RecvBufferResult>, "Bad first recv_resp result type"); | |
static_assert(std::is_same_v<decltype(send_req1), SendBufferResult>, "Bad first send_req result type"); | |
static_assert(std::is_same_v<decltype(offer2), OfferResult>, "Bad second offer result type"); | |
static_assert(std::is_same_v<decltype(recv_resp2), RecvBufferResult>, "Bad second recv_resp result type"); | |
static_assert(std::is_same_v<decltype(send_req2), SendBufferResult>, "Bad second send_req result type"); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment