Better operator support for Complex.

This commit is contained in:
CismonX 2019-04-18 18:15:33 +08:00
parent 1461b148b2
commit b49ef617c0
5 changed files with 67 additions and 84 deletions

View File

@ -98,9 +98,7 @@ namespace php_arma
template <typename T>
PHP_ARMA_METHOD(complex, neg, T)
{
auto current = zval_get_scalar<native_t>(getThis());
zval_set_scalar(return_value, -current);
operators::neg(getThis(), return_value);
}
template <typename T>

View File

@ -13,16 +13,28 @@
#ifdef PHP_ARMA_OPERATORS
// For non-assignment operators, first operand can be of type double.
#define PHP_ARMA_COMPLEX_OPERATOR(type, func) \
if (instanceof_function(_ce, complex<type>::ce)) { \
return complex<type>::operators::func(zv1, zv2, retval); \
if (instanceof_function(ce, complex<type>::ce)) { \
zval tmp; \
ZVAL_UNDEF(&tmp); \
if (zval_is_scalar<type>(zv1)) { \
auto real = zval_get_scalar<type>(zv1); \
zval_set_scalar(&tmp, std::complex<type>(real)); \
zv1 = &tmp; \
} \
auto v = complex<type>::operators::func(zv1, zv2, rv); \
if (Z_TYPE(tmp) != IS_UNDEF) { \
zval_ptr_dtor_nogc(&tmp); \
} \
return v; \
}
#define PHP_ARMA_COMPLEX_OPERATOR_ASSIGN(type, func) \
if (instanceof_function(_ce, complex<type>::ce)) { \
if (instanceof_function(ce, complex<type>::ce)) { \
auto v = complex<type>::operators::func(zv1, zv2, zv1); \
if (EX(opline)->result_type != IS_UNUSED) { \
ZVAL_COPY(retval, zv1); \
ZVAL_COPY(rv, zv1); \
} \
return v; \
}
@ -172,6 +184,14 @@ namespace php_arma
return false;
}
zend_always_inline
static void neg(zval *zv, zval *retval)
{
auto v = zval_get_scalar<native_t>(zv);
zval_set_scalar(retval, -v);
}
zend_always_inline
static bool mul(zval *zv1, zval *zv2, zval *retval)
{
@ -185,6 +205,11 @@ namespace php_arma
zval_set_scalar(retval, v1 * zval_get_scalar<T>(zv2));
return true;
}
if (Z_TYPE_P(zv2) == IS_LONG && Z_LVAL_P(zv2) == -1) {
// Negation operator is compiled as multiplication to -1.
neg(zv1, retval);
return true;
}
return false;
}

View File

