2019-04-02 08:16:11 +00:00
|
|
|
//
|
|
|
|
// php-armadillo/base.hh
|
|
|
|
//
|
|
|
|
// @Author CismonX
|
|
|
|
//
|
|
|
|
|
|
|
|
#ifndef PHP_ARMA_BASE_HH
|
|
|
|
#define PHP_ARMA_BASE_HH
|
|
|
|
|
2019-11-04 09:42:11 +00:00
|
|
|
#include "common/php_arma.hh"
|
2019-08-18 12:38:18 +00:00
|
|
|
#include "complex.hh"
|
2019-04-02 08:16:11 +00:00
|
|
|
|
2019-10-05 15:16:48 +00:00
|
|
|
#ifdef PHP_ARMA_OPERATORS
|
|
|
|
|
2019-08-18 20:24:08 +00:00
|
|
|
#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()
|
|
|
|
|
2019-10-05 15:16:48 +00:00
|
|
|
#endif // PHP_ARMA_OPERATORS
|
|
|
|
|
2019-04-02 08:16:11 +00:00
|
|
|
namespace php_arma
|
|
|
|
{
|
|
|
|
template <typename T, typename ChildT>
|
|
|
|
struct base
|
|
|
|
{
|
|
|
|
using native_t = typename ChildT::native_t;
|
2019-05-25 18:21:48 +00:00
|
|
|
|
|
|
|
struct operators;
|
|
|
|
|
2019-08-18 12:38:18 +00:00
|
|
|
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 {
|
2019-09-20 23:23:59 +00:00
|
|
|
std::optional<n_orig_t> ret;
|
2019-08-18 12:38:18 +00:00
|
|
|
auto o1 = Z_OBJ_P(zv1);
|
2019-08-25 14:15:33 +00:00
|
|
|
decltype(o1) o2;
|
2019-08-18 12:38:18 +00:00
|
|
|
if (zv2_is_scalar) {
|
|
|
|
if constexpr (AcceptScalar) {
|
|
|
|
auto scalar_val = zval_get_scalar<T>(zv2);
|
|
|
|
if (Z_OBJCE_P(zv1) == ChildT::orig_t::ce) {
|
2019-09-20 23:23:59 +00:00
|
|
|
ret = func(to_native_object<n_orig_t>(o1), &scalar_val);
|
2019-08-18 12:38:18 +00:00
|
|
|
} else if (EXPECTED(Z_OBJCE_P(zv1) == ChildT::subview_t::ce)) {
|
2019-09-20 23:23:59 +00:00
|
|
|
ret = func(to_native_object<n_subview_t>(o1), &scalar_val);
|
2019-08-18 12:38:18 +00:00
|
|
|
} else {
|
|
|
|
goto not_orig_or_subview;
|
|
|
|
}
|
2019-08-18 20:24:08 +00:00
|
|
|
} else {
|
|
|
|
__builtin_unreachable();
|
2019-08-18 12:38:18 +00:00
|
|
|
}
|
|
|
|
} else {
|
2019-08-25 14:15:33 +00:00
|
|
|
o2 = Z_OBJ_P(zv2);
|
2019-08-18 12:38:18 +00:00
|
|
|
if (Z_OBJCE_P(zv1) == ChildT::orig_t::ce) {
|
|
|
|
if (Z_OBJCE_P(zv2) == ChildT::orig_t::ce) {
|
2019-09-20 23:23:59 +00:00
|
|
|
ret = func(to_native_object<n_orig_t>(o1), to_native_object<n_orig_t>(o2));
|
2019-08-18 12:38:18 +00:00
|
|
|
} else if (EXPECTED(Z_OBJCE_P(zv2) == ChildT::subview_t::ce)) {
|
2019-09-20 23:23:59 +00:00
|
|
|
ret = func(to_native_object<n_orig_t>(o1), to_native_object<n_subview_t>(o2));
|
2019-08-18 12:38:18 +00:00
|
|
|
} 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) {
|
2019-09-20 23:23:59 +00:00
|
|
|
ret = func(to_native_object<n_subview_t>(o1), to_native_object<n_orig_t>(o2));
|
2019-08-18 12:38:18 +00:00
|
|
|
} else if (EXPECTED(Z_OBJCE_P(zv2) == ChildT::subview_t::ce)) {
|
2019-09-20 23:23:59 +00:00
|
|
|
ret = func(to_native_object<n_subview_t>(o1), to_native_object<n_subview_t>(o2));
|
2019-08-18 12:38:18 +00:00
|
|
|
} 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;
|
|
|
|
}
|
|
|
|
}
|
2019-08-18 20:24:08 +00:00
|
|
|
if (zv1 == return_value) {
|
|
|
|
// Release first operand in case of assign operator to prevent memory leak.
|
|
|
|
zval_ptr_dtor(zv1);
|
|
|
|
}
|
2019-09-20 23:23:59 +00:00
|
|
|
RETVAL_OBJ(ChildT::orig_t::create(std::move(*ret)));
|
2019-08-18 12:38:18 +00:00
|
|
|
return true;
|
|
|
|
} catch (const std::logic_error& err) {
|
|
|
|
throw_error(err.what());
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-05-25 18:21:48 +00:00
|
|
|
zend_always_inline
|
|
|
|
static int count_elements(zval *zv, zend_long *count)
|
|
|
|
{
|
2019-05-27 08:51:46 +00:00
|
|
|
*count = Z_NATIVE_OBJ_P(zv)->n_elem;
|
2019-05-25 18:21:48 +00:00
|
|
|
return SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
PHP_ARMA_COMMON_DECLARE();
|
|
|
|
|
|
|
|
private:
|
|
|
|
static PHP_FUNCTION(nElem);
|
|
|
|
static PHP_FUNCTION(add);
|
|
|
|
static PHP_FUNCTION(sub);
|
|
|
|
static PHP_FUNCTION(neg);
|
|
|
|
static PHP_FUNCTION(mul);
|
|
|
|
static PHP_FUNCTION(dotMul);
|
|
|
|
static PHP_FUNCTION(div);
|
|
|
|
static PHP_FUNCTION(replace);
|
|
|
|
static PHP_FUNCTION(transform);
|
|
|
|
static PHP_FUNCTION(forEach);
|
|
|
|
static PHP_FUNCTION(min);
|
|
|
|
static PHP_FUNCTION(max);
|
|
|
|
static PHP_FUNCTION(indexMin);
|
|
|
|
static PHP_FUNCTION(indexMax);
|
|
|
|
static PHP_FUNCTION(isEmpty);
|
|
|
|
static PHP_FUNCTION(isFinite);
|
|
|
|
static PHP_FUNCTION(hasInf);
|
|
|
|
static PHP_FUNCTION(hasNan);
|
|
|
|
static PHP_FUNCTION(print);
|
|
|
|
static PHP_FUNCTION(rawPrint);
|
2019-08-19 17:29:31 +00:00
|
|
|
static PHP_FUNCTION(__toString);
|
|
|
|
static PHP_FUNCTION(__debugInfo);
|
2019-04-02 08:16:11 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
void base_init();
|
|
|
|
|
2019-04-13 10:17:01 +00:00
|
|
|
constexpr const char base_php_name[] = "Base";
|
2019-04-02 08:16:11 +00:00
|
|
|
|
|
|
|
inline zend_class_entry *base_ce;
|
2019-05-25 18:21:48 +00:00
|
|
|
|
|
|
|
template <typename T, typename ChildT>
|
|
|
|
struct base<T, ChildT>::operators
|
|
|
|
{
|
2019-08-18 12:38:18 +00:00
|
|
|
static bool add(zval *zv1, zval *zv2, zval *retval)
|
|
|
|
{
|
|
|
|
return arithmetic_op<true>(zv1, zv2, retval, [](auto v1, auto v2) {
|
2019-08-25 14:15:33 +00:00
|
|
|
return (*v1 + *v2).eval();
|
2019-08-18 12:38:18 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool sub(zval *zv1, zval *zv2, zval *retval)
|
|
|
|
{
|
|
|
|
return arithmetic_op<true>(zv1, zv2, retval, [](auto v1, auto v2) {
|
2019-08-25 14:15:33 +00:00
|
|
|
return (*v1 - *v2).eval();
|
2019-08-18 12:38:18 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2019-08-18 20:24:08 +00:00
|
|
|
static bool neg(zval *zv, zval *retval)
|
|
|
|
{
|
|
|
|
return arithmetic_op<false>(zv, zv, retval, [](auto v1, auto v2) {
|
2019-08-25 14:15:33 +00:00
|
|
|
return (-*v1).eval();
|
2019-08-18 20:24:08 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2019-08-18 12:38:18 +00:00
|
|
|
static bool mul(zval *zv1, zval *zv2, zval *retval)
|
|
|
|
{
|
2019-08-18 20:24:08 +00:00
|
|
|
#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
|
|
|
|
}
|
2019-08-18 12:38:18 +00:00
|
|
|
return arithmetic_op<true>(zv1, zv2, retval, [](auto v1, auto v2) {
|
2019-08-25 14:15:33 +00:00
|
|
|
return (*v1 * *v2).eval();
|
2019-08-18 12:38:18 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool dotMul(zval *zv1, zval *zv2, zval *retval)
|
|
|
|
{
|
|
|
|
return arithmetic_op<false>(zv1, zv2, retval, [](auto v1, auto v2) {
|
2019-08-25 14:15:33 +00:00
|
|
|
return (*v1 % *v2).eval();
|
2019-08-18 12:38:18 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool div(zval *zv1, zval *zv2, zval *retval)
|
|
|
|
{
|
|
|
|
return arithmetic_op<true>(zv1, zv2, retval, [](auto v1, auto v2) {
|
2019-08-25 14:15:33 +00:00
|
|
|
return (*v1 / *v2).eval();
|
2019-08-18 12:38:18 +00:00
|
|
|
});
|
|
|
|
}
|
2019-05-25 18:21:48 +00:00
|
|
|
};
|
2019-04-02 08:16:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#endif // !PHP_ARMA_BASE_HH
|