This repository has been archived on 2020-06-07. You can view files and clone it, but cannot push or open issues or pull requests.
php-armadillo/src/complex.cc

415 lines
12 KiB
C++

//
// php-armadillo/complex.cc
//
// @Author CismonX
//
#include "complex.hh"
namespace php_arma
{
template <typename T, const char *Name>
zend_always_inline
void property_declare_scalar(zend_class_entry *ce)
{
zval property;
zval_set_scalar(&property, static_cast<T>(0));
property_declare<Name, ZEND_ACC_PUBLIC>(ce, &property);
}
template <typename T>
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<T>(real)) {
return;
}
object_set_property(current, 0, real);
if (EXPECTED(has_imag)) {
if (!zval_check_scalar<T>(imag)) {
return;
}
object_set_property(current, 1, imag);
}
}
current->handlers = &handlers;
}
template <typename T>
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<T>(r)) {
return;
}
if (!zval_check_scalar<T>(theta)) {
return;
}
auto retval = std::polar(zval_get_scalar<T>(r), zval_get_scalar<T>(theta));
zval_set_scalar(return_value, retval);
}
template <typename T>
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<T>(other);
}
}
template <typename T>
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<T>(other);
}
}
template <typename T>
PHP_ARMA_METHOD(complex, neg, T)
{
operators::neg(&EX(This), return_value);
}
template <typename T>
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<T>(other);
}
}
template <typename T>
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<T>(other);
}
}
template <typename T>
PHP_ARMA_METHOD(complex, abs, T)
{
auto current = zval_get_scalar<native_t>(&EX(This));
zval_set_scalar(return_value, std::abs(current));
}
template <typename T>
PHP_ARMA_METHOD(complex, arg, T)
{
auto current = zval_get_scalar<native_t>(&EX(This));
zval_set_scalar(return_value, std::arg(current));
}
template <typename T>
PHP_ARMA_METHOD(complex, norm, T)
{
auto current = zval_get_scalar<native_t>(&EX(This));
zval_set_scalar(return_value, std::norm(current));
}
template <typename T>
PHP_ARMA_METHOD(complex, conj, T)
{
operators::conj(&EX(This), nullptr, return_value);
}
template <typename T>
PHP_ARMA_METHOD(complex, exp, T)
{
auto current = zval_get_scalar<native_t>(&EX(This));
zval_set_scalar(return_value, std::exp(current));
}
template <typename T>
PHP_ARMA_METHOD(complex, log, T)
{
auto current = zval_get_scalar<native_t>(&EX(This));
zval_set_scalar(return_value, std::log(current));
}
template <typename T>
PHP_ARMA_METHOD(complex, log10, T)
{
auto current = zval_get_scalar<native_t>(&EX(This));
zval_set_scalar(return_value, std::log10(current));
}
template <typename T>
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<T>(other);
}
}
template <typename T>
PHP_ARMA_METHOD(complex, sqrt, T)
{
auto current = zval_get_scalar<native_t>(&EX(This));
zval_set_scalar(return_value, std::abs(current));
}
template <typename T>
PHP_ARMA_METHOD(complex, sin, T)
{
auto current = zval_get_scalar<native_t>(&EX(This));
zval_set_scalar(return_value, std::sin(current));
}
template <typename T>
PHP_ARMA_METHOD(complex, cos, T)
{
auto current = zval_get_scalar<native_t>(&EX(This));
zval_set_scalar(return_value, std::cos(current));
}
template <typename T>
PHP_ARMA_METHOD(complex, tan, T)
{
auto current = zval_get_scalar<native_t>(&EX(This));
zval_set_scalar(return_value, std::tan(current));
}
template <typename T>
PHP_ARMA_METHOD(complex, asin, T)
{
auto current = zval_get_scalar<native_t>(&EX(This));
zval_set_scalar(return_value, std::asin(current));
}
template <typename T>
PHP_ARMA_METHOD(complex, acos, T)
{
auto current = zval_get_scalar<native_t>(&EX(This));
zval_set_scalar(return_value, std::acos(current));
}
template <typename T>
PHP_ARMA_METHOD(complex, atan, T)
{
auto current = zval_get_scalar<native_t>(&EX(This));
zval_set_scalar(return_value, std::atan(current));
}
template <typename T>
PHP_ARMA_METHOD(complex, sinh, T)
{
auto current = zval_get_scalar<native_t>(&EX(This));
zval_set_scalar(return_value, std::sinh(current));
}
template <typename T>
PHP_ARMA_METHOD(complex, cosh, T)
{
auto current = zval_get_scalar<native_t>(&EX(This));
zval_set_scalar(return_value, std::cosh(current));
}
template <typename T>
PHP_ARMA_METHOD(complex, tanh, T)
{
auto current = zval_get_scalar<native_t>(&EX(This));
zval_set_scalar(return_value, std::tanh(current));
}
template <typename T>
PHP_ARMA_METHOD(complex, asinh, T)
{
auto current = zval_get_scalar<native_t>(&EX(This));
zval_set_scalar(return_value, std::asinh(current));
}
template <typename T>
PHP_ARMA_METHOD(complex, acosh, T)
{
auto current = zval_get_scalar<native_t>(&EX(This));
zval_set_scalar(return_value, std::acosh(current));
}
template <typename T>
PHP_ARMA_METHOD(complex, atanh, T)
{
auto current = zval_get_scalar<native_t>(&EX(This));
zval_set_scalar(return_value, std::atanh(current));
}
template <typename T>
PHP_ARMA_METHOD(complex, __toString, T)
{
auto current = zval_get_scalar<native_t>(&EX(This));
std::ostringstream oss;
oss << current;
auto retval = oss.str();
RETVAL_STRING(retval.c_str());
}
template <typename T>
zval *complex<T>::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 <typename T>
zobj_write_prop_ret_t complex<T>::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<T>(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 <typename T>
int complex<T>::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<native_t>(zv1);
auto v2 = zval_get_scalar<native_t>(zv2);
return v1 != v2;
}
template <typename T>
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 <typename T>
zend_always_inline
void complex<T>::ce_init(zend_class_entry *parent_ce)
{
ce = class_register<php_name::val>(parent_ce, me);
property_declare_scalar<T, real_property_name>(ce);
property_declare_scalar<T, imag_property_name>(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_php_name>();
complex<double>::ce_init(complex_ce);
}
}