374 lines
11 KiB
C++
374 lines
11 KiB
C++
//
|
|
// php-armadillo/base.cc
|
|
//
|
|
// @Author CismonX
|
|
//
|
|
|
|
#include "base.hh"
|
|
#include "dense.hh"
|
|
#include "mat.hh"
|
|
#include "subview_mat.hh"
|
|
#include "diagonal.hh"
|
|
#include "mapval.hh"
|
|
#include "common/stream_utils.hh"
|
|
|
|
#include <zend_interfaces.h>
|
|
|
|
namespace php_arma
|
|
{
|
|
template <typename T>
|
|
zend_always_inline
|
|
void to_string(T *src, zval *dest)
|
|
{
|
|
if (UNEXPECTED(src->n_elem == 0)) {
|
|
ZVAL_EMPTY_STRING(dest);
|
|
return;
|
|
}
|
|
std::ostringstream oss;
|
|
src->raw_print(oss);
|
|
std::string str = oss.str();
|
|
std::replace(str.begin(), str.end(), '\n', ';');
|
|
ZVAL_STRINGL(dest, str.c_str(), str.size() - 1);
|
|
}
|
|
|
|
template <typename T, typename T1>
|
|
PHP_ARMA_METHOD(base, nElem, T, T1)
|
|
{
|
|
zend_long count;
|
|
count_elements(&EX(This), &count);
|
|
RETVAL_LONG(count);
|
|
}
|
|
|
|
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>
|
|
PHP_ARMA_METHOD(base, neg, T, T1)
|
|
{
|
|
operators::neg(&EX(This), return_value);
|
|
}
|
|
|
|
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::mul(&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>
|
|
PHP_ARMA_METHOD(base, replace, T, T1)
|
|
{
|
|
zval *old_value;
|
|
zval *new_value;
|
|
ZEND_PARSE_PARAMETERS_START(2, 2)
|
|
Z_PARAM_ZVAL(old_value)
|
|
Z_PARAM_ZVAL(new_value)
|
|
ZEND_PARSE_PARAMETERS_END();
|
|
|
|
if (!zval_check_scalar<T>(old_value) || !zval_check_scalar<T>(new_value)) {
|
|
return;
|
|
}
|
|
|
|
auto native = THIS_NATIVE;
|
|
native->replace(zval_get_scalar<T>(old_value), zval_get_scalar<T>(new_value));
|
|
}
|
|
|
|
template <typename T, typename ChildT>
|
|
PHP_ARMA_METHOD(base, transform, T, ChildT)
|
|
{
|
|
zend_fcall_info fci;
|
|
zend_fcall_info_cache fcc;
|
|
ZEND_PARSE_PARAMETERS_START(1, 1)
|
|
Z_PARAM_FUNC(fci, fcc);
|
|
ZEND_PARSE_PARAMETERS_END();
|
|
|
|
if constexpr (util::is_any_v<ChildT, diagview<T>, spdiagview<T>>) {
|
|
throw_error("This method is not yet supported on diagview");
|
|
return;
|
|
} else {
|
|
zval params[1], retval;
|
|
fci.param_count = 1;
|
|
fci.params = params;
|
|
fci.retval = &retval;
|
|
|
|
if constexpr (std::is_same_v<T, cx_double>) {
|
|
// prevent segfault in `zval_set_scalar()`..
|
|
ZVAL_UNDEF(¶ms[0]);
|
|
}
|
|
|
|
auto native = THIS_NATIVE;
|
|
native->transform([&fci, &fcc](auto&& val) {
|
|
zval_set_scalar(&fci.params[0], val);
|
|
zend_call_function(&fci, &fcc);
|
|
if (!zval_check_scalar<T>(fci.retval)) {
|
|
zval_ptr_dtor(fci.retval);
|
|
return T();
|
|
}
|
|
T retval = zval_get_scalar<T>(fci.retval);
|
|
if constexpr (std::is_same_v<T, cx_double>) {
|
|
zval_ptr_dtor(fci.retval);
|
|
}
|
|
return retval;
|
|
});
|
|
|
|
if constexpr (std::is_same_v<T, cx_double>) {
|
|
zval_ptr_dtor(¶ms[0]);
|
|
}
|
|
}
|
|
}
|
|
|
|
template <typename T, typename ChildT>
|
|
PHP_ARMA_METHOD(base, forEach, T, ChildT)
|
|
{
|
|
zend_fcall_info fci;
|
|
zend_fcall_info_cache fcc;
|
|
ZEND_PARSE_PARAMETERS_START(1, 1)
|
|
Z_PARAM_FUNC(fci, fcc);
|
|
ZEND_PARSE_PARAMETERS_END();
|
|
|
|
if constexpr (util::is_any_v<ChildT, diagview<T>, spdiagview<T>>) {
|
|
throw_error("This method is not yet supported on diagview");
|
|
return;
|
|
} else {
|
|
zval params[1], retval;
|
|
fci.param_count = 1;
|
|
fci.params = params;
|
|
fci.retval = &retval;
|
|
|
|
auto native = THIS_NATIVE;
|
|
auto parent = get_parent_zval<ChildT>(&EX(This));
|
|
native->for_each([&fci, &fcc, parent](auto&& val) {
|
|
ZVAL_OBJ(&fci.params[0], mapval_dense<T>::create(parent, &val));
|
|
zend_call_function(&fci, &fcc);
|
|
zval_ptr_dtor(&fci.params[0]);
|
|
zval_ptr_dtor(fci.retval);
|
|
});
|
|
}
|
|
}
|
|
|
|
template <typename T, typename T1>
|
|
PHP_ARMA_METHOD(base, min, T, T1)
|
|
{
|
|
auto native = THIS_NATIVE;
|
|
zval_set_scalar(return_value, native->min());
|
|
}
|
|
|
|
template <typename T, typename T1>
|
|
PHP_ARMA_METHOD(base, max, T, T1)
|
|
{
|
|
auto native = THIS_NATIVE;
|
|
zval_set_scalar(return_value, native->max());
|
|
}
|
|
|
|
template <typename T, typename T1>
|
|
PHP_ARMA_METHOD(base, indexMin, T, T1)
|
|
{
|
|
auto native = THIS_NATIVE;
|
|
RETVAL_LONG(native->index_min());
|
|
}
|
|
|
|
template <typename T, typename T1>
|
|
PHP_ARMA_METHOD(base, indexMax, T, T1)
|
|
{
|
|
auto native = THIS_NATIVE;
|
|
RETVAL_LONG(native->index_max());
|
|
}
|
|
|
|
template <typename T, typename T1>
|
|
PHP_ARMA_METHOD(base, isEmpty, T, T1)
|
|
{
|
|
auto native = THIS_NATIVE;
|
|
RETVAL_BOOL(native->is_empty());
|
|
}
|
|
|
|
template <typename T, typename T1>
|
|
PHP_ARMA_METHOD(base, isFinite, T, T1)
|
|
{
|
|
auto native = THIS_NATIVE;
|
|
RETVAL_BOOL(native->is_finite());
|
|
}
|
|
|
|
template <typename T, typename T1>
|
|
PHP_ARMA_METHOD(base, isZero, T, T1)
|
|
{
|
|
zval *tol = nullptr;
|
|
ZEND_PARSE_PARAMETERS_START(0, 1)
|
|
Z_PARAM_OPTIONAL
|
|
Z_PARAM_ZVAL(tol)
|
|
ZEND_PARSE_PARAMETERS_END();
|
|
|
|
auto native = THIS_NATIVE;
|
|
if (tol == nullptr) {
|
|
RETURN_BOOL(native->is_zero());
|
|
}
|
|
|
|
using base_t = typename arma::get_pod_type<T>::result;
|
|
if (!zval_check_scalar<base_t>(tol)) {
|
|
return;
|
|
}
|
|
RETVAL_BOOL(native->is_zero(zval_get_scalar<base_t>(tol)));
|
|
}
|
|
|
|
template <typename T, typename T1>
|
|
PHP_ARMA_METHOD(base, hasInf, T, T1)
|
|
{
|
|
auto native = THIS_NATIVE;
|
|
RETVAL_BOOL(native->has_inf());
|
|
}
|
|
|
|
template <typename T, typename T1>
|
|
PHP_ARMA_METHOD(base, hasNan, T, T1)
|
|
{
|
|
auto native = THIS_NATIVE;
|
|
RETVAL_BOOL(native->has_nan());
|
|
}
|
|
|
|
template <typename T, typename T1>
|
|
PHP_ARMA_METHOD(base, print, T, T1)
|
|
{
|
|
zval *stream = nullptr;
|
|
ZEND_PARSE_PARAMETERS_START(0, 1)
|
|
Z_PARAM_OPTIONAL
|
|
Z_PARAM_ZVAL(stream)
|
|
ZEND_PARSE_PARAMETERS_END();
|
|
|
|
auto native = THIS_NATIVE;
|
|
if (stream == nullptr) {
|
|
native->print();
|
|
} else {
|
|
Z_OSTREAM_P(stream, os);
|
|
if constexpr (zval_to_iostream_supported) {
|
|
native->print(os);
|
|
}
|
|
}
|
|
}
|
|
|
|
template <typename T, typename T1>
|
|
PHP_ARMA_METHOD(base, rawPrint, T, T1)
|
|
{
|
|
zval *stream = nullptr;
|
|
ZEND_PARSE_PARAMETERS_START(0, 1)
|
|
Z_PARAM_OPTIONAL
|
|
Z_PARAM_ZVAL(stream)
|
|
ZEND_PARSE_PARAMETERS_END();
|
|
|
|
auto native = THIS_NATIVE;
|
|
if (stream == nullptr) {
|
|
native->raw_print();
|
|
} else {
|
|
Z_OSTREAM_P(stream, os);
|
|
if constexpr (zval_to_iostream_supported) {
|
|
native->raw_print(os);
|
|
}
|
|
}
|
|
}
|
|
|
|
template <typename T, typename T1>
|
|
PHP_ARMA_METHOD(base, __toString, T, T1)
|
|
{
|
|
auto native = THIS_NATIVE;
|
|
to_string(native, return_value);
|
|
}
|
|
|
|
template <typename T, typename ChildT>
|
|
PHP_ARMA_METHOD(base, __debugInfo, T, ChildT)
|
|
{
|
|
auto native = THIS_NATIVE;
|
|
zval n_rows, n_cols, data;
|
|
ZVAL_LONG(&n_rows, native->n_rows);
|
|
ZVAL_LONG(&n_cols, native->n_cols);
|
|
to_string(native, &data);
|
|
auto retval = reinterpret_cast<zend_array*>(emalloc(sizeof(zend_array)));
|
|
zend_hash_init(retval, HT_MIN_SIZE, nullptr, ZVAL_PTR_DTOR, 0);
|
|
zend_hash_str_add(retval, "nRows", sizeof("nRows") - 1, &n_rows);
|
|
zend_hash_str_add(retval, "nCols", sizeof("nRows") - 1, &n_cols);
|
|
zend_hash_str_add(retval, "data", sizeof("data") - 1, &data);
|
|
RETVAL_ARR(retval);
|
|
}
|
|
|
|
template <typename T, typename T1>
|
|
PHP_ARMA_START_ME(base, T, T1)
|
|
PHP_ARMA_ME(nElem, ZEND_ACC_PUBLIC)
|
|
PHP_ARMA_ME(add, ZEND_ACC_PUBLIC)
|
|
PHP_ARMA_ME(sub, ZEND_ACC_PUBLIC)
|
|
PHP_ARMA_ME(neg, ZEND_ACC_PUBLIC)
|
|
PHP_ARMA_ME(mul, ZEND_ACC_PUBLIC)
|
|
PHP_ARMA_ME(dotMul, ZEND_ACC_PUBLIC)
|
|
PHP_ARMA_ME(div, ZEND_ACC_PUBLIC)
|
|
PHP_ARMA_ME(replace, ZEND_ACC_PUBLIC)
|
|
PHP_ARMA_ME(transform, ZEND_ACC_PUBLIC)
|
|
PHP_ARMA_ME(forEach, ZEND_ACC_PUBLIC)
|
|
PHP_ARMA_ME(min, ZEND_ACC_PUBLIC)
|
|
PHP_ARMA_ME(max, ZEND_ACC_PUBLIC)
|
|
PHP_ARMA_ME(indexMin, ZEND_ACC_PUBLIC)
|
|
PHP_ARMA_ME(indexMax, ZEND_ACC_PUBLIC)
|
|
PHP_ARMA_ME(isEmpty, ZEND_ACC_PUBLIC)
|
|
PHP_ARMA_ME(isFinite, ZEND_ACC_PUBLIC)
|
|
PHP_ARMA_ME(isZero, ZEND_ACC_PUBLIC)
|
|
PHP_ARMA_ME(hasInf, ZEND_ACC_PUBLIC)
|
|
PHP_ARMA_ME(hasNan, ZEND_ACC_PUBLIC)
|
|
PHP_ARMA_ME(print, ZEND_ACC_PUBLIC)
|
|
PHP_ARMA_ME(rawPrint, ZEND_ACC_PUBLIC)
|
|
PHP_ARMA_ME(__toString, ZEND_ACC_PUBLIC)
|
|
PHP_ARMA_ME(__debugInfo, ZEND_ACC_PUBLIC)
|
|
PHP_ARMA_END_ME();
|
|
|
|
void base_init()
|
|
{
|
|
base_ce = interface_register<base_php_name>(
|
|
#if PHP_VERSION_ID >= 70200
|
|
zend_ce_countable
|
|
#endif
|
|
);
|
|
}
|
|
|
|
PHP_ARMA_INSTANTIATE(base, mat);
|
|
PHP_ARMA_INSTANTIATE(base, subview_mat);
|
|
PHP_ARMA_INSTANTIATE(base, diagview);
|
|
}
|