Select Git revision
CRSMatrix.hpp
BinaryExpressionProcessor.hpp 5.32 KiB
#ifndef BINARY_EXPRESSION_PROCESSOR_HPP
#define BINARY_EXPRESSION_PROCESSOR_HPP
#include <node_processor/INodeProcessor.hpp>
#include <Demangle.hpp>
#include <type_traits>
template <typename Op>
struct BinOp;
template <>
struct BinOp<language::and_op>
{
template <typename A, typename B>
PUGS_INLINE auto
eval(const A& a, const B& b) -> decltype(a and b)
{
return a and b;
}
};
template <>
struct BinOp<language::or_op>
{
template <typename A, typename B>
PUGS_INLINE auto
eval(const A& a, const B& b) -> decltype(a or b)
{
return a or b;
}
};
template <>
struct BinOp<language::xor_op>
{
template <typename A, typename B>
PUGS_INLINE auto
eval(const A& a, const B& b) -> decltype(a xor b)
{
return a xor b;
}
};
template <>
struct BinOp<language::eqeq_op>
{
template <typename A, typename B>
PUGS_INLINE auto
eval(const A& a, const B& b) -> decltype(a == b)
{
return a == b;
}
};
template <>
struct BinOp<language::not_eq_op>
{
template <typename A, typename B>
PUGS_INLINE auto
eval(const A& a, const B& b) -> decltype(a != b)
{
return a != b;
}
};
template <>
struct BinOp<language::lesser_op>
{
template <typename A, typename B>
PUGS_INLINE auto
eval(const A& a, const B& b) -> decltype(a < b)
{
return a < b;
}
};
template <>
struct BinOp<language::lesser_or_eq_op>
{
template <typename A, typename B>
PUGS_INLINE auto
eval(const A& a, const B& b) -> decltype(a <= b)
{
return a <= b;
}
};
template <>
struct BinOp<language::greater_op>
{
template <typename A, typename B>
PUGS_INLINE auto
eval(const A& a, const B& b) -> decltype(a > b)
{
return a > b;
}
};
template <>
struct BinOp<language::greater_or_eq_op>
{
template <typename A, typename B>
PUGS_INLINE auto
eval(const A& a, const B& b) -> decltype(a >= b)
{
return a >= b;
}
};
template <>
struct BinOp<language::plus_op>
{
template <typename A, typename B>
PUGS_INLINE auto
eval(const A& a, const B& b) -> decltype(a + b)
{
return a + b;
}
};
template <>
struct BinOp<language::minus_op>
{
template <typename A, typename B>
PUGS_INLINE auto
eval(const A& a, const B& b) -> decltype(a - b)
{
return a - b;
}
};
template <>
struct BinOp<language::multiply_op>
{
template <typename A, typename B>
PUGS_INLINE auto
eval(const A& a, const B& b) -> decltype(a * b)
{
return a * b;
}
};
template <>
struct BinOp<language::divide_op>
{
template <typename A, typename B>
PUGS_INLINE auto
eval(const A& a, const B& b) -> decltype(a / b)
{
return a / b;
}
};
template <typename BinaryOpT, typename A_DataT, typename B_DataT>
class BinaryExpressionProcessor final : public INodeProcessor
{
ASTNode& m_node;
PUGS_INLINE auto
_eval(const ASTNodeDataVariant& a, const ASTNodeDataVariant& b, ASTNodeDataVariant& value)
{
// Add 'signed' when necessary to avoid signed/unsigned comparison warnings
if constexpr ((not(std::is_same_v<A_DataT, bool> or std::is_same_v<B_DataT, bool>)) and
(std::is_same_v<BinaryOpT, language::and_op> or std::is_same_v<BinaryOpT, language::or_op> or
std::is_same_v<BinaryOpT, language::xor_op> or std::is_same_v<BinaryOpT, language::eqeq_op> or
std::is_same_v<BinaryOpT, language::not_eq_op> or std::is_same_v<BinaryOpT, language::lesser_op> or
std::is_same_v<BinaryOpT, language::lesser_or_eq_op> or
std::is_same_v<BinaryOpT, language::greater_op> or
std::is_same_v<BinaryOpT, language::greater_or_eq_op>) and
(std::is_signed_v<A_DataT> xor std::is_signed_v<B_DataT>)) {
if constexpr (std::is_unsigned_v<A_DataT>) {
using signed_A_DataT = std::make_signed_t<A_DataT>;
const signed_A_DataT signed_a = static_cast<signed_A_DataT>(std::get<A_DataT>(a));
value = BinOp<BinaryOpT>().eval(signed_a, std::get<B_DataT>(b));
} else {
using signed_B_DataT = std::make_signed_t<B_DataT>;
const signed_B_DataT signed_b = static_cast<signed_B_DataT>(std::get<B_DataT>(b));
value = BinOp<BinaryOpT>().eval(std::get<A_DataT>(a), signed_b);
}
} else {
auto result = BinOp<BinaryOpT>().eval(std::get<A_DataT>(a), std::get<B_DataT>(b));
if constexpr (std::is_same_v<decltype(result), int>) {
value = static_cast<int64_t>(result);
} else {
value = result;
}
}
}
static inline const bool _is_defined{[] {
if constexpr (std::is_same_v<BinaryOpT, language::xor_op>) {
return std::is_same_v<std::decay_t<A_DataT>, std::decay_t<B_DataT>> and std::is_integral_v<std::decay_t<A_DataT>>;
}
return true;
}()};
public:
std::string
describe() const
{
return demangle<decltype(*this)>();
}
void
execute(ExecUntilBreakOrContinue& exec_policy)
{
if constexpr (_is_defined) {
m_node.children[0]->execute(exec_policy);
m_node.children[1]->execute(exec_policy);
this->_eval(m_node.children[0]->m_value, m_node.children[1]->m_value, m_node.m_value);
}
}
BinaryExpressionProcessor(ASTNode& node) : m_node{node}
{
if constexpr (not _is_defined) {
throw parse_error("invalid operands to binary expression", std::vector{m_node.begin()});
}
}
};
#endif // BINARY_EXPRESSION_PROCESSOR_HPP