// // 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 Z_OBJNAME_P(zval_p) \ ZSTR_VAL(Z_OBJCE_P(zval_p)->name) #define PHP_ARMA_START_ME_1(name, t1) \ template \ struct name##_me \ { \ static constexpr zend_function_entry const val[] = { #define PHP_ARMA_END_ME_1(name, t1) \ PHP_FE_END \ }; \ }; \ template \ constexpr zend_function_entry const name##_me::val[]; #define PHP_ARMA_ME(cls, func, flags, ...) \ ZEND_FENTRY(func, ZEND_MN(cls##_##func<__VA_ARGS__>), nullptr, flags) #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 { /// Helper functions for initializing class entry and object handlers. 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... interfaces) { return ce_init(name, methods, zend_register_internal_class, interfaces...); } template zend_class_entry *interface_register(const char *name) { // Although methods are declared in interfaces as you see in the stubs, // nothing is declared in the internal interface implementation. 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); } zend_always_inline void object_handlers_init(zend_object_handlers *handlers) { memcpy(handlers, &std_object_handlers, sizeof(zend_object_handlers)); } 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; } /// Helper functions for creating objects. 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))); auto handlers = init(obj); auto zobj = to_zend_object(obj); zend_object_std_init(zobj, ce); zobj->handlers = handlers ? handlers : &std_object_handlers; return zobj; } zend_always_inline zend_object *object_create(zend_class_entry *ce, const zend_object_handlers *handlers = &std_object_handlers) { 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 = handlers; return zobj; } /// Helper functions for handling scalar types. template struct false_type : std::false_type {}; template void assert_bad_type() { static_assert(false_type::value, "Type should be zend_long, double or cx_double"); } template 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 const int value = IS_DOUBLE; }; template <> struct scalar_type { static const int value = IS_LONG; }; template 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 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 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; } 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