Fix bugs. Add object handler for `Complex`.
This commit is contained in:
parent
44bd1dbcce
commit
88136e9900
|
@ -1 +1 @@
|
|||
*.h linguist-language=C
|
||||
stubs/* linguist-documentation
|
||||
|
|
|
@ -4,7 +4,7 @@ PHP_ARG_ENABLE(arma, for armadillo support,
|
|||
if test "$PHP_ARMA" != "no"; then
|
||||
PHP_REQUIRE_CXX()
|
||||
ARMA_SRC=" \
|
||||
src/arma.cc \
|
||||
src/php_arma.cc \
|
||||
src/interfaces.cc \
|
||||
src/fill.cc \
|
||||
src/complex.cc"
|
||||
|
|
|
@ -4,15 +4,10 @@
|
|||
// @Author CismonX
|
||||
//
|
||||
|
||||
#include "php_arma.hh"
|
||||
#include "complex.hh"
|
||||
|
||||
namespace php_arma
|
||||
{
|
||||
PHP_ARMA_START_METHOD_ENTRY_1(complex, T)
|
||||
PHP_ARMA_ME_1(Complex, T, __construct, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR)
|
||||
PHP_ARMA_END_METHOD_ENTRY_1(complex, T)
|
||||
|
||||
template <typename T>
|
||||
PHP_METHOD(Complex, __construct)
|
||||
{
|
||||
|
@ -24,7 +19,7 @@ namespace php_arma
|
|||
ZEND_PARSE_PARAMETERS_END();
|
||||
|
||||
auto num_args = EX_NUM_ARGS();
|
||||
auto has_imag = num_args > 1;
|
||||
auto has_imag = num_args == 2;
|
||||
auto has_real = num_args > 0;
|
||||
|
||||
zval zero_val;
|
||||
|
@ -33,10 +28,14 @@ namespace php_arma
|
|||
zval *current = getThis();
|
||||
|
||||
if (EXPECTED(has_real)) {
|
||||
zval_check_scalar<T>(real);
|
||||
if (UNEXPECTED(!zval_check_scalar<T>(real))) {
|
||||
return;
|
||||
};
|
||||
object_set_property(Z_OBJ_P(current), 0, real);
|
||||
if (EXPECTED(has_imag)) {
|
||||
zval_check_scalar<T>(imag);
|
||||
if (UNEXPECTED(!zval_check_scalar<T>(imag))) {
|
||||
return;
|
||||
};
|
||||
object_set_property(Z_OBJ_P(current), 1, imag);
|
||||
} else {
|
||||
object_set_property(Z_OBJ_P(current), 1, &zero_val);
|
||||
|
@ -45,17 +44,54 @@ namespace php_arma
|
|||
object_set_property(Z_OBJ_P(current), 0, &zero_val);
|
||||
object_set_property(Z_OBJ_P(current), 1, &zero_val);
|
||||
}
|
||||
|
||||
Z_OBJ_P(current)->handlers = PHP_ARMA_HANDLERS(complex, T);
|
||||
}
|
||||
|
||||
PHP_ARMA_START_ME_1(complex, T)
|
||||
PHP_ARMA_ME(Complex, __construct, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR, T)
|
||||
PHP_ARMA_END_ME_1(complex, T)
|
||||
|
||||
template <typename T>
|
||||
void complex_write_property(zval* obj, zval* member, zval* value, void** unused)
|
||||
{
|
||||
// Theoretically we won't get non-string values here, add type check just in case.
|
||||
if (UNEXPECTED(Z_TYPE_P(member) != IS_STRING)) {
|
||||
zend_throw_exception(zend_ce_error, "Unexpected error. Please contact developer.", -2);
|
||||
return;
|
||||
}
|
||||
|
||||
if (UNEXPECTED(!zval_check_scalar<T>(value))) {
|
||||
return;
|
||||
};
|
||||
if (strcmp(Z_STRVAL_P(member), "real") == 0) {
|
||||
object_set_property(Z_OBJ_P(obj), 0, value);
|
||||
return;
|
||||
}
|
||||
if (strcmp(Z_STRVAL_P(member), "imag") == 0) {
|
||||
object_set_property(Z_OBJ_P(obj), 1, value);
|
||||
return;
|
||||
}
|
||||
|
||||
zend_throw_exception_ex(zend_ce_exception, -2,
|
||||
"Bad property name for %s, expected 'real' or 'imag', '%s' given.", Z_OBJNAME_P(obj), Z_STRVAL_P(member));
|
||||
}
|
||||
|
||||
void complex_init()
|
||||
{
|
||||
complex_ce = interface_register("Complex");
|
||||
|
||||
cx_double_ce = class_register("CxDouble", PHP_ARMA_METHOD_1(complex, double), complex_ce);
|
||||
property_declare(cx_double_ce, "real");
|
||||
property_declare(cx_double_ce, "imag");
|
||||
PHP_ARMA_CE(complex, double) = class_register("CxDouble", PHP_ARMA_METHODS(complex, double), complex_ce);
|
||||
property_declare(PHP_ARMA_CE(complex, double), "real");
|
||||
property_declare(PHP_ARMA_CE(complex, double), "imag");
|
||||
object_handlers_init(PHP_ARMA_HANDLERS(complex, double));
|
||||
PHP_ARMA_HANDLER_SET(complex, write_property, complex_write_property, double);
|
||||
}
|
||||
|
||||
|
||||
zend_class_entry *complex_ce;
|
||||
zend_class_entry *cx_double_ce;
|
||||
|
||||
template <typename T>
|
||||
PHP_ARMA_DEFINE_CE(complex, T);
|
||||
template <typename T>
|
||||
PHP_ARMA_DEFINE_OBJECT_HANDLER(complex, T);
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
#ifndef PHP_ARMA_COMPLEX_HH
|
||||
#define PHP_ARMA_COMPLEX_HH
|
||||
|
||||
#include <php.h>
|
||||
#include "php_arma.hh"
|
||||
|
||||
namespace php_arma
|
||||
{
|
||||
|
@ -17,7 +17,21 @@ namespace php_arma
|
|||
void complex_init();
|
||||
|
||||
extern zend_class_entry *complex_ce;
|
||||
extern zend_class_entry *cx_double_ce;
|
||||
|
||||
template <typename T>
|
||||
PHP_ARMA_DECLARE_CE_HANDLERS(complex);
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
template <> zend_always_inline
|
||||
const char *scalar_type_name<cx_double>()
|
||||
{
|
||||
return ZSTR_VAL(PHP_ARMA_CE(complex, double)->name);
|
||||
}
|
||||
}
|
||||
|
||||
#endif //!PHP_ARMA_COMPLEX_HH
|
||||
|
|
|
@ -11,8 +11,6 @@
|
|||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "complex.hh"
|
||||
|
||||
#include <php.h>
|
||||
#include <zend_exceptions.h>
|
||||
#include <complex>
|
||||
|
@ -27,26 +25,59 @@ extern zend_module_entry arma_module_entry;
|
|||
|
||||
typedef std::complex<double> cx_double;
|
||||
|
||||
/// Helper functions.
|
||||
/// Helper macros for method entry.
|
||||
|
||||
#define PHP_ARMA_START_METHOD_ENTRY_1(name, t1) \
|
||||
template <typename t1> \
|
||||
struct name##_methods \
|
||||
{ \
|
||||
#define Z_OBJNAME_P(zval_p) \
|
||||
ZSTR_VAL(Z_OBJCE_P(zval_p)->name)
|
||||
|
||||
#define PHP_ARMA_START_ME_1(name, t1) \
|
||||
template <typename t1> \
|
||||
struct name##_me \
|
||||
{ \
|
||||
static constexpr zend_function_entry const val[] = {
|
||||
|
||||
#define PHP_ARMA_END_METHOD_ENTRY_1(name, t1) \
|
||||
PHP_FE_END \
|
||||
}; \
|
||||
}; \
|
||||
template <typename t1> \
|
||||
constexpr zend_function_entry const name##_methods<t1>::val[];
|
||||
#define PHP_ARMA_END_ME_1(name, t1) \
|
||||
PHP_FE_END \
|
||||
}; \
|
||||
}; \
|
||||
template <typename t1> \
|
||||
constexpr zend_function_entry const name##_me<t1>::val[];
|
||||
|
||||
#define PHP_ARMA_ME_1(cls, t1, name, flags) \
|
||||
ZEND_FENTRY(name, ZEND_MN(cls##_##name<t1>), nullptr, flags)
|
||||
#define PHP_ARMA_ME(cls, func, flags, ...) \
|
||||
ZEND_FENTRY(func, ZEND_MN(cls##_##func<__VA_ARGS__>), nullptr, flags)
|
||||
|
||||
#define PHP_ARMA_METHOD_1(name, t1) \
|
||||
name##_methods<t1>::val
|
||||
#define PHP_ARMA_METHODS(name, ...) \
|
||||
name##_me<__VA_ARGS__>::val
|
||||
|
||||
/// Helper macros for class entry and object handlers
|
||||
|
||||
#define PHP_ARMA_DECLARE_CE(name) \
|
||||
struct name##_components \
|
||||
{ \
|
||||
static zend_class_entry *ce; \
|
||||
}
|
||||
|
||||
#define PHP_ARMA_DECLARE_CE_HANDLERS(name) \
|
||||
struct name##_components \
|
||||
{ \
|
||||
static zend_class_entry *ce; \
|
||||
static zend_object_handlers handlers; \
|
||||
}
|
||||
|
||||
#define PHP_ARMA_DEFINE_CE(name, ...) \
|
||||
zend_class_entry *name##_components<__VA_ARGS__>::ce
|
||||
|
||||
#define PHP_ARMA_DEFINE_OBJECT_HANDLER(name, ...) \
|
||||
zend_object_handlers name##_components<__VA_ARGS__>::handlers
|
||||
|
||||
#define PHP_ARMA_CE(name, ...) \
|
||||
name##_components<__VA_ARGS__>::ce
|
||||
|
||||
#define PHP_ARMA_HANDLERS(name, ...) \
|
||||
&name##_components<__VA_ARGS__>::handlers
|
||||
|
||||
#define PHP_ARMA_HANDLER_SET(name, handler, func, ...) \
|
||||
(PHP_ARMA_HANDLERS(name, __VA_ARGS__))->handler = func<__VA_ARGS__>
|
||||
|
||||
namespace php_arma
|
||||
{
|
||||
|
@ -107,6 +138,12 @@ namespace php_arma
|
|||
zend_declare_property_null(ce, name, strlen(name), ZEND_ACC_PUBLIC);
|
||||
}
|
||||
|
||||
zend_always_inline
|
||||
void object_handlers_init(zend_object_handlers *handlers)
|
||||
{
|
||||
memcpy(handlers, &std_object_handlers, sizeof(zend_object_handlers));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
zend_object *to_zend_object(T *obj)
|
||||
{
|
||||
|
@ -125,10 +162,10 @@ namespace php_arma
|
|||
{
|
||||
auto obj = reinterpret_cast<T*>(ecalloc(1,
|
||||
sizeof(T) + sizeof(zend_object) + zend_object_properties_size(ce)));
|
||||
init(obj);
|
||||
auto handlers = init(obj);
|
||||
auto zobj = to_zend_object(obj);
|
||||
zend_object_std_init(zobj, ce);
|
||||
zobj->handlers = &std_object_handlers;
|
||||
zobj->handlers = handlers ? handlers : &std_object_handlers;
|
||||
return zobj;
|
||||
}
|
||||
|
||||
|
@ -192,12 +229,6 @@ namespace php_arma
|
|||
return Z_TYPE_P(zv) == IS_LONG;
|
||||
}
|
||||
|
||||
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), cx_double_ce);
|
||||
}
|
||||
|
||||
template <typename>
|
||||
struct scalar_type {};
|
||||
|
||||
|
@ -234,12 +265,6 @@ namespace php_arma
|
|||
return zend_get_type_by_const(IS_LONG);
|
||||
}
|
||||
|
||||
template <> zend_always_inline
|
||||
const char *scalar_type_name<cx_double>()
|
||||
{
|
||||
return ZSTR_VAL(cx_double_ce->name);
|
||||
}
|
||||
|
||||
zend_always_inline
|
||||
const char *zval_get_type_name(zval *zv)
|
||||
{
|
||||
|
@ -253,15 +278,17 @@ namespace php_arma
|
|||
zend_always_inline
|
||||
void ex_bad_type(const char *expected, const char *got)
|
||||
{
|
||||
zend_throw_exception_ex(zend_ce_type_error, -1, "Bad type. Expected %s, got %s.", expected, got);
|
||||
zend_throw_exception_ex(zend_ce_type_error, -1, "Bad type, expected %s, %s given.", expected, got);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void zval_check_scalar(zval *zv)
|
||||
bool zval_check_scalar(zval *zv)
|
||||
{
|
||||
if (!zval_is_scalar<T>(zv)) {
|
||||
ex_bad_type(scalar_type_name<T>(), zval_get_type_name(zv));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
zend_always_inline
|
||||
|
|
Reference in New Issue