implement arithmetic operations.

This commit is contained in:
CismonX 2019-08-18 20:38:18 +08:00
parent 586bbe2046
commit 9033f84132
3 changed files with 134 additions and 10 deletions

View File

@ -26,13 +26,23 @@ namespace php_arma
template <typename T, typename T1>
PHP_ARMA_METHOD(base, add, T, T1)
{
zval *other;
ZEND_PARSE_PARAMETERS_START(1, 1)
Z_PARAM_ZVAL(other)
ZEND_PARSE_PARAMETERS_END();
operators::add(&EX(This), other, return_value);
}
template <typename T, typename T1>
PHP_ARMA_METHOD(base, sub, T, T1)
{
zval *other;
ZEND_PARSE_PARAMETERS_START(1, 1)
Z_PARAM_ZVAL(other)
ZEND_PARSE_PARAMETERS_END();
operators::sub(&EX(This), other, return_value);
}
template <typename T, typename T1>
@ -44,19 +54,34 @@ namespace php_arma
template <typename T, typename T1>
PHP_ARMA_METHOD(base, mul, T, T1)
{
zval *other;
ZEND_PARSE_PARAMETERS_START(1, 1)
Z_PARAM_ZVAL(other)
ZEND_PARSE_PARAMETERS_END();
operators::add(&EX(This), other, return_value);
}
template <typename T, typename T1>
PHP_ARMA_METHOD(base, dotMul, T, T1)
{
zval *other;
ZEND_PARSE_PARAMETERS_START(1, 1)
Z_PARAM_ZVAL(other)
ZEND_PARSE_PARAMETERS_END();
operators::dotMul(&EX(This), other, return_value);
}
template <typename T, typename T1>
PHP_ARMA_METHOD(base, div, T, T1)
{
zval *other;
ZEND_PARSE_PARAMETERS_START(1, 1)
Z_PARAM_ZVAL(other)
ZEND_PARSE_PARAMETERS_END();
operators::div(&EX(This), other, return_value);
}
template <typename T, typename T1>

View File

@ -8,6 +8,7 @@
#define PHP_ARMA_BASE_HH
#include "php_arma.hh"
#include "complex.hh"
namespace php_arma
{
@ -18,6 +19,71 @@ namespace php_arma
struct operators;
template <bool AcceptScalar, typename F>
zend_always_inline
static bool arithmetic_op(zval *zv1, zval *zv2, zval *return_value, F&& func)
{
bool zv2_is_scalar = false;
if (Z_TYPE_P(zv2) != IS_OBJECT) {
if constexpr (AcceptScalar && !std::is_same_v<T, cx_double>) {
if (EXPECTED(zval_is_scalar<T>(zv2))) {
zv2_is_scalar = true;
goto op_body;
}
}
throw_exception_ex(zend_ce_type_error, "bad arithmetic operation, unsupported type");
return false;
}
op_body:
using n_orig_t = typename ChildT::orig_t::native_t;
using n_subview_t = typename ChildT::subview_t::native_t;
try {
n_orig_t ret;
auto o1 = Z_OBJ_P(zv1);
auto o2 = Z_OBJ_P(zv2);
if (zv2_is_scalar) {
if constexpr (AcceptScalar) {
auto scalar_val = zval_get_scalar<T>(zv2);
if (Z_OBJCE_P(zv1) == ChildT::orig_t::ce) {
ret = func(to_native_object<n_orig_t>(o1), &scalar_val).eval();
} else if (EXPECTED(Z_OBJCE_P(zv1) == ChildT::subview_t::ce)) {
ret = func(to_native_object<n_subview_t>(o1), &scalar_val).eval();
} else {
goto not_orig_or_subview;
}
}
} else {
if (Z_OBJCE_P(zv1) == ChildT::orig_t::ce) {
if (Z_OBJCE_P(zv2) == ChildT::orig_t::ce) {
ret = func(to_native_object<n_orig_t>(o1), to_native_object<n_orig_t>(o2)).eval();
} else if (EXPECTED(Z_OBJCE_P(zv2) == ChildT::subview_t::ce)) {
ret = func(to_native_object<n_orig_t>(o1), to_native_object<n_subview_t>(o2)).eval();
} else {
goto not_orig_or_subview;
}
} else if (EXPECTED(Z_OBJCE_P(zv1) == ChildT::subview_t::ce)) {
if (Z_OBJCE_P(zv2) == ChildT::orig_t::ce) {
ret = func(to_native_object<n_subview_t>(o1), to_native_object<n_orig_t>(o2)).eval();
} else if (EXPECTED(Z_OBJCE_P(zv2) == ChildT::subview_t::ce)) {
ret = func(to_native_object<n_subview_t>(o1), to_native_object<n_subview_t>(o2)).eval();
} else {
goto not_orig_or_subview;
}
} else {
not_orig_or_subview:
throw_exception_ex(zend_ce_type_error, "bad arithmetic operation, object types should be the same");
return false;
}
}
RETVAL_OBJ(ChildT::orig_t::create(std::move(ret)));
return true;
} catch (const std::logic_error& err) {
throw_error(err.what());
return false;
}
}
zend_always_inline
static int count_elements(zval *zv, zend_long *count)
{
@ -59,7 +125,40 @@ namespace php_arma
template <typename T, typename ChildT>
struct base<T, ChildT>::operators
{
static bool add(zval *zv1, zval *zv2, zval *retval)
{
return arithmetic_op<true>(zv1, zv2, retval, [](auto v1, auto v2) {
return *v1 + *v2;
});
}
static bool sub(zval *zv1, zval *zv2, zval *retval)
{
return arithmetic_op<true>(zv1, zv2, retval, [](auto v1, auto v2) {
return *v1 - *v2;
});
}
static bool mul(zval *zv1, zval *zv2, zval *retval)
{
return arithmetic_op<true>(zv1, zv2, retval, [](auto v1, auto v2) {
return *v1 * *v2;
});
}
static bool dotMul(zval *zv1, zval *zv2, zval *retval)
{
return arithmetic_op<false>(zv1, zv2, retval, [](auto v1, auto v2) {
return *v1 % *v2;
});
}
static bool div(zval *zv1, zval *zv2, zval *retval)
{
return arithmetic_op<true>(zv1, zv2, retval, [](auto v1, auto v2) {
return *v1 / *v2;
});
}
};
}

View File

@ -22,7 +22,7 @@ interface Base extends Countable
/**
* Addition of two objects.
*
* @param mixed $other
* @param static|number|Complex $other
* @return static
*/
function add($other);
@ -30,7 +30,7 @@ interface Base extends Countable
/**
* Subtraction of two objects.
*
* @param mixed $other
* @param static|number|Complex $other
* @return static
*/
function sub($other);
@ -45,7 +45,7 @@ interface Base extends Countable
/**
* Matrix multiplication of two objects.
*
* @param mixed $other
* @param static|number|Complex $other
* @return static
*/
function mul($other);
@ -61,7 +61,7 @@ interface Base extends Countable
/**
* Element-wise division of an object by another object or a scalar.
*
* @param mixed $other
* @param static|number|Complex $other
* @return static
*/
function div($other);