implement arithmetic operations and corresponding operator overloading
This commit is contained in:
parent
cc8bafe60b
commit
1eb45fe29a
|
@ -48,7 +48,7 @@ namespace php_arma
|
|||
template <typename T, typename T1>
|
||||
PHP_ARMA_METHOD(base, neg, T, T1)
|
||||
{
|
||||
|
||||
operators::neg(&EX(This), return_value);
|
||||
}
|
||||
|
||||
template <typename T, typename T1>
|
||||
|
@ -59,7 +59,7 @@ namespace php_arma
|
|||
Z_PARAM_ZVAL(other)
|
||||
ZEND_PARSE_PARAMETERS_END();
|
||||
|
||||
operators::add(&EX(This), other, return_value);
|
||||
operators::mul(&EX(This), other, return_value);
|
||||
}
|
||||
|
||||
template <typename T, typename T1>
|
||||
|
|
49
src/base.hh
49
src/base.hh
|
@ -10,6 +10,34 @@
|
|||
#include "php_arma.hh"
|
||||
#include "complex.hh"
|
||||
|
||||
#define PHP_ARMA_BASE_OPERATOR_EX2(cls, type, func) \
|
||||
PHP_ARMA_OPERATOR_EX2((base<type, cls<type>>), cls<type>, func)
|
||||
|
||||
#define PHP_ARMA_BASE_OPERATOR_EX(cls, func) \
|
||||
PHP_ARMA_BASE_OPERATOR_EX2(cls, double, func) \
|
||||
PHP_ARMA_BASE_OPERATOR_EX2(cls, zend_long, func) \
|
||||
PHP_ARMA_BASE_OPERATOR_EX2(cls, cx_double, func)
|
||||
|
||||
#define PHP_ARMA_BASE_OPERATOR(func) \
|
||||
PHP_ARMA_OPERATOR_BEGIN(base_ce) \
|
||||
PHP_ARMA_BASE_OPERATOR_EX(mat, func) \
|
||||
PHP_ARMA_BASE_OPERATOR_EX(subview_mat, func) \
|
||||
PHP_ARMA_OPERATOR_END()
|
||||
|
||||
#define PHP_ARMA_BASE_ASSIGN_OPERATOR_EX2(cls, type, func) \
|
||||
PHP_ARMA_ASSIGN_OPERATOR_EX2((base<type, cls<type>>), cls<type>, func)
|
||||
|
||||
#define PHP_ARMA_BASE_ASSIGN_OPERATOR_EX(cls, func) \
|
||||
PHP_ARMA_BASE_ASSIGN_OPERATOR_EX2(cls, double, func) \
|
||||
PHP_ARMA_BASE_ASSIGN_OPERATOR_EX2(cls, zend_long, func) \
|
||||
PHP_ARMA_BASE_ASSIGN_OPERATOR_EX2(cls, cx_double, func)
|
||||
|
||||
#define PHP_ARMA_BASE_ASSIGN_OPERATOR(func) \
|
||||
PHP_ARMA_OPERATOR_BEGIN(base_ce) \
|
||||
PHP_ARMA_BASE_ASSIGN_OPERATOR_EX(mat, func) \
|
||||
PHP_ARMA_BASE_ASSIGN_OPERATOR_EX(subview_mat, func) \
|
||||
PHP_ARMA_OPERATOR_END()
|
||||
|
||||
namespace php_arma
|
||||
{
|
||||
template <typename T, typename ChildT>
|
||||
|
@ -52,6 +80,8 @@ namespace php_arma
|
|||
} else {
|
||||
goto not_orig_or_subview;
|
||||
}
|
||||
} else {
|
||||
__builtin_unreachable();
|
||||
}
|
||||
} else {
|
||||
if (Z_OBJCE_P(zv1) == ChildT::orig_t::ce) {
|
||||
|
@ -76,6 +106,10 @@ namespace php_arma
|
|||
return false;
|
||||
}
|
||||
}
|
||||
if (zv1 == return_value) {
|
||||
// Release first operand in case of assign operator to prevent memory leak.
|
||||
zval_ptr_dtor(zv1);
|
||||
}
|
||||
RETVAL_OBJ(ChildT::orig_t::create(std::move(ret)));
|
||||
return true;
|
||||
} catch (const std::logic_error& err) {
|
||||
|
@ -139,8 +173,23 @@ namespace php_arma
|
|||
});
|
||||
}
|
||||
|
||||
static bool neg(zval *zv, zval *retval)
|
||||
{
|
||||
return arithmetic_op<false>(zv, zv, retval, [](auto v1, auto v2) {
|
||||
return -*v1;
|
||||
});
|
||||
}
|
||||
|
||||
static bool mul(zval *zv1, zval *zv2, zval *retval)
|
||||
{
|
||||
#if PHP_VERSION_ID >= 70300
|
||||
if (Z_TYPE_P(zv2) == IS_LONG && Z_LVAL_P(zv2) == -1) {
|
||||
return neg(zv1, retval);
|
||||
#else
|
||||
if (Z_TYPE_P(zv1) == IS_LONG && Z_LVAL_P(zv1) == -1) {
|
||||
return neg(zv2, retval);
|
||||
#endif
|
||||
}
|
||||
return arithmetic_op<true>(zv1, zv2, retval, [](auto v1, auto v2) {
|
||||
return *v1 * *v2;
|
||||
});
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include "php_arma.hh"
|
||||
#include "operators.hh"
|
||||
#include "complex.hh"
|
||||
#include "base.hh"
|
||||
#include "dense.hh"
|
||||
#include "mat.hh"
|
||||
#include "subview_mat.hh"
|
||||
|
@ -91,6 +92,7 @@ namespace php_arma
|
|||
{
|
||||
return op_handler(execute_data, PHP_ARMA_OP_HANDLER_FUNC {
|
||||
PHP_ARMA_COMPLEX_OPERATOR(add);
|
||||
PHP_ARMA_BASE_OPERATOR(add);
|
||||
|
||||
return false;
|
||||
});
|
||||
|
@ -100,6 +102,7 @@ namespace php_arma
|
|||
{
|
||||
return op_handler(execute_data, PHP_ARMA_OP_HANDLER_FUNC {
|
||||
PHP_ARMA_COMPLEX_ASSIGN_OPERATOR(add);
|
||||
PHP_ARMA_BASE_ASSIGN_OPERATOR(add);
|
||||
|
||||
return false;
|
||||
});
|
||||
|
@ -109,6 +112,7 @@ namespace php_arma
|
|||
{
|
||||
return op_handler(execute_data, PHP_ARMA_OP_HANDLER_FUNC {
|
||||
PHP_ARMA_COMPLEX_OPERATOR(sub);
|
||||
PHP_ARMA_BASE_OPERATOR(sub);
|
||||
|
||||
return false;
|
||||
});
|
||||
|
@ -118,6 +122,7 @@ namespace php_arma
|
|||
{
|
||||
return op_handler(execute_data, PHP_ARMA_OP_HANDLER_FUNC {
|
||||
PHP_ARMA_COMPLEX_ASSIGN_OPERATOR(sub);
|
||||
PHP_ARMA_BASE_ASSIGN_OPERATOR(sub);
|
||||
|
||||
return false;
|
||||
});
|
||||
|
@ -127,6 +132,7 @@ namespace php_arma
|
|||
{
|
||||
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;
|
||||
|
@ -137,6 +143,7 @@ namespace php_arma
|
|||
{
|
||||
return op_handler(execute_data, PHP_ARMA_OP_HANDLER_FUNC {
|
||||
PHP_ARMA_COMPLEX_ASSIGN_OPERATOR(mul);
|
||||
PHP_ARMA_BASE_ASSIGN_OPERATOR(mul);
|
||||
|
||||
return false;
|
||||
});
|
||||
|
@ -146,6 +153,7 @@ namespace php_arma
|
|||
{
|
||||
return op_handler(execute_data, PHP_ARMA_OP_HANDLER_FUNC {
|
||||
PHP_ARMA_COMPLEX_OPERATOR(div);
|
||||
PHP_ARMA_BASE_OPERATOR(div);
|
||||
|
||||
return false;
|
||||
});
|
||||
|
@ -155,6 +163,25 @@ namespace php_arma
|
|||
{
|
||||
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;
|
||||
});
|
||||
|
@ -243,6 +270,8 @@ namespace php_arma
|
|||
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),
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
--TEST--
|
||||
Test for methods performing arithmetic operations.
|
||||
--SKIPIF--
|
||||
<?php
|
||||
require_once 'includes/loaded.php';
|
||||
is_php_arma_loaded();
|
||||
?>
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
require_once 'includes/assert.php';
|
||||
|
||||
$mat = Arma\IMat::fromString('1 2; 3 4');
|
||||
$mat1 = Arma\IMat::fromString('5 6; 7 8');
|
||||
|
||||
function str2mat($str) {
|
||||
return Arma\IMat::fromString($str);
|
||||
}
|
||||
|
||||
batch_assert_mat('arithmetic operations',
|
||||
[str2mat('6 8; 10 12'), $mat->add($mat1)],
|
||||
[str2mat('2 3; 4 5'), $mat->add(1)],
|
||||
[str2mat('-4 -4; -4 -4'), $mat->sub($mat1)],
|
||||
[str2mat('-1 0; 1 2'), $mat->sub(2)],
|
||||
[str2mat('-1 -2; -3 -4'), $mat->neg()],
|
||||
[str2mat('19 22; 43 50'), $mat->mul($mat1)],
|
||||
[str2mat('2 4; 6 8'), $mat->mul(2)],
|
||||
[str2mat('5 12; 21 32'), $mat->dotMul($mat1)],
|
||||
[str2mat('0 0; 0 0'), $mat->div($mat1)],
|
||||
[str2mat('0 1; 1 2'), $mat->div(2)],
|
||||
);
|
||||
|
||||
?>
|
||||
--EXPECT--
|
|
@ -0,0 +1,47 @@
|
|||
--TEST--
|
||||
Test for operator overloading of arithmetic operations.
|
||||
--SKIPIF--
|
||||
<?php
|
||||
require_once 'includes/loaded.php';
|
||||
require_once 'includes/supports.php';
|
||||
if (is_php_arma_loaded()) {
|
||||
supports_operator_overloading();
|
||||
}
|
||||
?>
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
require_once 'includes/assert.php';
|
||||
|
||||
$mat = Arma\IMat::init(2, 2, Arma\Fill::RANDN);
|
||||
$mat1 = Arma\IMat::init(2, 2, Arma\Fill::RANDN);
|
||||
|
||||
$mat1->forEach(function (Arma\MapVal $elem) {
|
||||
if ($elem->val() == 0) {
|
||||
$elem->setTo(7);
|
||||
}
|
||||
});
|
||||
|
||||
batch_assert_mat('operator overloading of arithmetic operations',
|
||||
[$mat->add($mat1), $mat + $mat1],
|
||||
[$mat->add(1), $mat + 1],
|
||||
[$mat->sub($mat1), $mat - $mat1],
|
||||
[$mat->sub(2), $mat - 2],
|
||||
[$mat->neg(), -$mat],
|
||||
[$mat->mul($mat1), $mat * $mat1],
|
||||
[$mat->mul(2), $mat * 2],
|
||||
[$mat->dotMul($mat1), $mat % $mat1],
|
||||
[$mat->div($mat1), $mat / $mat1],
|
||||
[$mat->div(2), $mat / 2]
|
||||
);
|
||||
|
||||
$mat2 = $mat->div($mat1);
|
||||
$mat3 = $mat1->add($mat2);
|
||||
$mat4 = $mat2->mul($mat3);
|
||||
$mat5 = $mat3->sub($mat4);
|
||||
$mat1 -= $mat *= $mat1 += $mat /= $mat1;
|
||||
|
||||
batch_assert_mat('operator overloading of arithmetic operations', [$mat5, $mat1]);
|
||||
|
||||
?>
|
||||
--EXPECT--
|
Reference in New Issue