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.hh

274 lines
8.6 KiB
C++
Raw Permalink Normal View History

//
// php-armadillo/complex.hh
//
// @Author CismonX
//
#ifndef PHP_ARMA_COMPLEX_HH
#define PHP_ARMA_COMPLEX_HH
2019-11-04 09:42:11 +00:00
#include "common/php_arma.hh"
2019-03-17 03:30:03 +00:00
#include <complex>
2019-04-16 11:00:50 +00:00
#ifdef PHP_ARMA_OPERATORS
2019-04-18 11:01:27 +00:00
#if PHP_VERSION_ID < 70300
// Before PHP 7.3, `-$a` is compile to `MUL -1, $a, ~` instead of `MUL $a, -1, ~`.
2019-12-09 04:27:30 +00:00
#define CONVERT_NEG_1_TO_COMPLEX \
else if (Z_TYPE_P(zv1) == IS_LONG && Z_LVAL_P(zv1) == -1) { \
std::swap(zv1, zv2); \
2019-04-18 11:01:27 +00:00
}
#else
2019-12-09 04:27:30 +00:00
#define CONVERT_NEG_1_TO_COMPLEX
2019-04-18 11:01:27 +00:00
#endif
2019-04-18 10:15:33 +00:00
// For non-assignment operators, first operand can be of type double.
2019-06-06 15:56:10 +00:00
#define PHP_ARMA_COMPLEX_OPERATOR_EX(type, func) \
2019-04-18 10:15:33 +00:00
if (instanceof_function(ce, complex<type>::ce)) { \
if (zval_is_scalar<type>(zv1)) { \
2019-12-09 04:27:30 +00:00
std::swap(zv1, zv2); \
2019-04-18 10:15:33 +00:00
} \
2019-12-09 04:27:30 +00:00
CONVERT_NEG_1_TO_COMPLEX \
2019-04-18 11:37:01 +00:00
else if (UNEXPECTED(Z_TYPE_P(zv1) != IS_OBJECT)) { \
return false; \
} \
2019-12-09 04:27:30 +00:00
ZVAL_UNDEF(rv); \
return complex<type>::operators::func(zv1, zv2, rv); \
2019-04-16 11:00:50 +00:00
}
2019-06-06 15:56:10 +00:00
#define PHP_ARMA_COMPLEX_OPERATOR(func) \
PHP_ARMA_OPERATOR_BEGIN(complex_ce) \
PHP_ARMA_COMPLEX_OPERATOR_EX(double, func) \
PHP_ARMA_OPERATOR_END()
2019-06-09 14:47:33 +00:00
#define PHP_ARMA_COMPLEX_ASSIGN_OPERATOR_EX(type, func) \
PHP_ARMA_ASSIGN_OPERATOR_EX(complex<type>, func)
2019-06-06 15:56:10 +00:00
2019-06-09 14:47:33 +00:00
#define PHP_ARMA_COMPLEX_ASSIGN_OPERATOR(func) \
2019-06-06 15:56:10 +00:00
PHP_ARMA_OPERATOR_BEGIN(complex_ce) \
2019-06-09 14:47:33 +00:00
PHP_ARMA_COMPLEX_ASSIGN_OPERATOR_EX(double, func) \
2019-06-06 15:56:10 +00:00
PHP_ARMA_OPERATOR_END()
2019-04-16 11:00:50 +00:00
#endif // PHP_ARMA_OPERATORS
2019-03-20 14:55:19 +00:00
using cx_double = std::complex<double>;
2019-03-17 03:30:03 +00:00
namespace php_arma
{
template <typename T>
2019-03-20 14:55:19 +00:00
struct complex
{
2019-04-13 10:17:01 +00:00
using native_t = std::complex<T>;
2019-04-16 11:00:50 +00:00
struct operators;
2019-03-20 14:55:19 +00:00
friend void complex_init();
2019-03-23 16:24:34 +00:00
PHP_ARMA_CE_HANDLRES_DECLARE();
2019-03-20 14:55:19 +00:00
private:
2019-04-13 10:17:01 +00:00
PHP_ARMA_COMMON_DECLARE();
2019-04-01 06:21:38 +00:00
2019-03-29 12:18:44 +00:00
static PHP_FUNCTION(__construct);
2019-04-13 10:17:01 +00:00
static PHP_FUNCTION(fromPolar);
static PHP_FUNCTION(add);
static PHP_FUNCTION(sub);
static PHP_FUNCTION(neg);
static PHP_FUNCTION(mul);
static PHP_FUNCTION(div);
static PHP_FUNCTION(abs);
static PHP_FUNCTION(arg);
static PHP_FUNCTION(norm);
static PHP_FUNCTION(conj);
static PHP_FUNCTION(exp);
static PHP_FUNCTION(log);
static PHP_FUNCTION(log10);
static PHP_FUNCTION(pow);
static PHP_FUNCTION(sqrt);
static PHP_FUNCTION(sin);
static PHP_FUNCTION(cos);
static PHP_FUNCTION(tan);
static PHP_FUNCTION(asin);
static PHP_FUNCTION(acos);
static PHP_FUNCTION(atan);
static PHP_FUNCTION(sinh);
static PHP_FUNCTION(cosh);
static PHP_FUNCTION(tanh);
static PHP_FUNCTION(asinh);
static PHP_FUNCTION(acosh);
static PHP_FUNCTION(atanh);
static PHP_FUNCTION(__toString);
2019-04-23 13:38:51 +00:00
static zval *read_dimension(zval*, zval*, int, zval*);
2019-12-08 17:32:19 +00:00
static zobj_write_prop_ret_t write_property(zval*, zval*, zval*, void**);
2019-04-13 10:17:01 +00:00
static int compare_objects(zval*, zval*);
2019-03-20 14:55:19 +00:00
2019-04-01 06:04:46 +00:00
static void ce_init(zend_class_entry*);
2019-03-20 14:55:19 +00:00
};
void complex_init();
2019-05-30 14:02:11 +00:00
constexpr const char complex_php_name[] = "Complex";
2019-05-25 18:21:48 +00:00
constexpr const char real_property_name[] = "real";
constexpr const char imag_property_name[] = "imag";
2019-04-01 06:04:46 +00:00
2019-03-20 14:55:19 +00:00
inline zend_class_entry *complex_ce;
2019-03-17 03:30:03 +00:00
/// Helper functions for handling cx_double types.
2019-03-22 08:30:44 +00:00
template <>
zend_always_inline
bool zval_is_scalar<cx_double>(zval *zv)
{
return Z_TYPE_P(zv) == IS_OBJECT && instanceof_function(Z_OBJCE_P(zv), PHP_ARMA_CE(complex, double));
}
2019-03-22 08:30:44 +00:00
template <>
zend_always_inline
const char *scalar_type_name<cx_double>()
{
return ZSTR_VAL(PHP_ARMA_CE(complex, double)->name);
}
2019-03-17 03:30:03 +00:00
2019-03-22 08:30:44 +00:00
template <>
zend_always_inline
2019-03-17 03:30:03 +00:00
cx_double zval_get_scalar<cx_double>(zval *zv)
{
auto zobj = Z_OBJ_P(zv);
return { Z_DVAL_P(OBJ_PROP_NUM(zobj, 0)), Z_DVAL_P(OBJ_PROP_NUM(zobj, 1)) };
}
zend_always_inline
2019-06-06 15:56:10 +00:00
void zval_set_scalar(zval *zv, const cx_double& val)
2019-03-17 03:30:03 +00:00
{
auto zobj = object_create(PHP_ARMA_CE(complex, double), PHP_ARMA_HANDLERS(complex, double));
ZVAL_DOUBLE(OBJ_PROP_NUM(zobj, 0), val.real());
ZVAL_DOUBLE(OBJ_PROP_NUM(zobj, 1), val.imag());
zval_ptr_dtor(zv);
ZVAL_OBJ(zv, zobj);
}
2019-04-13 10:17:01 +00:00
template <typename T>
zend_always_inline
void ex_bad_type(zval *zv) {
auto real_type_name = scalar_type_name<T>();
auto complex_type_name = scalar_type_name<typename complex<T>::native_t>();
auto expected = (char*)malloc((strlen(real_type_name) + strlen(complex_type_name) + 5) * sizeof(char));
sprintf(expected, "%s or %s", real_type_name, complex_type_name);
auto got = Z_TYPE_P(zv) == IS_OBJECT ? Z_OBJNAME_P(zv) : zend_get_type_by_const(Z_TYPE_P(zv));
ex_bad_type(expected, got);
free(expected);
}
2019-04-16 11:00:50 +00:00
template <typename T>
struct complex<T>::operators
{
zend_always_inline
static bool add(zval *zv1, zval *zv2, zval *retval)
{
auto v1 = zval_get_scalar<native_t>(zv1);
if (zval_is_scalar<native_t>(zv2)) {
zval_set_scalar(retval, v1 + zval_get_scalar<native_t>(zv2));
return true;
}
if (zval_is_scalar<T>(zv2)) {
zval_set_scalar(retval, v1 + zval_get_scalar<T>(zv2));
return true;
}
return false;
}
zend_always_inline
static bool sub(zval *zv1, zval *zv2, zval *retval)
{
auto v1 = zval_get_scalar<native_t>(zv1);
if (zval_is_scalar<native_t>(zv2)) {
zval_set_scalar(retval, v1 - zval_get_scalar<native_t>(zv2));
return true;
}
if (zval_is_scalar<T>(zv2)) {
zval_set_scalar(retval, v1 - zval_get_scalar<T>(zv2));
return true;
}
return false;
}
2019-04-18 10:15:33 +00:00
zend_always_inline
static void neg(zval *zv, zval *retval)
{
auto v = zval_get_scalar<native_t>(zv);
zval_set_scalar(retval, -v);
}
2019-04-16 11:00:50 +00:00
zend_always_inline
static bool mul(zval *zv1, zval *zv2, zval *retval)
{
auto v1 = zval_get_scalar<native_t>(zv1);
if (zval_is_scalar<native_t>(zv2)) {
zval_set_scalar(retval, v1 * zval_get_scalar<native_t>(zv2));
return true;
}
if (zval_is_scalar<T>(zv2)) {
zval_set_scalar(retval, v1 * zval_get_scalar<T>(zv2));
return true;
}
2019-04-18 10:15:33 +00:00
if (Z_TYPE_P(zv2) == IS_LONG && Z_LVAL_P(zv2) == -1) {
// Negation operator is compiled as multiplication to -1.
neg(zv1, retval);
return true;
}
2019-04-16 11:00:50 +00:00
return false;
}
zend_always_inline
static bool div(zval *zv1, zval *zv2, zval *retval)
{
auto v1 = zval_get_scalar<native_t>(zv1);
if (zval_is_scalar<native_t>(zv2)) {
zval_set_scalar(retval, v1 / zval_get_scalar<native_t>(zv2));
return true;
}
if (zval_is_scalar<T>(zv2)) {
zval_set_scalar(retval, v1 / zval_get_scalar<T>(zv2));
return true;
}
return false;
}
zend_always_inline
static bool pow(zval *zv1, zval *zv2, zval *retval)
{
auto v1 = zval_get_scalar<native_t>(zv1);
if (zval_is_scalar<native_t>(zv2)) {
zval_set_scalar(retval, std::pow(v1, zval_get_scalar<native_t>(zv2)));
return true;
}
if (zval_is_scalar<T>(zv2)) {
zval_set_scalar(retval, std::pow(v1, zval_get_scalar<T>(zv2)));
return true;
}
return false;
}
zend_always_inline
static bool conj(zval *zv, zval *unused, zval *retval)
{
zval_set_scalar(retval, std::conj(zval_get_scalar<native_t>(zv)));
return true;
}
};
}
2019-03-25 07:14:53 +00:00
#endif // !PHP_ARMA_COMPLEX_HH