@ -9,7 +9,7 @@
#include "complex.hh"
#if PHP_VERSION_ID >= 70300
// See https://github.com/php/php-src/blob/PHP-7.3/UPGRADING.INTERNALS#L61 section 3.1.b.
// 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
@ -63,13 +63,17 @@ namespace php_arma
if (op2) {
ZVAL_DEREF(op2);
}
if ((op1 && Z_TYPE_P(op1) != IS_OBJECT) && (op2 && Z_TYPE_P(op2) != IS_OBJECT)) {
return ZEND_USER_OPCODE_DISPATCH;
}
if (UNEXPECTED(opcode_is_greater(opline))) {
std::swap(op1, op2);
std::swap(free_op1, free_op2);
}
if (!handler(op1, op2, EX_VAR(opline->result.var))) {
auto ce = Z_TYPE_P(op1) == IS_OBJECT ? Z_OBJCE_P(op1) : Z_OBJCE_P(op2);
if (!handler(op1, op2, EX_VAR(opline->result.var), ce)) {
return ZEND_USER_OPCODE_DISPATCH;
}
@ -85,12 +89,8 @@ namespace php_arma
int add_handler(zend_execute_data *execute_data)
{
return op_handler(execute_data, [] (auto zv1, auto zv2, auto retval) {
if (UNEXPECTED(Z_TYPE_P(zv1) != IS_OBJECT)) {
return false;
}
PHP_ARMA_OPERATOR_BEGIN(zv1, complex_ce)
return op_handler(execute_data, [] (auto zv1, auto zv2, auto rv, auto ce) {
PHP_ARMA_OPERATOR_BEGIN(complex_ce)
PHP_ARMA_COMPLEX_OPERATOR(double, add)
PHP_ARMA_OPERATOR_END();
@ -100,12 +100,8 @@ namespace php_arma
int add_assign_handler(zend_execute_data *execute_data)
{
return op_handler(execute_data, [execute_data] (auto zv1, auto zv2, auto retval) {
if (UNEXPECTED(Z_TYPE_P(zv1) != IS_OBJECT)) {
return false;
}
PHP_ARMA_OPERATOR_BEGIN(zv1, complex_ce)
return op_handler(execute_data, [execute_data] (auto zv1, auto zv2, auto rv, auto ce) {
PHP_ARMA_OPERATOR_BEGIN(complex_ce)
PHP_ARMA_COMPLEX_OPERATOR_ASSIGN(double, add)
PHP_ARMA_OPERATOR_END();
@ -115,12 +111,8 @@ namespace php_arma
int sub_handler(zend_execute_data *execute_data)
{
return op_handler(execute_data, [] (auto zv1, auto zv2, auto retval) {
if (UNEXPECTED(Z_TYPE_P(zv1) != IS_OBJECT)) {
return false;
}
PHP_ARMA_OPERATOR_BEGIN(zv1, complex_ce)
return op_handler(execute_data, [] (auto zv1, auto zv2, auto rv, auto ce) {
PHP_ARMA_OPERATOR_BEGIN(complex_ce)
PHP_ARMA_COMPLEX_OPERATOR(double, sub)
PHP_ARMA_OPERATOR_END();
@ -130,12 +122,8 @@ namespace php_arma
int sub_assign_handler(zend_execute_data *execute_data)
{
return op_handler(execute_data, [execute_data] (auto zv1, auto zv2, auto retval) {
if (UNEXPECTED(Z_TYPE_P(zv1) != IS_OBJECT)) {
return false;
}
PHP_ARMA_OPERATOR_BEGIN(zv1, complex_ce)
return op_handler(execute_data, [execute_data] (auto zv1, auto zv2, auto rv, auto ce) {
PHP_ARMA_OPERATOR_BEGIN(complex_ce)
PHP_ARMA_COMPLEX_OPERATOR_ASSIGN(double, sub)
PHP_ARMA_OPERATOR_END();
@ -145,12 +133,8 @@ namespace php_arma
int mul_handler(zend_execute_data *execute_data)
{
return op_handler(execute_data, [] (auto zv1, auto zv2, auto retval) {
if (UNEXPECTED(Z_TYPE_P(zv1) != IS_OBJECT)) {
return false;
}
PHP_ARMA_OPERATOR_BEGIN(zv1, complex_ce)
return op_handler(execute_data, [] (auto zv1, auto zv2, auto rv, auto ce) {
PHP_ARMA_OPERATOR_BEGIN(complex_ce)
PHP_ARMA_COMPLEX_OPERATOR(double, mul)
PHP_ARMA_OPERATOR_END();
@ -160,12 +144,8 @@ namespace php_arma
int mul_assign_handler(zend_execute_data *execute_data)
{
return op_handler(execute_data, [execute_data] (auto zv1, auto zv2, auto retval) {
if (UNEXPECTED(Z_TYPE_P(zv1) != IS_OBJECT)) {
return false;
}
PHP_ARMA_OPERATOR_BEGIN(zv1, complex_ce)
return op_handler(execute_data, [execute_data] (auto zv1, auto zv2, auto rv, auto ce) {
PHP_ARMA_OPERATOR_BEGIN(complex_ce)
PHP_ARMA_COMPLEX_OPERATOR_ASSIGN(double, mul)
PHP_ARMA_OPERATOR_END();
@ -175,12 +155,8 @@ namespace php_arma
int div_handler(zend_execute_data *execute_data)
{
return op_handler(execute_data, [] (auto zv1, auto zv2, auto retval) {
if (UNEXPECTED(Z_TYPE_P(zv1) != IS_OBJECT)) {
return false;
}
PHP_ARMA_OPERATOR_BEGIN(zv1, complex_ce)
return op_handler(execute_data, [] (auto zv1, auto zv2, auto rv, auto ce) {
PHP_ARMA_OPERATOR_BEGIN(complex_ce)
PHP_ARMA_COMPLEX_OPERATOR(double, div)
PHP_ARMA_OPERATOR_END();
@ -190,12 +166,8 @@ namespace php_arma
int div_assign_handler(zend_execute_data *execute_data)
{
return op_handler(execute_data, [execute_data] (auto zv1, auto zv2, auto retval) {
if (UNEXPECTED(Z_TYPE_P(zv1) != IS_OBJECT)) {
return false;
}
PHP_ARMA_OPERATOR_BEGIN(zv1, complex_ce)
return op_handler(execute_data, [execute_data] (auto zv1, auto zv2, auto rv, auto ce) {
PHP_ARMA_OPERATOR_BEGIN(complex_ce)
PHP_ARMA_COMPLEX_OPERATOR_ASSIGN(double, div)
PHP_ARMA_OPERATOR_END();
@ -205,12 +177,8 @@ namespace php_arma
int pow_handler(zend_execute_data *execute_data)
{
return op_handler(execute_data, [] (auto zv1, auto zv2, auto retval) {
if (UNEXPECTED(Z_TYPE_P(zv1) != IS_OBJECT)) {
return false;
}
PHP_ARMA_OPERATOR_BEGIN(zv1, complex_ce)
return op_handler(execute_data, [] (auto zv1, auto zv2, auto rv, auto ce) {
PHP_ARMA_OPERATOR_BEGIN(complex_ce)
PHP_ARMA_COMPLEX_OPERATOR(double, pow)
PHP_ARMA_OPERATOR_END();
@ -220,12 +188,8 @@ namespace php_arma
int pow_assign_handler(zend_execute_data *execute_data)
{
return op_handler(execute_data, [execute_data] (auto zv1, auto zv2, auto retval) {
if (UNEXPECTED(Z_TYPE_P(zv1) != IS_OBJECT)) {
return false;
}
PHP_ARMA_OPERATOR_BEGIN(zv1, complex_ce)
return op_handler(execute_data, [execute_data] (auto zv1, auto zv2, auto rv, auto ce) {
PHP_ARMA_OPERATOR_BEGIN(complex_ce)
PHP_ARMA_COMPLEX_OPERATOR_ASSIGN(double, pow)
PHP_ARMA_OPERATOR_END();
@ -235,12 +199,8 @@ namespace php_arma
int bw_not_handler(zend_execute_data *execute_data)
{
return op_handler(execute_data, [] (auto zv1, auto zv2, auto retval) {
if (UNEXPECTED(Z_TYPE_P(zv1) != IS_OBJECT)) {
return false;
}
PHP_ARMA_OPERATOR_BEGIN(zv1, complex_ce)
return op_handler(execute_data, [] (auto zv1, auto zv2, auto rv, auto ce) {
PHP_ARMA_OPERATOR_BEGIN(complex_ce)
PHP_ARMA_COMPLEX_OPERATOR(double, conj)
PHP_ARMA_OPERATOR_END();

View File

@ -69,14 +69,13 @@ extern zend_module_entry arma_module_entry;
/// Helper macros for handling operator overloading.
#define PHP_ARMA_OPERATOR_BEGIN(zv, parent_ce) \
{ \
auto _ce = Z_OBJCE_P(zv); \
if (instanceof_function(_ce, parent_ce)) {
#define PHP_ARMA_OPERATOR_BEGIN(parent_ce) \
{ \
if (instanceof_function(ce, parent_ce)) {
#define PHP_ARMA_OPERATOR_END() \
return false; \
} \
#define PHP_ARMA_OPERATOR_END() \
return false; \
} \
}
#endif // PHP_ARMA_OPERATORS
@ -233,7 +232,7 @@ namespace php_arma
zend_always_inline
zend_object *object_create(zend_class_entry *ce, const zend_object_handlers *handlers)
{
auto zobj = reinterpret_cast<zend_object *>(emalloc(
auto zobj = reinterpret_cast<zend_object*>(emalloc(
sizeof(zend_object) + zend_object_properties_size(ce)));
zobj->handlers = handlers;
zend_object_std_init(zobj, ce);

View File

@ -19,10 +19,11 @@ $bar = new Arma\CxDouble(2.3, 2.6);
batch_assert('operator overloading of Arma\\Complex',
[$foo->add($bar), $foo + $bar],
[$foo->sub($bar), $foo - $bar],
[$foo->neg(), -$foo],
[$foo->mul($bar), $foo * $bar],
[$foo->div($bar), $foo / $bar],
[$foo->pow($bar), $foo ** $bar],
[$foo->conj(), ~$foo]
[$foo->conj(), ~$foo]
);
$foo1 = $foo->add($bar);