rosa/inc/alsk/edsl/op/impl/serial.h

121 lines
3.4 KiB
C++

#ifndef ALSK_ALSK_EDSL_OP_IMPL_SERIAL_H
#define ALSK_ALSK_EDSL_OP_IMPL_SERIAL_H
#include <utility>
#include "../traits.h"
#include "../../../skeleton/bone/serial.h"
#include "../../../skeleton/struct/struct.h"
#include "../../../skeleton/link/link.h"
namespace alsk {
namespace edsl {
template<typename Signature_, typename... Operands>
struct Serial: OperandBase {
std::tuple<Operands...> operands;
constexpr Serial(Operands... operands): operands{operands...} {}
template<typename S>
constexpr Serial(Serial<S, Operands...> const& o): operands{o.operands} {}
template<typename S>
constexpr Serial(Serial<S, Operands...>&& o): operands{std::move(o.operands)} {}
using Signature = Signature_;
using Struct = S<alsk::Serial, typename Operands::Struct...>;
using Links = L<alsk::Serial, Signature, typename Operands::Links...>;
template<typename S>
constexpr void setup(S& skeleton) const {
setup(skeleton, std::make_index_sequence<sizeof...(Operands)>());
}
template<typename S, std::size_t... indices>
constexpr void setup(S& skeleton, std::index_sequence<indices...>) const {
using Expander = int[];
static_cast<void>(Expander{(OperandBase::setupFor(std::get<indices>(operands), skeleton.template task<indices>()), 0)...});
}
template<typename Signature>
constexpr auto link() const&& {
return Serial<Signature, Operands...>{std::move(*this)};
}
template<typename Signature>
constexpr auto link() const& {
return Serial<Signature, Operands...>{*this};
}
};
namespace impl {
template<typename Lhs, std::size_t... lIndices, typename Rhs, std::size_t... rIndices>
constexpr auto mergeSerial(Lhs const& lhs, std::index_sequence<lIndices...>, Rhs const& rhs, std::index_sequence<rIndices...>) {
return Serial<void(), std::tuple_element_t<lIndices, Lhs>..., std::tuple_element_t<rIndices, Rhs>...>{
std::get<lIndices>(lhs)..., std::get<rIndices>(rhs)...
};
}
template<typename Lhs, typename Rhs>
constexpr auto mergeSerial(Lhs const& lhs, Rhs const& rhs) {
return mergeSerial(lhs, std::make_index_sequence<std::tuple_size<Lhs>{}>(),
rhs, std::make_index_sequence<std::tuple_size<Rhs>{}>());
}
template<typename T>
constexpr auto operandTuple(T const& t) {
return std::make_tuple(t);
}
template<typename... Ts>
constexpr auto operandTuple(Serial<Ts...> const& s) noexcept {
return s.operands;
}
template<typename...> struct SerialBuilder;
template<typename Arg, typename... Args>
struct SerialBuilder<Arg, Args...> {
static constexpr auto build(Arg const& arg, Args const&... args) {
return mergeSerial(operandTuple(arg), operandTuple(SerialBuilder<Args...>::build(args...)));
}
};
template<typename Arg>
struct SerialBuilder<Arg> {
static constexpr auto build(Arg const& arg) {
return arg;
}
};
}
template<typename... Args, std::enable_if_t<(sizeof...(Args) > 1) and allOperands<Args...>>* = nullptr>
constexpr auto serial(Args const&... args) {
return impl::SerialBuilder<Args...>::build(args...);
}
template<
typename Lhs, typename Rhs,
std::enable_if_t<isOperand<Lhs> and isOperand<Rhs>>* = nullptr
>
constexpr auto operator,(Lhs const& lhs, Rhs const& rhs) {
return impl::mergeSerial(impl::operandTuple(lhs), impl::operandTuple(rhs));
}
template<
typename Lhs, typename Rhs,
std::enable_if_t<isOperand<Lhs> and isOperand<Rhs>>* = nullptr
>
constexpr auto operator&(Lhs const& lhs, Rhs const& rhs) {
return impl::mergeSerial(impl::operandTuple(lhs), impl::operandTuple(rhs));
}
}
}
#endif