pfor/src/pfor/expression/operators.h

138 lines
5.7 KiB
C++

#ifndef PFOR_PFOR_EXPRESSION_OPERATORS_H
#define PFOR_PFOR_EXPRESSION_OPERATORS_H
#include "asexpression.h"
#include "expression.h"
#include "op.h"
#define PFOR_EXPR_DEF_UN_OP(OP, OPSYM) \
template<typename T, std::enable_if_t<isExpression<T>>* = nullptr> \
inline auto operator OPSYM(T const& t) { return Expression<OP, T>{{}, t}; }
#define PFOR_EXPR_DEF_BIN_OP(OP, OPSYM) \
template<typename Lhs, typename Rhs, std::enable_if_t<anyExpression<Lhs, Rhs>>* = nullptr> \
inline auto operator OPSYM(Lhs const& lhs, Rhs const& rhs) { \
return Expression<OP, AsExpression<Lhs>, AsExpression<Rhs>>{{}, lhs, rhs}; \
}
#define PFOR_EXPR_DEF_OPS() \
PFOR_EXPR_DEF_UN_OP (op::Plus, +) \
PFOR_EXPR_DEF_UN_OP (op::Minus, -) \
PFOR_EXPR_DEF_UN_OP (op::Not, !) \
PFOR_EXPR_DEF_UN_OP (op::BitNot, ~) \
PFOR_EXPR_DEF_UN_OP (op::Indirection, *) \
PFOR_EXPR_DEF_UN_OP (op::AddressOf, &) \
\
PFOR_EXPR_DEF_BIN_OP(op::Multiplication, *) \
PFOR_EXPR_DEF_BIN_OP(op::Division, /) \
PFOR_EXPR_DEF_BIN_OP(op::Modulo, %) \
PFOR_EXPR_DEF_BIN_OP(op::Addition, +) \
PFOR_EXPR_DEF_BIN_OP(op::Subtraction, -) \
PFOR_EXPR_DEF_BIN_OP(op::LeftShift, <<) \
PFOR_EXPR_DEF_BIN_OP(op::RightShift, >>) \
PFOR_EXPR_DEF_BIN_OP(op::Lower, <) \
PFOR_EXPR_DEF_BIN_OP(op::LowerEqual, <=) \
PFOR_EXPR_DEF_BIN_OP(op::Greater, >) \
PFOR_EXPR_DEF_BIN_OP(op::GreaterEqual, >=) \
PFOR_EXPR_DEF_BIN_OP(op::Equal, ==) \
PFOR_EXPR_DEF_BIN_OP(op::NotEqual, !=) \
PFOR_EXPR_DEF_BIN_OP(op::BitAnd, &) \
PFOR_EXPR_DEF_BIN_OP(op::BitXor, ^) \
PFOR_EXPR_DEF_BIN_OP(op::BitOr, |) \
PFOR_EXPR_DEF_BIN_OP(op::And, &&) \
PFOR_EXPR_DEF_BIN_OP(op::Or, ||) \
PFOR_EXPR_DEF_BIN_OP(op::AssignAdd, +=) \
PFOR_EXPR_DEF_BIN_OP(op::AssignSub, -=) \
PFOR_EXPR_DEF_BIN_OP(op::AssignMul, *=) \
PFOR_EXPR_DEF_BIN_OP(op::AssignDiv, /=) \
PFOR_EXPR_DEF_BIN_OP(op::AssignMod, %=) \
PFOR_EXPR_DEF_BIN_OP(op::AssignLS, <<=) \
PFOR_EXPR_DEF_BIN_OP(op::AssignRS, >>=) \
PFOR_EXPR_DEF_BIN_OP(op::AssignAnd, &=) \
PFOR_EXPR_DEF_BIN_OP(op::AssignXor, ^=) \
PFOR_EXPR_DEF_BIN_OP(op::AssignOr, |=)
namespace pfor {
namespace expr {
PFOR_EXPR_DEF_OPS();
template<typename Cond, typename T, typename F>
inline decltype(auto) If(Cond const& cond, T const& t, F const& f) {
return Expression<op::If, Cond, T, F>{{}, cond, t, f};
}
/**
*/
template<typename, typename> struct CommaMergerImpl;
template<typename LOp, typename... LTs, typename ROp, typename... RTs>
struct CommaMergerImpl<Expression<LOp, LTs...>, Expression<ROp, RTs...>> {
using type = Expression<op::Comma, Expression<LOp, LTs...>, Expression<ROp, RTs...>>;
};
template<typename... LTs, typename ROp, typename... RTs>
struct CommaMergerImpl<Expression<op::Comma, LTs...>, Expression<ROp, RTs...>> {
using type = Expression<op::Comma, LTs..., Expression<ROp, RTs...>>;
};
template<typename LOp, typename... LTs, typename... RTs>
struct CommaMergerImpl<Expression<LOp, LTs...>, Expression<op::Comma, RTs...>> {
using type = Expression<op::Comma, Expression<LOp, LTs...>, RTs...>;
};
template<typename... LTs, typename... RTs>
struct CommaMergerImpl<Expression<op::Comma, LTs...>, Expression<op::Comma, RTs...>> {
using type = Expression<op::Comma, LTs..., RTs...>;
};
template<typename Lhs, typename Rhs>
using CommaMerger = typename CommaMergerImpl<Lhs, Rhs>::type;
/**
*/
template<typename... Ts, std::enable_if_t<allExpression<Ts...>>* = nullptr>
inline auto commaMerger(Ts... ts) {
return Expression<op::Comma, Ts...>{{}, ts...};
}
template<typename... LTs, std::size_t... lindices, typename... RTs, std::size_t... rindices>
inline auto commaMerger(std::tuple<LTs...> const& lhs,
std::index_sequence<lindices...> const&,
std::tuple<RTs...> const& rhs,
std::index_sequence<rindices...> const&) {
return Expression<op::Comma, LTs..., RTs...>{{}, std::get<lindices>(lhs)..., std::get<rindices>(rhs)...};
}
template<typename LOp, typename... LTs, typename ROp, typename... RTs,
std::enable_if_t<not std::is_same<LOp, op::Comma>::value>* = nullptr, std::enable_if_t<not std::is_same<ROp, op::Comma>::value>* = nullptr>
inline auto operator,(Expression<LOp, LTs...> const& lhs, Expression<ROp, RTs...> const& rhs) {
using Lhs = Expression<LOp, LTs...>;
using Rhs = Expression<ROp, RTs...>;
return CommaMerger<Lhs, Rhs>{{}, lhs, rhs};
}
template<typename LOp, typename... LTs, typename... RTs, std::enable_if_t<not std::is_same<LOp, op::Comma>::value>* = nullptr>
inline auto operator,(Expression<LOp, LTs...> const& lhs, Expression<op::Comma, RTs...> const& rhs) {
return commaMerger(std::make_tuple(lhs), std::make_index_sequence<1>{}, rhs.operands, std::make_index_sequence<sizeof...(RTs)>{});
}
template<typename... LTs, typename ROp, typename... RTs, std::enable_if_t<not std::is_same<ROp, op::Comma>::value>* = nullptr>
inline auto operator,(Expression<op::Comma, LTs...> const& lhs, Expression<ROp, RTs...> const& rhs) {
return commaMerger(lhs.operands, std::make_index_sequence<sizeof...(LTs)>{}, std::make_tuple(rhs), std::make_index_sequence<1>{});
}
template<typename... LTs, typename... RTs>
inline auto operator,(Expression<op::Comma, LTs...> const& lhs, Expression<op::Comma, RTs...> const& rhs) {
return commaMerger(lhs.operands, std::make_index_sequence<sizeof...(LTs)>{}, rhs.operands, std::make_index_sequence<sizeof...(RTs)>{});
}
}
}
#undef PFOR_EXPR_DEF_UN_OP
#undef PFOR_EXPR_DEF_BIN_OP
#undef PFOR_EXPR_DEF_OPS
#endif