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>
|
template <typename T, typename T1>
|
||||||
PHP_ARMA_METHOD(base, neg, T, T1)
|
PHP_ARMA_METHOD(base, neg, T, T1)
|
||||||
{
|
{
|
||||||
|
operators::neg(&EX(This), return_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T, typename T1>
|
template <typename T, typename T1>
|
||||||
|
@ -59,7 +59,7 @@ namespace php_arma
|
||||||
Z_PARAM_ZVAL(other)
|
Z_PARAM_ZVAL(other)
|
||||||
ZEND_PARSE_PARAMETERS_END();
|
ZEND_PARSE_PARAMETERS_END();
|
||||||
|
|
||||||
operators::add(&EX(This), other, return_value);
|
operators::mul(&EX(This), other, return_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T, typename T1>
|
template <typename T, typename T1>
|
||||||
|
|
49
src/base.hh
49
src/base.hh
|
@ -10,6 +10,34 @@
|
||||||
#include "php_arma.hh"
|
#include "php_arma.hh"
|
||||||
#include "complex.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
|
namespace php_arma
|
||||||
{
|
{
|
||||||
template <typename T, typename ChildT>
|
template <typename T, typename ChildT>
|
||||||
|
@ -52,6 +80,8 @@ namespace php_arma
|
||||||
} else {
|
} else {
|
||||||
goto not_orig_or_subview;
|
goto not_orig_or_subview;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
__builtin_unreachable();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (Z_OBJCE_P(zv1) == ChildT::orig_t::ce) {
|
if (Z_OBJCE_P(zv1) == ChildT::orig_t::ce) {
|
||||||
|
@ -76,6 +106,10 @@ namespace php_arma
|
||||||
return false;
|
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)));
|
RETVAL_OBJ(ChildT::orig_t::create(std::move(ret)));
|
||||||
return true;
|
return true;
|
||||||
} catch (const std::logic_error& err) {
|
} 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)
|
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 arithmetic_op<true>(zv1, zv2, retval, [](auto v1, auto v2) {
|
||||||
return *v1 * *v2;
|
return *v1 * *v2;
|
||||||
});
|
});
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
#include "php_arma.hh"
|
#include "php_arma.hh"
|
||||||
#include "operators.hh"
|
#include "operators.hh"
|
||||||
#include "complex.hh"
|
#include "complex.hh"
|
||||||
|
#include "base.hh"
|
||||||
#include "dense.hh"
|
#include "dense.hh"
|
||||||
#include "mat.hh"
|
#include "mat.hh"
|
||||||
#include "subview_mat.hh"
|
#include "subview_mat.hh"
|
||||||
|
@ -91,6 +92,7 @@ namespace php_arma
|
||||||
{
|
{
|
||||||
return op_handler(execute_data, PHP_ARMA_OP_HANDLER_FUNC {
|
return op_handler(execute_data, PHP_ARMA_OP_HANDLER_FUNC {
|
||||||
PHP_ARMA_COMPLEX_OPERATOR(add);
|
PHP_ARMA_COMPLEX_OPERATOR(add);
|
||||||
|
PHP_ARMA_BASE_OPERATOR(add);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
@ -100,6 +102,7 @@ namespace php_arma
|
||||||
{
|
{
|
||||||
return op_handler(execute_data, PHP_ARMA_OP_HANDLER_FUNC {
|
return op_handler(execute_data, PHP_ARMA_OP_HANDLER_FUNC {
|
||||||
PHP_ARMA_COMPLEX_ASSIGN_OPERATOR(add);
|
PHP_ARMA_COMPLEX_ASSIGN_OPERATOR(add);
|
||||||
|
PHP_ARMA_BASE_ASSIGN_OPERATOR(add);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
@ -109,6 +112,7 @@ namespace php_arma
|
||||||
{
|
{
|
||||||
return op_handler(execute_data, PHP_ARMA_OP_HANDLER_FUNC {
|
return op_handler(execute_data, PHP_ARMA_OP_HANDLER_FUNC {
|
||||||
PHP_ARMA_COMPLEX_OPERATOR(sub);
|
PHP_ARMA_COMPLEX_OPERATOR(sub);
|
||||||
|
PHP_ARMA_BASE_OPERATOR(sub);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
@ -118,6 +122,7 @@ namespace php_arma
|
||||||
{
|
{
|
||||||
return op_handler(execute_data, PHP_ARMA_OP_HANDLER_FUNC {
|
return op_handler(execute_data, PHP_ARMA_OP_HANDLER_FUNC {
|
||||||
PHP_ARMA_COMPLEX_ASSIGN_OPERATOR(sub);
|
PHP_ARMA_COMPLEX_ASSIGN_OPERATOR(sub);
|
||||||
|
PHP_ARMA_BASE_ASSIGN_OPERATOR(sub);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
@ -127,6 +132,7 @@ namespace php_arma
|
||||||
{
|
{
|
||||||
return op_handler(execute_data, PHP_ARMA_OP_HANDLER_FUNC {
|
return op_handler(execute_data, PHP_ARMA_OP_HANDLER_FUNC {
|
||||||
PHP_ARMA_COMPLEX_OPERATOR(mul);
|
PHP_ARMA_COMPLEX_OPERATOR(mul);
|
||||||
|
PHP_ARMA_BASE_OPERATOR(mul);
|
||||||
PHP_ARMA_MAPVAL_OPERATOR(mul);
|
PHP_ARMA_MAPVAL_OPERATOR(mul);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
@ -137,6 +143,7 @@ namespace php_arma
|
||||||
{
|
{
|
||||||
return op_handler(execute_data, PHP_ARMA_OP_HANDLER_FUNC {
|
return op_handler(execute_data, PHP_ARMA_OP_HANDLER_FUNC {
|
||||||
PHP_ARMA_COMPLEX_ASSIGN_OPERATOR(mul);
|
PHP_ARMA_COMPLEX_ASSIGN_OPERATOR(mul);
|
||||||
|
PHP_ARMA_BASE_ASSIGN_OPERATOR(mul);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
@ -146,6 +153,7 @@ namespace php_arma
|
||||||
{
|
{
|
||||||
return op_handler(execute_data, PHP_ARMA_OP_HANDLER_FUNC {
|
return op_handler(execute_data, PHP_ARMA_OP_HANDLER_FUNC {
|
||||||
PHP_ARMA_COMPLEX_OPERATOR(div);
|
PHP_ARMA_COMPLEX_OPERATOR(div);
|
||||||
|
PHP_ARMA_BASE_OPERATOR(div);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
@ -155,6 +163,25 @@ namespace php_arma
|
||||||
{
|
{
|
||||||
return op_handler(execute_data, PHP_ARMA_OP_HANDLER_FUNC {
|
return op_handler(execute_data, PHP_ARMA_OP_HANDLER_FUNC {
|
||||||
PHP_ARMA_COMPLEX_ASSIGN_OPERATOR(div);
|
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;
|
return false;
|
||||||
});
|
});
|
||||||
|
@ -243,6 +270,8 @@ namespace php_arma
|
||||||
std::make_tuple(ZEND_ASSIGN_MUL, mul_assign_handler),
|
std::make_tuple(ZEND_ASSIGN_MUL, mul_assign_handler),
|
||||||
std::make_tuple(ZEND_DIV, div_handler),
|
std::make_tuple(ZEND_DIV, div_handler),
|
||||||
std::make_tuple(ZEND_ASSIGN_DIV, div_assign_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_POW, pow_handler),
|
||||||
std::make_tuple(ZEND_ASSIGN_POW, pow_assign_handler),
|
std::make_tuple(ZEND_ASSIGN_POW, pow_assign_handler),
|
||||||
std::make_tuple(ZEND_BW_NOT, bw_not_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