// // php-armadillo/complex.cc // // @Author CismonX // #include "complex.hh" namespace php_arma { template zend_always_inline void property_declare_scalar(zend_class_entry *ce) { zval property; zval_set_scalar(&property, static_cast(0)); property_declare(ce, &property); } template PHP_ARMA_METHOD(complex, __construct, T) { zval *real, *imag; ZEND_PARSE_PARAMETERS_START(0, 2) Z_PARAM_OPTIONAL Z_PARAM_ZVAL(real) Z_PARAM_ZVAL(imag) ZEND_PARSE_PARAMETERS_END(); auto num_args = EX_NUM_ARGS(); auto has_imag = num_args == 2; auto has_real = num_args > 0; auto current = Z_OBJ(EX(This)); if (EXPECTED(has_real)) { if (!zval_check_scalar(real)) { return; } object_set_property(current, 0, real); if (EXPECTED(has_imag)) { if (!zval_check_scalar(imag)) { return; } object_set_property(current, 1, imag); } } current->handlers = &handlers; } template PHP_ARMA_METHOD(complex, fromPolar, T) { zval *r, *theta; ZEND_PARSE_PARAMETERS_START(2, 2) Z_PARAM_ZVAL(r) Z_PARAM_ZVAL(theta) ZEND_PARSE_PARAMETERS_END(); if (!zval_check_scalar(r)) { return; } if (!zval_check_scalar(theta)) { return; } auto retval = std::polar(zval_get_scalar(r), zval_get_scalar(theta)); zval_set_scalar(return_value, retval); } template PHP_ARMA_METHOD(complex, add, T) { zval *other; ZEND_PARSE_PARAMETERS_START(1, 1) Z_PARAM_ZVAL(other) ZEND_PARSE_PARAMETERS_END(); if (!operators::add(&EX(This), other, return_value)) { ex_bad_type(other); } } template PHP_ARMA_METHOD(complex, sub, T) { zval *other; ZEND_PARSE_PARAMETERS_START(1, 1) Z_PARAM_ZVAL(other) ZEND_PARSE_PARAMETERS_END(); if (!operators::sub(&EX(This), other, return_value)) { ex_bad_type(other); } } template PHP_ARMA_METHOD(complex, neg, T) { operators::neg(&EX(This), return_value); } template PHP_ARMA_METHOD(complex, mul, T) { zval *other; ZEND_PARSE_PARAMETERS_START(1, 1) Z_PARAM_ZVAL(other) ZEND_PARSE_PARAMETERS_END(); if (!operators::mul(&EX(This), other, return_value)) { ex_bad_type(other); } } template PHP_ARMA_METHOD(complex, div, T) { zval *other; ZEND_PARSE_PARAMETERS_START(1, 1) Z_PARAM_ZVAL(other) ZEND_PARSE_PARAMETERS_END(); if (!operators::div(&EX(This), other, return_value)) { ex_bad_type(other); } } template PHP_ARMA_METHOD(complex, abs, T) { auto current = zval_get_scalar(&EX(This)); zval_set_scalar(return_value, std::abs(current)); } template PHP_ARMA_METHOD(complex, arg, T) { auto current = zval_get_scalar(&EX(This)); zval_set_scalar(return_value, std::arg(current)); } template PHP_ARMA_METHOD(complex, norm, T) { auto current = zval_get_scalar(&EX(This)); zval_set_scalar(return_value, std::norm(current)); } template PHP_ARMA_METHOD(complex, conj, T) { operators::conj(&EX(This), nullptr, return_value); } template PHP_ARMA_METHOD(complex, exp, T) { auto current = zval_get_scalar(&EX(This)); zval_set_scalar(return_value, std::exp(current)); } template PHP_ARMA_METHOD(complex, log, T) { auto current = zval_get_scalar(&EX(This)); zval_set_scalar(return_value, std::log(current)); } template PHP_ARMA_METHOD(complex, log10, T) { auto current = zval_get_scalar(&EX(This)); zval_set_scalar(return_value, std::log10(current)); } template PHP_ARMA_METHOD(complex, pow, T) { zval *other; ZEND_PARSE_PARAMETERS_START(1, 1) Z_PARAM_ZVAL(other) ZEND_PARSE_PARAMETERS_END(); if (!operators::pow(&EX(This), other, return_value)) { ex_bad_type(other); } } template PHP_ARMA_METHOD(complex, sqrt, T) { auto current = zval_get_scalar(&EX(This)); zval_set_scalar(return_value, std::abs(current)); } template PHP_ARMA_METHOD(complex, sin, T) { auto current = zval_get_scalar(&EX(This)); zval_set_scalar(return_value, std::sin(current)); } template PHP_ARMA_METHOD(complex, cos, T) { auto current = zval_get_scalar(&EX(This)); zval_set_scalar(return_value, std::cos(current)); } template PHP_ARMA_METHOD(complex, tan, T) { auto current = zval_get_scalar(&EX(This)); zval_set_scalar(return_value, std::tan(current)); } template PHP_ARMA_METHOD(complex, asin, T) { auto current = zval_get_scalar(&EX(This)); zval_set_scalar(return_value, std::asin(current)); } template PHP_ARMA_METHOD(complex, acos, T) { auto current = zval_get_scalar(&EX(This)); zval_set_scalar(return_value, std::acos(current)); } template PHP_ARMA_METHOD(complex, atan, T) { auto current = zval_get_scalar(&EX(This)); zval_set_scalar(return_value, std::atan(current)); } template PHP_ARMA_METHOD(complex, sinh, T) { auto current = zval_get_scalar(&EX(This)); zval_set_scalar(return_value, std::sinh(current)); } template PHP_ARMA_METHOD(complex, cosh, T) { auto current = zval_get_scalar(&EX(This)); zval_set_scalar(return_value, std::cosh(current)); } template PHP_ARMA_METHOD(complex, tanh, T) { auto current = zval_get_scalar(&EX(This)); zval_set_scalar(return_value, std::tanh(current)); } template PHP_ARMA_METHOD(complex, asinh, T) { auto current = zval_get_scalar(&EX(This)); zval_set_scalar(return_value, std::asinh(current)); } template PHP_ARMA_METHOD(complex, acosh, T) { auto current = zval_get_scalar(&EX(This)); zval_set_scalar(return_value, std::acosh(current)); } template PHP_ARMA_METHOD(complex, atanh, T) { auto current = zval_get_scalar(&EX(This)); zval_set_scalar(return_value, std::atanh(current)); } template PHP_ARMA_METHOD(complex, __toString, T) { auto current = zval_get_scalar(&EX(This)); std::ostringstream oss; oss << current; auto retval = oss.str(); RETVAL_STRING(retval.c_str()); } template zval *complex::read_dimension(zval *obj, zval *offset, int type, zval*) { if (UNEXPECTED(Z_TYPE_P(offset) != IS_LONG)) { ex_bad_type("int", zval_get_type_name(offset)); return nullptr; } if (UNEXPECTED(type != BP_VAR_R)) { throw_exception("numeric offset of class %s is read-only", Z_OBJNAME_P(obj)); return nullptr; } auto zobj = Z_OBJ_P(obj); auto idx = Z_LVAL_P(offset); if (EXPECTED(idx == 0 || idx == 1)) { return OBJ_PROP_NUM(zobj, idx); } throw_exception("bad offset for %s, expected 0 or 1, %ld given", Z_OBJNAME_P(obj), idx); return nullptr; } template zobj_write_prop_ret_t complex::write_property(zval *obj, zval *member, zval *value, void**) { zend_object *zobj = Z_OBJ_P(obj); // Theoretically we won't get non-string values here, add type check just in case. if (UNEXPECTED(Z_TYPE_P(member) != IS_STRING)) { throw_error("unexpected error, please contact developer."); ZOBJ_WRITE_PROP_FAIL_RET(); } if (UNEXPECTED(!zval_check_scalar(value))) { ZOBJ_WRITE_PROP_FAIL_RET(); } if (strcmp(Z_STRVAL_P(member), "real") == 0) { object_set_property(zobj, 0, value); ZOBJ_WRITE_PROP_RET(OBJ_PROP_NUM(zobj, 0)); } if (strcmp(Z_STRVAL_P(member), "imag") == 0) { object_set_property(zobj, 1, value); ZOBJ_WRITE_PROP_RET(OBJ_PROP_NUM(zobj, 1)); } throw_error("bad property name for %s, expected 'real' or 'imag', '%s' given", Z_OBJNAME_P(obj), Z_STRVAL_P(member)); ZOBJ_WRITE_PROP_FAIL_RET(); } template int complex::compare_objects(zval *zv1, zval *zv2) { auto zobj1 = Z_OBJ_P(zv1); auto zobj2 = Z_OBJ_P(zv2); if (zobj1 == zobj2) { return 0; } if (UNEXPECTED(zobj1->ce != zobj2->ce)) { return 1; } auto v1 = zval_get_scalar(zv1); auto v2 = zval_get_scalar(zv2); return v1 != v2; } template PHP_ARMA_START_ME(complex, T) PHP_ARMA_ME(__construct, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR) PHP_ARMA_ME(fromPolar, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC) 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(div, ZEND_ACC_PUBLIC) PHP_ARMA_ME(abs, ZEND_ACC_PUBLIC) PHP_ARMA_ME(arg, ZEND_ACC_PUBLIC) PHP_ARMA_ME(norm, ZEND_ACC_PUBLIC) PHP_ARMA_ME(conj, ZEND_ACC_PUBLIC) PHP_ARMA_ME(exp, ZEND_ACC_PUBLIC) PHP_ARMA_ME(log, ZEND_ACC_PUBLIC) PHP_ARMA_ME(log10, ZEND_ACC_PUBLIC) PHP_ARMA_ME(pow, ZEND_ACC_PUBLIC) PHP_ARMA_ME(sqrt, ZEND_ACC_PUBLIC) PHP_ARMA_ME(sin, ZEND_ACC_PUBLIC) PHP_ARMA_ME(cos, ZEND_ACC_PUBLIC) PHP_ARMA_ME(tan, ZEND_ACC_PUBLIC) PHP_ARMA_ME(asin, ZEND_ACC_PUBLIC) PHP_ARMA_ME(acos, ZEND_ACC_PUBLIC) PHP_ARMA_ME(atan, ZEND_ACC_PUBLIC) PHP_ARMA_ME(sinh, ZEND_ACC_PUBLIC) PHP_ARMA_ME(cosh, ZEND_ACC_PUBLIC) PHP_ARMA_ME(tanh, ZEND_ACC_PUBLIC) PHP_ARMA_ME(asinh, ZEND_ACC_PUBLIC) PHP_ARMA_ME(acosh, ZEND_ACC_PUBLIC) PHP_ARMA_ME(atanh, ZEND_ACC_PUBLIC) PHP_ARMA_ME(__toString, ZEND_ACC_PUBLIC) PHP_ARMA_END_ME(); template zend_always_inline void complex::ce_init(zend_class_entry *parent_ce) { ce = class_register(parent_ce, me); property_declare_scalar(ce); property_declare_scalar(ce); object_handlers_init(&handlers); handlers.read_dimension = read_dimension; handlers.write_property = write_property; handlers.compare_objects = compare_objects; } PHP_ARMA_NAME_DECLARE(complex, "CxDouble", double); void complex_init() { complex_ce = abstract_class_register(); complex::ce_init(complex_ce); } }