121 lines
3.4 KiB
C++
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
|