// // php-armadillo/php_arma.hh // // @Author CismonX // #ifndef PHP_ARMA_HH #define PHP_ARMA_HH #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #define PHP_ARMA_VERSION "0.0.1" #if PHP_VERSION_ID >= 70400 #define ZEND_ACC_CTOR 0 #endif extern zend_module_entry arma_module_entry; /// Helper macros for method entry. #define PHP_ARMA_START_ME() \ static constexpr zend_function_entry const me[] = { #define PHP_ARMA_END_ME() \ PHP_FE_END \ } #define PHP_ARMA_ME(func, flags) \ ZEND_FENTRY(func, func, nullptr, flags) #define PHP_ARMA_METHODS(cls, ...) \ cls<__VA_ARGS__>::me #define PHP_ARMA_FUNCTION(cls, func, ...) \ void ZEND_FASTCALL cls<__VA_ARGS__>::func(INTERNAL_FUNCTION_PARAMETERS) /// Helper macros for class entry and object handlers #define PHP_ARMA_CE_HANDLRES_DECLARE() \ static inline zend_class_entry *ce; \ static inline zend_object_handlers handlers #define PHP_ARMA_CE(cls, ...) \ cls<__VA_ARGS__>::ce #define PHP_ARMA_HANDLERS(cls, ...) \ &cls<__VA_ARGS__>::handlers #define Z_OBJNAME_P(zval_p) \ ZSTR_VAL(Z_OBJCE_P(zval_p)->name) namespace php_arma { /// Helper functions for initializing class entry and object handlers. template zend_always_inline zend_class_entry *ce_init(const char *name, const zend_function_entry *methods, F init_func) { char full_name[40] = { "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_always_inline zend_class_entry *ce_init(const char *name, const zend_function_entry *methods, F init_func, Ts... interfaces) { auto ce = ce_init(name, methods, init_func); zend_class_implements(ce, sizeof...(Ts), interfaces...); return ce; } zend_always_inline zend_class_entry *class_register(const char *name, zend_class_entry *parent, const zend_function_entry *methods) { using std::placeholders::_1; return ce_init(name, methods, std::bind(zend_register_internal_class_ex, _1, parent)); } zend_always_inline zend_class_entry *abstract_class_register(const char *name) { auto ce = ce_init(name, nullptr, zend_register_internal_class); ce->ce_flags |= ZEND_ACC_EXPLICIT_ABSTRACT_CLASS; return ce; } template zend_always_inline zend_class_entry *abstract_class_register(const char *name, Ts... interfaces) { auto ce = ce_init(name, nullptr, zend_register_internal_class, interfaces...); ce->ce_flags |= ZEND_ACC_EXPLICIT_ABSTRACT_CLASS; return ce; } zend_always_inline void property_declare(zend_class_entry *ce, const char *name) { 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 zend_always_inline zend_object *to_zend_object(T *obj) { return reinterpret_cast(obj + 1); } template zend_always_inline T *to_native_object(zend_object *zobj) { return reinterpret_cast(zobj) - 1; } /// Helper functions for handling objects. template zend_always_inline 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))); auto zobj = to_zend_object(obj); zobj->handlers = init(obj); zend_object_std_init(zobj, ce); return zobj; } zend_always_inline zend_object *object_create(zend_class_entry *ce, const zend_object_handlers *handlers) { auto zobj = reinterpret_cast(ecalloc(1, sizeof(zend_object) + zend_object_properties_size(ce))); zobj->handlers = handlers; zend_object_std_init(zobj, ce); object_properties_init(zobj, ce); return zobj; } 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); } /// Helper functions for handling scalar types. template struct false_type : std::false_type {}; template zend_always_inline void assert_bad_type() { static_assert(false_type::value, "Type should be zend_long, double or cx_double"); } template zend_always_inline bool zval_is_scalar(zval *zv) { assert_bad_type(); } 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 struct scalar_type {}; template <> struct scalar_type { static constexpr auto value = IS_DOUBLE; }; template <> struct scalar_type { static constexpr auto value = IS_LONG; }; template zend_always_inline const char *scalar_type_name() { assert_bad_type(); } 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 T zval_get_scalar(zval *zv) { assert_bad_type(); } 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); } 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); } 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)); } } /// Helper functions for throwing exceptions when errors occur. 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, %s given.", expected, got); } template zend_always_inline bool zval_check_scalar(zval *zv) { if (!zval_is_scalar(zv)) { ex_bad_type(scalar_type_name(), zval_get_type_name(zv)); return false; } return true; } } #endif // !PHP_ARMA_HH