This repository has been archived on 2020-06-07. You can view files and clone it, but cannot push or open issues or pull requests.
php-armadillo/src/php_arma.hh

311 lines
8.8 KiB
C++

//
// php-armadillo/php_arma.hh
//
// @Author CismonX
//
#ifndef PHP_ARMA_HH
#define PHP_ARMA_HH
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <php.h>
#include <zend_exceptions.h>
#include <type_traits>
#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 <typename t1> \
struct name##_me \
{ \
static constexpr zend_function_entry const 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(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 <typename F>
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 <typename F, typename... Ts>
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 <typename>
zend_class_entry *class_register(const char *name, const zend_function_entry *methods)
{
return ce_init(name, methods, zend_register_internal_class);
}
template <typename... Ts>
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 <typename>
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 <typename... Ts>
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 <typename T>
zend_object *to_zend_object(T *obj)
{
return reinterpret_cast<zend_object*>(obj + 1);
}
template <typename T>
T *to_native_object(zend_object *zobj)
{
return reinterpret_cast<T*>(zobj) - 1;
}
/// Helper functions for creating objects.
template <typename T, typename F>
zend_object *object_create(zend_class_entry *ce, F init)
{
auto obj = reinterpret_cast<T*>(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<zend_object*>(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 <typename>
struct false_type : std::false_type {};
template <typename T>
void assert_bad_type()
{
static_assert(false_type<T>::value, "Type should be zend_long, double or cx_double");
}
template <typename T>
bool zval_is_scalar(zval *zv)
{
assert_bad_type<T>();
}
template <> zend_always_inline
bool zval_is_scalar<double>(zval *zv)
{
return Z_TYPE_P(zv) == IS_DOUBLE;
}
template <> zend_always_inline
bool zval_is_scalar<zend_long>(zval *zv)
{
return Z_TYPE_P(zv) == IS_LONG;
}
template <typename>
struct scalar_type {};
template <>
struct scalar_type<double> {
static const int value = IS_DOUBLE;
};
template <>
struct scalar_type<zend_long> {
static const int value = IS_LONG;
};
template <typename T>
const char *scalar_type_name()
{
assert_bad_type<T>();
}
template <> zend_always_inline
const char *scalar_type_name<double>()
{
return zend_get_type_by_const(IS_DOUBLE);
}
template <> zend_always_inline
const char *scalar_type_name<zend_long>()
{
return zend_get_type_by_const(IS_LONG);
}
template <typename T>
T zval_get_scalar(zval *zv)
{
assert_bad_type<T>();
}
template <> zend_always_inline
double zval_get_scalar<double>(zval *zv)
{
return Z_DVAL_P(zv);
}
template <> zend_always_inline
zend_long zval_get_scalar<zend_long>(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 <typename T>
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
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