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

383 lines
10 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 <functional>
#define PHP_ARMA_VERSION "0.0.1"
#if PHP_VERSION_ID >= 70400
#define ZEND_ACC_CTOR 0
#endif
/// Helper macros for method entry.
#define PHP_ARMA_START_ME(cls, ...) \
zend_function_entry cls<__VA_ARGS__>::me[] = {
#define PHP_ARMA_END_ME() \
PHP_FE_END \
}
#define PHP_ARMA_ME(func, flags) \
ZEND_FENTRY(func, zif_##func, nullptr, flags)
#define PHP_ARMA_METHOD(cls, func, ...) \
void ZEND_FASTCALL cls<__VA_ARGS__>::zif_##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)
#define PHP_ARMA_COMMON_DECLARE() \
struct php_name; \
static zend_function_entry me[]
#define PHP_ARMA_NAME_DECLARE(cls, name, ...) \
template <> \
struct cls<__VA_ARGS__>::php_name \
{ \
static constexpr const char val[] = name; \
}
/// Helper macros for parameter parsing.
#ifndef Z_PARAM_DOUBLE_DEREF
#define Z_PARAM_DOUBLE_DEREF(dest) \
Z_PARAM_DOUBLE_EX2(dest, _dummy, 0, 1, 0)
#endif // !Z_PARAM_DOUBLE_DEREF
#ifdef PHP_ARMA_OPERATORS
/// Helper macros for handling operator overloading.
#define PHP_ARMA_OPERATOR_BEGIN(parent_ce) \
{ \
if (instanceof_function(ce, parent_ce)) {
#define PHP_ARMA_OPERATOR_END() \
return false; \
} \
}
#endif // PHP_ARMA_OPERATORS
namespace php_arma
{
extern zend_module_entry module_entry;
/// Helpers for compile-time string concatenation for better module startup performance.
namespace str
{
template <size_t... S>
using seq = std::integer_sequence<size_t, S...>;
template <size_t N>
using seq_impl = std::make_integer_sequence<size_t, N>;
constexpr auto get_len(const char *str)
{
auto i = 0;
for (; *str != 0; ++i, ++str);
return i;
}
template <const char*, typename, const char*, typename>
struct concat_impl;
template <const char* Str1, size_t... Len1, const char* Str2, size_t... Len2>
struct concat_impl<Str1, seq<Len1...>, Str2, seq<Len2...>>
{
static constexpr const char value[]
{
Str1[Len1]..., Str2[Len2]..., 0
};
};
template <const char *Str1, const char *Str2>
constexpr auto concat
{
concat_impl<Str1, seq_impl<get_len(Str1)>, Str2, seq_impl<get_len(Str2)>>::value
};
constexpr const char namespace_prefix[] = "Arma\\";
constexpr const char internal_prefix[] = "Internal\\";
template <const char *Str>
constexpr auto with_arma_prefix
{
concat<namespace_prefix, Str>
};
template <const char *Str>
constexpr auto with_internal_prefix
{
concat<internal_prefix, Str>
};
}
/// Helper functions for initializing class entry and object handlers.
template <const char *Name, typename F>
zend_always_inline
zend_class_entry *ce_init(const zend_function_entry *methods, F init_func)
{
zend_class_entry tmp_ce;
constexpr auto name = str::with_arma_prefix<Name>;
constexpr auto name_len = str::get_len(name);
INIT_CLASS_ENTRY_EX(tmp_ce, name, name_len, methods);
return init_func(&tmp_ce);
}
template <const char *Name, typename F, typename... Ts>
zend_always_inline
zend_class_entry *ce_init(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;
}
template <const char *Name>
zend_always_inline
zend_class_entry *interface_register()
{
// Although methods are declared in interfaces as you see in the stubs,
// nothing is declared in the internal interface implementation.
return ce_init<str::with_internal_prefix<Name>>(nullptr, zend_register_internal_class);
}
template <const char *Name, typename... Ts>
zend_always_inline
zend_class_entry *interface_register(Ts... parents)
{
return ce_init<str::with_internal_prefix<Name>>(nullptr, zend_register_internal_class, parents...);
}
template <const char *Name>
zend_always_inline
zend_class_entry *class_register(zend_class_entry *parent, const zend_function_entry *methods)
{
auto init_func = std::bind(zend_register_internal_class_ex, std::placeholders::_1, parent);
return ce_init<Name>(methods, init_func);
}
template <const char *Name>
zend_always_inline
zend_class_entry *abstract_class_register()
{
auto ce = ce_init<Name>(nullptr, zend_register_internal_class);
ce->ce_flags |= ZEND_ACC_EXPLICIT_ABSTRACT_CLASS;
return ce;
}
template <const char *Name, typename... Ts>
zend_always_inline
zend_class_entry *abstract_class_register(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 object_handlers_init(zend_object_handlers *handlers)
{
memcpy(handlers, &std_object_handlers, sizeof(zend_object_handlers));
}
template <typename T>
zend_always_inline
zend_object *to_zend_object(T *obj)
{
return reinterpret_cast<zend_object*>(obj + 1);
}
template <typename T>
zend_always_inline
T *to_native_object(zend_object *zobj)
{
return reinterpret_cast<T*>(zobj) - 1;
}
/// Helper functions for handling objects.
template <typename T, typename F>
zend_always_inline
zend_object *object_create(zend_class_entry *ce, F init)
{
auto obj = reinterpret_cast<T*>(emalloc(sizeof(T) + sizeof(zend_object) - sizeof(zval)));
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<zend_object*>(emalloc(
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);
}
zend_always_inline
zend_object *object_non_constructible(zend_class_entry *ce)
{
zend_throw_exception_ex(zend_ce_error, -3,
"Class %s is not explicitly constructible.", ZSTR_VAL(ce->name));
return zend_objects_new(ce);
}
/// Helper functions for handling scalar types.
template <typename>
struct false_type : std::false_type {};
template <typename T>
zend_always_inline
constexpr void bad_scalar_type()
{
static_assert(false_type<T>::value, "Type should be zend_long, double or cx_double");
}
template <typename T>
zend_always_inline
bool zval_is_scalar(zval *zv)
{
bad_scalar_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 T>
zend_always_inline
const char *scalar_type_name()
{
bad_scalar_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>
zend_always_inline
T zval_get_scalar(zval *zv)
{
bad_scalar_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>
zend_always_inline
bool zval_check_scalar(zval *zv)
{
if (UNEXPECTED(!zval_is_scalar<T>(zv))) {
ex_bad_type(scalar_type_name<T>(), zval_get_type_name(zv));
return false;
}
return true;
}
}
#endif // !PHP_ARMA_HH