pfor/src/pfor/expression/op.h

212 lines
8.1 KiB
C++

#ifndef PFOR_PFOR_EXPRESSION_OP_H
#define PFOR_PFOR_EXPRESSION_OP_H
#include "access.h"
#include "optraits.h"
#include "traits.h"
#define PFOR_EXPR_DEF_OPERATION_UNARY(OPNAME, OPSYM) \
struct OPNAME { \
template<typename T, std::enable_if_t<expr::isExpression<T>>* = nullptr> \
inline static decltype(auto) eval(T&& value) { \
return OPSYM std::forward<T>(value).eval(); \
} \
template<typename T> \
inline static decltype(auto) eval(long i, T&& value) { \
return OPSYM std::forward<T>(value)[i]; \
} \
}
#define PFOR_EXPR_DEF_OPERATION_POST_UNARY(OPNAME, OPSYM) \
struct OPNAME { \
template<typename T, std::enable_if_t<expr::isExpression<T>>* = nullptr> \
inline static decltype(auto) eval(T&& value) { \
return std::forward<T>(value).eval() OPSYM; \
} \
template<typename T> \
inline static decltype(auto) eval(long i, T&& value) { \
return std::forward<T>(value)[i] OPSYM; \
} \
}
#define PFOR_EXPR_DEF_OPERATION_BINARY(OPNAME, OPSYM) \
struct OPNAME { \
template<typename Lhs, typename Rhs, \
std::enable_if_t<expr::isExpression<Lhs>>* = nullptr> \
inline static decltype(auto) eval(Lhs&& lhs, Rhs&& rhs) { \
return std::forward<Lhs>(lhs).eval() OPSYM std::forward<Rhs>(rhs).eval(); \
} \
template<typename Lhs, typename Rhs> \
inline static decltype(auto) eval(long i, Lhs&& lhs, Rhs&& rhs) { \
return std::forward<Lhs>(lhs)[i] OPSYM std::forward<Rhs>(rhs)[i]; \
} \
}
namespace pfor {
namespace expr {
namespace op {
/* from: http://en.cppreference.com/w/cpp/language/operator_precedence
* excluding non overloadable operators
*
* [02] a++, a--, a(), a[]
* [03] ++a, --a, +a, -a, !a, ~a, *a, &a
* [04] ->*
* [05] a*b, a/b, a%b
* [06] a+b, a-b
* [07] <<, >>
* [08] <, <=, >, >=
* [09] ==, !=
* [10] a&b
* [11] ^
* [12] |
* [13] &&
* [14] ||
* [15] =, +=, -=, *=, /=, %=, <<=, >>=, &=, ^=, |=
* [16] ,
*/
/* ===== Unary ===== */
PFOR_EXPR_DEF_OPERATION_POST_UNARY(PostIncr, ++);
PFOR_EXPR_DEF_OPERATION_POST_UNARY(PostDecr, --);
PFOR_EXPR_DEF_OPERATION_UNARY(PreIncr, ++);
PFOR_EXPR_DEF_OPERATION_UNARY(PreDecr, --);
PFOR_EXPR_DEF_OPERATION_UNARY(Plus, +);
PFOR_EXPR_DEF_OPERATION_UNARY(Minus, -);
PFOR_EXPR_DEF_OPERATION_UNARY(Not, !);
PFOR_EXPR_DEF_OPERATION_UNARY(BitNot, ~);
PFOR_EXPR_DEF_OPERATION_UNARY(Indirection, *);
PFOR_EXPR_DEF_OPERATION_UNARY(AddressOf, &);
/* ===== Binary ===== */
PFOR_EXPR_DEF_OPERATION_BINARY(PtrToMem, ->*);
PFOR_EXPR_DEF_OPERATION_BINARY(Multiplication, *);
PFOR_EXPR_DEF_OPERATION_BINARY(Division, /);
PFOR_EXPR_DEF_OPERATION_BINARY(Modulo, %);
PFOR_EXPR_DEF_OPERATION_BINARY(Addition, +);
PFOR_EXPR_DEF_OPERATION_BINARY(Subtraction, -);
PFOR_EXPR_DEF_OPERATION_BINARY(LeftShift, <<);
PFOR_EXPR_DEF_OPERATION_BINARY(RightShift, >>);
PFOR_EXPR_DEF_OPERATION_BINARY(Lower, <);
PFOR_EXPR_DEF_OPERATION_BINARY(LowerEqual, <=);
PFOR_EXPR_DEF_OPERATION_BINARY(Greater, >);
PFOR_EXPR_DEF_OPERATION_BINARY(GreaterEqual, >=);
PFOR_EXPR_DEF_OPERATION_BINARY(Equal, ==);
PFOR_EXPR_DEF_OPERATION_BINARY(NotEqual, !=);
PFOR_EXPR_DEF_OPERATION_BINARY(BitAnd, &);
PFOR_EXPR_DEF_OPERATION_BINARY(BitXor, ^);
PFOR_EXPR_DEF_OPERATION_BINARY(BitOr, |);
PFOR_EXPR_DEF_OPERATION_BINARY(And, &&);
PFOR_EXPR_DEF_OPERATION_BINARY(Or, ||);
PFOR_EXPR_DEF_OPERATION_BINARY(Assign, =);
PFOR_EXPR_DEF_OPERATION_BINARY(AssignAdd, +=);
PFOR_EXPR_DEF_OPERATION_BINARY(AssignSub, -=);
PFOR_EXPR_DEF_OPERATION_BINARY(AssignMul, *=);
PFOR_EXPR_DEF_OPERATION_BINARY(AssignDiv, /=);
PFOR_EXPR_DEF_OPERATION_BINARY(AssignMod, %=);
PFOR_EXPR_DEF_OPERATION_BINARY(AssignLS, <<=);
PFOR_EXPR_DEF_OPERATION_BINARY(AssignRS, >>=);
PFOR_EXPR_DEF_OPERATION_BINARY(AssignAnd, &=);
PFOR_EXPR_DEF_OPERATION_BINARY(AssignXor, ^=);
PFOR_EXPR_DEF_OPERATION_BINARY(AssignOr, |=);
struct Subscript {
template<typename T, typename Index, std::enable_if_t<isExpression<T>>* = nullptr>
inline static decltype(auto) eval(T&& t, Index&& index) {
return std::forward<T>(t).eval()[std::forward<Index>(index).eval()];
}
template<typename T, typename Index>
inline static decltype(auto) eval(long i, T&& t, Index&& index) {
return std::forward<T>(t)[i][std::forward<Index>(index)[i]];
}
};
struct Comma {
template<typename Lhs, typename... Rhs, std::enable_if_t<isExpression<Lhs>>* = nullptr>
inline static decltype(auto) eval(Lhs&& lhs, Rhs&&... rhs) {
return std::forward<Lhs>(lhs).eval(), eval(std::forward<Rhs>(rhs)...);
}
template<typename Lhs, typename Rhs, std::enable_if_t<isExpression<Lhs>>* = nullptr>
inline static decltype(auto) eval(Lhs&& lhs, Rhs&& rhs) {
return std::forward<Lhs>(lhs).eval(), std::forward<Rhs>(rhs).eval();
}
template<typename Lhs, typename... Rhs>
inline static decltype(auto) eval(long i, Lhs&& lhs, Rhs&&... rhs) {
return std::forward<Lhs>(lhs)[i], eval(i, std::forward<Rhs>(rhs)...);
}
template<typename Lhs, typename Rhs>
inline static decltype(auto) eval(long i, Lhs&& lhs, Rhs&& rhs) {
return std::forward<Lhs>(lhs)[i], std::forward<Rhs>(rhs)[i];
}
template<typename Lhs>
inline static decltype(auto) eval(long i, Lhs&& lhs) {
return std::forward<Lhs>(lhs)[i];
}
};
/* ===== Ternary ===== */
struct If {
template<typename Cond, typename T, typename F, std::enable_if_t<isExpression<Cond>>* = nullptr>
inline static decltype(auto) eval(Cond&& cond, T&& t, F&& f) {
return std::forward<Cond>(cond).eval()? std::forward<T>(t).eval():std::forward<F>(f).eval();
}
template<typename Cond, typename T, typename F>
inline static decltype(auto) eval(long i, Cond&& cond, T&& t, F&& f) {
return std::forward<Cond>(cond)[i]? std::forward<T>(t)[i]:std::forward<F>(f)[i];
}
};
/* ==== N-ary ===== */
struct FunctionCall {
template<typename F, typename... Ts, std::enable_if_t<isExpression<F>>* = nullptr>
inline static decltype(auto) eval(F&& f, Ts&&... values) {
return std::forward<F>(f).eval()(std::forward<Ts>(values).eval()...);
}
template<typename F, typename... Ts>
inline static decltype(auto) eval(long i, F&& f, Ts&&... values) {
return std::forward<F>(f)[i](std::forward<Ts>(values)[i]...);
}
};
#undef PFOR_EXPR_DEF_OPERATION_POST_UNARY
#undef PFOR_EXPR_DEF_OPERATION_UNARY
#undef PFOR_EXPR_DEF_OPERATION_BINARY
template<typename Op>
struct View;
}
#define PFOR_EXPR_SPECIALIZE_ASSIGN(O) \
template<typename T> \
struct OperationTraits<op::O, T, 0> { \
static constexpr Access access = Access::write; \
}
PFOR_EXPR_SPECIALIZE_ASSIGN(Assign);
PFOR_EXPR_SPECIALIZE_ASSIGN(AssignAdd);
PFOR_EXPR_SPECIALIZE_ASSIGN(AssignSub);
PFOR_EXPR_SPECIALIZE_ASSIGN(AssignMul);
PFOR_EXPR_SPECIALIZE_ASSIGN(AssignDiv);
PFOR_EXPR_SPECIALIZE_ASSIGN(AssignMod);
PFOR_EXPR_SPECIALIZE_ASSIGN(AssignLS);
PFOR_EXPR_SPECIALIZE_ASSIGN(AssignRS);
PFOR_EXPR_SPECIALIZE_ASSIGN(AssignAnd);
PFOR_EXPR_SPECIALIZE_ASSIGN(AssignXor);
PFOR_EXPR_SPECIALIZE_ASSIGN(AssignOr);
#undef PFOR_EXPR_SPECIALIZE_ASSIGN
}
}
#endif