// // php-armadillo/dense.hh // // @Author CismonX // #ifndef PHP_ARMA_DENSE_HH #define PHP_ARMA_DENSE_HH #include "php_arma.hh" #include "complex.hh" #ifdef PHP_ARMA_OPERATORS #define PHP_ARMA_DENSE_OPERATOR_EX2(cls, type, func) \ PHP_ARMA_OPERATOR_EX2((dense>), cls, 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() #endif // PHP_ARMA_OPERATORS namespace php_arma { template struct dense { using native_t = typename ChildT::native_t; struct operators; template 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) { 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> 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(o1), to_native_object(o2)); } else if (EXPECTED(Z_OBJCE_P(zv2) == ChildT::subview_t::ce)) { ret = func(to_native_object(o1), to_native_object(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(o1), to_native_object(o2)); } else if (EXPECTED(Z_OBJCE_P(zv2) == ChildT::subview_t::ce)) { ret = func(to_native_object(o1), to_native_object(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::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 static void compare(INTERNAL_FUNCTION_PARAMETERS, F&&); }; void dense_init(); constexpr const char dense_php_name[] = "Dense"; inline zend_class_entry *dense_ce; template struct dense::operators { zend_always_inline static bool equals(zval *zv1, zval *zv2, zval *retval) { return compare_op(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(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(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(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(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(zv1, zv2, retval, [](auto v1, auto v2) { return (*v1 >= *v2).eval(); }); } }; } #endif // !PHP_ARMA_DENSE_HH