276 lines
7.3 KiB
C++
276 lines
7.3 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 "complex.hh"
|
||
|
|
||
|
#include <php.h>
|
||
|
#include <zend_exceptions.h>
|
||
|
#include <complex>
|
||
|
|
||
|
#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<double> cx_double;
|
||
|
|
||
|
/// Helper functions.
|
||
|
|
||
|
#define PHP_ARMA_START_METHOD_ENTRY_1(name, t1) \
|
||
|
template <typename t1> \
|
||
|
struct name##_methods \
|
||
|
{ \
|
||
|
static constexpr zend_function_entry const val[] = {
|
||
|
|
||
|
#define PHP_ARMA_END_METHOD_ENTRY_1(name, t1) \
|
||
|
PHP_FE_END \
|
||
|
}; \
|
||
|
}; \
|
||
|
template <typename t1> \
|
||
|
constexpr zend_function_entry const name##_methods<t1>::val[];
|
||
|
|
||
|
#define PHP_ARMA_ME_1(cls, t1, name, flags) \
|
||
|
ZEND_FENTRY(name, ZEND_MN(cls##_##name<t1>), nullptr, flags)
|
||
|
|
||
|
#define PHP_ARMA_METHOD_1(name, t1) \
|
||
|
name##_methods<t1>::val
|
||
|
|
||
|
namespace php_arma
|
||
|
{
|
||
|
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... 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 <typename>
|
||
|
zend_class_entry *interface_register(const char *name)
|
||
|
{
|
||
|
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);
|
||
|
}
|
||
|
|
||
|
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;
|
||
|
}
|
||
|
|
||
|
/// Create a zend_object which wraps a native object.
|
||
|
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)));
|
||
|
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 <typename T>
|
||
|
zend_object *object_create(zend_class_entry *ce)
|
||
|
{
|
||
|
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 = &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 <typename T>
|
||
|
T zval_get_scalar(zval *zv)
|
||
|
{
|
||
|
assert(false);
|
||
|
}
|
||
|
|
||
|
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);
|
||
|
}
|
||
|
|
||
|
template <typename>
|
||
|
bool zval_is_scalar(zval *zv)
|
||
|
{
|
||
|
assert(false);
|
||
|
}
|
||
|
|
||
|
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 <> zend_always_inline
|
||
|
bool zval_is_scalar<cx_double>(zval *zv)
|
||
|
{
|
||
|
return Z_TYPE_P(zv) == IS_OBJECT && instanceof_function(Z_OBJCE_P(zv), cx_double_ce);
|
||
|
}
|
||
|
|
||
|
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 <>
|
||
|
struct scalar_type<cx_double> {
|
||
|
static const int value = IS_OBJECT;
|
||
|
};
|
||
|
|
||
|
template <typename>
|
||
|
const char *scalar_type_name()
|
||
|
{
|
||
|
assert(false);
|
||
|
}
|
||
|
|
||
|
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 <> zend_always_inline
|
||
|
const char *scalar_type_name<cx_double>()
|
||
|
{
|
||
|
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 <typename T>
|
||
|
void zval_check_scalar(zval *zv)
|
||
|
{
|
||
|
if (!zval_is_scalar<T>(zv)) {
|
||
|
ex_bad_type(scalar_type_name<T>(), 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
|