// // php-armadillo/php_arma.hh // // @Author CismonX // #ifndef PHP_ARMA_HH #define PHP_ARMA_HH #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "complex.hh" #include #include #include #if PHP_VERSION_ID >= 70400 #define ZEND_ACC_CTOR 0 #endif extern zend_module_entry arma_module_entry; #define PHP_ARMA_VERSION "0.0.1" typedef std::complex cx_double; /// Helper functions. #define PHP_ARMA_START_METHOD_ENTRY_1(name, t1) \ template \ struct name##_methods \ { \ static constexpr zend_function_entry const val[] = { #define PHP_ARMA_END_METHOD_ENTRY_1(name, t1) \ PHP_FE_END \ }; \ }; \ template \ constexpr zend_function_entry const name##_methods::val[]; #define PHP_ARMA_ME_1(cls, t1, name, flags) \ ZEND_FENTRY(name, ZEND_MN(cls##_##name), nullptr, flags) #define PHP_ARMA_METHOD_1(name, t1) \ name##_methods::val namespace php_arma { template zend_class_entry *ce_init(const char *name, const zend_function_entry *methods, F init_func) { char full_name[30] = { "Arma\\" }; strcat(full_name, name); zend_class_entry tmp_ce; INIT_CLASS_ENTRY_EX(tmp_ce, full_name, strlen(full_name), methods); return init_func(&tmp_ce); } template zend_class_entry *ce_init(const char *name, const zend_function_entry *methods, F init_func, Ts... parents) { auto ce = ce_init(name, methods, init_func); zend_class_implements(ce, sizeof...(Ts), parents...); return ce; } template zend_class_entry *class_register(const char *name, const zend_function_entry *methods) { return ce_init(name, methods, zend_register_internal_class); } template zend_class_entry *class_register(const char *name, const zend_function_entry *methods, Ts... parents) { return ce_init(name, methods, zend_register_internal_class, parents...); } // Although methods are declared in interfaces as you see in the stubs, // nothing is declared in the internal interface implementation. template zend_class_entry *interface_register(const char *name) { return ce_init(name, nullptr, zend_register_internal_class); } template zend_class_entry *interface_register(const char *name, Ts... parents) { return ce_init(name, nullptr, zend_register_internal_class, parents...); } zend_always_inline void const_declare(zend_class_entry *ce, const char *name, zend_long val) { zend_declare_class_constant_long(ce, name, strlen(name), val); } zend_always_inline void property_declare(zend_class_entry *ce, const char *name) { zend_declare_property_null(ce, name, strlen(name), ZEND_ACC_PUBLIC); } template zend_object *to_zend_object(T *obj) { return reinterpret_cast(obj + 1); } template T *to_native_object(zend_object* zobj) { return reinterpret_cast(zobj) - 1; } /// Create a zend_object which wraps a native object. template zend_object *object_create(zend_class_entry *ce, F init) { auto obj = reinterpret_cast(ecalloc(1, sizeof(T) + sizeof(zend_object) + zend_object_properties_size(ce))); init(obj); auto zobj = to_zend_object(obj); zend_object_std_init(zobj, ce); zobj->handlers = &std_object_handlers; return zobj; } /// Create a normal zend_object. template zend_object *object_create(zend_class_entry *ce) { auto zobj = reinterpret_cast(ecalloc(1, sizeof(zend_object) + zend_object_properties_size(ce))); zend_object_std_init(zobj, ce); object_properties_init(zobj, ce); zobj->handlers = &std_object_handlers; return zobj; } zend_always_inline void zval_set_scalar(zval *zv, double val) { ZVAL_DOUBLE(zv, val); } zend_always_inline void zval_set_scalar(zval *zv, zend_long val) { ZVAL_LONG(zv, val); } template T zval_get_scalar(zval *zv) { assert(false); } template <> zend_always_inline double zval_get_scalar(zval *zv) { return Z_DVAL_P(zv); } template <> zend_always_inline zend_long zval_get_scalar(zval *zv) { return Z_LVAL_P(zv); } template bool zval_is_scalar(zval *zv) { assert(false); } template <> zend_always_inline bool zval_is_scalar(zval *zv) { return Z_TYPE_P(zv) == IS_DOUBLE; } template <> zend_always_inline bool zval_is_scalar(zval *zv) { return Z_TYPE_P(zv) == IS_LONG; } template <> zend_always_inline bool zval_is_scalar(zval *zv) { return Z_TYPE_P(zv) == IS_OBJECT && instanceof_function(Z_OBJCE_P(zv), cx_double_ce); } template struct scalar_type {}; template <> struct scalar_type { static const int value = IS_DOUBLE; }; template <> struct scalar_type { static const int value = IS_LONG; }; template <> struct scalar_type { static const int value = IS_OBJECT; }; template const char *scalar_type_name() { assert(false); } template <> zend_always_inline const char *scalar_type_name() { return zend_get_type_by_const(IS_DOUBLE); } template <> zend_always_inline const char *scalar_type_name() { return zend_get_type_by_const(IS_LONG); } template <> zend_always_inline const char *scalar_type_name() { return ZSTR_VAL(cx_double_ce->name); } zend_always_inline const char *zval_get_type_name(zval *zv) { if (Z_TYPE_P(zv) == IS_OBJECT) { return ZSTR_VAL(Z_OBJCE_P(zv)->name); } else { return zend_get_type_by_const(Z_TYPE_P(zv)); } } 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); } template void zval_check_scalar(zval *zv) { if (!zval_is_scalar(zv)) { ex_bad_type(scalar_type_name(), zval_get_type_name(zv)); } } zend_always_inline void object_set_property(zend_object *obj, size_t idx, zval *val) { zval_ptr_dtor(OBJ_PROP_NUM(obj, idx)); ZVAL_COPY(OBJ_PROP_NUM(obj, idx), val); } } #endif // !PHP_ARMA_HH