163 lines
5.9 KiB
C++
163 lines
5.9 KiB
C++
//
|
|
// php-armadillo/dense.hh
|
|
//
|
|
// @Author CismonX
|
|
//
|
|
|
|
#ifndef PHP_ARMA_DENSE_HH
|
|
#define PHP_ARMA_DENSE_HH
|
|
|
|
#include "php_arma.hh"
|
|
#include "complex.hh"
|
|
|
|
#define PHP_ARMA_DENSE_OPERATOR_EX2(cls, type, func) \
|
|
PHP_ARMA_OPERATOR_EX2((dense<type, cls<type>>), cls<type>, func)
|
|
|
|
#define PHP_ARMA_DENSE_OPERATOR_EX(cls, func) \
|
|
PHP_ARMA_DENSE_OPERATOR_EX2(cls, double, func) \
|
|
PHP_ARMA_DENSE_OPERATOR_EX2(cls, zend_long, func) \
|
|
PHP_ARMA_DENSE_OPERATOR_EX2(cls, cx_double, func)
|
|
|
|
#define PHP_ARMA_DENSE_OPERATOR(func) \
|
|
PHP_ARMA_OPERATOR_BEGIN(dense_ce) \
|
|
PHP_ARMA_DENSE_OPERATOR_EX(mat, func) \
|
|
PHP_ARMA_DENSE_OPERATOR_EX(subview_mat, func) \
|
|
PHP_ARMA_OPERATOR_END()
|
|
|
|
namespace php_arma
|
|
{
|
|
template <typename T, typename ChildT>
|
|
struct dense
|
|
{
|
|
using native_t = typename ChildT::native_t;
|
|
|
|
struct operators;
|
|
|
|
template <bool IsEq, typename F>
|
|
zend_always_inline
|
|
static bool compare_op(zval *zv1, zval *zv2, zval *return_value, F&& func)
|
|
{
|
|
if (UNEXPECTED(Z_TYPE_P(zv1) != IS_OBJECT) || UNEXPECTED(Z_TYPE_P(zv2) != IS_OBJECT)) {
|
|
throw_exception_ex(zend_ce_type_error, "bad comparison, cannot compare to non-object");
|
|
return false;
|
|
}
|
|
|
|
if constexpr (!IsEq && std::is_same_v<T, cx_double>) {
|
|
throw_error("no such comparison for complex elements");
|
|
return false;
|
|
} else {
|
|
using n_orig_t = typename ChildT::orig_t::native_t;
|
|
using n_subview_t = typename ChildT::subview_t::native_t;
|
|
using dest_t = typename ChildT::with_int_elem_t::orig_t;
|
|
using dest_native_t = typename dest_t::native_t;
|
|
try {
|
|
std::optional<std::invoke_result_t<F, n_orig_t*, n_orig_t*>> ret;
|
|
auto o1 = Z_OBJ_P(zv1);
|
|
auto o2 = Z_OBJ_P(zv2);
|
|
if (Z_OBJCE_P(zv1) == ChildT::orig_t::ce) {
|
|
if (Z_OBJCE_P(zv2) == ChildT::orig_t::ce) {
|
|
ret = func(to_native_object<n_orig_t>(o1), to_native_object<n_orig_t>(o2));
|
|
} else if (EXPECTED(Z_OBJCE_P(zv2) == ChildT::subview_t::ce)) {
|
|
ret = func(to_native_object<n_orig_t>(o1), to_native_object<n_subview_t>(o2));
|
|
} else {
|
|
goto not_orig_or_subview;
|
|
}
|
|
} else if (EXPECTED(Z_OBJCE_P(zv1) == ChildT::subview_t::ce)) {
|
|
if (Z_OBJCE_P(zv2) == ChildT::orig_t::ce) {
|
|
ret = func(to_native_object<n_subview_t>(o1), to_native_object<n_orig_t>(o2));
|
|
} else if (EXPECTED(Z_OBJCE_P(zv2) == ChildT::subview_t::ce)) {
|
|
ret = func(to_native_object<n_subview_t>(o1), to_native_object<n_subview_t>(o2));
|
|
} else {
|
|
goto not_orig_or_subview;
|
|
}
|
|
} else {
|
|
not_orig_or_subview:
|
|
throw_exception_ex(zend_ce_type_error, "bad comparison, object types should be the same");
|
|
return false;
|
|
}
|
|
RETVAL_OBJ(dest_t::create(std::move(arma::conv_to<dest_native_t>::from(*ret))));
|
|
return true;
|
|
} catch (const std::logic_error& err) {
|
|
throw_error(err.what());
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
PHP_ARMA_COMMON_DECLARE();
|
|
|
|
private:
|
|
static PHP_FUNCTION(equals);
|
|
static PHP_FUNCTION(notEquals);
|
|
static PHP_FUNCTION(greaterThan);
|
|
static PHP_FUNCTION(smallerThan);
|
|
static PHP_FUNCTION(notGreaterThan);
|
|
static PHP_FUNCTION(notSmallerThan);
|
|
static PHP_FUNCTION(fill);
|
|
static PHP_FUNCTION(imbue);
|
|
|
|
template <bool, typename F>
|
|
static void compare(INTERNAL_FUNCTION_PARAMETERS, F&&);
|
|
};
|
|
|
|
void dense_init();
|
|
|
|
constexpr const char dense_php_name[] = "Dense";
|
|
|
|
inline zend_class_entry *dense_ce;
|
|
|
|
template <typename T, typename ChildT>
|
|
struct dense<T, ChildT>::operators
|
|
{
|
|
zend_always_inline
|
|
static bool equals(zval *zv1, zval *zv2, zval *retval)
|
|
{
|
|
return compare_op<true>(zv1, zv2, retval, [](auto v1, auto v2) {
|
|
return (*v1 == *v2).eval();
|
|
});
|
|
}
|
|
|
|
zend_always_inline
|
|
static bool not_equals(zval *zv1, zval *zv2, zval *retval)
|
|
{
|
|
return compare_op<true>(zv1, zv2, retval, [](auto v1, auto v2) {
|
|
return (*v1 != *v2).eval();
|
|
});
|
|
}
|
|
|
|
zend_always_inline
|
|
static bool greater_than(zval *zv1, zval *zv2, zval *retval)
|
|
{
|
|
return compare_op<false>(zv1, zv2, retval, [](auto v1, auto v2) {
|
|
return (*v1 > *v2).eval();
|
|
});
|
|
}
|
|
|
|
zend_always_inline
|
|
static bool smaller_than(zval *zv1, zval *zv2, zval *retval)
|
|
{
|
|
return compare_op<false>(zv1, zv2, retval, [](auto v1, auto v2) {
|
|
return (*v1 < *v2).eval();
|
|
});
|
|
}
|
|
|
|
zend_always_inline
|
|
static bool not_greater_than(zval *zv1, zval *zv2, zval *retval)
|
|
{
|
|
return compare_op<false>(zv1, zv2, retval, [](auto v1, auto v2) {
|
|
return (*v1 <= *v2).eval();
|
|
});
|
|
}
|
|
|
|
zend_always_inline
|
|
static bool not_smaller_than(zval *zv1, zval *zv2, zval *retval)
|
|
{
|
|
return compare_op<false>(zv1, zv2, retval, [](auto v1, auto v2) {
|
|
return (*v1 >= *v2).eval();
|
|
});
|
|
}
|
|
};
|
|
}
|
|
|
|
#endif // !PHP_ARMA_DENSE_HH
|