Skip to content

Instantly share code, notes, and snippets.

@qookei
Created April 6, 2020 18:58
Show Gist options
  • Save qookei/3b9289690e3869042b705cdc64fba2c7 to your computer and use it in GitHub Desktop.
Save qookei/3b9289690e3869042b705cdc64fba2c7 to your computer and use it in GitHub Desktop.
#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