// // 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 namespace php_arma { template 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 PHP_ARMA_METHOD(base, nElem, T, T1) { zend_long count; count_elements(&EX(This), &count); RETVAL_LONG(count); } template 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 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 PHP_ARMA_METHOD(base, neg, T, T1) { operators::neg(&EX(This), return_value); } template 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 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 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 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(old_value) || !zval_check_scalar(new_value)) { return; } auto native = THIS_NATIVE; native->replace(zval_get_scalar(old_value), zval_get_scalar(new_value)); } template 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, spdiagview>) { 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) { // 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(fci.retval)) { zval_ptr_dtor(fci.retval); return T(); } T retval = zval_get_scalar(fci.retval); if constexpr (std::is_same_v) { zval_ptr_dtor(fci.retval); } return retval; }); if constexpr (std::is_same_v) { zval_ptr_dtor(¶ms[0]); } } } template 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, spdiagview>) { 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(&EX(This)); native->for_each([&fci, &fcc, parent](auto&& val) { ZVAL_OBJ(&fci.params[0], mapval_dense::create(parent, &val)); zend_call_function(&fci, &fcc); zval_ptr_dtor(&fci.params[0]); zval_ptr_dtor(fci.retval); }); } } template PHP_ARMA_METHOD(base, min, T, T1) { auto native = THIS_NATIVE; zval_set_scalar(return_value, native->min()); } template PHP_ARMA_METHOD(base, max, T, T1) { auto native = THIS_NATIVE; zval_set_scalar(return_value, native->max()); } template PHP_ARMA_METHOD(base, indexMin, T, T1) { auto native = THIS_NATIVE; RETVAL_LONG(native->index_min()); } template PHP_ARMA_METHOD(base, indexMax, T, T1) { auto native = THIS_NATIVE; RETVAL_LONG(native->index_max()); } template PHP_ARMA_METHOD(base, isEmpty, T, T1) { auto native = THIS_NATIVE; RETVAL_BOOL(native->is_empty()); } template PHP_ARMA_METHOD(base, isFinite, T, T1) { auto native = THIS_NATIVE; RETVAL_BOOL(native->is_finite()); } template 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::result; if (!zval_check_scalar(tol)) { return; } RETVAL_BOOL(native->is_zero(zval_get_scalar(tol))); } template PHP_ARMA_METHOD(base, hasInf, T, T1) { auto native = THIS_NATIVE; RETVAL_BOOL(native->has_inf()); } template PHP_ARMA_METHOD(base, hasNan, T, T1) { auto native = THIS_NATIVE; RETVAL_BOOL(native->has_nan()); } template 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 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 PHP_ARMA_METHOD(base, __toString, T, T1) { auto native = THIS_NATIVE; to_string(native, return_value); } template 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(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 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( #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); }