diff --git a/src/base.cc b/src/base.cc index 53c3e4f..b9adecf 100644 --- a/src/base.cc +++ b/src/base.cc @@ -62,13 +62,58 @@ namespace php_arma 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 (UNEXPECTED(!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, T1) { - + zend_fcall_info fci; + zend_fcall_info_cache fcc; + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_FUNC(fci, fcc); + ZEND_PARSE_PARAMETERS_END(); + + 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 @@ -86,7 +131,7 @@ namespace php_arma fci.retval = &retval; auto native = THIS_NATIVE; - native->for_each([&fci, &fcc](T& val) { + native->for_each([&fci, &fcc](auto&& val) { ZVAL_OBJ(&fci.params[0], mapval_dense::create(&val)); zend_call_function(&fci, &fcc); zval_ptr_dtor(&fci.params[0]); diff --git a/stubs/internal/Base.php b/stubs/internal/Base.php index 93eedc9..b716b5c 100644 --- a/stubs/internal/Base.php +++ b/stubs/internal/Base.php @@ -82,10 +82,10 @@ interface Base extends Countable * * Transformation is done column-by-column, and for SpMat only non-zero elements will be transformed. * - * @param callable $callback (Scalar) => $new_value + * @param callable $transform (number|Complex) => $new_value * @return void */ - function transform($callback); + function transform($transform); /** * For each element, pass its reference to a callback function. diff --git a/tests/013-foreach.phpt b/tests/013-foreach-transform-replace.phpt similarity index 63% rename from tests/013-foreach.phpt rename to tests/013-foreach-transform-replace.phpt index f8f66d7..8f6e11a 100644 --- a/tests/013-foreach.phpt +++ b/tests/013-foreach-transform-replace.phpt @@ -1,5 +1,5 @@ --TEST-- -Test for method `forEach()`. +Test for methods `forEach()`, `transform()`, `replace()`. --SKIPIF-- forEach(function (Arma\MapVal $elem) { }); echo PHP_EOL; $mat->rawPrint(); +$mat->transform(function (int $elem) { + return $elem + 4; +}); +$mat->rawPrint(); +$mat->replace(10, -1); +$mat->replace(11, -2); +$mat->rawPrint(); ?> --EXPECT-- @@ -27,3 +34,7 @@ $mat->rawPrint(); 1324 5 6 7 8 +9 10 +11 12 +9 -1 +-2 12