2019-03-14 15:04:34 +00:00
|
|
|
//
|
|
|
|
// php-armadillo/complex.hh
|
|
|
|
//
|
|
|
|
// @Author CismonX
|
|
|
|
//
|
|
|
|
|
|
|
|
#ifndef PHP_ARMA_COMPLEX_HH
|
|
|
|
#define PHP_ARMA_COMPLEX_HH
|
|
|
|
|
2019-03-15 15:25:24 +00:00
|
|
|
#include "php_arma.hh"
|
2019-03-14 15:04:34 +00:00
|
|
|
|
2019-03-17 03:30:03 +00:00
|
|
|
#include <complex>
|
|
|
|
|
2019-04-16 11:00:50 +00:00
|
|
|
#ifdef PHP_ARMA_OPERATORS
|
|
|
|
|
|
|
|
#define PHP_ARMA_COMPLEX_OPERATOR(type, func) \
|
|
|
|
if (instanceof_function(_ce, complex<type>::ce)) { \
|
|
|
|
return complex<type>::operators::func(zv1, zv2, retval); \
|
|
|
|
}
|
|
|
|
|
|
|
|
#define PHP_ARMA_COMPLEX_OPERATOR_ASSIGN(type, func) \
|
|
|
|
if (instanceof_function(_ce, complex<type>::ce)) { \
|
|
|
|
auto v = complex<type>::operators::func(zv1, zv2, zv1); \
|
|
|
|
if (EX(opline)->result_type != IS_UNUSED) { \
|
|
|
|
ZVAL_COPY(retval, zv1); \
|
|
|
|
} \
|
|
|
|
return v; \
|
|
|
|
}
|
|
|
|
|
|
|
|
#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
|
|
|
|
2019-03-14 15:04:34 +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-14 15:04:34 +00:00
|
|
|
|
2019-03-23 16:24:34 +00:00
|
|
|
PHP_ARMA_CE_HANDLRES_DECLARE();
|
2019-03-14 15:04:34 +00:00
|
|
|
|
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);
|
2019-03-15 15:25:24 +00:00
|
|
|
|
2019-03-20 14:55:19 +00:00
|
|
|
static void 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-04-01 06:04:46 +00:00
|
|
|
constexpr const char complex_php_name[] = "Complex";
|
|
|
|
|
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-15 15:25:24 +00:00
|
|
|
|
2019-03-22 08:30:44 +00:00
|
|
|
template <>
|
|
|
|
zend_always_inline
|
2019-03-15 15:25:24 +00:00
|
|
|
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
|
2019-03-15 15:25:24 +00:00
|
|
|
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
|
|
|
|
void zval_set_scalar(zval *zv, cx_double val)
|
|
|
|
{
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
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-14 15:04:34 +00:00
|
|
|
}
|
|
|
|
|
2019-03-25 07:14:53 +00:00
|
|
|
#endif // !PHP_ARMA_COMPLEX_HH
|