282 lines
8.0 KiB
C++
282 lines
8.0 KiB
C++
//
|
|
// php-armadillo/operators.cc
|
|
//
|
|
// @Author CismonX
|
|
//
|
|
|
|
#include "operators.hh"
|
|
#include "complex.hh"
|
|
#include "base.hh"
|
|
#include "dense.hh"
|
|
#include "mat.hh"
|
|
#include "subview_mat.hh"
|
|
#include "mapval.hh"
|
|
|
|
#if PHP_VERSION_ID >= 70300
|
|
// See https://github.com/php/php-src/blob/PHP-7.3/UPGRADING.INTERNALS section 3.1.b.
|
|
#define EX_CONSTANT(op) RT_CONSTANT(EX(opline), op)
|
|
#endif
|
|
|
|
#define PHP_ARMA_OP_HANDLER_FUNC \
|
|
[](auto zv1, auto zv2, auto rv, auto ce)
|
|
|
|
namespace php_arma
|
|
{
|
|
zend_always_inline
|
|
zval *get_zval_ptr_undef(
|
|
zend_uchar op_type,
|
|
const znode_op *op,
|
|
zend_free_op *free_op,
|
|
zend_execute_data *execute_data
|
|
) {
|
|
switch (op_type) {
|
|
case IS_TMP_VAR:
|
|
case IS_VAR:
|
|
return *free_op = EX_VAR(op->var);
|
|
case IS_CONST:
|
|
return EX_CONSTANT(*op);
|
|
case IS_CV:
|
|
return EX_VAR(op->var);
|
|
default:
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
template <typename F>
|
|
zend_always_inline
|
|
int op_handler(zend_execute_data *execute_data, F handler)
|
|
{
|
|
const zend_op *opline = EX(opline);
|
|
zend_free_op free_op1 = nullptr;
|
|
zend_free_op free_op2 = nullptr;
|
|
auto op1 = get_zval_ptr_undef(opline->op1_type, &opline->op1, &free_op1, execute_data);
|
|
auto op2 = get_zval_ptr_undef(opline->op2_type, &opline->op2, &free_op2, execute_data);
|
|
zend_class_entry *ce = nullptr;
|
|
|
|
if (EXPECTED(op1)) {
|
|
ZVAL_DEREF(op1);
|
|
if (Z_TYPE_P(op1) == IS_OBJECT) {
|
|
ce = Z_OBJCE_P(op1);
|
|
}
|
|
}
|
|
if (op2) {
|
|
ZVAL_DEREF(op2);
|
|
if (ce == nullptr) {
|
|
if (Z_TYPE_P(op2) == IS_OBJECT) {
|
|
ce = Z_OBJCE_P(op2);
|
|
} else {
|
|
return ZEND_USER_OPCODE_DISPATCH;
|
|
}
|
|
}
|
|
}
|
|
|
|
zval *result = opline->result_type == IS_UNUSED ? nullptr : EX_VAR(opline->result.var);
|
|
if (ce == nullptr || !handler(op1, op2, result, ce)) {
|
|
return ZEND_USER_OPCODE_DISPATCH;
|
|
}
|
|
|
|
if (free_op2) {
|
|
zval_ptr_dtor_nogc(free_op2);
|
|
}
|
|
if (free_op1) {
|
|
zval_ptr_dtor_nogc(free_op1);
|
|
}
|
|
EX(opline) = opline + 1;
|
|
return ZEND_USER_OPCODE_CONTINUE;
|
|
}
|
|
|
|
int add_handler(zend_execute_data *execute_data)
|
|
{
|
|
return op_handler(execute_data, PHP_ARMA_OP_HANDLER_FUNC {
|
|
PHP_ARMA_COMPLEX_OPERATOR(add);
|
|
PHP_ARMA_BASE_OPERATOR(add);
|
|
|
|
return false;
|
|
});
|
|
}
|
|
|
|
int add_assign_handler(zend_execute_data *execute_data)
|
|
{
|
|
return op_handler(execute_data, PHP_ARMA_OP_HANDLER_FUNC {
|
|
PHP_ARMA_COMPLEX_ASSIGN_OPERATOR(add);
|
|
PHP_ARMA_BASE_ASSIGN_OPERATOR(add);
|
|
|
|
return false;
|
|
});
|
|
}
|
|
|
|
int sub_handler(zend_execute_data *execute_data)
|
|
{
|
|
return op_handler(execute_data, PHP_ARMA_OP_HANDLER_FUNC {
|
|
PHP_ARMA_COMPLEX_OPERATOR(sub);
|
|
PHP_ARMA_BASE_OPERATOR(sub);
|
|
|
|
return false;
|
|
});
|
|
}
|
|
|
|
int sub_assign_handler(zend_execute_data *execute_data)
|
|
{
|
|
return op_handler(execute_data, PHP_ARMA_OP_HANDLER_FUNC {
|
|
PHP_ARMA_COMPLEX_ASSIGN_OPERATOR(sub);
|
|
PHP_ARMA_BASE_ASSIGN_OPERATOR(sub);
|
|
|
|
return false;
|
|
});
|
|
}
|
|
|
|
int mul_handler(zend_execute_data *execute_data)
|
|
{
|
|
return op_handler(execute_data, PHP_ARMA_OP_HANDLER_FUNC {
|
|
PHP_ARMA_COMPLEX_OPERATOR(mul);
|
|
PHP_ARMA_BASE_OPERATOR(mul);
|
|
PHP_ARMA_MAPVAL_OPERATOR(mul);
|
|
|
|
return false;
|
|
});
|
|
}
|
|
|
|
int mul_assign_handler(zend_execute_data *execute_data)
|
|
{
|
|
return op_handler(execute_data, PHP_ARMA_OP_HANDLER_FUNC {
|
|
PHP_ARMA_COMPLEX_ASSIGN_OPERATOR(mul);
|
|
PHP_ARMA_BASE_ASSIGN_OPERATOR(mul);
|
|
|
|
return false;
|
|
});
|
|
}
|
|
|
|
int div_handler(zend_execute_data *execute_data)
|
|
{
|
|
return op_handler(execute_data, PHP_ARMA_OP_HANDLER_FUNC {
|
|
PHP_ARMA_COMPLEX_OPERATOR(div);
|
|
PHP_ARMA_BASE_OPERATOR(div);
|
|
|
|
return false;
|
|
});
|
|
}
|
|
|
|
int div_assign_handler(zend_execute_data *execute_data)
|
|
{
|
|
return op_handler(execute_data, PHP_ARMA_OP_HANDLER_FUNC {
|
|
PHP_ARMA_COMPLEX_ASSIGN_OPERATOR(div);
|
|
PHP_ARMA_BASE_ASSIGN_OPERATOR(div);
|
|
|
|
return false;
|
|
});
|
|
}
|
|
|
|
int mod_handler(zend_execute_data *execute_data)
|
|
{
|
|
return op_handler(execute_data, PHP_ARMA_OP_HANDLER_FUNC {
|
|
PHP_ARMA_BASE_OPERATOR(dotMul);
|
|
|
|
return false;
|
|
});
|
|
}
|
|
|
|
int mod_assign_handler(zend_execute_data *execute_data)
|
|
{
|
|
return op_handler(execute_data, PHP_ARMA_OP_HANDLER_FUNC {
|
|
PHP_ARMA_BASE_ASSIGN_OPERATOR(dotMul);
|
|
|
|
return false;
|
|
});
|
|
}
|
|
|
|
int pow_handler(zend_execute_data *execute_data)
|
|
{
|
|
return op_handler(execute_data, PHP_ARMA_OP_HANDLER_FUNC {
|
|
PHP_ARMA_COMPLEX_OPERATOR(pow);
|
|
|
|
return false;
|
|
});
|
|
}
|
|
|
|
int pow_assign_handler(zend_execute_data *execute_data)
|
|
{
|
|
return op_handler(execute_data, PHP_ARMA_OP_HANDLER_FUNC {
|
|
PHP_ARMA_COMPLEX_ASSIGN_OPERATOR(pow);
|
|
|
|
return false;
|
|
});
|
|
}
|
|
|
|
int bw_not_handler(zend_execute_data *execute_data)
|
|
{
|
|
return op_handler(execute_data, PHP_ARMA_OP_HANDLER_FUNC {
|
|
PHP_ARMA_COMPLEX_OPERATOR(conj);
|
|
|
|
return false;
|
|
});
|
|
}
|
|
|
|
int is_equal_handler(zend_execute_data *execute_data)
|
|
{
|
|
return op_handler(execute_data, PHP_ARMA_OP_HANDLER_FUNC {
|
|
PHP_ARMA_DENSE_OPERATOR(equals);
|
|
|
|
return false;
|
|
});
|
|
}
|
|
|
|
int is_not_equal_handler(zend_execute_data *execute_data)
|
|
{
|
|
return op_handler(execute_data, PHP_ARMA_OP_HANDLER_FUNC {
|
|
PHP_ARMA_DENSE_OPERATOR(not_equals);
|
|
|
|
return false;
|
|
});
|
|
}
|
|
|
|
int is_smaller_handler(zend_execute_data *execute_data)
|
|
{
|
|
return op_handler(execute_data, PHP_ARMA_OP_HANDLER_FUNC {
|
|
PHP_ARMA_DENSE_OPERATOR(smaller_than);
|
|
|
|
return false;
|
|
});
|
|
}
|
|
|
|
int is_smaller_or_equal_handler(zend_execute_data *execute_data)
|
|
{
|
|
return op_handler(execute_data, PHP_ARMA_OP_HANDLER_FUNC {
|
|
PHP_ARMA_DENSE_OPERATOR(not_greater_than);
|
|
|
|
return false;
|
|
});
|
|
}
|
|
|
|
template <typename... Ts>
|
|
zend_always_inline
|
|
void set_op_handlers(Ts&&... op_handlers)
|
|
{
|
|
for (auto [opcode, handler] : { op_handlers... }) {
|
|
zend_set_user_opcode_handler(opcode, handler);
|
|
}
|
|
}
|
|
|
|
void operators_init()
|
|
{
|
|
set_op_handlers(
|
|
std::make_tuple(ZEND_ADD, add_handler),
|
|
std::make_tuple(ZEND_ASSIGN_ADD, add_assign_handler),
|
|
std::make_tuple(ZEND_SUB, sub_handler),
|
|
std::make_tuple(ZEND_ASSIGN_SUB, sub_assign_handler),
|
|
std::make_tuple(ZEND_MUL, mul_handler),
|
|
std::make_tuple(ZEND_ASSIGN_MUL, mul_assign_handler),
|
|
std::make_tuple(ZEND_DIV, div_handler),
|
|
std::make_tuple(ZEND_ASSIGN_DIV, div_assign_handler),
|
|
std::make_tuple(ZEND_MOD, mod_handler),
|
|
std::make_tuple(ZEND_ASSIGN_MOD, mod_assign_handler),
|
|
std::make_tuple(ZEND_POW, pow_handler),
|
|
std::make_tuple(ZEND_ASSIGN_POW, pow_assign_handler),
|
|
std::make_tuple(ZEND_BW_NOT, bw_not_handler),
|
|
std::make_tuple(ZEND_IS_EQUAL, is_equal_handler),
|
|
std::make_tuple(ZEND_IS_NOT_EQUAL, is_not_equal_handler),
|
|
std::make_tuple(ZEND_IS_SMALLER, is_smaller_handler),
|
|
std::make_tuple(ZEND_IS_SMALLER_OR_EQUAL, is_smaller_or_equal_handler)
|
|
);
|
|
}
|
|
}
|