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/arma.hh

276 lines
7.3 KiB
C++
Raw Normal View History

//
// 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