Better operator support for Complex.
This commit is contained in:
parent
1461b148b2
commit
b49ef617c0
|
@ -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>
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
Reference in New Issue