From 2566e8f44ea606ad9f203f88f41d31685d83dcc2 Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Sat, 11 May 2013 18:33:37 +0200 Subject: [PATCH 01/11] Implement operator overloading and improve GMP --- Zend/zend_object_handlers.c | 1 + Zend/zend_object_handlers.h | 4 +- Zend/zend_operators.c | 104 +++++ Zend/zend_operators.h | 28 +- ext/gmp/gmp.c | 740 ++++++++++++++++++++++----------- ext/gmp/tests/004.phpt | 4 +- ext/gmp/tests/005.phpt | 2 +- ext/gmp/tests/006.phpt | 10 +- ext/gmp/tests/007.phpt | 142 ++++--- ext/gmp/tests/008.phpt | 2 +- ext/gmp/tests/009.phpt | 82 ++-- ext/gmp/tests/010.phpt | 10 +- ext/gmp/tests/014.phpt | 7 +- ext/gmp/tests/016.phpt | 5 +- ext/gmp/tests/033.phpt | 6 +- ext/gmp/tests/034.phpt | 2 +- ext/gmp/tests/040.phpt | 5 +- ext/gmp/tests/cast.phpt | 22 + ext/gmp/tests/clone.phpt | 22 + ext/gmp/tests/overloading.phpt | 225 ++++++++++ ext/gmp/tests/serialize.phpt | 22 + 21 files changed, 1078 insertions(+), 367 deletions(-) create mode 100644 ext/gmp/tests/cast.phpt create mode 100644 ext/gmp/tests/clone.phpt create mode 100644 ext/gmp/tests/overloading.phpt create mode 100644 ext/gmp/tests/serialize.phpt diff --git a/Zend/zend_object_handlers.c b/Zend/zend_object_handlers.c index 92c67c3436d4..24d4a85f79c8 100644 --- a/Zend/zend_object_handlers.c +++ b/Zend/zend_object_handlers.c @@ -1643,6 +1643,7 @@ ZEND_API zend_object_handlers std_object_handlers = { NULL, /* get_debug_info */ zend_std_get_closure, /* get_closure */ zend_std_get_gc, /* get_gc */ + NULL, /* do_operation */ }; /* diff --git a/Zend/zend_object_handlers.h b/Zend/zend_object_handlers.h index 3ea6008350d2..b8580300c087 100644 --- a/Zend/zend_object_handlers.h +++ b/Zend/zend_object_handlers.h @@ -113,6 +113,8 @@ typedef int (*zend_object_get_closure_t)(zval *obj, zend_class_entry **ce_ptr, u typedef HashTable *(*zend_object_get_gc_t)(zval *object, zval ***table, int *n TSRMLS_DC); +typedef int (*zend_object_do_operation_t)(zend_uchar opcode, zval *result, zval *op1, zval *op2 TSRMLS_DC); + struct _zend_object_handlers { /* general object functions */ zend_object_add_ref_t add_ref; @@ -142,6 +144,7 @@ struct _zend_object_handlers { zend_object_get_debug_info_t get_debug_info; zend_object_get_closure_t get_closure; zend_object_get_gc_t get_gc; + zend_object_do_operation_t do_operation; }; extern ZEND_API zend_object_handlers std_object_handlers; @@ -172,7 +175,6 @@ ZEND_API int zend_check_protected(zend_class_entry *ce, zend_class_entry *scope) ZEND_API int zend_check_property_access(zend_object *zobj, const char *prop_info_name, int prop_info_name_len TSRMLS_DC); ZEND_API void zend_std_call_user_call(INTERNAL_FUNCTION_PARAMETERS); -END_EXTERN_C() #endif diff --git a/Zend/zend_operators.c b/Zend/zend_operators.c index c8b868d16a80..6cb8f6adc404 100644 --- a/Zend/zend_operators.c +++ b/Zend/zend_operators.c @@ -857,6 +857,10 @@ ZEND_API int add_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ * default: if (!converted) { + if (zend_object_do_operation(ZEND_ADD, result, op1, op2 TSRMLS_CC) == SUCCESS) { + return SUCCESS; + } + zendi_convert_scalar_to_number(op1, op1_copy, result); zendi_convert_scalar_to_number(op2, op2_copy, result); converted = 1; @@ -904,6 +908,10 @@ ZEND_API int sub_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ * default: if (!converted) { + if (zend_object_do_operation(ZEND_SUB, result, op1, op2 TSRMLS_CC) == SUCCESS) { + return SUCCESS; + } + zendi_convert_scalar_to_number(op1, op1_copy, result); zendi_convert_scalar_to_number(op2, op2_copy, result); converted = 1; @@ -945,6 +953,10 @@ ZEND_API int mul_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ * default: if (!converted) { + if (zend_object_do_operation(ZEND_MUL, result, op1, op2 TSRMLS_CC) == SUCCESS) { + return SUCCESS; + } + zendi_convert_scalar_to_number(op1, op1_copy, result); zendi_convert_scalar_to_number(op2, op2_copy, result); converted = 1; @@ -1010,6 +1022,10 @@ ZEND_API int div_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ * default: if (!converted) { + if (zend_object_do_operation(ZEND_DIV, result, op1, op2 TSRMLS_CC) == SUCCESS) { + return SUCCESS; + } + zendi_convert_scalar_to_number(op1, op1_copy, result); zendi_convert_scalar_to_number(op2, op2_copy, result); converted = 1; @@ -1026,6 +1042,10 @@ ZEND_API int mod_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ * { zval op1_copy, op2_copy; long op1_lval; + + if (zend_object_do_operation(ZEND_MOD, result, op1, op2 TSRMLS_CC) == SUCCESS) { + return SUCCESS; + } zendi_convert_to_long(op1, op1_copy, result); op1_lval = Z_LVAL_P(op1); @@ -1053,6 +1073,10 @@ ZEND_API int boolean_xor_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) zval op1_copy, op2_copy; long op1_lval; + if (zend_object_do_operation(ZEND_BOOL_XOR, result, op1, op2 TSRMLS_CC) == SUCCESS) { + return SUCCESS; + } + zendi_convert_to_boolean(op1, op1_copy, result); op1_lval = Z_LVAL_P(op1); zendi_convert_to_boolean(op2, op2_copy, result); @@ -1065,6 +1089,10 @@ ZEND_API int boolean_not_function(zval *result, zval *op1 TSRMLS_DC) /* {{{ */ { zval op1_copy; + if (zend_object_do_operation(ZEND_BOOL_NOT, result, op1, NULL TSRMLS_CC) == SUCCESS) { + return SUCCESS; + } + zendi_convert_to_boolean(op1, op1_copy, result); ZVAL_BOOL(result, !Z_LVAL_P(op1)); return SUCCESS; @@ -1075,6 +1103,10 @@ ZEND_API int bitwise_not_function(zval *result, zval *op1 TSRMLS_DC) /* {{{ */ { zval op1_copy = *op1; + if (zend_object_do_operation(ZEND_BW_NOT, result, op1, NULL TSRMLS_CC) == SUCCESS) { + return SUCCESS; + } + op1 = &op1_copy; if (Z_TYPE_P(op1) == IS_LONG) { @@ -1130,6 +1162,11 @@ ZEND_API int bitwise_or_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) / Z_STRLEN_P(result) = result_len; return SUCCESS; } + + if (zend_object_do_operation(ZEND_BW_OR, result, op1, op2 TSRMLS_CC) == SUCCESS) { + return SUCCESS; + } + zendi_convert_to_long(op1, op1_copy, result); op1_lval = Z_LVAL_P(op1); zendi_convert_to_long(op2, op2_copy, result); @@ -1171,6 +1208,9 @@ ZEND_API int bitwise_and_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) return SUCCESS; } + if (zend_object_do_operation(ZEND_BW_AND, result, op1, op2 TSRMLS_CC) == SUCCESS) { + return SUCCESS; + } zendi_convert_to_long(op1, op1_copy, result); op1_lval = Z_LVAL_P(op1); @@ -1213,6 +1253,10 @@ ZEND_API int bitwise_xor_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) return SUCCESS; } + if (zend_object_do_operation(ZEND_BW_XOR, result, op1, op2 TSRMLS_CC) == SUCCESS) { + return SUCCESS; + } + zendi_convert_to_long(op1, op1_copy, result); op1_lval = Z_LVAL_P(op1); zendi_convert_to_long(op2, op2_copy, result); @@ -1227,6 +1271,10 @@ ZEND_API int shift_left_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) / zval op1_copy, op2_copy; long op1_lval; + if (zend_object_do_operation(ZEND_SL, result, op1, op2 TSRMLS_CC) == SUCCESS) { + return SUCCESS; + } + zendi_convert_to_long(op1, op1_copy, result); op1_lval = Z_LVAL_P(op1); zendi_convert_to_long(op2, op2_copy, result); @@ -1240,6 +1288,10 @@ ZEND_API int shift_right_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) zval op1_copy, op2_copy; long op1_lval; + if (zend_object_do_operation(ZEND_SR, result, op1, op2 TSRMLS_CC) == SUCCESS) { + return SUCCESS; + } + zendi_convert_to_long(op1, op1_copy, result); op1_lval = Z_LVAL_P(op1); zendi_convert_to_long(op2, op2_copy, result); @@ -1291,6 +1343,10 @@ ZEND_API int concat_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{ zval op1_copy, op2_copy; int use_copy1 = 0, use_copy2 = 0; + if (zend_object_do_operation(ZEND_CONCAT, result, op1, op2 TSRMLS_CC) == SUCCESS) { + return SUCCESS; + } + if (Z_TYPE_P(op1) != IS_STRING) { zend_make_printable_zval(op1, &op1_copy, &use_copy1); } @@ -1693,9 +1749,14 @@ ZEND_API int is_not_identical_function(zval *result, zval *op1, zval *op2 TSRMLS ZEND_API int is_equal_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */ { + if (zend_object_do_operation(ZEND_IS_EQUAL, result, op1, op2 TSRMLS_CC) == SUCCESS) { + return SUCCESS; + } + if (compare_function(result, op1, op2 TSRMLS_CC) == FAILURE) { return FAILURE; } + ZVAL_BOOL(result, (Z_LVAL_P(result) == 0)); return SUCCESS; } @@ -1703,9 +1764,14 @@ ZEND_API int is_equal_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* ZEND_API int is_not_equal_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */ { + if (zend_object_do_operation(ZEND_IS_NOT_EQUAL, result, op1, op2 TSRMLS_CC) == SUCCESS) { + return SUCCESS; + } + if (compare_function(result, op1, op2 TSRMLS_CC) == FAILURE) { return FAILURE; } + ZVAL_BOOL(result, (Z_LVAL_P(result) != 0)); return SUCCESS; } @@ -1713,9 +1779,14 @@ ZEND_API int is_not_equal_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) ZEND_API int is_smaller_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */ { + if (zend_object_do_operation(ZEND_IS_SMALLER, result, op1, op2 TSRMLS_CC) == SUCCESS) { + return SUCCESS; + } + if (compare_function(result, op1, op2 TSRMLS_CC) == FAILURE) { return FAILURE; } + ZVAL_BOOL(result, (Z_LVAL_P(result) < 0)); return SUCCESS; } @@ -1723,9 +1794,14 @@ ZEND_API int is_smaller_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) / ZEND_API int is_smaller_or_equal_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */ { + if (zend_object_do_operation(ZEND_IS_SMALLER_OR_EQUAL, result, op1, op2 TSRMLS_CC) == SUCCESS) { + return SUCCESS; + } + if (compare_function(result, op1, op2 TSRMLS_CC) == FAILURE) { return FAILURE; } + ZVAL_BOOL(result, (Z_LVAL_P(result) <= 0)); return SUCCESS; } @@ -1890,6 +1966,20 @@ ZEND_API int increment_function(zval *op1) /* {{{ */ } } break; + case IS_OBJECT: + if (Z_OBJ_HANDLER_P(op1, do_operation)) { + zval *op2; + int res; + TSRMLS_FETCH(); + + MAKE_STD_ZVAL(op2); + ZVAL_LONG(op2, 1); + res = Z_OBJ_HANDLER_P(op1, do_operation)(ZEND_ADD, op1, op1, op2 TSRMLS_CC); + zval_ptr_dtor(&op2); + + return res; + } + return FAILURE; default: return FAILURE; } @@ -1936,6 +2026,20 @@ ZEND_API int decrement_function(zval *op1) /* {{{ */ break; } break; + case IS_OBJECT: + if (Z_OBJ_HANDLER_P(op1, do_operation)) { + zval *op2; + int res; + TSRMLS_FETCH(); + + MAKE_STD_ZVAL(op2); + ZVAL_LONG(op2, 1); + res = Z_OBJ_HANDLER_P(op1, do_operation)(ZEND_SUB, op1, op1, op2 TSRMLS_CC); + zval_ptr_dtor(&op2); + + return res; + } + return FAILURE; default: return FAILURE; } diff --git a/Zend/zend_operators.h b/Zend/zend_operators.h index 0b890ff48cc5..483012662a98 100644 --- a/Zend/zend_operators.h +++ b/Zend/zend_operators.h @@ -884,8 +884,8 @@ static zend_always_inline int fast_equal_function(zval *result, zval *op1, zval return Z_DVAL_P(op1) == ((double)Z_LVAL_P(op2)); } } - compare_function(result, op1, op2 TSRMLS_CC); - return Z_LVAL_P(result) == 0; + is_equal_function(result, op1, op2 TSRMLS_CC); + return Z_LVAL_P(result); } static zend_always_inline int fast_not_equal_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) @@ -903,8 +903,8 @@ static zend_always_inline int fast_not_equal_function(zval *result, zval *op1, z return Z_DVAL_P(op1) != ((double)Z_LVAL_P(op2)); } } - compare_function(result, op1, op2 TSRMLS_CC); - return Z_LVAL_P(result) != 0; + is_not_equal_function(result, op1, op2 TSRMLS_CC); + return Z_LVAL_P(result); } static zend_always_inline int fast_is_smaller_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) @@ -922,8 +922,8 @@ static zend_always_inline int fast_is_smaller_function(zval *result, zval *op1, return Z_DVAL_P(op1) < ((double)Z_LVAL_P(op2)); } } - compare_function(result, op1, op2 TSRMLS_CC); - return Z_LVAL_P(result) < 0; + is_smaller_function(result, op1, op2 TSRMLS_CC); + return Z_LVAL_P(result); } static zend_always_inline int fast_is_smaller_or_equal_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) @@ -941,10 +941,22 @@ static zend_always_inline int fast_is_smaller_or_equal_function(zval *result, zv return Z_DVAL_P(op1) <= ((double)Z_LVAL_P(op2)); } } - compare_function(result, op1, op2 TSRMLS_CC); - return Z_LVAL_P(result) <= 0; + is_smaller_or_equal_function(result, op1, op2 TSRMLS_CC); + return Z_LVAL_P(result); } +static inline int zend_object_do_operation(int opcode, zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */ +{ + if (Z_TYPE_P(op1) == IS_OBJECT && Z_OBJ_HANDLER_P(op1, do_operation)) { + return Z_OBJ_HANDLER_P(op1, do_operation)(opcode, result, op1, op2 TSRMLS_CC); + } else if (op2 != NULL && Z_TYPE_P(op2) == IS_OBJECT && Z_OBJ_HANDLER_P(op2, do_operation)) { + return Z_OBJ_HANDLER_P(op2, do_operation)(opcode, result, op1, op2 TSRMLS_CC); + } else { + return FAILURE; + } +} +/* }}} */ + #endif /* diff --git a/ext/gmp/gmp.c b/ext/gmp/gmp.c index c9da09b230bb..bffd973882a8 100644 --- a/ext/gmp/gmp.c +++ b/ext/gmp/gmp.c @@ -24,6 +24,7 @@ #include "php_ini.h" #include "php_gmp.h" #include "ext/standard/info.h" +#include "zend_exceptions.h" #if HAVE_GMP @@ -34,9 +35,6 @@ #include "ext/standard/php_lcg.h" #define GMP_ABS(x) ((x) >= 0 ? (x) : -(x)) -/* True global resources - no need for thread safety here */ -static int le_gmp; - /* {{{ arginfo */ ZEND_BEGIN_ARG_INFO_EX(arginfo_gmp_init, 0, 0, 1) ZEND_ARG_INFO(0, number) @@ -308,9 +306,42 @@ zend_module_entry gmp_module_entry = { ZEND_GET_MODULE(gmp) #endif -static void _php_gmpnum_free(zend_rsrc_list_entry *rsrc TSRMLS_DC); +zend_class_entry *gmp_ce; +static zend_object_handlers gmp_object_handlers; + +/* {{{ typedefs + */ +typedef struct _gmp_object { + zend_object std; + mpz_t *num; +} gmp_object; + +typedef mpz_t* gmp_temp_t; + +typedef void (*gmp_unary_op_t)(mpz_ptr, mpz_srcptr); +typedef int (*gmp_unary_opl_t)(mpz_srcptr); + +typedef void (*gmp_unary_ui_op_t)(mpz_ptr, unsigned long); -#define GMP_RESOURCE_NAME "GMP integer" +typedef void (*gmp_binary_op_t)(mpz_ptr, mpz_srcptr, mpz_srcptr); +typedef int (*gmp_binary_opl_t)(mpz_srcptr, mpz_srcptr); + +typedef unsigned long (*gmp_binary_ui_op_t)(mpz_ptr, mpz_srcptr, unsigned long); +typedef void (*gmp_binary_op2_t)(mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr); +typedef unsigned long (*gmp_binary_ui_op2_t)(mpz_ptr, mpz_ptr, mpz_srcptr, unsigned long); +/* }}} */ + +#define gmp_zval_binary_ui_op(r, a, b, o, u) gmp_zval_binary_ui_op_ex(r, a, b, o, u, 0, 0, 0 TSRMLS_CC) +#define gmp_zval_binary_ui_op2(r, a, b, o, u) gmp_zval_binary_ui_op2_ex(r, a, b, o, u, 0, 0, 0 TSRMLS_CC) + +#define gmp_binary_ui_op(op, uop) _gmp_binary_ui_op(INTERNAL_FUNCTION_PARAM_PASSTHRU, op, uop) +#define gmp_binary_op(op) _gmp_binary_ui_op(INTERNAL_FUNCTION_PARAM_PASSTHRU, op, NULL) +#define gmp_binary_opl(op) _gmp_binary_opl(INTERNAL_FUNCTION_PARAM_PASSTHRU, op) + +/* Unary operations */ +#define gmp_unary_op(op) _gmp_unary_op(INTERNAL_FUNCTION_PARAM_PASSTHRU, op) +#define gmp_unary_opl(op) _gmp_unary_opl(INTERNAL_FUNCTION_PARAM_PASSTHRU, op) +#define gmp_unary_ui_op(op) _gmp_unary_ui_op(INTERNAL_FUNCTION_PARAM_PASSTHRU, op) #define GMP_ROUND_ZERO 0 #define GMP_ROUND_PLUSINF 1 @@ -324,6 +355,64 @@ static void _php_gmpnum_free(zend_rsrc_list_entry *rsrc TSRMLS_DC); # define MAX_BASE 36 #endif +#define IS_GMP_P(zval) \ + (Z_TYPE_P(zval) == IS_OBJECT && instanceof_function(Z_OBJCE_P(zval), gmp_ce TSRMLS_CC)) +#define IS_GMP_PP(zval) IS_GMP_P(*zval) + +#define FETCH_GMP_ZVAL_NO_TEMP(gmpnumber, zval) do { \ + gmpnumber = ((gmp_object *) zend_object_store_get_object(*(zval) TSRMLS_CC))->num; \ +} while (0); + +#define FREE_GMP_TEMP(temp) \ + if (temp) { \ + FREE_GMP_NUM(temp); \ + } + +/* Fetch zval to be GMP number. + Initially, zval can be also number or string */ +#define FETCH_GMP_ZVAL_DEP_DEP(gmpnumber, zval, temp, dep1, dep2) \ +if (IS_GMP_PP(zval)) { \ + FETCH_GMP_ZVAL_NO_TEMP(gmpnumber, zval) \ + temp = NULL; \ +} else { \ + if (convert_to_gmp(&gmpnumber, zval, 0 TSRMLS_CC) == FAILURE) { \ + FREE_GMP_TEMP(dep1); \ + FREE_GMP_TEMP(dep2); \ + RETURN_FALSE; \ + } \ + temp = gmpnumber; \ +} + +#define FETCH_GMP_ZVAL_DEP(gmpnumber, zval, temp, dep) \ + FETCH_GMP_ZVAL_DEP_DEP(gmpnumber, zval, temp, dep, (gmp_temp_t) NULL) +#define FETCH_GMP_ZVAL(gmpnumber, zval, temp) \ + FETCH_GMP_ZVAL_DEP(gmpnumber, zval, temp, (gmp_temp_t) NULL) + +/* create a new initialized GMP number */ +#define INIT_GMP_NUM(gmpnumber) { gmpnumber = emalloc(sizeof(mpz_t)); mpz_init(*gmpnumber); } +#define FREE_GMP_NUM(gmpnumber) { mpz_clear(*gmpnumber); efree(gmpnumber); } + +#define RETVAL_GMP(gmpnumber) do { \ + zval *_r = gmp_create((gmpnumber) TSRMLS_CC); \ + RETVAL_ZVAL(_r, 1, 1) \ +} while (0); + +#define ADD_INDEX_GMP(array, index, gmpnumber) do { \ + zval *_r = gmp_create((gmpnumber) TSRMLS_CC); \ + add_index_zval((array), (index), _r); \ +} while (0); +#define ADD_ASSOC_GMP(array, key, gmpnumber) do { \ + zval *_r = gmp_create((gmpnumber) TSRMLS_CC); \ + add_assoc_zval((array), (key), _r); \ +} while (0); + +static void gmp_strval(zval *result, mpz_t *gmpnum, long base); +static int convert_to_gmp(mpz_t **gmpnumber, zval **val, int base TSRMLS_DC); +static void gmp_cmp(zval *return_value, zval **a_arg, zval **b_arg TSRMLS_DC); + +static inline void gmp_zval_binary_ui_op_ex(zval *return_value, zval **a_arg, zval **b_arg, gmp_binary_op_t gmp_op, gmp_binary_ui_op_t gmp_ui_op, int allow_ui_return, int check_b_zero, int use_sign TSRMLS_DC); +static inline void gmp_zval_unary_op(zval *return_value, zval **a_arg, gmp_unary_op_t gmp_op TSRMLS_DC); + /* {{{ gmp_emalloc */ static void *gmp_emalloc(size_t size) @@ -348,6 +437,225 @@ static void gmp_efree(void *ptr, size_t size) } /* }}} */ +static void gmp_free_object_storage(gmp_object *intern TSRMLS_DC) /* {{{ */ +{ + FREE_GMP_NUM(intern->num); + + zend_object_std_dtor(&intern->std TSRMLS_CC); + efree(intern); +} +/* }}} */ + +static zend_object_value gmp_create_object(zend_class_entry *ce TSRMLS_DC) /* {{{ */ +{ + zend_object_value retval; + gmp_object *intern = emalloc(sizeof(gmp_object)); + memset(intern, 0, sizeof(gmp_object)); + + zend_object_std_init(&intern->std, ce TSRMLS_CC); + object_properties_init(&intern->std, ce); + + INIT_GMP_NUM(intern->num); + + retval.handle = zend_objects_store_put( + intern, (zend_objects_store_dtor_t) zend_objects_destroy_object, + (zend_objects_free_object_storage_t) gmp_free_object_storage, + NULL TSRMLS_CC + ); + retval.handlers = &gmp_object_handlers; + + return retval; +} +/* }}} */ + +static zval *gmp_create(mpz_t *gmpnumber TSRMLS_DC) /* {{{ */ +{ + zval *obj; + gmp_object *intern; + MAKE_STD_ZVAL(obj); + + object_init_ex(obj, gmp_ce); + intern = (gmp_object *) zend_object_store_get_object(obj TSRMLS_CC); + + FREE_GMP_NUM(intern->num); + intern->num = gmpnumber; + + return obj; +} +/* }}} */ + +static int gmp_cast_object(zval *readobj, zval *writeobj, int type TSRMLS_DC) /* {{{ */ +{ + mpz_t *gmpnum; + switch (type) { + case IS_STRING: + FETCH_GMP_ZVAL_NO_TEMP(gmpnum, &readobj); + INIT_PZVAL(writeobj); + gmp_strval(writeobj, gmpnum, 10); + return SUCCESS; + case IS_LONG: + FETCH_GMP_ZVAL_NO_TEMP(gmpnum, &readobj); + INIT_PZVAL(writeobj); + ZVAL_LONG(writeobj, mpz_get_si(*gmpnum)); + return SUCCESS; + case IS_DOUBLE: + FETCH_GMP_ZVAL_NO_TEMP(gmpnum, &readobj); + INIT_PZVAL(writeobj); + ZVAL_DOUBLE(writeobj, mpz_get_d(*gmpnum)); + return SUCCESS; + default: + return FAILURE; + } +} +/* }}} */ + +static HashTable *gmp_get_properties(zval *obj TSRMLS_DC) /* {{{ */ +{ + HashTable *ht = zend_std_get_properties(obj TSRMLS_CC); + mpz_t *gmpnum; + zval *zv; + + FETCH_GMP_ZVAL_NO_TEMP(gmpnum, &obj); + + MAKE_STD_ZVAL(zv); + gmp_strval(zv, gmpnum, 10); + zend_hash_update(ht, "num", sizeof("num"), &zv, sizeof(zval *), NULL); + + return ht; +} +/* }}} */ + +static zend_object_value gmp_clone_obj(zval *obj TSRMLS_DC) /* {{{ */ +{ + gmp_object *old_object = zend_object_store_get_object(obj TSRMLS_CC); + zend_object_value new_object_val = gmp_create_object(Z_OBJCE_P(obj) TSRMLS_CC); + gmp_object *new_object = zend_object_store_get_object_by_handle( + new_object_val.handle TSRMLS_CC + ); + + zend_objects_clone_members( + &new_object->std, new_object_val, + &old_object->std, Z_OBJ_HANDLE_P(obj) TSRMLS_CC + ); + + mpz_set(*new_object->num, *old_object->num); + + return new_object_val; +} +/* }}} */ + +#define DO_BINARY_UI_OP_EX(op, uop, check_b_zero, use_sign) \ + gmp_zval_binary_ui_op_ex( \ + result, &op1, &op2, op, (gmp_binary_ui_op_t) uop, \ + 0, check_b_zero, use_sign TSRMLS_CC \ + ); \ + return SUCCESS; /* Not sure if this should be FAILURE on bool(false) */ + +#define DO_BINARY_UI_OP(op) DO_BINARY_UI_OP_EX(op, op ## _ui, 0, 0) +#define DO_BINARY_OP(op) DO_BINARY_UI_OP_EX(op, NULL, 0, 0) + +#define DO_UNARY_OP(op) \ + gmp_zval_unary_op(result, &op1, op TSRMLS_CC); \ + return SUCCESS; + +static int gmp_do_operation(zend_uchar opcode, zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */ +{ + switch (opcode) { + case ZEND_ADD: + DO_BINARY_UI_OP(mpz_add); + case ZEND_SUB: + DO_BINARY_UI_OP(mpz_sub); + case ZEND_MUL: + DO_BINARY_UI_OP(mpz_mul); + case ZEND_DIV: + DO_BINARY_UI_OP_EX(mpz_tdiv_q, mpz_tdiv_q_ui, 1, 1); + case ZEND_MOD: + DO_BINARY_UI_OP_EX(mpz_mod, mpz_mod_ui, 1, 0); + case ZEND_SL: + /*convert_to_long_ex(&op2); + if (Z_LVAL_P(op2) < 0) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Shift cannot be negative"); + ZVAL_FALSE(return_value); + } else { + mpz_t *gmpnum, *resultnum; + gmp_temp_t temp; + zval *result_tmp; + FETCH_GMP_ZVAL(gmpnum, &op1, temp); + mpz_mul_2exp(resultnum, gmpnum, (unsigned long) Z_LVAL_P(op2)) + FREE_GMP_TEMP(temp); + RETVAL_GMP(resultnum); + } + return SUCCESS;*/ + case ZEND_SR: + return FAILURE; + case ZEND_BW_OR: + DO_BINARY_OP(mpz_ior); + case ZEND_BW_AND: + DO_BINARY_OP(mpz_and); + case ZEND_BW_XOR: + DO_BINARY_OP(mpz_xor); + case ZEND_BW_NOT: + DO_UNARY_OP(mpz_com); + case ZEND_IS_EQUAL: + gmp_cmp(result, &op1, &op2 TSRMLS_CC); + ZVAL_BOOL(result, Z_LVAL_P(result) == 0); + return SUCCESS; + case ZEND_IS_NOT_EQUAL: + gmp_cmp(result, &op1, &op2 TSRMLS_CC); + ZVAL_BOOL(result, Z_LVAL_P(result) != 0); + return SUCCESS; + case ZEND_IS_SMALLER: + gmp_cmp(result, &op1, &op2 TSRMLS_CC); + ZVAL_BOOL(result, Z_LVAL_P(result) < 0); + return SUCCESS; + case ZEND_IS_SMALLER_OR_EQUAL: + gmp_cmp(result, &op1, &op2 TSRMLS_CC); + ZVAL_BOOL(result, Z_LVAL_P(result) <= 0); + return SUCCESS; + + default: + return FAILURE; + } +} +/* }}} */ + +PHP_METHOD(GMP, __wakeup) /* {{{ */ +{ + HashTable *props; + zval **num_zv; + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + props = zend_std_get_properties(getThis() TSRMLS_CC); + if (zend_hash_find(props, "num", sizeof("num"), (void **) &num_zv) == SUCCESS + && Z_TYPE_PP(num_zv) == IS_STRING && Z_STRLEN_PP(num_zv) > 0 + ) { + gmp_object *intern = (gmp_object *) zend_object_store_get_object(getThis() TSRMLS_CC); + mpz_t *gmpnumber; + + if (convert_to_gmp(&gmpnumber, num_zv, 10 TSRMLS_CC) == SUCCESS) { + FREE_GMP_NUM(intern->num); + intern->num = gmpnumber; + return; + } + } + + zend_throw_exception( + NULL, "Invalid serialization data", 0 TSRMLS_CC + ); +} +/* }}} */ + +ZEND_BEGIN_ARG_INFO_EX(arginfo_wakeup, 0, 0, 0) +ZEND_END_ARG_INFO() + +const zend_function_entry gmp_methods[] = { + PHP_ME(GMP, __wakeup, arginfo_wakeup, ZEND_ACC_PUBLIC) + PHP_FE_END +}; + /* {{{ ZEND_GINIT_FUNCTION */ static ZEND_GINIT_FUNCTION(gmp) @@ -358,9 +666,19 @@ static ZEND_GINIT_FUNCTION(gmp) /* {{{ ZEND_MINIT_FUNCTION */ -ZEND_MODULE_STARTUP_D(gmp) +ZEND_MINIT_FUNCTION(gmp) { - le_gmp = zend_register_list_destructors_ex(_php_gmpnum_free, NULL, GMP_RESOURCE_NAME, module_number); + zend_class_entry tmp_ce; + INIT_CLASS_ENTRY(tmp_ce, "GMP", gmp_methods); /* No methods on the class for now */ + gmp_ce = zend_register_internal_class(&tmp_ce TSRMLS_CC); + gmp_ce->create_object = gmp_create_object; + + memcpy(&gmp_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); + gmp_object_handlers.cast_object = gmp_cast_object; + gmp_object_handlers.get_properties = gmp_get_properties; + gmp_object_handlers.clone_obj = gmp_clone_obj; + gmp_object_handlers.do_operation = gmp_do_operation; + REGISTER_LONG_CONSTANT("GMP_ROUND_ZERO", GMP_ROUND_ZERO, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("GMP_ROUND_PLUSINF", GMP_ROUND_PLUSINF, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("GMP_ROUND_MINUSINF", GMP_ROUND_MINUSINF, CONST_CS | CONST_PERSISTENT); @@ -403,106 +721,109 @@ ZEND_MODULE_INFO_D(gmp) } /* }}} */ -/* Fetch zval to be GMP number. - Initially, zval can be also number or string */ -#define FETCH_GMP_ZVAL(gmpnumber, zval, tmp_resource) \ -if (Z_TYPE_PP(zval) == IS_RESOURCE) { \ - ZEND_FETCH_RESOURCE(gmpnumber, mpz_t *, zval, -1, GMP_RESOURCE_NAME, le_gmp); \ - tmp_resource = 0; \ -} else { \ - if (convert_to_gmp(&gmpnumber, zval, 0 TSRMLS_CC) == FAILURE) { \ - RETURN_FALSE; \ - } \ - tmp_resource = ZEND_REGISTER_RESOURCE(NULL, gmpnumber, le_gmp); \ -} - -#define FREE_GMP_TEMP(tmp_resource) \ - if(tmp_resource) { \ - zend_list_delete(tmp_resource); \ - } - - -/* create a new initialized GMP number */ -#define INIT_GMP_NUM(gmpnumber) { gmpnumber=emalloc(sizeof(mpz_t)); mpz_init(*gmpnumber); } -#define FREE_GMP_NUM(gmpnumber) { mpz_clear(*gmpnumber); efree(gmpnumber); } /* {{{ convert_to_gmp * Convert zval to be gmp number */ -static int convert_to_gmp(mpz_t * *gmpnumber, zval **val, int base TSRMLS_DC) +static int convert_to_gmp(mpz_t **gmpnumber, zval **val, int base TSRMLS_DC) { - int ret = 0; - int skip_lead = 0; - - *gmpnumber = emalloc(sizeof(mpz_t)); - switch (Z_TYPE_PP(val)) { case IS_LONG: case IS_BOOL: - case IS_CONSTANT: - { - convert_to_long_ex(val); - mpz_init_set_si(**gmpnumber, Z_LVAL_PP(val)); - } - break; - case IS_STRING: - { - char *numstr = Z_STRVAL_PP(val); - - if (Z_STRLEN_PP(val) > 2) { - if (numstr[0] == '0') { - if (numstr[1] == 'x' || numstr[1] == 'X') { - base = 16; - skip_lead = 1; - } else if (base != 16 && (numstr[1] == 'b' || numstr[1] == 'B')) { - base = 2; - skip_lead = 1; - } + case IS_CONSTANT: { + convert_to_long_ex(val); + *gmpnumber = emalloc(sizeof(mpz_t)); + mpz_init_set_si(**gmpnumber, Z_LVAL_PP(val)); + return SUCCESS; + } + case IS_STRING: { + char *numstr = Z_STRVAL_PP(val); + int ret = 0, skip_lead = 0; + + if (Z_STRLEN_PP(val) > 2) { + if (numstr[0] == '0') { + if (numstr[1] == 'x' || numstr[1] == 'X') { + base = 16; + skip_lead = 1; + } else if (base != 16 && (numstr[1] == 'b' || numstr[1] == 'B')) { + base = 2; + skip_lead = 1; } } - ret = mpz_init_set_str(**gmpnumber, (skip_lead ? &numstr[2] : numstr), base); } - break; - default: - php_error_docref(NULL TSRMLS_CC, E_WARNING,"Unable to convert variable to GMP - wrong type"); - efree(*gmpnumber); - return FAILURE; - } - if (ret) { - FREE_GMP_NUM(*gmpnumber); + *gmpnumber = emalloc(sizeof(mpz_t)); + ret = mpz_init_set_str(**gmpnumber, (skip_lead ? &numstr[2] : numstr), base); + if (ret == FAILURE) { + FREE_GMP_NUM(*gmpnumber); + } + return ret; + } + default: + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to convert variable to GMP - wrong type"); return FAILURE; } - - return SUCCESS; } /* }}} */ -/* {{{ typedefs - */ -typedef void (*gmp_unary_op_t)(mpz_ptr, mpz_srcptr); -typedef int (*gmp_unary_opl_t)(mpz_srcptr); +static void gmp_strval(zval *result, mpz_t *gmpnum, long base) /* {{{ */ +{ + int num_len; + char *out_string; -typedef void (*gmp_unary_ui_op_t)(mpz_ptr, unsigned long); + num_len = mpz_sizeinbase(*gmpnum, abs(base)); + if (mpz_sgn(*gmpnum) < 0) { + num_len++; + } -typedef void (*gmp_binary_op_t)(mpz_ptr, mpz_srcptr, mpz_srcptr); -typedef int (*gmp_binary_opl_t)(mpz_srcptr, mpz_srcptr); + out_string = emalloc(num_len + 1); + mpz_get_str(out_string, base, *gmpnum); + + /* + * From GMP documentation for mpz_sizeinbase(): + * The returned value will be exact or 1 too big. If base is a power of + * 2, the returned value will always be exact. + * + * So let's check to see if we already have a \0 byte... + */ + + if (out_string[num_len - 1] == '\0') { + num_len--; + } else { + out_string[num_len] = '\0'; + } -typedef unsigned long (*gmp_binary_ui_op_t)(mpz_ptr, mpz_srcptr, unsigned long); -typedef void (*gmp_binary_op2_t)(mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr); -typedef unsigned long (*gmp_binary_ui_op2_t)(mpz_ptr, mpz_ptr, mpz_srcptr, unsigned long); + ZVAL_STRINGL(result, out_string, num_len, 0); +} /* }}} */ -#define gmp_zval_binary_ui_op(r, a, b, o, u) gmp_zval_binary_ui_op_ex(r, a, b, o, u, 0, 0, 0 TSRMLS_CC) -#define gmp_zval_binary_ui_op2(r, a, b, o, u) gmp_zval_binary_ui_op2_ex(r, a, b, o, u, 0, 0, 0 TSRMLS_CC) +static void gmp_cmp(zval *return_value, zval **a_arg, zval **b_arg TSRMLS_DC) /* {{{ */ +{ + mpz_t *gmpnum_a, *gmpnum_b; + gmp_temp_t temp_a, temp_b; + zend_bool use_si = 0; + long res; -#define gmp_binary_ui_op(op, uop) _gmp_binary_ui_op(INTERNAL_FUNCTION_PARAM_PASSTHRU, op, uop) -#define gmp_binary_op(op) _gmp_binary_ui_op(INTERNAL_FUNCTION_PARAM_PASSTHRU, op, NULL) -#define gmp_binary_opl(op) _gmp_binary_opl(INTERNAL_FUNCTION_PARAM_PASSTHRU, op) + FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a); -/* Unary operations */ -#define gmp_unary_op(op) _gmp_unary_op(INTERNAL_FUNCTION_PARAM_PASSTHRU, op) -#define gmp_unary_opl(op) _gmp_unary_opl(INTERNAL_FUNCTION_PARAM_PASSTHRU, op) -#define gmp_unary_ui_op(op) _gmp_unary_ui_op(INTERNAL_FUNCTION_PARAM_PASSTHRU, op) + if (Z_TYPE_PP(b_arg) == IS_LONG) { + use_si = 1; + temp_b = NULL; + } else { + FETCH_GMP_ZVAL_DEP(gmpnum_b, b_arg, temp_b, temp_a); + } + + if (use_si) { + res = mpz_cmp_si(*gmpnum_a, Z_LVAL_PP(b_arg)); + } else { + res = mpz_cmp(*gmpnum_a, *gmpnum_b); + } + + FREE_GMP_TEMP(temp_a); + FREE_GMP_TEMP(temp_b); + + RETURN_LONG(res); +} +/* }}} */ /* {{{ gmp_zval_binary_ui_op_ex Execute GMP binary operation. @@ -513,14 +834,15 @@ static inline void gmp_zval_binary_ui_op_ex(zval *return_value, zval **a_arg, zv mpz_t *gmpnum_a, *gmpnum_b, *gmpnum_result; unsigned long long_result = 0; int use_ui = 0; - int arga_tmp = 0, argb_tmp = 0; + gmp_temp_t temp_a, temp_b; - FETCH_GMP_ZVAL(gmpnum_a, a_arg, arga_tmp); + FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a); if (gmp_ui_op && Z_TYPE_PP(b_arg) == IS_LONG && Z_LVAL_PP(b_arg) >= 0) { use_ui = 1; + temp_b = NULL; } else { - FETCH_GMP_ZVAL(gmpnum_b, b_arg, argb_tmp); + FETCH_GMP_ZVAL_DEP(gmpnum_b, b_arg, temp_b, temp_a); } if(check_b_zero) { @@ -533,8 +855,8 @@ static inline void gmp_zval_binary_ui_op_ex(zval *return_value, zval **a_arg, zv if(b_is_zero) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "Zero operand not allowed"); - FREE_GMP_TEMP(arga_tmp); - FREE_GMP_TEMP(argb_tmp); + FREE_GMP_TEMP(temp_a); + FREE_GMP_TEMP(temp_b); RETURN_FALSE; } } @@ -554,14 +876,14 @@ static inline void gmp_zval_binary_ui_op_ex(zval *return_value, zval **a_arg, zv gmp_op(*gmpnum_result, *gmpnum_a, *gmpnum_b); } - FREE_GMP_TEMP(arga_tmp); - FREE_GMP_TEMP(argb_tmp); + FREE_GMP_TEMP(temp_a); + FREE_GMP_TEMP(temp_b); if (use_ui && allow_ui_return) { FREE_GMP_NUM(gmpnum_result); RETURN_LONG((long)long_result); } else { - ZEND_REGISTER_RESOURCE(return_value, gmpnum_result, le_gmp); + RETVAL_GMP(gmpnum_result); } } /* }}} */ @@ -573,32 +895,32 @@ static inline void gmp_zval_binary_ui_op_ex(zval *return_value, zval **a_arg, zv static inline void gmp_zval_binary_ui_op2_ex(zval *return_value, zval **a_arg, zval **b_arg, gmp_binary_op2_t gmp_op, gmp_binary_ui_op2_t gmp_ui_op, int allow_ui_return, int check_b_zero TSRMLS_DC) { mpz_t *gmpnum_a, *gmpnum_b, *gmpnum_result1, *gmpnum_result2; - zval r; int use_ui = 0; unsigned long long_result = 0; - int arga_tmp = 0, argb_tmp = 0; + gmp_temp_t temp_a, temp_b; - FETCH_GMP_ZVAL(gmpnum_a, a_arg, arga_tmp); + FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a); if (gmp_ui_op && Z_TYPE_PP(b_arg) == IS_LONG && Z_LVAL_PP(b_arg) >= 0) { /* use _ui function */ use_ui = 1; + temp_b = NULL; } else { - FETCH_GMP_ZVAL(gmpnum_b, b_arg, argb_tmp); + FETCH_GMP_ZVAL_DEP(gmpnum_b, b_arg, temp_b, temp_a); } - if(check_b_zero) { + if (check_b_zero) { int b_is_zero = 0; - if(use_ui) { + if (use_ui) { b_is_zero = (Z_LVAL_PP(b_arg) == 0); } else { b_is_zero = !mpz_cmp_ui(*gmpnum_b, 0); } - if(b_is_zero) { + if (b_is_zero) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "Zero operand not allowed"); - FREE_GMP_TEMP(arga_tmp); - FREE_GMP_TEMP(argb_tmp); + FREE_GMP_TEMP(temp_a); + FREE_GMP_TEMP(temp_b); RETURN_FALSE; } } @@ -616,18 +938,16 @@ static inline void gmp_zval_binary_ui_op2_ex(zval *return_value, zval **a_arg, z gmp_op(*gmpnum_result1, *gmpnum_result2, *gmpnum_a, *gmpnum_b); } - FREE_GMP_TEMP(arga_tmp); - FREE_GMP_TEMP(argb_tmp); + FREE_GMP_TEMP(temp_a); + FREE_GMP_TEMP(temp_b); array_init(return_value); - ZEND_REGISTER_RESOURCE(&r, gmpnum_result1, le_gmp); - add_index_resource(return_value, 0, Z_LVAL(r)); + ADD_INDEX_GMP(return_value, 0, gmpnum_result1); if (use_ui && allow_ui_return) { mpz_clear(*gmpnum_result2); add_index_long(return_value, 1, long_result); } else { - ZEND_REGISTER_RESOURCE(&r, gmpnum_result2, le_gmp); - add_index_resource(return_value, 1, Z_LVAL(r)); + ADD_INDEX_GMP(return_value, 1, gmpnum_result2); } } /* }}} */ @@ -653,7 +973,7 @@ static inline void _gmp_binary_ui_op(INTERNAL_FUNCTION_PARAMETERS, gmp_binary_op static inline void gmp_zval_unary_op(zval *return_value, zval **a_arg, gmp_unary_op_t gmp_op TSRMLS_DC) { mpz_t *gmpnum_a, *gmpnum_result; - int temp_a; + gmp_temp_t temp_a; FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a); @@ -661,7 +981,7 @@ static inline void gmp_zval_unary_op(zval *return_value, zval **a_arg, gmp_unary gmp_op(*gmpnum_result, *gmpnum_a); FREE_GMP_TEMP(temp_a); - ZEND_REGISTER_RESOURCE(return_value, gmpnum_result, le_gmp); + RETVAL_GMP(gmpnum_result); } /* }}} */ @@ -676,7 +996,7 @@ static inline void gmp_zval_unary_ui_op(zval *return_value, zval **a_arg, gmp_un INIT_GMP_NUM(gmpnum_result); gmp_op(*gmpnum_result, Z_LVAL_PP(a_arg)); - ZEND_REGISTER_RESOURCE(return_value, gmpnum_result, le_gmp); + RETVAL_GMP(gmpnum_result); } /* }}} */ @@ -715,7 +1035,7 @@ static inline void _gmp_unary_opl(INTERNAL_FUNCTION_PARAMETERS, gmp_unary_opl_t { zval **a_arg; mpz_t *gmpnum_a; - int temp_a; + gmp_temp_t temp_a; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z", &a_arg) == FAILURE){ return; @@ -733,14 +1053,14 @@ static inline void _gmp_binary_opl(INTERNAL_FUNCTION_PARAMETERS, gmp_binary_opl_ { zval **a_arg, **b_arg; mpz_t *gmpnum_a, *gmpnum_b; - int temp_a, temp_b; + gmp_temp_t temp_a, temp_b; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ZZ", &a_arg, &b_arg) == FAILURE){ return; } FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a); - FETCH_GMP_ZVAL(gmpnum_b, b_arg, temp_b); + FETCH_GMP_ZVAL_DEP(gmpnum_b, b_arg, temp_b, temp_a); RETVAL_LONG(gmp_op(*gmpnum_a, *gmpnum_b)); @@ -771,7 +1091,7 @@ ZEND_FUNCTION(gmp_init) } /* Write your own code here to handle argument number. */ - ZEND_REGISTER_RESOURCE(return_value, gmpnumber, le_gmp); + RETVAL_GMP(gmpnumber); } /* }}} */ @@ -786,8 +1106,8 @@ ZEND_FUNCTION(gmp_intval) return; } - if (Z_TYPE_PP(gmpnumber_arg) == IS_RESOURCE) { - ZEND_FETCH_RESOURCE(gmpnum, mpz_t *, gmpnumber_arg, -1, GMP_RESOURCE_NAME, le_gmp); + if (IS_GMP_PP(gmpnumber_arg)) { + FETCH_GMP_ZVAL_NO_TEMP(gmpnum, gmpnumber_arg); RETVAL_LONG(mpz_get_si(*gmpnum)); } else { convert_to_long_ex(gmpnumber_arg); @@ -801,13 +1121,11 @@ ZEND_FUNCTION(gmp_intval) ZEND_FUNCTION(gmp_strval) { zval **gmpnumber_arg; - int num_len; long base = 10; - mpz_t * gmpnum; - char *out_string; - int temp_a; + mpz_t *gmpnum; + gmp_temp_t temp_a; - if( zend_parse_parameters( ZEND_NUM_ARGS() TSRMLS_CC, "Z|l", &gmpnumber_arg, &base ) == FAILURE ) { + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z|l", &gmpnumber_arg, &base) == FAILURE) { return; } @@ -825,29 +1143,9 @@ ZEND_FUNCTION(gmp_strval) FETCH_GMP_ZVAL(gmpnum, gmpnumber_arg, temp_a); - num_len = mpz_sizeinbase(*gmpnum, abs(base)); - out_string = emalloc(num_len+2); - if (mpz_sgn(*gmpnum) < 0) { - num_len++; - } - mpz_get_str(out_string, base, *gmpnum); - - FREE_GMP_TEMP(temp_a); - - /* - From GMP documentation for mpz_sizeinbase(): - The returned value will be exact or 1 too big. If base is a power of - 2, the returned value will always be exact. - - So let's check to see if we already have a \0 byte... - */ + gmp_strval(return_value, gmpnum, base); - if (out_string[num_len-1] == '\0') { - num_len--; - } else { - out_string[num_len] = '\0'; - } - RETVAL_STRINGL(out_string, num_len, 0); + FREE_GMP_TEMP(temp_a); } /* }}} */ @@ -897,7 +1195,6 @@ ZEND_FUNCTION(gmp_div_qr) gmp_zval_binary_ui_op2_ex(return_value, a_arg, b_arg, mpz_fdiv_qr, (gmp_binary_ui_op2_t)mpz_fdiv_qr_ui, 0, 1 TSRMLS_CC); break; } - } /* }}} */ @@ -1002,14 +1299,13 @@ ZEND_FUNCTION(gmp_fact) { zval **a_arg; mpz_t *gmpnum_tmp; - int temp_a; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z", &a_arg) == FAILURE){ return; } - if (Z_TYPE_PP(a_arg) == IS_RESOURCE) { - FETCH_GMP_ZVAL(gmpnum_tmp, a_arg, temp_a); /* no need to free this since it's IS_RESOURCE */ + if (IS_GMP_PP(a_arg)) { + FETCH_GMP_ZVAL_NO_TEMP(gmpnum_tmp, a_arg) if (mpz_sgn(*gmpnum_tmp) < 0) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "Number has to be greater than or equal to 0"); RETURN_FALSE; @@ -1021,7 +1317,9 @@ ZEND_FUNCTION(gmp_fact) RETURN_FALSE; } } - + + /* TODO This one looks like a bug. If you passed a GMP resource it would + * take the factorial of the GMP resource ID rather than the GMP number. */ gmp_zval_unary_ui_op(return_value, a_arg, mpz_fac_ui TSRMLS_CC); } /* }}} */ @@ -1033,24 +1331,25 @@ ZEND_FUNCTION(gmp_pow) zval **base_arg; mpz_t *gmpnum_result, *gmpnum_base; int use_ui = 0; - int temp_base; + gmp_temp_t temp_base; long exp; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Zl", &base_arg, &exp) == FAILURE) { return; } + if (exp < 0) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Negative exponent not supported"); + RETURN_FALSE; + } + if (Z_TYPE_PP(base_arg) == IS_LONG && Z_LVAL_PP(base_arg) >= 0) { use_ui = 1; + temp_base = NULL; } else { FETCH_GMP_ZVAL(gmpnum_base, base_arg, temp_base); } - if (exp < 0) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Negative exponent not supported"); - RETURN_FALSE; - } - INIT_GMP_NUM(gmpnum_result); if (use_ui) { mpz_ui_pow_ui(*gmpnum_result, Z_LVAL_PP(base_arg), exp); @@ -1058,7 +1357,7 @@ ZEND_FUNCTION(gmp_pow) mpz_pow_ui(*gmpnum_result, *gmpnum_base, exp); FREE_GMP_TEMP(temp_base); } - ZEND_REGISTER_RESOURCE(return_value, gmpnum_result, le_gmp); + RETVAL_GMP(gmpnum_result); } /* }}} */ @@ -1069,7 +1368,7 @@ ZEND_FUNCTION(gmp_powm) zval **base_arg, **exp_arg, **mod_arg; mpz_t *gmpnum_base, *gmpnum_exp, *gmpnum_mod, *gmpnum_result; int use_ui = 0; - int temp_base, temp_exp, temp_mod; + gmp_temp_t temp_base, temp_exp, temp_mod; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ZZZ", &base_arg, &exp_arg, &mod_arg) == FAILURE){ return; @@ -1079,14 +1378,17 @@ ZEND_FUNCTION(gmp_powm) if (Z_TYPE_PP(exp_arg) == IS_LONG && Z_LVAL_PP(exp_arg) >= 0) { use_ui = 1; + temp_exp = NULL; } else { - FETCH_GMP_ZVAL(gmpnum_exp, exp_arg, temp_exp); + FETCH_GMP_ZVAL_DEP(gmpnum_exp, exp_arg, temp_exp, temp_base); if (mpz_sgn(*gmpnum_exp) < 0) { - php_error_docref(NULL TSRMLS_CC, E_WARNING,"Second parameter cannot be less than 0"); + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Second parameter cannot be less than 0"); + FREE_GMP_TEMP(temp_base); + FREE_GMP_TEMP(temp_exp); RETURN_FALSE; } } - FETCH_GMP_ZVAL(gmpnum_mod, mod_arg, temp_mod); + FETCH_GMP_ZVAL_DEP_DEP(gmpnum_mod, mod_arg, temp_mod, temp_exp, temp_base); if (!mpz_cmp_ui(*gmpnum_mod, 0)) { FREE_GMP_TEMP(temp_base); @@ -1108,7 +1410,7 @@ ZEND_FUNCTION(gmp_powm) FREE_GMP_TEMP(temp_base); FREE_GMP_TEMP(temp_mod); - ZEND_REGISTER_RESOURCE(return_value, gmpnum_result, le_gmp); + RETVAL_GMP(gmpnum_result); } /* }}} */ @@ -1119,7 +1421,7 @@ ZEND_FUNCTION(gmp_sqrt) { zval **a_arg; mpz_t *gmpnum_a, *gmpnum_result; - int temp_a; + gmp_temp_t temp_a; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z", &a_arg) == FAILURE){ return; @@ -1132,12 +1434,12 @@ ZEND_FUNCTION(gmp_sqrt) FREE_GMP_TEMP(temp_a); RETURN_FALSE; } - + INIT_GMP_NUM(gmpnum_result); mpz_sqrt(*gmpnum_result, *gmpnum_a); FREE_GMP_TEMP(temp_a); - ZEND_REGISTER_RESOURCE(return_value, gmpnum_result, le_gmp); + RETVAL_GMP(gmpnum_result); } /* }}} */ @@ -1147,17 +1449,17 @@ ZEND_FUNCTION(gmp_sqrtrem) { zval **a_arg; mpz_t *gmpnum_a, *gmpnum_result1, *gmpnum_result2; - zval r; - int temp_a; + gmp_temp_t temp_a; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z", &a_arg) == FAILURE){ return; } FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a); - + if (mpz_sgn(*gmpnum_a) < 0) { php_error_docref(NULL TSRMLS_CC, E_WARNING,"Number has to be greater than or equal to 0"); + FREE_GMP_TEMP(temp_a); RETURN_FALSE; } @@ -1168,10 +1470,8 @@ ZEND_FUNCTION(gmp_sqrtrem) FREE_GMP_TEMP(temp_a); array_init(return_value); - ZEND_REGISTER_RESOURCE(&r, gmpnum_result1, le_gmp); - add_index_resource(return_value, 0, Z_LVAL(r)); - ZEND_REGISTER_RESOURCE(&r, gmpnum_result2, le_gmp); - add_index_resource(return_value, 1, Z_LVAL(r)); + ADD_INDEX_GMP(return_value, 0, gmpnum_result1); + ADD_INDEX_GMP(return_value, 1, gmpnum_result2); } /* }}} */ @@ -1181,7 +1481,7 @@ ZEND_FUNCTION(gmp_perfect_square) { zval **a_arg; mpz_t *gmpnum_a; - int temp_a; + gmp_temp_t temp_a; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z", &a_arg) == FAILURE){ return; @@ -1201,7 +1501,7 @@ ZEND_FUNCTION(gmp_prob_prime) zval **gmpnumber_arg; mpz_t *gmpnum_a; long reps = 10; - int temp_a; + gmp_temp_t temp_a; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z|l", &gmpnumber_arg, &reps) == FAILURE) { return; @@ -1234,15 +1534,14 @@ ZEND_FUNCTION(gmp_gcdext) { zval **a_arg, **b_arg; mpz_t *gmpnum_a, *gmpnum_b, *gmpnum_t, *gmpnum_s, *gmpnum_g; - zval r; - int temp_a, temp_b; + gmp_temp_t temp_a, temp_b; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ZZ", &a_arg, &b_arg) == FAILURE){ return; } FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a); - FETCH_GMP_ZVAL(gmpnum_b, b_arg, temp_b); + FETCH_GMP_ZVAL_DEP(gmpnum_b, b_arg, temp_b, temp_a); INIT_GMP_NUM(gmpnum_g); INIT_GMP_NUM(gmpnum_s); @@ -1254,12 +1553,9 @@ ZEND_FUNCTION(gmp_gcdext) array_init(return_value); - ZEND_REGISTER_RESOURCE(&r, gmpnum_g, le_gmp); - add_assoc_resource(return_value, "g", Z_LVAL(r)); - ZEND_REGISTER_RESOURCE(&r, gmpnum_s, le_gmp); - add_assoc_resource(return_value, "s", Z_LVAL(r)); - ZEND_REGISTER_RESOURCE(&r, gmpnum_t, le_gmp); - add_assoc_resource(return_value, "t", Z_LVAL(r)); + ADD_ASSOC_GMP(return_value, "g", gmpnum_g); + ADD_ASSOC_GMP(return_value, "s", gmpnum_s); + ADD_ASSOC_GMP(return_value, "t", gmpnum_t); } /* }}} */ @@ -1269,7 +1565,7 @@ ZEND_FUNCTION(gmp_invert) { zval **a_arg, **b_arg; mpz_t *gmpnum_a, *gmpnum_b, *gmpnum_result; - int temp_a, temp_b; + gmp_temp_t temp_a, temp_b; int res; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ZZ", &a_arg, &b_arg) == FAILURE){ @@ -1277,14 +1573,14 @@ ZEND_FUNCTION(gmp_invert) } FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a); - FETCH_GMP_ZVAL(gmpnum_b, b_arg, temp_b); + FETCH_GMP_ZVAL_DEP(gmpnum_b, b_arg, temp_b, temp_a); INIT_GMP_NUM(gmpnum_result); res=mpz_invert(*gmpnum_result, *gmpnum_a, *gmpnum_b); FREE_GMP_TEMP(temp_a); FREE_GMP_TEMP(temp_b); if (res) { - ZEND_REGISTER_RESOURCE(return_value, gmpnum_result, le_gmp); + RETVAL_GMP(gmpnum_result); } else { FREE_GMP_NUM(gmpnum_result); RETURN_FALSE; @@ -1313,30 +1609,12 @@ ZEND_FUNCTION(gmp_legendre) ZEND_FUNCTION(gmp_cmp) { zval **a_arg, **b_arg; - mpz_t *gmpnum_a, *gmpnum_b; - int use_si = 0, res; - int temp_a, temp_b; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ZZ", &a_arg, &b_arg) == FAILURE){ return; } - FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a); - - if (Z_TYPE_PP(b_arg) == IS_LONG) { - use_si = 1; - } else { - FETCH_GMP_ZVAL(gmpnum_b, b_arg, temp_b); - } - - if (use_si) { - res = mpz_cmp_si(*gmpnum_a, Z_LVAL_PP(b_arg)); - } else { - res = mpz_cmp(*gmpnum_a, *gmpnum_b); - } - FREE_GMP_TEMP(temp_a); - - RETURN_LONG(res); + gmp_cmp(return_value, a_arg, b_arg TSRMLS_CC); } /* }}} */ @@ -1346,7 +1624,7 @@ ZEND_FUNCTION(gmp_sign) { zval **a_arg; mpz_t *gmpnum_a; - int temp_a; + gmp_temp_t temp_a; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z", &a_arg) == FAILURE){ return; @@ -1386,7 +1664,7 @@ ZEND_FUNCTION(gmp_random) #else mpz_urandomb(*gmpnum_result, GMPG(rand_state), GMP_ABS (limiter) * __GMP_BITS_PER_MP_LIMB); #endif - ZEND_REGISTER_RESOURCE(return_value, gmpnum_result, le_gmp); + RETVAL_GMP(gmpnum_result); } /* }}} */ @@ -1426,17 +1704,17 @@ ZEND_FUNCTION(gmp_nextprime) Calculates logical exclusive OR of a and b */ ZEND_FUNCTION(gmp_xor) { - /* use formula: a^b = (a|b)&^(a&b) */ + /* use formula: a^b = (a|b)&~(a&b) */ zval **a_arg, **b_arg; mpz_t *gmpnum_a, *gmpnum_b, *gmpnum_result, *gmpnum_t; - int temp_a, temp_b; + gmp_temp_t temp_a, temp_b; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ZZ", &a_arg, &b_arg) == FAILURE){ return; } FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a); - FETCH_GMP_ZVAL(gmpnum_b, b_arg, temp_b); + FETCH_GMP_ZVAL_DEP(gmpnum_b, b_arg, temp_b, temp_a); INIT_GMP_NUM(gmpnum_result); INIT_GMP_NUM(gmpnum_t); @@ -1451,7 +1729,7 @@ ZEND_FUNCTION(gmp_xor) FREE_GMP_TEMP(temp_a); FREE_GMP_TEMP(temp_b); - ZEND_REGISTER_RESOURCE(return_value, gmpnum_result, le_gmp); + RETVAL_GMP(gmpnum_result); } /* }}} */ @@ -1459,16 +1737,16 @@ ZEND_FUNCTION(gmp_xor) Sets or clear bit in a */ ZEND_FUNCTION(gmp_setbit) { - zval **a_arg; + zval *a_arg; long index; zend_bool set = 1; mpz_t *gmpnum_a; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Zl|b", &a_arg, &index, &set) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Ol|b", &a_arg, gmp_ce, &index, &set) == FAILURE) { return; } - ZEND_FETCH_RESOURCE(gmpnum_a, mpz_t *, a_arg, -1, GMP_RESOURCE_NAME, le_gmp); + FETCH_GMP_ZVAL_NO_TEMP(gmpnum_a, &a_arg); if (index < 0) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "Index must be greater than or equal to zero"); @@ -1487,15 +1765,15 @@ ZEND_FUNCTION(gmp_setbit) Clears bit in a */ ZEND_FUNCTION(gmp_clrbit) { - zval **a_arg; + zval *a_arg; long index; mpz_t *gmpnum_a; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Zl", &a_arg, &index) == FAILURE){ + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Ol", &a_arg, gmp_ce, &index) == FAILURE){ return; } - ZEND_FETCH_RESOURCE(gmpnum_a, mpz_t *, a_arg, -1, GMP_RESOURCE_NAME, le_gmp); + FETCH_GMP_ZVAL_NO_TEMP(gmpnum_a, &a_arg); if (index < 0) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "Index must be greater than or equal to zero"); @@ -1518,13 +1796,14 @@ ZEND_FUNCTION(gmp_testbit) return; } - ZEND_FETCH_RESOURCE(gmpnum_a, mpz_t *, a_arg, -1, GMP_RESOURCE_NAME, le_gmp); - if (index < 0) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "Index must be greater than or equal to zero"); RETURN_FALSE; } + /* TODO Why NO_TEMP? */ + FETCH_GMP_ZVAL_NO_TEMP(gmpnum_a, a_arg); + if (mpz_tstbit(*gmpnum_a, index)) { RETURN_TRUE; } @@ -1538,7 +1817,7 @@ ZEND_FUNCTION(gmp_popcount) { zval **a_arg; mpz_t *gmpnum_a; - int temp_a; + gmp_temp_t temp_a; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z", &a_arg) == FAILURE){ return; @@ -1557,14 +1836,14 @@ ZEND_FUNCTION(gmp_hamdist) { zval **a_arg, **b_arg; mpz_t *gmpnum_a, *gmpnum_b; - int temp_a, temp_b; + gmp_temp_t temp_a, temp_b; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ZZ", &a_arg, &b_arg) == FAILURE){ return; } FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a); - FETCH_GMP_ZVAL(gmpnum_b, b_arg, temp_b); + FETCH_GMP_ZVAL_DEP(gmpnum_b, b_arg, temp_b, temp_a); RETVAL_LONG(mpz_hamdist(*gmpnum_a, *gmpnum_b)); FREE_GMP_TEMP(temp_a); @@ -1578,20 +1857,20 @@ ZEND_FUNCTION(gmp_scan0) { zval **a_arg; mpz_t *gmpnum_a; - int temp_a; + gmp_temp_t temp_a; long start; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Zl", &a_arg, &start) == FAILURE){ return; } - FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a); - if (start < 0) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "Starting index must be greater than or equal to zero"); RETURN_FALSE; } + FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a); + RETVAL_LONG(mpz_scan0(*gmpnum_a, start)); FREE_GMP_TEMP(temp_a); } @@ -1603,34 +1882,25 @@ ZEND_FUNCTION(gmp_scan1) { zval **a_arg; mpz_t *gmpnum_a; - int temp_a; + gmp_temp_t temp_a; long start; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Zl", &a_arg, &start) == FAILURE){ return; } - FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a); if (start < 0) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "Starting index must be greater than or equal to zero"); RETURN_FALSE; } + FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a); + RETVAL_LONG(mpz_scan1(*gmpnum_a, start)); FREE_GMP_TEMP(temp_a); } /* }}} */ -/* {{{ _php_gmpnum_free - */ -static void _php_gmpnum_free(zend_rsrc_list_entry *rsrc TSRMLS_DC) -{ - mpz_t *gmpnum = (mpz_t *)rsrc->ptr; - - FREE_GMP_NUM(gmpnum); -} -/* }}} */ - #endif /* HAVE_GMP */ /* diff --git a/ext/gmp/tests/004.phpt b/ext/gmp/tests/004.phpt index a0fa1cd133c9..088dd08fd8ee 100644 --- a/ext/gmp/tests/004.phpt +++ b/ext/gmp/tests/004.phpt @@ -38,8 +38,6 @@ int(2342344) Notice: Object of class stdClass could not be converted to int in %s on line %d int(1) int(0) - -Warning: gmp_intval(): supplied resource is not a valid GMP integer resource in %s on line %d -bool(false) +int(%d) int(12345678) Done diff --git a/ext/gmp/tests/005.phpt b/ext/gmp/tests/005.phpt index 7907ffbf53e9..4ae0cb750a41 100644 --- a/ext/gmp/tests/005.phpt +++ b/ext/gmp/tests/005.phpt @@ -47,7 +47,7 @@ bool(false) Warning: gmp_strval() expects parameter 2 to be long, string given in %s on line %d NULL -Warning: gmp_strval(): supplied resource is not a valid GMP integer resource in %s on line %d +Warning: gmp_strval(): Unable to convert variable to GMP - wrong type in %s on line %d bool(false) string(7) "9765456" diff --git a/ext/gmp/tests/006.phpt b/ext/gmp/tests/006.phpt index dedbcd04726a..740760631d4e 100644 --- a/ext/gmp/tests/006.phpt +++ b/ext/gmp/tests/006.phpt @@ -35,9 +35,15 @@ NULL Warning: gmp_sub(): Unable to convert variable to GMP - wrong type in %s on line %d bool(false) -resource(%d) of type (GMP integer) +object(GMP)#%d (1) { + ["num"]=> + string(2) "-1" +} string(2) "-1" -resource(%d) of type (GMP integer) +object(GMP)#%d (1) { + ["num"]=> + string(5) "10001" +} string(5) "10001" Warning: gmp_sub(): Unable to convert variable to GMP - wrong type in %s on line %d diff --git a/ext/gmp/tests/007.phpt b/ext/gmp/tests/007.phpt index 4d4a993a1729..3b49cf51fc4f 100644 --- a/ext/gmp/tests/007.phpt +++ b/ext/gmp/tests/007.phpt @@ -8,34 +8,16 @@ gmp_div_qr() tests var_dump(gmp_div_qr()); var_dump(gmp_div_qr("")); -var_dump($r = gmp_div_qr(0,1)); -var_dump(gmp_strval($r[0])); -var_dump(gmp_strval($r[1])); -var_dump($r = gmp_div_qr(1,0)); -var_dump($r = gmp_div_qr(12653,23482734)); -var_dump(gmp_strval($r[0])); -var_dump(gmp_strval($r[1])); -var_dump($r = gmp_div_qr(12653,23482734, 10)); -var_dump(gmp_strval($r[0])); -var_dump(gmp_strval($r[1])); -var_dump($r = gmp_div_qr(1123123,123)); -var_dump(gmp_strval($r[0])); -var_dump(gmp_strval($r[1])); -var_dump($r = gmp_div_qr(1123123,123, 1)); -var_dump(gmp_strval($r[0])); -var_dump(gmp_strval($r[1])); -var_dump($r = gmp_div_qr(1123123,123, 2)); -var_dump(gmp_strval($r[0])); -var_dump(gmp_strval($r[1])); -var_dump($r = gmp_div_qr(1123123,123, GMP_ROUND_ZERO)); -var_dump(gmp_strval($r[0])); -var_dump(gmp_strval($r[1])); -var_dump($r = gmp_div_qr(1123123,123, GMP_ROUND_PLUSINF)); -var_dump(gmp_strval($r[0])); -var_dump(gmp_strval($r[1])); -var_dump($r = gmp_div_qr(1123123,123, GMP_ROUND_MINUSINF)); -var_dump(gmp_strval($r[0])); -var_dump(gmp_strval($r[1])); +var_dump(gmp_div_qr(0,1)); +var_dump(gmp_div_qr(1,0)); +var_dump(gmp_div_qr(12653,23482734)); +var_dump(gmp_div_qr(12653,23482734, 10)); +var_dump(gmp_div_qr(1123123,123)); +var_dump(gmp_div_qr(1123123,123, 1)); +var_dump(gmp_div_qr(1123123,123, 2)); +var_dump(gmp_div_qr(1123123,123, GMP_ROUND_ZERO)); +var_dump(gmp_div_qr(1123123,123, GMP_ROUND_PLUSINF)); +var_dump(gmp_div_qr(1123123,123, GMP_ROUND_MINUSINF)); $fp = fopen(__FILE__, 'r'); @@ -52,80 +34,106 @@ Warning: gmp_div_qr() expects at least 2 parameters, 1 given in %s on line %d NULL array(2) { [0]=> - resource(%d) of type (GMP integer) + object(GMP)#%d (1) { + ["num"]=> + string(1) "0" + } [1]=> - resource(%d) of type (GMP integer) + object(GMP)#%d (1) { + ["num"]=> + string(1) "0" + } } -string(1) "0" -string(1) "0" Warning: gmp_div_qr(): Zero operand not allowed in %s on line %d bool(false) array(2) { [0]=> - resource(%d) of type (GMP integer) + object(GMP)#%d (1) { + ["num"]=> + string(1) "0" + } [1]=> - resource(%d) of type (GMP integer) + object(GMP)#%d (1) { + ["num"]=> + string(5) "12653" + } } -string(1) "0" -string(5) "12653" NULL - -Warning: gmp_strval(): Unable to convert variable to GMP - wrong type in %s on line %d -bool(false) - -Warning: gmp_strval(): Unable to convert variable to GMP - wrong type in %s on line %d -bool(false) array(2) { [0]=> - resource(%d) of type (GMP integer) + object(GMP)#%d (1) { + ["num"]=> + string(4) "9131" + } [1]=> - resource(%d) of type (GMP integer) + object(GMP)#%d (1) { + ["num"]=> + string(2) "10" + } } -string(4) "9131" -string(2) "10" array(2) { [0]=> - resource(%d) of type (GMP integer) + object(GMP)#%d (1) { + ["num"]=> + string(4) "9132" + } [1]=> - resource(%d) of type (GMP integer) + object(GMP)#%d (1) { + ["num"]=> + string(4) "-113" + } } -string(4) "9132" -string(4) "-113" array(2) { [0]=> - resource(%d) of type (GMP integer) + object(GMP)#%d (1) { + ["num"]=> + string(4) "9131" + } [1]=> - resource(%d) of type (GMP integer) + object(GMP)#%d (1) { + ["num"]=> + string(2) "10" + } } -string(4) "9131" -string(2) "10" array(2) { [0]=> - resource(%d) of type (GMP integer) + object(GMP)#%d (1) { + ["num"]=> + string(4) "9131" + } [1]=> - resource(%d) of type (GMP integer) + object(GMP)#%d (1) { + ["num"]=> + string(2) "10" + } } -string(4) "9131" -string(2) "10" array(2) { [0]=> - resource(%d) of type (GMP integer) + object(GMP)#%d (1) { + ["num"]=> + string(4) "9132" + } [1]=> - resource(%d) of type (GMP integer) + object(GMP)#%d (1) { + ["num"]=> + string(4) "-113" + } } -string(4) "9132" -string(4) "-113" array(2) { [0]=> - resource(%d) of type (GMP integer) + object(GMP)#%d (1) { + ["num"]=> + string(4) "9131" + } [1]=> - resource(%d) of type (GMP integer) + object(GMP)#%d (1) { + ["num"]=> + string(2) "10" + } } -string(4) "9131" -string(2) "10" -Warning: gmp_div_qr(): supplied resource is not a valid GMP integer resource in %s on line %d +Warning: gmp_div_qr(): Unable to convert variable to GMP - wrong type in %s on line %d bool(false) Warning: gmp_div_qr(): Unable to convert variable to GMP - wrong type in %s on line %d diff --git a/ext/gmp/tests/008.phpt b/ext/gmp/tests/008.phpt index 4e44ec10bf88..d67b01b0fd3c 100644 --- a/ext/gmp/tests/008.phpt +++ b/ext/gmp/tests/008.phpt @@ -65,7 +65,7 @@ string(3) "113" int(10) string(2) "10" -Warning: gmp_div_r(): supplied resource is not a valid GMP integer resource in %s on line %d +Warning: gmp_div_r(): Unable to convert variable to GMP - wrong type in %s on line %d bool(false) Warning: gmp_div_r(): Unable to convert variable to GMP - wrong type in %s on line %d diff --git a/ext/gmp/tests/009.phpt b/ext/gmp/tests/009.phpt index 745a4ef63841..ec0eb4bc6e8f 100644 --- a/ext/gmp/tests/009.phpt +++ b/ext/gmp/tests/009.phpt @@ -8,25 +8,16 @@ gmp_div_q() tests var_dump(gmp_div_q()); var_dump(gmp_div_q("")); -var_dump($r = gmp_div_q(0,1)); -var_dump(gmp_strval($r)); -var_dump($r = gmp_div_q(1,0)); -var_dump($r = gmp_div_q(12653,23482734)); -var_dump(gmp_strval($r)); -var_dump($r = gmp_div_q(12653,23482734, 10)); -var_dump(gmp_strval($r)); -var_dump($r = gmp_div_q(1123123,123)); -var_dump(gmp_strval($r)); -var_dump($r = gmp_div_q(1123123,123, 1)); -var_dump(gmp_strval($r)); -var_dump($r = gmp_div_q(1123123,123, 2)); -var_dump(gmp_strval($r)); -var_dump($r = gmp_div_q(1123123,123, GMP_ROUND_ZERO)); -var_dump(gmp_strval($r)); -var_dump($r = gmp_div_q(1123123,123, GMP_ROUND_PLUSINF)); -var_dump(gmp_strval($r)); -var_dump($r = gmp_div_q(1123123,123, GMP_ROUND_MINUSINF)); -var_dump(gmp_strval($r)); +var_dump(gmp_div_q(0,1)); +var_dump(gmp_div_q(1,0)); +var_dump(gmp_div_q(12653,23482734)); +var_dump(gmp_div_q(12653,23482734, 10)); +var_dump(gmp_div_q(1123123,123)); +var_dump(gmp_div_q(1123123,123, 1)); +var_dump(gmp_div_q(1123123,123, 2)); +var_dump(gmp_div_q(1123123,123, GMP_ROUND_ZERO)); +var_dump(gmp_div_q(1123123,123, GMP_ROUND_PLUSINF)); +var_dump(gmp_div_q(1123123,123, GMP_ROUND_MINUSINF)); $fp = fopen(__FILE__, 'r'); @@ -41,31 +32,44 @@ NULL Warning: gmp_div_q() expects at least 2 parameters, 1 given in %s on line %d NULL -resource(%d) of type (GMP integer) -string(1) "0" +object(GMP)#%d (1) { + ["num"]=> + string(1) "0" +} Warning: gmp_div_q(): Zero operand not allowed in %s on line %d bool(false) -resource(%d) of type (GMP integer) -string(1) "0" +object(GMP)#%d (1) { + ["num"]=> + string(1) "0" +} NULL +object(GMP)#%d (1) { + ["num"]=> + string(4) "9131" +} +object(GMP)#%d (1) { + ["num"]=> + string(4) "9132" +} +object(GMP)#%d (1) { + ["num"]=> + string(4) "9131" +} +object(GMP)#%d (1) { + ["num"]=> + string(4) "9131" +} +object(GMP)#%d (1) { + ["num"]=> + string(4) "9132" +} +object(GMP)#%d (1) { + ["num"]=> + string(4) "9131" +} -Warning: gmp_strval(): Unable to convert variable to GMP - wrong type in %s on line %d -bool(false) -resource(%d) of type (GMP integer) -string(4) "9131" -resource(%d) of type (GMP integer) -string(4) "9132" -resource(%d) of type (GMP integer) -string(4) "9131" -resource(%d) of type (GMP integer) -string(4) "9131" -resource(%d) of type (GMP integer) -string(4) "9132" -resource(%d) of type (GMP integer) -string(4) "9131" - -Warning: gmp_div_q(): supplied resource is not a valid GMP integer resource in %s on line %d +Warning: gmp_div_q(): Unable to convert variable to GMP - wrong type in %s on line %d bool(false) Warning: gmp_div_q(): Unable to convert variable to GMP - wrong type in %s on line %d diff --git a/ext/gmp/tests/010.phpt b/ext/gmp/tests/010.phpt index 293a2a0bf20c..59b8d847004a 100644 --- a/ext/gmp/tests/010.phpt +++ b/ext/gmp/tests/010.phpt @@ -29,12 +29,18 @@ Warning: gmp_mod() expects exactly 2 parameters, 1 given in %s on line %d NULL bool(false) int(0) -resource(%d) of type (GMP integer) +object(GMP)#%d (1) { + ["num"]=> + string(1) "0" +} Warning: gmp_mod(): Zero operand not allowed in %s on line %d bool(false) Warning: gmp_mod(): Unable to convert variable to GMP - wrong type in %s on line %d bool(false) -resource(%d) of type (GMP integer) +object(GMP)#%d (1) { + ["num"]=> + string(5) "31161" +} Done diff --git a/ext/gmp/tests/014.phpt b/ext/gmp/tests/014.phpt index 40e10c6fbe03..6afccaf936cc 100644 --- a/ext/gmp/tests/014.phpt +++ b/ext/gmp/tests/014.phpt @@ -43,7 +43,7 @@ string(19) "2432902008176640000" string(65) "30414093201713378043612608166064768844377641568960512000000000000" string(7) "3628800" string(1) "1" -string(11) "87178291200" +string(9) "479001600" Warning: gmp_fact(): Number has to be greater than or equal to 0 in %s on line %d string(1) "0" @@ -53,6 +53,9 @@ NULL Warning: gmp_fact() expects exactly 1 parameter, 2 given in %s on line %d NULL -resource(%d) of type (GMP integer) +object(GMP)#%d (1) { + ["num"]=> + string(1) "1" +} string(1) "1" Done diff --git a/ext/gmp/tests/016.phpt b/ext/gmp/tests/016.phpt index 44360865ca8a..8a0b34458fe3 100644 --- a/ext/gmp/tests/016.phpt +++ b/ext/gmp/tests/016.phpt @@ -69,5 +69,8 @@ NULL Warning: gmp_powm(): Second parameter cannot be less than 0 in %s on line %d bool(false) -resource(%d) of type (GMP integer) +object(GMP)#%d (1) { + ["num"]=> + string(1) "1" +} Done diff --git a/ext/gmp/tests/033.phpt b/ext/gmp/tests/033.phpt index 38ff5be5bf94..99848959d52d 100644 --- a/ext/gmp/tests/033.phpt +++ b/ext/gmp/tests/033.phpt @@ -52,13 +52,13 @@ string(12) "100008388608" string(12) "100000000000" string(12) "100000000008" -Warning: gmp_setbit(): supplied argument is not a valid GMP integer resource in %s on line %d +Warning: gmp_setbit() expects parameter 1 to be GMP, string given in %s on line %d Warning: gmp_setbit() expects at least 2 parameters, 1 given in %s on line %d Warning: gmp_setbit() expects at most 3 parameters, 4 given in %s on line %d -Warning: gmp_setbit() expects parameter 2 to be long, array given in %s on line %d +Warning: gmp_setbit() expects parameter 1 to be GMP, string given in %s on line %d -Warning: gmp_setbit() expects parameter 2 to be long, array given in %s on line %d +Warning: gmp_setbit() expects parameter 1 to be GMP, array given in %s on line %d Done diff --git a/ext/gmp/tests/034.phpt b/ext/gmp/tests/034.phpt index 601102990557..079d5d669f37 100644 --- a/ext/gmp/tests/034.phpt +++ b/ext/gmp/tests/034.phpt @@ -46,7 +46,7 @@ string(7) "1000000" string(7) "1000000" string(30) "238462734628347239571822592658" -Warning: gmp_clrbit(): supplied argument is not a valid GMP integer resource in %s on line %d +Warning: gmp_clrbit() expects parameter 1 to be GMP, array given in %s on line %d Warning: gmp_clrbit() expects exactly 2 parameters, 3 given in %s on line %d diff --git a/ext/gmp/tests/040.phpt b/ext/gmp/tests/040.phpt index 3af18cce59aa..9cc497edc6c1 100644 --- a/ext/gmp/tests/040.phpt +++ b/ext/gmp/tests/040.phpt @@ -18,7 +18,10 @@ var_dump(gmp_strval(gmp_init("993247326237679187178",3))); echo "Done\n"; ?> --EXPECTF-- -resource(%d) of type (GMP integer) +object(GMP)#%d (1) { + ["num"]=> + string(8) "98765678" +} string(8) "98765678" Warning: gmp_init() expects at least 1 parameter, 0 given in %s on line %d diff --git a/ext/gmp/tests/cast.phpt b/ext/gmp/tests/cast.phpt new file mode 100644 index 000000000000..eb1832c4dd91 --- /dev/null +++ b/ext/gmp/tests/cast.phpt @@ -0,0 +1,22 @@ +--TEST-- +GMP casting using casting operators +--SKIPIF-- + +--FILE-- + +--EXPECTF-- +42 +string(2) "42" +int(42) +float(42) + +Catchable fatal error: Object of class GMP could not be converted to boolean in %s on line %d diff --git a/ext/gmp/tests/clone.phpt b/ext/gmp/tests/clone.phpt new file mode 100644 index 000000000000..56b5ca3dfeee --- /dev/null +++ b/ext/gmp/tests/clone.phpt @@ -0,0 +1,22 @@ +--TEST-- +Cloning GMP instances +--SKIPIF-- + +--FILE-- + +--EXPECTF-- +object(GMP)#1 (1) { + ["num"]=> + string(1) "2" +} +object(GMP)#2 (1) { + ["num"]=> + string(1) "3" +} diff --git a/ext/gmp/tests/overloading.phpt b/ext/gmp/tests/overloading.phpt new file mode 100644 index 000000000000..05b6e6729e0f --- /dev/null +++ b/ext/gmp/tests/overloading.phpt @@ -0,0 +1,225 @@ +--TEST-- +GMP operator overloading +--FILE-- + $b); +var_dump($a >= $b); + +var_dump($a == $a); +var_dump($a != $a); + +var_dump($a == 42); +var_dump($a != 42); +var_dump($a < 42); +var_dump($a <= 42); +var_dump($a > 42); +var_dump($a >= 42); + +$a += 1; +var_dump($a); +$a -= 1; +var_dump($a); + +var_dump(++$a); +var_dump($a++); +var_dump($a); + +var_dump(--$a); +var_dump($a--); +var_dump($a); + +?> +--EXPECTF-- +object(GMP)#%d (1) { + ["num"]=> + string(2) "59" +} +object(GMP)#%d (1) { + ["num"]=> + string(2) "59" +} +object(GMP)#%d (1) { + ["num"]=> + string(2) "59" +} +object(GMP)#%d (1) { + ["num"]=> + string(2) "25" +} +object(GMP)#%d (1) { + ["num"]=> + string(2) "25" +} +object(GMP)#%d (1) { + ["num"]=> + string(2) "25" +} +object(GMP)#%d (1) { + ["num"]=> + string(1) "2" +} +object(GMP)#%d (1) { + ["num"]=> + string(1) "2" +} +object(GMP)#%d (1) { + ["num"]=> + string(1) "2" +} + +Warning: main(): Zero operand not allowed in %s on line %d +bool(false) +object(GMP)#%d (1) { + ["num"]=> + string(1) "8" +} +object(GMP)#%d (1) { + ["num"]=> + string(1) "8" +} +object(GMP)#%d (1) { + ["num"]=> + string(1) "8" +} + +Warning: main(): Zero operand not allowed in %s on line %d +bool(false) +object(GMP)#%d (1) { + ["num"]=> + string(2) "59" +} +object(GMP)#%d (1) { + ["num"]=> + string(2) "59" +} +object(GMP)#%d (1) { + ["num"]=> + string(2) "59" +} +object(GMP)#%d (1) { + ["num"]=> + string(1) "0" +} +object(GMP)#%d (1) { + ["num"]=> + string(1) "0" +} +object(GMP)#%d (1) { + ["num"]=> + string(1) "0" +} +object(GMP)#%d (1) { + ["num"]=> + string(2) "59" +} +object(GMP)#%d (1) { + ["num"]=> + string(2) "59" +} +object(GMP)#%d (1) { + ["num"]=> + string(2) "59" +} +object(GMP)#%d (1) { + ["num"]=> + string(3) "-43" +} +object(GMP)#%d (1) { + ["num"]=> + string(3) "-42" +} +object(GMP)#%d (1) { + ["num"]=> + string(2) "42" +} +bool(false) +bool(true) +bool(false) +bool(false) +bool(true) +bool(true) +bool(true) +bool(false) +bool(true) +bool(false) +bool(false) +bool(true) +bool(false) +bool(true) +object(GMP)#%d (1) { + ["num"]=> + string(2) "43" +} +object(GMP)#%d (1) { + ["num"]=> + string(2) "42" +} +object(GMP)#%d (1) { + ["num"]=> + string(2) "43" +} +object(GMP)#%d (1) { + ["num"]=> + string(2) "43" +} +object(GMP)#%d (1) { + ["num"]=> + string(2) "44" +} +object(GMP)#%d (1) { + ["num"]=> + string(2) "43" +} +object(GMP)#%d (1) { + ["num"]=> + string(2) "43" +} +object(GMP)#%d (1) { + ["num"]=> + string(2) "42" +} + diff --git a/ext/gmp/tests/serialize.phpt b/ext/gmp/tests/serialize.phpt new file mode 100644 index 000000000000..26716b659c36 --- /dev/null +++ b/ext/gmp/tests/serialize.phpt @@ -0,0 +1,22 @@ +--TEST-- +GMP serialization and unserialization +--SKIPIF-- + +--FILE-- + +--EXPECTF-- +object(GMP)#%d (1) { + ["num"]=> + string(2) "42" +} +string(33) "O:3:"GMP":1:{s:3:"num";s:2:"42";}" +object(GMP)#%d (1) { + ["num"]=> + string(2) "42" +} From 1234aca01184d09bcb76bae3655977356c6c5585 Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Sun, 12 May 2013 20:24:38 +0200 Subject: [PATCH 02/11] Improve GMP performance a) Allow to specify an initial value when creating a GMP object b) Allow creating the object into an existing zval rather than doing a alloc, copy, dtor cycle --- Zend/zend_object_handlers.h | 1 + ext/gmp/gmp.c | 37 ++++++++++++++++++++++--------------- 2 files changed, 23 insertions(+), 15 deletions(-) diff --git a/Zend/zend_object_handlers.h b/Zend/zend_object_handlers.h index b8580300c087..0dec586b4936 100644 --- a/Zend/zend_object_handlers.h +++ b/Zend/zend_object_handlers.h @@ -175,6 +175,7 @@ ZEND_API int zend_check_protected(zend_class_entry *ce, zend_class_entry *scope) ZEND_API int zend_check_property_access(zend_object *zobj, const char *prop_info_name, int prop_info_name_len TSRMLS_DC); ZEND_API void zend_std_call_user_call(INTERNAL_FUNCTION_PARAMETERS); +END_EXTERN_C() #endif diff --git a/ext/gmp/gmp.c b/ext/gmp/gmp.c index bffd973882a8..d83c3f92dc6a 100644 --- a/ext/gmp/gmp.c +++ b/ext/gmp/gmp.c @@ -392,10 +392,8 @@ if (IS_GMP_PP(zval)) { \ #define INIT_GMP_NUM(gmpnumber) { gmpnumber = emalloc(sizeof(mpz_t)); mpz_init(*gmpnumber); } #define FREE_GMP_NUM(gmpnumber) { mpz_clear(*gmpnumber); efree(gmpnumber); } -#define RETVAL_GMP(gmpnumber) do { \ - zval *_r = gmp_create((gmpnumber) TSRMLS_CC); \ - RETVAL_ZVAL(_r, 1, 1) \ -} while (0); +#define RETVAL_GMP(gmpnumber) \ + gmp_create_ex(return_value, (gmpnumber) TSRMLS_CC) #define ADD_INDEX_GMP(array, index, gmpnumber) do { \ zval *_r = gmp_create((gmpnumber) TSRMLS_CC); \ @@ -446,16 +444,19 @@ static void gmp_free_object_storage(gmp_object *intern TSRMLS_DC) /* {{{ */ } /* }}} */ -static zend_object_value gmp_create_object(zend_class_entry *ce TSRMLS_DC) /* {{{ */ +static zend_object_value gmp_create_object_ex(zend_class_entry *ce, mpz_t *init_num TSRMLS_DC) /* {{{ */ { zend_object_value retval; gmp_object *intern = emalloc(sizeof(gmp_object)); - memset(intern, 0, sizeof(gmp_object)); zend_object_std_init(&intern->std, ce TSRMLS_CC); object_properties_init(&intern->std, ce); - INIT_GMP_NUM(intern->num); + if (init_num) { + intern->num = init_num; + } else { + INIT_GMP_NUM(intern->num); + } retval.handle = zend_objects_store_put( intern, (zend_objects_store_dtor_t) zend_objects_destroy_object, @@ -468,18 +469,24 @@ static zend_object_value gmp_create_object(zend_class_entry *ce TSRMLS_DC) /* {{ } /* }}} */ +static zend_object_value gmp_create_object(zend_class_entry *ce TSRMLS_DC) /* {{{ */ +{ + return gmp_create_object_ex(ce, NULL TSRMLS_DC); +} +/* }}} */ + +static inline void gmp_create_ex(zval *target, mpz_t *gmpnumber TSRMLS_DC) /* {{{ */ +{ + Z_TYPE_P(target) = IS_OBJECT; + Z_OBJVAL_P(target) = gmp_create_object_ex(gmp_ce, gmpnumber TSRMLS_CC); +} +/* }}} */ + static zval *gmp_create(mpz_t *gmpnumber TSRMLS_DC) /* {{{ */ { zval *obj; - gmp_object *intern; MAKE_STD_ZVAL(obj); - - object_init_ex(obj, gmp_ce); - intern = (gmp_object *) zend_object_store_get_object(obj TSRMLS_CC); - - FREE_GMP_NUM(intern->num); - intern->num = gmpnumber; - + gmp_create_ex(obj, gmpnumber TSRMLS_DC); return obj; } /* }}} */ From 9ba573986e2762485bf817660b9cda648f5d5a38 Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Sun, 12 May 2013 21:43:16 +0200 Subject: [PATCH 03/11] More perf improvement --- ext/gmp/gmp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/gmp/gmp.c b/ext/gmp/gmp.c index d83c3f92dc6a..f5ac7e95def2 100644 --- a/ext/gmp/gmp.c +++ b/ext/gmp/gmp.c @@ -444,7 +444,7 @@ static void gmp_free_object_storage(gmp_object *intern TSRMLS_DC) /* {{{ */ } /* }}} */ -static zend_object_value gmp_create_object_ex(zend_class_entry *ce, mpz_t *init_num TSRMLS_DC) /* {{{ */ +static inline zend_object_value gmp_create_object_ex(zend_class_entry *ce, mpz_t *init_num TSRMLS_DC) /* {{{ */ { zend_object_value retval; gmp_object *intern = emalloc(sizeof(gmp_object)); From 208442f84afd7ccd8e2dce8138c0950719a2e031 Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Mon, 13 May 2013 12:43:20 +0200 Subject: [PATCH 04/11] Add compare object handler (rather than going through do_operation) --- Zend/zend_object_handlers.c | 71 ++++++++++++++++++++++++++++ Zend/zend_object_handlers.h | 7 ++- Zend/zend_operators.c | 88 +++-------------------------------- Zend/zend_operators.h | 16 +++---- ext/gmp/gmp.c | 28 ++++------- ext/gmp/tests/comparison.phpt | 35 ++++++++++++++ 6 files changed, 136 insertions(+), 109 deletions(-) create mode 100644 ext/gmp/tests/comparison.phpt diff --git a/Zend/zend_object_handlers.c b/Zend/zend_object_handlers.c index 24d4a85f79c8..99a8bf447429 100644 --- a/Zend/zend_object_handlers.c +++ b/Zend/zend_object_handlers.c @@ -1393,6 +1393,77 @@ static int zend_std_compare_objects(zval *o1, zval *o2 TSRMLS_DC) /* {{{ */ } /* }}} */ +static inline void zend_free_obj_get_result(zval *op TSRMLS_DC) /* {{{ */ +{ + if (Z_REFCOUNT_P(op) == 0) { + GC_REMOVE_ZVAL_FROM_BUFFER(op); + zval_dtor(op); + FREE_ZVAL(op); + } else { + zval_ptr_dtor(&op); + } +} +/* }}} */ + +ZEND_API int zend_std_compare(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */ +{ + int ret; + zval *op_free; + + if (Z_TYPE_P(op1) == IS_OBJECT && Z_TYPE_P(op2) == IS_OBJECT) { + if (Z_OBJ_HANDLE_P(op1) == Z_OBJ_HANDLE_P(op2)) { + ZVAL_LONG(result, 0); + return SUCCESS; + } + if (Z_OBJ_HANDLER_P(op1, compare_objects) == Z_OBJ_HANDLER_P(op2, compare_objects)) { + ZVAL_LONG(result, Z_OBJ_HANDLER_P(op1, compare_objects)(op1, op2 TSRMLS_CC)); + return SUCCESS; + } + } + + if (Z_TYPE_P(op1) == IS_OBJECT) { + if (Z_OBJ_HT_P(op1)->get) { + op_free = Z_OBJ_HT_P(op1)->get(op1 TSRMLS_CC); + ret = compare_function(result, op_free, op2 TSRMLS_CC); + zend_free_obj_get_result(op_free TSRMLS_CC); + return ret; + } else if (Z_TYPE_P(op2) != IS_OBJECT && Z_OBJ_HT_P(op1)->cast_object) { + ALLOC_INIT_ZVAL(op_free); + if (Z_OBJ_HT_P(op1)->cast_object(op1, op_free, Z_TYPE_P(op2) TSRMLS_CC) == FAILURE) { + ZVAL_LONG(result, 1); + zend_free_obj_get_result(op_free TSRMLS_CC); + return SUCCESS; + } + ret = compare_function(result, op_free, op2 TSRMLS_CC); + zend_free_obj_get_result(op_free TSRMLS_CC); + return ret; + } + } + + if (Z_TYPE_P(op2) == IS_OBJECT) { + if (Z_OBJ_HT_P(op2)->get) { + op_free = Z_OBJ_HT_P(op2)->get(op2 TSRMLS_CC); + ret = compare_function(result, op1, op_free TSRMLS_CC); + zend_free_obj_get_result(op_free TSRMLS_CC); + return ret; + } else if (Z_TYPE_P(op1) != IS_OBJECT && Z_OBJ_HT_P(op2)->cast_object) { + ALLOC_INIT_ZVAL(op_free); + if (Z_OBJ_HT_P(op2)->cast_object(op2, op_free, Z_TYPE_P(op1) TSRMLS_CC) == FAILURE) { + ZVAL_LONG(result, -1); + zend_free_obj_get_result(op_free TSRMLS_CC); + return SUCCESS; + } + ret = compare_function(result, op1, op_free TSRMLS_CC); + zend_free_obj_get_result(op_free TSRMLS_CC); + return ret; + } + } + + ZVAL_LONG(result, 1); + return SUCCESS; +} +/* }}} */ + static int zend_std_has_property(zval *object, zval *member, int has_set_exists, const zend_literal *key TSRMLS_DC) /* {{{ */ { zend_object *zobj; diff --git a/Zend/zend_object_handlers.h b/Zend/zend_object_handlers.h index 0dec586b4936..c6d1f96d90a9 100644 --- a/Zend/zend_object_handlers.h +++ b/Zend/zend_object_handlers.h @@ -99,7 +99,8 @@ typedef zend_object_value (*zend_object_clone_obj_t)(zval *object TSRMLS_DC); typedef zend_class_entry *(*zend_object_get_class_entry_t)(const zval *object TSRMLS_DC); typedef int (*zend_object_get_class_name_t)(const zval *object, const char **class_name, zend_uint *class_name_len, int parent TSRMLS_DC); -typedef int (*zend_object_compare_t)(zval *object1, zval *object2 TSRMLS_DC); +typedef int (*zend_object_compare_objects_t)(zval *object1, zval *object2 TSRMLS_DC); +typedef int (*zend_object_compare_t)(zval *resul, zval *op1, zval *op2 TSRMLS_DC); /* Cast an object to some other type */ @@ -138,13 +139,14 @@ struct _zend_object_handlers { zend_object_get_constructor_t get_constructor; zend_object_get_class_entry_t get_class_entry; zend_object_get_class_name_t get_class_name; - zend_object_compare_t compare_objects; + zend_object_compare_objects_t compare_objects; zend_object_cast_t cast_object; zend_object_count_elements_t count_elements; zend_object_get_debug_info_t get_debug_info; zend_object_get_closure_t get_closure; zend_object_get_gc_t get_gc; zend_object_do_operation_t do_operation; + zend_object_compare_t compare; }; extern ZEND_API zend_object_handlers std_object_handlers; @@ -162,6 +164,7 @@ ZEND_API HashTable *zend_std_get_properties(zval *object TSRMLS_DC); ZEND_API HashTable *zend_std_get_debug_info(zval *object, int *is_temp TSRMLS_DC); ZEND_API int zend_std_cast_object_tostring(zval *readobj, zval *writeobj, int type TSRMLS_DC); ZEND_API void zend_std_write_property(zval *object, zval *member, zval *value, const struct _zend_literal *key TSRMLS_DC); +ZEND_API int zend_std_compare(zval *result, zval *op1, zval *op2 TSRMLS_DC); ZEND_API void rebuild_object_properties(zend_object *zobj); diff --git a/Zend/zend_operators.c b/Zend/zend_operators.c index 6cb8f6adc404..30c75c071e13 100644 --- a/Zend/zend_operators.c +++ b/Zend/zend_operators.c @@ -1498,24 +1498,10 @@ ZEND_API int numeric_compare_function(zval *result, zval *op1, zval *op2 TSRMLS_ } /* }}} */ -static inline void zend_free_obj_get_result(zval *op TSRMLS_DC) /* {{{ */ -{ - if (Z_REFCOUNT_P(op) == 0) { - GC_REMOVE_ZVAL_FROM_BUFFER(op); - zval_dtor(op); - FREE_ZVAL(op); - } else { - zval_ptr_dtor(&op); - } -} -/* }}} */ - ZEND_API int compare_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */ { - int ret; int converted = 0; zval op1_copy, op2_copy; - zval *op_free; while (1) { switch (TYPE_PAIR(Z_TYPE_P(op1), Z_TYPE_P(op2))) { @@ -1582,59 +1568,15 @@ ZEND_API int compare_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* { ZVAL_LONG(result, -1); return SUCCESS; - case TYPE_PAIR(IS_OBJECT, IS_OBJECT): - /* If both are objects sharing the same comparision handler then use is */ - if (Z_OBJ_HANDLER_P(op1,compare_objects) == Z_OBJ_HANDLER_P(op2,compare_objects)) { - if (Z_OBJ_HANDLE_P(op1) == Z_OBJ_HANDLE_P(op2)) { - /* object handles are identical, apprently this is the same object */ - ZVAL_LONG(result, 0); - return SUCCESS; - } - ZVAL_LONG(result, Z_OBJ_HT_P(op1)->compare_objects(op1, op2 TSRMLS_CC)); - return SUCCESS; - } - /* break missing intentionally */ - default: - if (Z_TYPE_P(op1) == IS_OBJECT) { - if (Z_OBJ_HT_P(op1)->get) { - op_free = Z_OBJ_HT_P(op1)->get(op1 TSRMLS_CC); - ret = compare_function(result, op_free, op2 TSRMLS_CC); - zend_free_obj_get_result(op_free TSRMLS_CC); - return ret; - } else if (Z_TYPE_P(op2) != IS_OBJECT && Z_OBJ_HT_P(op1)->cast_object) { - ALLOC_INIT_ZVAL(op_free); - if (Z_OBJ_HT_P(op1)->cast_object(op1, op_free, Z_TYPE_P(op2) TSRMLS_CC) == FAILURE) { - ZVAL_LONG(result, 1); - zend_free_obj_get_result(op_free TSRMLS_CC); - return SUCCESS; - } - ret = compare_function(result, op_free, op2 TSRMLS_CC); - zend_free_obj_get_result(op_free TSRMLS_CC); - return ret; - } - } - if (Z_TYPE_P(op2) == IS_OBJECT) { - if (Z_OBJ_HT_P(op2)->get) { - op_free = Z_OBJ_HT_P(op2)->get(op2 TSRMLS_CC); - ret = compare_function(result, op1, op_free TSRMLS_CC); - zend_free_obj_get_result(op_free TSRMLS_CC); - return ret; - } else if (Z_TYPE_P(op1) != IS_OBJECT && Z_OBJ_HT_P(op2)->cast_object) { - ALLOC_INIT_ZVAL(op_free); - if (Z_OBJ_HT_P(op2)->cast_object(op2, op_free, Z_TYPE_P(op1) TSRMLS_CC) == FAILURE) { - ZVAL_LONG(result, -1); - zend_free_obj_get_result(op_free TSRMLS_CC); - return SUCCESS; - } - ret = compare_function(result, op1, op_free TSRMLS_CC); - zend_free_obj_get_result(op_free TSRMLS_CC); - return ret; - } else if (Z_TYPE_P(op1) == IS_OBJECT) { - ZVAL_LONG(result, 1); - return SUCCESS; - } + if (Z_TYPE_P(op1) == IS_OBJECT && Z_OBJ_HANDLER_P(op1, compare)) { + return Z_OBJ_HANDLER_P(op1, compare)(result, op1, op2 TSRMLS_CC); + } else if (Z_TYPE_P(op2) == IS_OBJECT && Z_OBJ_HANDLER_P(op2, compare)) { + return Z_OBJ_HANDLER_P(op2, compare)(result, op1, op2 TSRMLS_CC); + } else if (Z_TYPE_P(op1) == IS_OBJECT || Z_TYPE_P(op2) == IS_OBJECT) { + return zend_std_compare(result, op1, op2 TSRMLS_CC); } + if (!converted) { if (Z_TYPE_P(op1) == IS_NULL) { zendi_convert_to_boolean(op2, op2_copy, result); @@ -1749,10 +1691,6 @@ ZEND_API int is_not_identical_function(zval *result, zval *op1, zval *op2 TSRMLS ZEND_API int is_equal_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */ { - if (zend_object_do_operation(ZEND_IS_EQUAL, result, op1, op2 TSRMLS_CC) == SUCCESS) { - return SUCCESS; - } - if (compare_function(result, op1, op2 TSRMLS_CC) == FAILURE) { return FAILURE; } @@ -1764,10 +1702,6 @@ ZEND_API int is_equal_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* ZEND_API int is_not_equal_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */ { - if (zend_object_do_operation(ZEND_IS_NOT_EQUAL, result, op1, op2 TSRMLS_CC) == SUCCESS) { - return SUCCESS; - } - if (compare_function(result, op1, op2 TSRMLS_CC) == FAILURE) { return FAILURE; } @@ -1779,10 +1713,6 @@ ZEND_API int is_not_equal_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) ZEND_API int is_smaller_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */ { - if (zend_object_do_operation(ZEND_IS_SMALLER, result, op1, op2 TSRMLS_CC) == SUCCESS) { - return SUCCESS; - } - if (compare_function(result, op1, op2 TSRMLS_CC) == FAILURE) { return FAILURE; } @@ -1794,10 +1724,6 @@ ZEND_API int is_smaller_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) / ZEND_API int is_smaller_or_equal_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */ { - if (zend_object_do_operation(ZEND_IS_SMALLER_OR_EQUAL, result, op1, op2 TSRMLS_CC) == SUCCESS) { - return SUCCESS; - } - if (compare_function(result, op1, op2 TSRMLS_CC) == FAILURE) { return FAILURE; } diff --git a/Zend/zend_operators.h b/Zend/zend_operators.h index 483012662a98..9a0684af18e2 100644 --- a/Zend/zend_operators.h +++ b/Zend/zend_operators.h @@ -884,8 +884,8 @@ static zend_always_inline int fast_equal_function(zval *result, zval *op1, zval return Z_DVAL_P(op1) == ((double)Z_LVAL_P(op2)); } } - is_equal_function(result, op1, op2 TSRMLS_CC); - return Z_LVAL_P(result); + compare_function(result, op1, op2 TSRMLS_CC); + return Z_LVAL_P(result) == 0; } static zend_always_inline int fast_not_equal_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) @@ -903,8 +903,8 @@ static zend_always_inline int fast_not_equal_function(zval *result, zval *op1, z return Z_DVAL_P(op1) != ((double)Z_LVAL_P(op2)); } } - is_not_equal_function(result, op1, op2 TSRMLS_CC); - return Z_LVAL_P(result); + compare_function(result, op1, op2 TSRMLS_CC); + return Z_LVAL_P(result) != 0; } static zend_always_inline int fast_is_smaller_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) @@ -922,8 +922,8 @@ static zend_always_inline int fast_is_smaller_function(zval *result, zval *op1, return Z_DVAL_P(op1) < ((double)Z_LVAL_P(op2)); } } - is_smaller_function(result, op1, op2 TSRMLS_CC); - return Z_LVAL_P(result); + compare_function(result, op1, op2 TSRMLS_CC); + return Z_LVAL_P(result) < 0; } static zend_always_inline int fast_is_smaller_or_equal_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) @@ -941,8 +941,8 @@ static zend_always_inline int fast_is_smaller_or_equal_function(zval *result, zv return Z_DVAL_P(op1) <= ((double)Z_LVAL_P(op2)); } } - is_smaller_or_equal_function(result, op1, op2 TSRMLS_CC); - return Z_LVAL_P(result); + compare_function(result, op1, op2 TSRMLS_CC); + return Z_LVAL_P(result) <= 0; } static inline int zend_object_do_operation(int opcode, zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */ diff --git a/ext/gmp/gmp.c b/ext/gmp/gmp.c index f5ac7e95def2..0f91ea0462c3 100644 --- a/ext/gmp/gmp.c +++ b/ext/gmp/gmp.c @@ -471,7 +471,7 @@ static inline zend_object_value gmp_create_object_ex(zend_class_entry *ce, mpz_t static zend_object_value gmp_create_object(zend_class_entry *ce TSRMLS_DC) /* {{{ */ { - return gmp_create_object_ex(ce, NULL TSRMLS_DC); + return gmp_create_object_ex(ce, NULL TSRMLS_CC); } /* }}} */ @@ -486,7 +486,7 @@ static zval *gmp_create(mpz_t *gmpnumber TSRMLS_DC) /* {{{ */ { zval *obj; MAKE_STD_ZVAL(obj); - gmp_create_ex(obj, gmpnumber TSRMLS_DC); + gmp_create_ex(obj, gmpnumber TSRMLS_CC); return obj; } /* }}} */ @@ -603,22 +603,6 @@ static int gmp_do_operation(zend_uchar opcode, zval *result, zval *op1, zval *op DO_BINARY_OP(mpz_xor); case ZEND_BW_NOT: DO_UNARY_OP(mpz_com); - case ZEND_IS_EQUAL: - gmp_cmp(result, &op1, &op2 TSRMLS_CC); - ZVAL_BOOL(result, Z_LVAL_P(result) == 0); - return SUCCESS; - case ZEND_IS_NOT_EQUAL: - gmp_cmp(result, &op1, &op2 TSRMLS_CC); - ZVAL_BOOL(result, Z_LVAL_P(result) != 0); - return SUCCESS; - case ZEND_IS_SMALLER: - gmp_cmp(result, &op1, &op2 TSRMLS_CC); - ZVAL_BOOL(result, Z_LVAL_P(result) < 0); - return SUCCESS; - case ZEND_IS_SMALLER_OR_EQUAL: - gmp_cmp(result, &op1, &op2 TSRMLS_CC); - ZVAL_BOOL(result, Z_LVAL_P(result) <= 0); - return SUCCESS; default: return FAILURE; @@ -626,6 +610,13 @@ static int gmp_do_operation(zend_uchar opcode, zval *result, zval *op1, zval *op } /* }}} */ +static int gmp_compare(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */ +{ + gmp_cmp(result, &op1, &op2 TSRMLS_CC); + return SUCCESS; +} +/* }}} */ + PHP_METHOD(GMP, __wakeup) /* {{{ */ { HashTable *props; @@ -685,6 +676,7 @@ ZEND_MINIT_FUNCTION(gmp) gmp_object_handlers.get_properties = gmp_get_properties; gmp_object_handlers.clone_obj = gmp_clone_obj; gmp_object_handlers.do_operation = gmp_do_operation; + gmp_object_handlers.compare = gmp_compare; REGISTER_LONG_CONSTANT("GMP_ROUND_ZERO", GMP_ROUND_ZERO, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("GMP_ROUND_PLUSINF", GMP_ROUND_PLUSINF, CONST_CS | CONST_PERSISTENT); diff --git a/ext/gmp/tests/comparison.phpt b/ext/gmp/tests/comparison.phpt new file mode 100644 index 000000000000..764f76fe9b70 --- /dev/null +++ b/ext/gmp/tests/comparison.phpt @@ -0,0 +1,35 @@ +--TEST-- +Overloaded GMP comparison in sort() etc +--FILE-- + +--EXPECT-- +array(4) { + [0]=> + int(-3) + [1]=> + object(GMP)#1 (1) { + ["num"]=> + string(1) "0" + } + [2]=> + int(1) + [3]=> + object(GMP)#2 (1) { + ["num"]=> + string(1) "2" + } +} +object(GMP)#3 (1) { + ["num"]=> + string(1) "3" +} +int(4) From 4f9b11446843e62e8df12002ae15032735576599 Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Mon, 13 May 2013 18:04:43 +0200 Subject: [PATCH 05/11] Move std_compare code back to compare_function --- Zend/zend_object_handlers.c | 72 +------------------------------------ Zend/zend_object_handlers.h | 1 - Zend/zend_operators.c | 69 +++++++++++++++++++++++++++++++---- 3 files changed, 64 insertions(+), 78 deletions(-) diff --git a/Zend/zend_object_handlers.c b/Zend/zend_object_handlers.c index 99a8bf447429..4830e0a095eb 100644 --- a/Zend/zend_object_handlers.c +++ b/Zend/zend_object_handlers.c @@ -1393,77 +1393,6 @@ static int zend_std_compare_objects(zval *o1, zval *o2 TSRMLS_DC) /* {{{ */ } /* }}} */ -static inline void zend_free_obj_get_result(zval *op TSRMLS_DC) /* {{{ */ -{ - if (Z_REFCOUNT_P(op) == 0) { - GC_REMOVE_ZVAL_FROM_BUFFER(op); - zval_dtor(op); - FREE_ZVAL(op); - } else { - zval_ptr_dtor(&op); - } -} -/* }}} */ - -ZEND_API int zend_std_compare(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */ -{ - int ret; - zval *op_free; - - if (Z_TYPE_P(op1) == IS_OBJECT && Z_TYPE_P(op2) == IS_OBJECT) { - if (Z_OBJ_HANDLE_P(op1) == Z_OBJ_HANDLE_P(op2)) { - ZVAL_LONG(result, 0); - return SUCCESS; - } - if (Z_OBJ_HANDLER_P(op1, compare_objects) == Z_OBJ_HANDLER_P(op2, compare_objects)) { - ZVAL_LONG(result, Z_OBJ_HANDLER_P(op1, compare_objects)(op1, op2 TSRMLS_CC)); - return SUCCESS; - } - } - - if (Z_TYPE_P(op1) == IS_OBJECT) { - if (Z_OBJ_HT_P(op1)->get) { - op_free = Z_OBJ_HT_P(op1)->get(op1 TSRMLS_CC); - ret = compare_function(result, op_free, op2 TSRMLS_CC); - zend_free_obj_get_result(op_free TSRMLS_CC); - return ret; - } else if (Z_TYPE_P(op2) != IS_OBJECT && Z_OBJ_HT_P(op1)->cast_object) { - ALLOC_INIT_ZVAL(op_free); - if (Z_OBJ_HT_P(op1)->cast_object(op1, op_free, Z_TYPE_P(op2) TSRMLS_CC) == FAILURE) { - ZVAL_LONG(result, 1); - zend_free_obj_get_result(op_free TSRMLS_CC); - return SUCCESS; - } - ret = compare_function(result, op_free, op2 TSRMLS_CC); - zend_free_obj_get_result(op_free TSRMLS_CC); - return ret; - } - } - - if (Z_TYPE_P(op2) == IS_OBJECT) { - if (Z_OBJ_HT_P(op2)->get) { - op_free = Z_OBJ_HT_P(op2)->get(op2 TSRMLS_CC); - ret = compare_function(result, op1, op_free TSRMLS_CC); - zend_free_obj_get_result(op_free TSRMLS_CC); - return ret; - } else if (Z_TYPE_P(op1) != IS_OBJECT && Z_OBJ_HT_P(op2)->cast_object) { - ALLOC_INIT_ZVAL(op_free); - if (Z_OBJ_HT_P(op2)->cast_object(op2, op_free, Z_TYPE_P(op1) TSRMLS_CC) == FAILURE) { - ZVAL_LONG(result, -1); - zend_free_obj_get_result(op_free TSRMLS_CC); - return SUCCESS; - } - ret = compare_function(result, op1, op_free TSRMLS_CC); - zend_free_obj_get_result(op_free TSRMLS_CC); - return ret; - } - } - - ZVAL_LONG(result, 1); - return SUCCESS; -} -/* }}} */ - static int zend_std_has_property(zval *object, zval *member, int has_set_exists, const zend_literal *key TSRMLS_DC) /* {{{ */ { zend_object *zobj; @@ -1715,6 +1644,7 @@ ZEND_API zend_object_handlers std_object_handlers = { zend_std_get_closure, /* get_closure */ zend_std_get_gc, /* get_gc */ NULL, /* do_operation */ + NULL, /* compare */ }; /* diff --git a/Zend/zend_object_handlers.h b/Zend/zend_object_handlers.h index c6d1f96d90a9..59421b665e71 100644 --- a/Zend/zend_object_handlers.h +++ b/Zend/zend_object_handlers.h @@ -164,7 +164,6 @@ ZEND_API HashTable *zend_std_get_properties(zval *object TSRMLS_DC); ZEND_API HashTable *zend_std_get_debug_info(zval *object, int *is_temp TSRMLS_DC); ZEND_API int zend_std_cast_object_tostring(zval *readobj, zval *writeobj, int type TSRMLS_DC); ZEND_API void zend_std_write_property(zval *object, zval *member, zval *value, const struct _zend_literal *key TSRMLS_DC); -ZEND_API int zend_std_compare(zval *result, zval *op1, zval *op2 TSRMLS_DC); ZEND_API void rebuild_object_properties(zend_object *zobj); diff --git a/Zend/zend_operators.c b/Zend/zend_operators.c index 30c75c071e13..1b884d6cbd83 100644 --- a/Zend/zend_operators.c +++ b/Zend/zend_operators.c @@ -1498,10 +1498,24 @@ ZEND_API int numeric_compare_function(zval *result, zval *op1, zval *op2 TSRMLS_ } /* }}} */ +static inline void zend_free_obj_get_result(zval *op TSRMLS_DC) /* {{{ */ +{ + if (Z_REFCOUNT_P(op) == 0) { + GC_REMOVE_ZVAL_FROM_BUFFER(op); + zval_dtor(op); + FREE_ZVAL(op); + } else { + zval_ptr_dtor(&op); + } +} +/* }}} */ + ZEND_API int compare_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */ { + int ret; int converted = 0; zval op1_copy, op2_copy; + zval *op_free; while (1) { switch (TYPE_PAIR(Z_TYPE_P(op1), Z_TYPE_P(op2))) { @@ -1573,10 +1587,57 @@ ZEND_API int compare_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* { return Z_OBJ_HANDLER_P(op1, compare)(result, op1, op2 TSRMLS_CC); } else if (Z_TYPE_P(op2) == IS_OBJECT && Z_OBJ_HANDLER_P(op2, compare)) { return Z_OBJ_HANDLER_P(op2, compare)(result, op1, op2 TSRMLS_CC); - } else if (Z_TYPE_P(op1) == IS_OBJECT || Z_TYPE_P(op2) == IS_OBJECT) { - return zend_std_compare(result, op1, op2 TSRMLS_CC); } + if (Z_TYPE_P(op1) == IS_OBJECT && Z_TYPE_P(op2) == IS_OBJECT) { + if (Z_OBJ_HANDLE_P(op1) == Z_OBJ_HANDLE_P(op2)) { + ZVAL_LONG(result, 0); + return SUCCESS; + } + if (Z_OBJ_HANDLER_P(op1, compare_objects) == Z_OBJ_HANDLER_P(op2, compare_objects)) { + ZVAL_LONG(result, Z_OBJ_HANDLER_P(op1, compare_objects)(op1, op2 TSRMLS_CC)); + return SUCCESS; + } + } + if (Z_TYPE_P(op1) == IS_OBJECT) { + if (Z_OBJ_HT_P(op1)->get) { + op_free = Z_OBJ_HT_P(op1)->get(op1 TSRMLS_CC); + ret = compare_function(result, op_free, op2 TSRMLS_CC); + zend_free_obj_get_result(op_free TSRMLS_CC); + return ret; + } else if (Z_TYPE_P(op2) != IS_OBJECT && Z_OBJ_HT_P(op1)->cast_object) { + ALLOC_INIT_ZVAL(op_free); + if (Z_OBJ_HT_P(op1)->cast_object(op1, op_free, Z_TYPE_P(op2) TSRMLS_CC) == FAILURE) { + ZVAL_LONG(result, 1); + zend_free_obj_get_result(op_free TSRMLS_CC); + return SUCCESS; + } + ret = compare_function(result, op_free, op2 TSRMLS_CC); + zend_free_obj_get_result(op_free TSRMLS_CC); + return ret; + } + } + if (Z_TYPE_P(op2) == IS_OBJECT) { + if (Z_OBJ_HT_P(op2)->get) { + op_free = Z_OBJ_HT_P(op2)->get(op2 TSRMLS_CC); + ret = compare_function(result, op1, op_free TSRMLS_CC); + zend_free_obj_get_result(op_free TSRMLS_CC); + return ret; + } else if (Z_TYPE_P(op1) != IS_OBJECT && Z_OBJ_HT_P(op2)->cast_object) { + ALLOC_INIT_ZVAL(op_free); + if (Z_OBJ_HT_P(op2)->cast_object(op2, op_free, Z_TYPE_P(op1) TSRMLS_CC) == FAILURE) { + ZVAL_LONG(result, -1); + zend_free_obj_get_result(op_free TSRMLS_CC); + return SUCCESS; + } + ret = compare_function(result, op1, op_free TSRMLS_CC); + zend_free_obj_get_result(op_free TSRMLS_CC); + return ret; + } else if (Z_TYPE_P(op1) == IS_OBJECT) { + ZVAL_LONG(result, 1); + return SUCCESS; + } + } if (!converted) { if (Z_TYPE_P(op1) == IS_NULL) { zendi_convert_to_boolean(op2, op2_copy, result); @@ -1694,7 +1755,6 @@ ZEND_API int is_equal_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* if (compare_function(result, op1, op2 TSRMLS_CC) == FAILURE) { return FAILURE; } - ZVAL_BOOL(result, (Z_LVAL_P(result) == 0)); return SUCCESS; } @@ -1705,7 +1765,6 @@ ZEND_API int is_not_equal_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) if (compare_function(result, op1, op2 TSRMLS_CC) == FAILURE) { return FAILURE; } - ZVAL_BOOL(result, (Z_LVAL_P(result) != 0)); return SUCCESS; } @@ -1716,7 +1775,6 @@ ZEND_API int is_smaller_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) / if (compare_function(result, op1, op2 TSRMLS_CC) == FAILURE) { return FAILURE; } - ZVAL_BOOL(result, (Z_LVAL_P(result) < 0)); return SUCCESS; } @@ -1727,7 +1785,6 @@ ZEND_API int is_smaller_or_equal_function(zval *result, zval *op1, zval *op2 TSR if (compare_function(result, op1, op2 TSRMLS_CC) == FAILURE) { return FAILURE; } - ZVAL_BOOL(result, (Z_LVAL_P(result) <= 0)); return SUCCESS; } From 2ca35437cb4d3c8a4b6c19e54ddbd66e20c4ca64 Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Mon, 13 May 2013 21:53:22 +0200 Subject: [PATCH 06/11] A bit more cleanup * gmp_mod and gmp_div_r no longer return a long result if the modulus is long. Now a GMP instance is always return (which is of course castable to a long). * Due to the above change gmp_div_r no longer returns incorrect results in some rounding modes with a long exponent. * If an invalid rounding mode is passed a warning is thrown rather than silently returning NULL. --- ext/gmp/gmp.c | 134 +++++++++++++++-------------------------- ext/gmp/tests/007.phpt | 4 +- ext/gmp/tests/008.phpt | 60 +++++++++--------- ext/gmp/tests/009.phpt | 4 +- ext/gmp/tests/010.phpt | 5 +- 5 files changed, 93 insertions(+), 114 deletions(-) diff --git a/ext/gmp/gmp.c b/ext/gmp/gmp.c index 0f91ea0462c3..a66a8808572d 100644 --- a/ext/gmp/gmp.c +++ b/ext/gmp/gmp.c @@ -331,12 +331,11 @@ typedef void (*gmp_binary_op2_t)(mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr); typedef unsigned long (*gmp_binary_ui_op2_t)(mpz_ptr, mpz_ptr, mpz_srcptr, unsigned long); /* }}} */ -#define gmp_zval_binary_ui_op(r, a, b, o, u) gmp_zval_binary_ui_op_ex(r, a, b, o, u, 0, 0, 0 TSRMLS_CC) -#define gmp_zval_binary_ui_op2(r, a, b, o, u) gmp_zval_binary_ui_op2_ex(r, a, b, o, u, 0, 0, 0 TSRMLS_CC) - -#define gmp_binary_ui_op(op, uop) _gmp_binary_ui_op(INTERNAL_FUNCTION_PARAM_PASSTHRU, op, uop) -#define gmp_binary_op(op) _gmp_binary_ui_op(INTERNAL_FUNCTION_PARAM_PASSTHRU, op, NULL) +#define gmp_binary_ui_op(op, uop) _gmp_binary_ui_op(INTERNAL_FUNCTION_PARAM_PASSTHRU, op, uop, 0) +#define gmp_binary_op(op) _gmp_binary_ui_op(INTERNAL_FUNCTION_PARAM_PASSTHRU, op, NULL, 0) #define gmp_binary_opl(op) _gmp_binary_opl(INTERNAL_FUNCTION_PARAM_PASSTHRU, op) +#define gmp_binary_ui_op_no_zero(op, uop) \ + _gmp_binary_ui_op(INTERNAL_FUNCTION_PARAM_PASSTHRU, op, uop, 1) /* Unary operations */ #define gmp_unary_op(op) _gmp_unary_op(INTERNAL_FUNCTION_PARAM_PASSTHRU, op) @@ -408,7 +407,7 @@ static void gmp_strval(zval *result, mpz_t *gmpnum, long base); static int convert_to_gmp(mpz_t **gmpnumber, zval **val, int base TSRMLS_DC); static void gmp_cmp(zval *return_value, zval **a_arg, zval **b_arg TSRMLS_DC); -static inline void gmp_zval_binary_ui_op_ex(zval *return_value, zval **a_arg, zval **b_arg, gmp_binary_op_t gmp_op, gmp_binary_ui_op_t gmp_ui_op, int allow_ui_return, int check_b_zero, int use_sign TSRMLS_DC); +static inline void gmp_zval_binary_ui_op(zval *return_value, zval **a_arg, zval **b_arg, gmp_binary_op_t gmp_op, gmp_binary_ui_op_t gmp_ui_op, int check_b_zero TSRMLS_DC); static inline void gmp_zval_unary_op(zval *return_value, zval **a_arg, gmp_unary_op_t gmp_op TSRMLS_DC); /* {{{ gmp_emalloc @@ -551,15 +550,15 @@ static zend_object_value gmp_clone_obj(zval *obj TSRMLS_DC) /* {{{ */ } /* }}} */ -#define DO_BINARY_UI_OP_EX(op, uop, check_b_zero, use_sign) \ - gmp_zval_binary_ui_op_ex( \ +#define DO_BINARY_UI_OP_EX(op, uop, check_b_zero) \ + gmp_zval_binary_ui_op( \ result, &op1, &op2, op, (gmp_binary_ui_op_t) uop, \ - 0, check_b_zero, use_sign TSRMLS_CC \ - ); \ - return SUCCESS; /* Not sure if this should be FAILURE on bool(false) */ + check_b_zero TSRMLS_CC \ + ); \ + return SUCCESS; -#define DO_BINARY_UI_OP(op) DO_BINARY_UI_OP_EX(op, op ## _ui, 0, 0) -#define DO_BINARY_OP(op) DO_BINARY_UI_OP_EX(op, NULL, 0, 0) +#define DO_BINARY_UI_OP(op) DO_BINARY_UI_OP_EX(op, op ## _ui, 0) +#define DO_BINARY_OP(op) DO_BINARY_UI_OP_EX(op, NULL, 0) #define DO_UNARY_OP(op) \ gmp_zval_unary_op(result, &op1, op TSRMLS_CC); \ @@ -575,9 +574,9 @@ static int gmp_do_operation(zend_uchar opcode, zval *result, zval *op1, zval *op case ZEND_MUL: DO_BINARY_UI_OP(mpz_mul); case ZEND_DIV: - DO_BINARY_UI_OP_EX(mpz_tdiv_q, mpz_tdiv_q_ui, 1, 1); + DO_BINARY_UI_OP_EX(mpz_tdiv_q, mpz_tdiv_q_ui, 1); case ZEND_MOD: - DO_BINARY_UI_OP_EX(mpz_mod, mpz_mod_ui, 1, 0); + DO_BINARY_UI_OP_EX(mpz_mod, mpz_mod_ui, 1); case ZEND_SL: /*convert_to_long_ex(&op2); if (Z_LVAL_P(op2) < 0) { @@ -824,14 +823,13 @@ static void gmp_cmp(zval *return_value, zval **a_arg, zval **b_arg TSRMLS_DC) /* } /* }}} */ -/* {{{ gmp_zval_binary_ui_op_ex +/* {{{ gmp_zval_binary_ui_op Execute GMP binary operation. May return GMP resource or long if operation allows this */ -static inline void gmp_zval_binary_ui_op_ex(zval *return_value, zval **a_arg, zval **b_arg, gmp_binary_op_t gmp_op, gmp_binary_ui_op_t gmp_ui_op, int allow_ui_return, int check_b_zero, int use_sign TSRMLS_DC) +static inline void gmp_zval_binary_ui_op(zval *return_value, zval **a_arg, zval **b_arg, gmp_binary_op_t gmp_op, gmp_binary_ui_op_t gmp_ui_op, int check_b_zero TSRMLS_DC) { mpz_t *gmpnum_a, *gmpnum_b, *gmpnum_result; - unsigned long long_result = 0; int use_ui = 0; gmp_temp_t temp_a, temp_b; @@ -844,15 +842,15 @@ static inline void gmp_zval_binary_ui_op_ex(zval *return_value, zval **a_arg, zv FETCH_GMP_ZVAL_DEP(gmpnum_b, b_arg, temp_b, temp_a); } - if(check_b_zero) { + if (check_b_zero) { int b_is_zero = 0; - if(use_ui) { + if (use_ui) { b_is_zero = (Z_LVAL_PP(b_arg) == 0); } else { b_is_zero = !mpz_cmp_ui(*gmpnum_b, 0); } - if(b_is_zero) { + if (b_is_zero) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "Zero operand not allowed"); FREE_GMP_TEMP(temp_a); FREE_GMP_TEMP(temp_b); @@ -862,15 +860,8 @@ static inline void gmp_zval_binary_ui_op_ex(zval *return_value, zval **a_arg, zv INIT_GMP_NUM(gmpnum_result); - if (use_ui && gmp_ui_op) { - if (allow_ui_return) { - long_result = gmp_ui_op(*gmpnum_result, *gmpnum_a, (unsigned long)Z_LVAL_PP(b_arg)); - if (use_sign && mpz_sgn(*gmpnum_a) == -1) { - long_result = -long_result; - } - } else { - gmp_ui_op(*gmpnum_result, *gmpnum_a, (unsigned long)Z_LVAL_PP(b_arg)); - } + if (use_ui) { + gmp_ui_op(*gmpnum_result, *gmpnum_a, (unsigned long) Z_LVAL_PP(b_arg)); } else { gmp_op(*gmpnum_result, *gmpnum_a, *gmpnum_b); } @@ -878,24 +869,18 @@ static inline void gmp_zval_binary_ui_op_ex(zval *return_value, zval **a_arg, zv FREE_GMP_TEMP(temp_a); FREE_GMP_TEMP(temp_b); - if (use_ui && allow_ui_return) { - FREE_GMP_NUM(gmpnum_result); - RETURN_LONG((long)long_result); - } else { - RETVAL_GMP(gmpnum_result); - } + RETVAL_GMP(gmpnum_result); } /* }}} */ -/* {{{ gmp_zval_binary_ui_op2_ex +/* {{{ gmp_zval_binary_ui_op2 Execute GMP binary operation which returns 2 values. May return GMP resources or longs if operation allows this. */ -static inline void gmp_zval_binary_ui_op2_ex(zval *return_value, zval **a_arg, zval **b_arg, gmp_binary_op2_t gmp_op, gmp_binary_ui_op2_t gmp_ui_op, int allow_ui_return, int check_b_zero TSRMLS_DC) +static inline void gmp_zval_binary_ui_op2(zval *return_value, zval **a_arg, zval **b_arg, gmp_binary_op2_t gmp_op, gmp_binary_ui_op2_t gmp_ui_op, int check_b_zero TSRMLS_DC) { mpz_t *gmpnum_a, *gmpnum_b, *gmpnum_result1, *gmpnum_result2; int use_ui = 0; - unsigned long long_result = 0; gmp_temp_t temp_a, temp_b; FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a); @@ -927,12 +912,8 @@ static inline void gmp_zval_binary_ui_op2_ex(zval *return_value, zval **a_arg, z INIT_GMP_NUM(gmpnum_result1); INIT_GMP_NUM(gmpnum_result2); - if (use_ui && gmp_ui_op) { - if (allow_ui_return) { - long_result = gmp_ui_op(*gmpnum_result1, *gmpnum_result2, *gmpnum_a, (unsigned long)Z_LVAL_PP(b_arg)); - } else { - gmp_ui_op(*gmpnum_result1, *gmpnum_result2, *gmpnum_a, (unsigned long)Z_LVAL_PP(b_arg)); - } + if (use_ui) { + gmp_ui_op(*gmpnum_result1, *gmpnum_result2, *gmpnum_a, (unsigned long)Z_LVAL_PP(b_arg)); } else { gmp_op(*gmpnum_result1, *gmpnum_result2, *gmpnum_a, *gmpnum_b); } @@ -942,18 +923,13 @@ static inline void gmp_zval_binary_ui_op2_ex(zval *return_value, zval **a_arg, z array_init(return_value); ADD_INDEX_GMP(return_value, 0, gmpnum_result1); - if (use_ui && allow_ui_return) { - mpz_clear(*gmpnum_result2); - add_index_long(return_value, 1, long_result); - } else { - ADD_INDEX_GMP(return_value, 1, gmpnum_result2); - } + ADD_INDEX_GMP(return_value, 1, gmpnum_result2); } /* }}} */ /* {{{ _gmp_binary_ui_op */ -static inline void _gmp_binary_ui_op(INTERNAL_FUNCTION_PARAMETERS, gmp_binary_op_t gmp_op, gmp_binary_ui_op_t gmp_ui_op) +static inline void _gmp_binary_ui_op(INTERNAL_FUNCTION_PARAMETERS, gmp_binary_op_t gmp_op, gmp_binary_ui_op_t gmp_ui_op, int check_b_zero) { zval **a_arg, **b_arg; @@ -961,7 +937,7 @@ static inline void _gmp_binary_ui_op(INTERNAL_FUNCTION_PARAMETERS, gmp_binary_op return; } - gmp_zval_binary_ui_op(return_value, a_arg, b_arg, gmp_op, gmp_ui_op); + gmp_zval_binary_ui_op(return_value, a_arg, b_arg, gmp_op, gmp_ui_op, check_b_zero TSRMLS_CC); } /* }}} */ @@ -1089,7 +1065,6 @@ ZEND_FUNCTION(gmp_init) RETURN_FALSE; } - /* Write your own code here to handle argument number. */ RETVAL_GMP(gmpnumber); } /* }}} */ @@ -1185,14 +1160,17 @@ ZEND_FUNCTION(gmp_div_qr) switch (round) { case GMP_ROUND_ZERO: - gmp_zval_binary_ui_op2_ex(return_value, a_arg, b_arg, mpz_tdiv_qr, (gmp_binary_ui_op2_t)mpz_tdiv_qr_ui, 0, 1 TSRMLS_CC); + gmp_zval_binary_ui_op2(return_value, a_arg, b_arg, mpz_tdiv_qr, (gmp_binary_ui_op2_t)mpz_tdiv_qr_ui, 1 TSRMLS_CC); break; case GMP_ROUND_PLUSINF: - gmp_zval_binary_ui_op2_ex(return_value, a_arg, b_arg, mpz_cdiv_qr, (gmp_binary_ui_op2_t)mpz_cdiv_qr_ui, 0, 1 TSRMLS_CC); + gmp_zval_binary_ui_op2(return_value, a_arg, b_arg, mpz_cdiv_qr, (gmp_binary_ui_op2_t)mpz_cdiv_qr_ui, 1 TSRMLS_CC); break; case GMP_ROUND_MINUSINF: - gmp_zval_binary_ui_op2_ex(return_value, a_arg, b_arg, mpz_fdiv_qr, (gmp_binary_ui_op2_t)mpz_fdiv_qr_ui, 0, 1 TSRMLS_CC); + gmp_zval_binary_ui_op2(return_value, a_arg, b_arg, mpz_fdiv_qr, (gmp_binary_ui_op2_t)mpz_fdiv_qr_ui, 1 TSRMLS_CC); break; + default: + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid rounding mode"); + RETURN_FALSE; } } /* }}} */ @@ -1210,14 +1188,17 @@ ZEND_FUNCTION(gmp_div_r) switch (round) { case GMP_ROUND_ZERO: - gmp_zval_binary_ui_op_ex(return_value, a_arg, b_arg, mpz_tdiv_r, (gmp_binary_ui_op_t)mpz_tdiv_r_ui, 1, 1, 1 TSRMLS_CC); + gmp_zval_binary_ui_op(return_value, a_arg, b_arg, mpz_tdiv_r, (gmp_binary_ui_op_t)mpz_tdiv_r_ui, 1 TSRMLS_CC); break; case GMP_ROUND_PLUSINF: - gmp_zval_binary_ui_op_ex(return_value, a_arg, b_arg, mpz_cdiv_r, (gmp_binary_ui_op_t)mpz_cdiv_r_ui, 1, 1, 1 TSRMLS_CC); + gmp_zval_binary_ui_op(return_value, a_arg, b_arg, mpz_cdiv_r, (gmp_binary_ui_op_t)mpz_cdiv_r_ui, 1 TSRMLS_CC); break; case GMP_ROUND_MINUSINF: - gmp_zval_binary_ui_op_ex(return_value, a_arg, b_arg, mpz_fdiv_r, (gmp_binary_ui_op_t)mpz_fdiv_r_ui, 1, 1, 1 TSRMLS_CC); + gmp_zval_binary_ui_op(return_value, a_arg, b_arg, mpz_fdiv_r, (gmp_binary_ui_op_t)mpz_fdiv_r_ui, 1 TSRMLS_CC); break; + default: + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid rounding mode"); + RETURN_FALSE; } } /* }}} */ @@ -1235,14 +1216,17 @@ ZEND_FUNCTION(gmp_div_q) switch (round) { case GMP_ROUND_ZERO: - gmp_zval_binary_ui_op_ex(return_value, a_arg, b_arg, mpz_tdiv_q, (gmp_binary_ui_op_t)mpz_tdiv_q_ui, 0, 1, 1 TSRMLS_CC); + gmp_zval_binary_ui_op(return_value, a_arg, b_arg, mpz_tdiv_q, (gmp_binary_ui_op_t)mpz_tdiv_q_ui, 1 TSRMLS_CC); break; case GMP_ROUND_PLUSINF: - gmp_zval_binary_ui_op_ex(return_value, a_arg, b_arg, mpz_cdiv_q, (gmp_binary_ui_op_t)mpz_cdiv_q_ui, 0, 1, 1 TSRMLS_CC); + gmp_zval_binary_ui_op(return_value, a_arg, b_arg, mpz_cdiv_q, (gmp_binary_ui_op_t)mpz_cdiv_q_ui, 1 TSRMLS_CC); break; case GMP_ROUND_MINUSINF: - gmp_zval_binary_ui_op_ex(return_value, a_arg, b_arg, mpz_fdiv_q, (gmp_binary_ui_op_t)mpz_fdiv_q_ui, 0, 1, 1 TSRMLS_CC); + gmp_zval_binary_ui_op(return_value, a_arg, b_arg, mpz_fdiv_q, (gmp_binary_ui_op_t)mpz_fdiv_q_ui, 1 TSRMLS_CC); break; + default: + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid rounding mode"); + RETURN_FALSE; } } @@ -1252,13 +1236,7 @@ ZEND_FUNCTION(gmp_div_q) Computes a modulo b */ ZEND_FUNCTION(gmp_mod) { - zval **a_arg, **b_arg; - - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ZZ", &a_arg, &b_arg) == FAILURE){ - return; - } - - gmp_zval_binary_ui_op_ex(return_value, a_arg, b_arg, mpz_mod, (gmp_binary_ui_op_t)mpz_mod_ui, 1, 1, 0 TSRMLS_CC); + gmp_binary_ui_op_no_zero(mpz_mod, (gmp_binary_ui_op_t)mpz_mod_ui); } /* }}} */ @@ -1266,13 +1244,7 @@ ZEND_FUNCTION(gmp_mod) Divide a by b using exact division algorithm */ ZEND_FUNCTION(gmp_divexact) { - zval **a_arg, **b_arg; - - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ZZ", &a_arg, &b_arg) == FAILURE){ - return; - } - - gmp_zval_binary_ui_op_ex(return_value, a_arg, b_arg, mpz_divexact, NULL, 0, 1, 1 TSRMLS_CC); + gmp_binary_ui_op_no_zero(mpz_divexact, NULL); } /* }}} */ @@ -1517,13 +1489,7 @@ ZEND_FUNCTION(gmp_prob_prime) Computes greatest common denominator (gcd) of a and b */ ZEND_FUNCTION(gmp_gcd) { - zval **a_arg, **b_arg; - - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ZZ", &a_arg, &b_arg) == FAILURE){ - return; - } - - gmp_zval_binary_ui_op_ex(return_value, a_arg, b_arg, mpz_gcd, (gmp_binary_ui_op_t)mpz_gcd_ui, 0, 0, 1 TSRMLS_CC); + gmp_binary_ui_op(mpz_gcd, (gmp_binary_ui_op_t)mpz_gcd_ui); } /* }}} */ diff --git a/ext/gmp/tests/007.phpt b/ext/gmp/tests/007.phpt index 3b49cf51fc4f..e391c121f8d1 100644 --- a/ext/gmp/tests/007.phpt +++ b/ext/gmp/tests/007.phpt @@ -59,7 +59,9 @@ array(2) { string(5) "12653" } } -NULL + +Warning: gmp_div_qr(): Invalid rounding mode in %s on line %d +bool(false) array(2) { [0]=> object(GMP)#%d (1) { diff --git a/ext/gmp/tests/008.phpt b/ext/gmp/tests/008.phpt index d67b01b0fd3c..c1874c86f901 100644 --- a/ext/gmp/tests/008.phpt +++ b/ext/gmp/tests/008.phpt @@ -9,24 +9,15 @@ var_dump(gmp_div_r()); var_dump(gmp_div_r("")); var_dump($r = gmp_div_r(0,1)); -var_dump(gmp_strval($r)); var_dump($r = gmp_div_r(1,0)); var_dump($r = gmp_div_r(12653,23482734)); -var_dump(gmp_strval($r)); var_dump($r = gmp_div_r(12653,23482734, 10)); -var_dump(gmp_strval($r)); var_dump($r = gmp_div_r(1123123,123)); -var_dump(gmp_strval($r)); var_dump($r = gmp_div_r(1123123,123, 1)); -var_dump(gmp_strval($r)); var_dump($r = gmp_div_r(1123123,123, 2)); -var_dump(gmp_strval($r)); var_dump($r = gmp_div_r(1123123,123, GMP_ROUND_ZERO)); -var_dump(gmp_strval($r)); var_dump($r = gmp_div_r(1123123,123, GMP_ROUND_PLUSINF)); -var_dump(gmp_strval($r)); var_dump($r = gmp_div_r(1123123,123, GMP_ROUND_MINUSINF)); -var_dump(gmp_strval($r)); $fp = fopen(__FILE__, 'r'); @@ -41,29 +32,44 @@ NULL Warning: gmp_div_r() expects at least 2 parameters, 1 given in %s on line %d NULL -int(0) -string(1) "0" +object(GMP)#%d (1) { + ["num"]=> + string(1) "0" +} Warning: gmp_div_r(): Zero operand not allowed in %s on line %d bool(false) -int(12653) -string(5) "12653" -NULL +object(GMP)#%d (1) { + ["num"]=> + string(5) "12653" +} -Warning: gmp_strval(): Unable to convert variable to GMP - wrong type in %s on line %d +Warning: gmp_div_r(): Invalid rounding mode in %s on line %d bool(false) -int(10) -string(2) "10" -int(113) -string(3) "113" -int(10) -string(2) "10" -int(10) -string(2) "10" -int(113) -string(3) "113" -int(10) -string(2) "10" +object(GMP)#%d (1) { + ["num"]=> + string(2) "10" +} +object(GMP)#%d (1) { + ["num"]=> + string(4) "-113" +} +object(GMP)#%d (1) { + ["num"]=> + string(2) "10" +} +object(GMP)#%d (1) { + ["num"]=> + string(2) "10" +} +object(GMP)#%d (1) { + ["num"]=> + string(4) "-113" +} +object(GMP)#%d (1) { + ["num"]=> + string(2) "10" +} Warning: gmp_div_r(): Unable to convert variable to GMP - wrong type in %s on line %d bool(false) diff --git a/ext/gmp/tests/009.phpt b/ext/gmp/tests/009.phpt index ec0eb4bc6e8f..3b75a48e1825 100644 --- a/ext/gmp/tests/009.phpt +++ b/ext/gmp/tests/009.phpt @@ -43,7 +43,9 @@ object(GMP)#%d (1) { ["num"]=> string(1) "0" } -NULL + +Warning: gmp_div_q(): Invalid rounding mode %s on line %d +bool(false) object(GMP)#%d (1) { ["num"]=> string(4) "9131" diff --git a/ext/gmp/tests/010.phpt b/ext/gmp/tests/010.phpt index 59b8d847004a..e3f85ec44f1e 100644 --- a/ext/gmp/tests/010.phpt +++ b/ext/gmp/tests/010.phpt @@ -28,7 +28,10 @@ NULL Warning: gmp_mod() expects exactly 2 parameters, 1 given in %s on line %d NULL bool(false) -int(0) +object(GMP)#%d (1) { + ["num"]=> + string(1) "0" +} object(GMP)#%d (1) { ["num"]=> string(1) "0" From efbbf2091a4606613b8c5990798edb70836fc34e Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Tue, 14 May 2013 19:21:00 +0200 Subject: [PATCH 07/11] Remove various indirections Rather than allocating mpz_t structures and storing them in mpz_t* pointers directly work with the mpz_t structures (without additional allocation). mpz_t is already a (pseudo) indirection. Also now uses zval*s everywhere rather than zval**s. --- ext/gmp/gmp.c | 711 +++++++++++++++++++++++++------------------------- 1 file changed, 350 insertions(+), 361 deletions(-) diff --git a/ext/gmp/gmp.c b/ext/gmp/gmp.c index a66a8808572d..4cd8a6a69616 100644 --- a/ext/gmp/gmp.c +++ b/ext/gmp/gmp.c @@ -309,15 +309,116 @@ ZEND_GET_MODULE(gmp) zend_class_entry *gmp_ce; static zend_object_handlers gmp_object_handlers; -/* {{{ typedefs - */ typedef struct _gmp_object { zend_object std; - mpz_t *num; + mpz_t num; } gmp_object; -typedef mpz_t* gmp_temp_t; +typedef struct _gmp_temp { + mpz_t num; + zend_bool is_used; +} gmp_temp_t; + +#define GMP_ROUND_ZERO 0 +#define GMP_ROUND_PLUSINF 1 +#define GMP_ROUND_MINUSINF 2 + +/* The maximum base for input and output conversions is 62 from GMP 4.2 + * onwards. */ +#if (__GNU_MP_VERSION >= 5) || (__GNU_MP_VERSION >= 4 && __GNU_MP_VERSION_MINOR >= 2) +# define MAX_BASE 62 +#else +# define MAX_BASE 36 +#endif + +#define IS_GMP(zval) \ + (Z_TYPE_P(zval) == IS_OBJECT && instanceof_function(Z_OBJCE_P(zval), gmp_ce TSRMLS_CC)) + +#define GET_GMP_FROM_ZVAL(zval) \ + (((gmp_object *) zend_object_store_get_object((zval) TSRMLS_CC))->num) + +/* The FETCH_GMP_ZVAL_* family of macros is used to fetch a gmp number + * (mpz_ptr) from a zval. If the zval is not a GMP instance, then we + * try to convert the value to a temporary gmp number using convert_to_gmp. + * This temporary number is stored in the temp argument, which is of type + * gmp_temp_t. This temporary value needs to be freed lateron using the + * FREE_GMP_TEMP macro. + * + * If the conversion to a gmp number fails, the macros return false. + * The _DEP / _DEP_DEP variants additionally free the temporary values + * passed in the last / last two arguments. + * + * If one zval can sometimes be fetched as a long you have to set the + * is_used member of the corresponding gmp_temp_t value to 0, otherwise + * the FREE_GMP_TEMP and *_DEP macros will not work properly. + * + * The three FETCH_GMP_ZVAL_* macros below are mostly copy & paste code + * as I couldn't find a way to combine them. + */ +#define FREE_GMP_TEMP(temp) \ + if (temp.is_used) { \ + mpz_clear(temp.num); \ + } + +#define FETCH_GMP_ZVAL_DEP_DEP(gmpnumber, zval, temp, dep1, dep2) \ +if (IS_GMP(zval)) { \ + gmpnumber = GET_GMP_FROM_ZVAL(zval); \ + temp.is_used = 0; \ +} else { \ + mpz_init(temp.num); \ + if (convert_to_gmp(temp.num, zval, 0 TSRMLS_CC) == FAILURE) { \ + mpz_clear(temp.num); \ + FREE_GMP_TEMP(dep1); \ + FREE_GMP_TEMP(dep2); \ + RETURN_FALSE; \ + } \ + temp.is_used = 1; \ + gmpnumber = temp.num; \ +} + +#define FETCH_GMP_ZVAL_DEP(gmpnumber, zval, temp, dep) \ +if (IS_GMP(zval)) { \ + gmpnumber = GET_GMP_FROM_ZVAL(zval); \ + temp.is_used = 0; \ +} else { \ + mpz_init(temp.num); \ + if (convert_to_gmp(temp.num, zval, 0 TSRMLS_CC) == FAILURE) { \ + mpz_clear(temp.num); \ + FREE_GMP_TEMP(dep); \ + RETURN_FALSE; \ + } \ + temp.is_used = 1; \ + gmpnumber = temp.num; \ +} + +#define FETCH_GMP_ZVAL(gmpnumber, zval, temp) \ +if (IS_GMP(zval)) { \ + gmpnumber = GET_GMP_FROM_ZVAL(zval); \ + temp.is_used = 0; \ +} else { \ + mpz_init(temp.num); \ + if (convert_to_gmp(temp.num, zval, 0 TSRMLS_CC) == FAILURE) { \ + mpz_clear(temp.num); \ + RETURN_FALSE; \ + } \ + temp.is_used = 1; \ + gmpnumber = temp.num; \ +} + +#define INIT_GMP_RETVAL(gmpnumber) \ + gmp_create_ex(return_value, &gmpnumber TSRMLS_CC) + +static void gmp_strval(zval *result, mpz_t gmpnum, long base); +static int convert_to_gmp(mpz_t gmpnumber, zval *val, int base TSRMLS_DC); +static void gmp_cmp(zval *return_value, zval *a_arg, zval *b_arg TSRMLS_DC); + +/* + * The gmp_*_op functions provide an implementation for several common types + * of GMP functions. The gmp_zval_(unary|binary)_*_op functions have to be manually + * passed zvals to work on, whereas the gmp_(unary|binary)_*_op macros already + * include parameter parsing. + */ typedef void (*gmp_unary_op_t)(mpz_ptr, mpz_srcptr); typedef int (*gmp_unary_opl_t)(mpz_srcptr); @@ -326,11 +427,16 @@ typedef void (*gmp_unary_ui_op_t)(mpz_ptr, unsigned long); typedef void (*gmp_binary_op_t)(mpz_ptr, mpz_srcptr, mpz_srcptr); typedef int (*gmp_binary_opl_t)(mpz_srcptr, mpz_srcptr); -typedef unsigned long (*gmp_binary_ui_op_t)(mpz_ptr, mpz_srcptr, unsigned long); +typedef void (*gmp_binary_ui_op_t)(mpz_ptr, mpz_srcptr, unsigned long); typedef void (*gmp_binary_op2_t)(mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr); -typedef unsigned long (*gmp_binary_ui_op2_t)(mpz_ptr, mpz_ptr, mpz_srcptr, unsigned long); -/* }}} */ +typedef void (*gmp_binary_ui_op2_t)(mpz_ptr, mpz_ptr, mpz_srcptr, unsigned long); + +static inline void gmp_zval_binary_ui_op(zval *return_value, zval *a_arg, zval *b_arg, gmp_binary_op_t gmp_op, gmp_binary_ui_op_t gmp_ui_op, int check_b_zero TSRMLS_DC); +static inline void gmp_zval_binary_ui_op2(zval *return_value, zval *a_arg, zval *b_arg, gmp_binary_op2_t gmp_op, gmp_binary_ui_op2_t gmp_ui_op, int check_b_zero TSRMLS_DC); +static inline void gmp_zval_unary_op(zval *return_value, zval *a_arg, gmp_unary_op_t gmp_op TSRMLS_DC); +static inline void gmp_zval_unary_ui_op(zval *return_value, zval *a_arg, gmp_unary_ui_op_t gmp_op TSRMLS_DC); +/* Binary operations */ #define gmp_binary_ui_op(op, uop) _gmp_binary_ui_op(INTERNAL_FUNCTION_PARAM_PASSTHRU, op, uop, 0) #define gmp_binary_op(op) _gmp_binary_ui_op(INTERNAL_FUNCTION_PARAM_PASSTHRU, op, NULL, 0) #define gmp_binary_opl(op) _gmp_binary_opl(INTERNAL_FUNCTION_PARAM_PASSTHRU, op) @@ -342,74 +448,6 @@ typedef unsigned long (*gmp_binary_ui_op2_t)(mpz_ptr, mpz_ptr, mpz_srcptr, unsig #define gmp_unary_opl(op) _gmp_unary_opl(INTERNAL_FUNCTION_PARAM_PASSTHRU, op) #define gmp_unary_ui_op(op) _gmp_unary_ui_op(INTERNAL_FUNCTION_PARAM_PASSTHRU, op) -#define GMP_ROUND_ZERO 0 -#define GMP_ROUND_PLUSINF 1 -#define GMP_ROUND_MINUSINF 2 - -/* The maximum base for input and output conversions is 62 from GMP 4.2 - * onwards. */ -#if (__GNU_MP_VERSION >= 5) || (__GNU_MP_VERSION >= 4 && __GNU_MP_VERSION_MINOR >= 2) -# define MAX_BASE 62 -#else -# define MAX_BASE 36 -#endif - -#define IS_GMP_P(zval) \ - (Z_TYPE_P(zval) == IS_OBJECT && instanceof_function(Z_OBJCE_P(zval), gmp_ce TSRMLS_CC)) -#define IS_GMP_PP(zval) IS_GMP_P(*zval) - -#define FETCH_GMP_ZVAL_NO_TEMP(gmpnumber, zval) do { \ - gmpnumber = ((gmp_object *) zend_object_store_get_object(*(zval) TSRMLS_CC))->num; \ -} while (0); - -#define FREE_GMP_TEMP(temp) \ - if (temp) { \ - FREE_GMP_NUM(temp); \ - } - -/* Fetch zval to be GMP number. - Initially, zval can be also number or string */ -#define FETCH_GMP_ZVAL_DEP_DEP(gmpnumber, zval, temp, dep1, dep2) \ -if (IS_GMP_PP(zval)) { \ - FETCH_GMP_ZVAL_NO_TEMP(gmpnumber, zval) \ - temp = NULL; \ -} else { \ - if (convert_to_gmp(&gmpnumber, zval, 0 TSRMLS_CC) == FAILURE) { \ - FREE_GMP_TEMP(dep1); \ - FREE_GMP_TEMP(dep2); \ - RETURN_FALSE; \ - } \ - temp = gmpnumber; \ -} - -#define FETCH_GMP_ZVAL_DEP(gmpnumber, zval, temp, dep) \ - FETCH_GMP_ZVAL_DEP_DEP(gmpnumber, zval, temp, dep, (gmp_temp_t) NULL) -#define FETCH_GMP_ZVAL(gmpnumber, zval, temp) \ - FETCH_GMP_ZVAL_DEP(gmpnumber, zval, temp, (gmp_temp_t) NULL) - -/* create a new initialized GMP number */ -#define INIT_GMP_NUM(gmpnumber) { gmpnumber = emalloc(sizeof(mpz_t)); mpz_init(*gmpnumber); } -#define FREE_GMP_NUM(gmpnumber) { mpz_clear(*gmpnumber); efree(gmpnumber); } - -#define RETVAL_GMP(gmpnumber) \ - gmp_create_ex(return_value, (gmpnumber) TSRMLS_CC) - -#define ADD_INDEX_GMP(array, index, gmpnumber) do { \ - zval *_r = gmp_create((gmpnumber) TSRMLS_CC); \ - add_index_zval((array), (index), _r); \ -} while (0); -#define ADD_ASSOC_GMP(array, key, gmpnumber) do { \ - zval *_r = gmp_create((gmpnumber) TSRMLS_CC); \ - add_assoc_zval((array), (key), _r); \ -} while (0); - -static void gmp_strval(zval *result, mpz_t *gmpnum, long base); -static int convert_to_gmp(mpz_t **gmpnumber, zval **val, int base TSRMLS_DC); -static void gmp_cmp(zval *return_value, zval **a_arg, zval **b_arg TSRMLS_DC); - -static inline void gmp_zval_binary_ui_op(zval *return_value, zval **a_arg, zval **b_arg, gmp_binary_op_t gmp_op, gmp_binary_ui_op_t gmp_ui_op, int check_b_zero TSRMLS_DC); -static inline void gmp_zval_unary_op(zval *return_value, zval **a_arg, gmp_unary_op_t gmp_op TSRMLS_DC); - /* {{{ gmp_emalloc */ static void *gmp_emalloc(size_t size) @@ -434,16 +472,29 @@ static void gmp_efree(void *ptr, size_t size) } /* }}} */ +static inline long gmp_get_long(zval *zv) /* {{{ */ +{ + if (Z_TYPE_P(zv) == IS_LONG) { + return Z_LVAL_P(zv); + } else { + zval tmp_zv; + MAKE_COPY_ZVAL(&zv, &tmp_zv); + convert_to_long(&tmp_zv); + return Z_LVAL(tmp_zv); + } +} +/* }}} */ + static void gmp_free_object_storage(gmp_object *intern TSRMLS_DC) /* {{{ */ { - FREE_GMP_NUM(intern->num); + mpz_clear(intern->num); zend_object_std_dtor(&intern->std TSRMLS_CC); efree(intern); } /* }}} */ -static inline zend_object_value gmp_create_object_ex(zend_class_entry *ce, mpz_t *init_num TSRMLS_DC) /* {{{ */ +static inline zend_object_value gmp_create_object_ex(zend_class_entry *ce, mpz_ptr *gmpnum_target TSRMLS_DC) /* {{{ */ { zend_object_value retval; gmp_object *intern = emalloc(sizeof(gmp_object)); @@ -451,11 +502,8 @@ static inline zend_object_value gmp_create_object_ex(zend_class_entry *ce, mpz_t zend_object_std_init(&intern->std, ce TSRMLS_CC); object_properties_init(&intern->std, ce); - if (init_num) { - intern->num = init_num; - } else { - INIT_GMP_NUM(intern->num); - } + mpz_init(intern->num); + *gmpnum_target = intern->num; retval.handle = zend_objects_store_put( intern, (zend_objects_store_dtor_t) zend_objects_destroy_object, @@ -470,44 +518,45 @@ static inline zend_object_value gmp_create_object_ex(zend_class_entry *ce, mpz_t static zend_object_value gmp_create_object(zend_class_entry *ce TSRMLS_DC) /* {{{ */ { - return gmp_create_object_ex(ce, NULL TSRMLS_CC); + mpz_ptr gmpnum_dummy; + return gmp_create_object_ex(ce, &gmpnum_dummy TSRMLS_CC); } /* }}} */ -static inline void gmp_create_ex(zval *target, mpz_t *gmpnumber TSRMLS_DC) /* {{{ */ +static inline void gmp_create_ex(zval *target, mpz_ptr *gmpnum_target TSRMLS_DC) /* {{{ */ { Z_TYPE_P(target) = IS_OBJECT; - Z_OBJVAL_P(target) = gmp_create_object_ex(gmp_ce, gmpnumber TSRMLS_CC); + Z_OBJVAL_P(target) = gmp_create_object_ex(gmp_ce, gmpnum_target TSRMLS_CC); } /* }}} */ -static zval *gmp_create(mpz_t *gmpnumber TSRMLS_DC) /* {{{ */ +static zval *gmp_create(mpz_ptr *gmpnum_target TSRMLS_DC) /* {{{ */ { zval *obj; MAKE_STD_ZVAL(obj); - gmp_create_ex(obj, gmpnumber TSRMLS_CC); + gmp_create_ex(obj, gmpnum_target TSRMLS_CC); return obj; } /* }}} */ static int gmp_cast_object(zval *readobj, zval *writeobj, int type TSRMLS_DC) /* {{{ */ { - mpz_t *gmpnum; + mpz_ptr gmpnum; switch (type) { case IS_STRING: - FETCH_GMP_ZVAL_NO_TEMP(gmpnum, &readobj); + gmpnum = GET_GMP_FROM_ZVAL(readobj); INIT_PZVAL(writeobj); gmp_strval(writeobj, gmpnum, 10); return SUCCESS; case IS_LONG: - FETCH_GMP_ZVAL_NO_TEMP(gmpnum, &readobj); + gmpnum = GET_GMP_FROM_ZVAL(readobj); INIT_PZVAL(writeobj); - ZVAL_LONG(writeobj, mpz_get_si(*gmpnum)); + ZVAL_LONG(writeobj, mpz_get_si(gmpnum)); return SUCCESS; case IS_DOUBLE: - FETCH_GMP_ZVAL_NO_TEMP(gmpnum, &readobj); + gmpnum = GET_GMP_FROM_ZVAL(readobj); INIT_PZVAL(writeobj); - ZVAL_DOUBLE(writeobj, mpz_get_d(*gmpnum)); + ZVAL_DOUBLE(writeobj, mpz_get_d(gmpnum)); return SUCCESS; default: return FAILURE; @@ -518,11 +567,9 @@ static int gmp_cast_object(zval *readobj, zval *writeobj, int type TSRMLS_DC) /* static HashTable *gmp_get_properties(zval *obj TSRMLS_DC) /* {{{ */ { HashTable *ht = zend_std_get_properties(obj TSRMLS_CC); - mpz_t *gmpnum; + mpz_ptr gmpnum = GET_GMP_FROM_ZVAL(obj); zval *zv; - FETCH_GMP_ZVAL_NO_TEMP(gmpnum, &obj); - MAKE_STD_ZVAL(zv); gmp_strval(zv, gmpnum, 10); zend_hash_update(ht, "num", sizeof("num"), &zv, sizeof(zval *), NULL); @@ -544,24 +591,24 @@ static zend_object_value gmp_clone_obj(zval *obj TSRMLS_DC) /* {{{ */ &old_object->std, Z_OBJ_HANDLE_P(obj) TSRMLS_CC ); - mpz_set(*new_object->num, *old_object->num); + mpz_set(new_object->num, old_object->num); return new_object_val; } /* }}} */ -#define DO_BINARY_UI_OP_EX(op, uop, check_b_zero) \ - gmp_zval_binary_ui_op( \ - result, &op1, &op2, op, (gmp_binary_ui_op_t) uop, \ - check_b_zero TSRMLS_CC \ - ); \ +#define DO_BINARY_UI_OP_EX(op, uop, check_b_zero) \ + gmp_zval_binary_ui_op( \ + result, op1, op2, op, (gmp_binary_ui_op_t) uop, \ + check_b_zero TSRMLS_CC \ + ); \ return SUCCESS; #define DO_BINARY_UI_OP(op) DO_BINARY_UI_OP_EX(op, op ## _ui, 0) #define DO_BINARY_OP(op) DO_BINARY_UI_OP_EX(op, NULL, 0) #define DO_UNARY_OP(op) \ - gmp_zval_unary_op(result, &op1, op TSRMLS_CC); \ + gmp_zval_unary_op(result, op1, op TSRMLS_CC); \ return SUCCESS; static int gmp_do_operation(zend_uchar opcode, zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */ @@ -611,7 +658,7 @@ static int gmp_do_operation(zend_uchar opcode, zval *result, zval *op1, zval *op static int gmp_compare(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */ { - gmp_cmp(result, &op1, &op2 TSRMLS_CC); + gmp_cmp(result, op1, op2 TSRMLS_CC); return SUCCESS; } /* }}} */ @@ -629,12 +676,8 @@ PHP_METHOD(GMP, __wakeup) /* {{{ */ if (zend_hash_find(props, "num", sizeof("num"), (void **) &num_zv) == SUCCESS && Z_TYPE_PP(num_zv) == IS_STRING && Z_STRLEN_PP(num_zv) > 0 ) { - gmp_object *intern = (gmp_object *) zend_object_store_get_object(getThis() TSRMLS_CC); - mpz_t *gmpnumber; - - if (convert_to_gmp(&gmpnumber, num_zv, 10 TSRMLS_CC) == SUCCESS) { - FREE_GMP_NUM(intern->num); - intern->num = gmpnumber; + mpz_ptr gmpnumber = GET_GMP_FROM_ZVAL(getThis()); + if (convert_to_gmp(gmpnumber, *num_zv, 10 TSRMLS_CC) == SUCCESS) { return; } } @@ -722,22 +765,20 @@ ZEND_MODULE_INFO_D(gmp) /* {{{ convert_to_gmp * Convert zval to be gmp number */ -static int convert_to_gmp(mpz_t **gmpnumber, zval **val, int base TSRMLS_DC) +static int convert_to_gmp(mpz_t gmpnumber, zval *val, int base TSRMLS_DC) { - switch (Z_TYPE_PP(val)) { + switch (Z_TYPE_P(val)) { case IS_LONG: case IS_BOOL: case IS_CONSTANT: { - convert_to_long_ex(val); - *gmpnumber = emalloc(sizeof(mpz_t)); - mpz_init_set_si(**gmpnumber, Z_LVAL_PP(val)); + mpz_set_si(gmpnumber, gmp_get_long(val)); return SUCCESS; } case IS_STRING: { - char *numstr = Z_STRVAL_PP(val); - int ret = 0, skip_lead = 0; + char *numstr = Z_STRVAL_P(val); + int skip_lead = 0; - if (Z_STRLEN_PP(val) > 2) { + if (Z_STRLEN_P(val) > 2) { if (numstr[0] == '0') { if (numstr[1] == 'x' || numstr[1] == 'X') { base = 16; @@ -749,12 +790,7 @@ static int convert_to_gmp(mpz_t **gmpnumber, zval **val, int base TSRMLS_DC) } } - *gmpnumber = emalloc(sizeof(mpz_t)); - ret = mpz_init_set_str(**gmpnumber, (skip_lead ? &numstr[2] : numstr), base); - if (ret == FAILURE) { - FREE_GMP_NUM(*gmpnumber); - } - return ret; + return mpz_set_str(gmpnumber, (skip_lead ? &numstr[2] : numstr), base); } default: php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to convert variable to GMP - wrong type"); @@ -763,18 +799,18 @@ static int convert_to_gmp(mpz_t **gmpnumber, zval **val, int base TSRMLS_DC) } /* }}} */ -static void gmp_strval(zval *result, mpz_t *gmpnum, long base) /* {{{ */ +static void gmp_strval(zval *result, mpz_t gmpnum, long base) /* {{{ */ { int num_len; char *out_string; - num_len = mpz_sizeinbase(*gmpnum, abs(base)); - if (mpz_sgn(*gmpnum) < 0) { + num_len = mpz_sizeinbase(gmpnum, abs(base)); + if (mpz_sgn(gmpnum) < 0) { num_len++; } out_string = emalloc(num_len + 1); - mpz_get_str(out_string, base, *gmpnum); + mpz_get_str(out_string, base, gmpnum); /* * From GMP documentation for mpz_sizeinbase(): @@ -794,26 +830,26 @@ static void gmp_strval(zval *result, mpz_t *gmpnum, long base) /* {{{ */ } /* }}} */ -static void gmp_cmp(zval *return_value, zval **a_arg, zval **b_arg TSRMLS_DC) /* {{{ */ +static void gmp_cmp(zval *return_value, zval *a_arg, zval *b_arg TSRMLS_DC) /* {{{ */ { - mpz_t *gmpnum_a, *gmpnum_b; + mpz_ptr gmpnum_a, gmpnum_b; gmp_temp_t temp_a, temp_b; zend_bool use_si = 0; long res; FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a); - if (Z_TYPE_PP(b_arg) == IS_LONG) { + if (Z_TYPE_P(b_arg) == IS_LONG) { use_si = 1; - temp_b = NULL; + temp_b.is_used = 0; } else { FETCH_GMP_ZVAL_DEP(gmpnum_b, b_arg, temp_b, temp_a); } if (use_si) { - res = mpz_cmp_si(*gmpnum_a, Z_LVAL_PP(b_arg)); + res = mpz_cmp_si(gmpnum_a, Z_LVAL_P(b_arg)); } else { - res = mpz_cmp(*gmpnum_a, *gmpnum_b); + res = mpz_cmp(gmpnum_a, gmpnum_b); } FREE_GMP_TEMP(temp_a); @@ -827,17 +863,17 @@ static void gmp_cmp(zval *return_value, zval **a_arg, zval **b_arg TSRMLS_DC) /* Execute GMP binary operation. May return GMP resource or long if operation allows this */ -static inline void gmp_zval_binary_ui_op(zval *return_value, zval **a_arg, zval **b_arg, gmp_binary_op_t gmp_op, gmp_binary_ui_op_t gmp_ui_op, int check_b_zero TSRMLS_DC) +static inline void gmp_zval_binary_ui_op(zval *return_value, zval *a_arg, zval *b_arg, gmp_binary_op_t gmp_op, gmp_binary_ui_op_t gmp_ui_op, int check_b_zero TSRMLS_DC) { - mpz_t *gmpnum_a, *gmpnum_b, *gmpnum_result; + mpz_ptr gmpnum_a, gmpnum_b, gmpnum_result; int use_ui = 0; gmp_temp_t temp_a, temp_b; FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a); - if (gmp_ui_op && Z_TYPE_PP(b_arg) == IS_LONG && Z_LVAL_PP(b_arg) >= 0) { + if (gmp_ui_op && Z_TYPE_P(b_arg) == IS_LONG && Z_LVAL_P(b_arg) >= 0) { use_ui = 1; - temp_b = NULL; + temp_b.is_used = 0; } else { FETCH_GMP_ZVAL_DEP(gmpnum_b, b_arg, temp_b, temp_a); } @@ -845,9 +881,9 @@ static inline void gmp_zval_binary_ui_op(zval *return_value, zval **a_arg, zval if (check_b_zero) { int b_is_zero = 0; if (use_ui) { - b_is_zero = (Z_LVAL_PP(b_arg) == 0); + b_is_zero = (Z_LVAL_P(b_arg) == 0); } else { - b_is_zero = !mpz_cmp_ui(*gmpnum_b, 0); + b_is_zero = !mpz_cmp_ui(gmpnum_b, 0); } if (b_is_zero) { @@ -858,37 +894,34 @@ static inline void gmp_zval_binary_ui_op(zval *return_value, zval **a_arg, zval } } - INIT_GMP_NUM(gmpnum_result); + INIT_GMP_RETVAL(gmpnum_result); if (use_ui) { - gmp_ui_op(*gmpnum_result, *gmpnum_a, (unsigned long) Z_LVAL_PP(b_arg)); + gmp_ui_op(gmpnum_result, gmpnum_a, (unsigned long) Z_LVAL_P(b_arg)); } else { - gmp_op(*gmpnum_result, *gmpnum_a, *gmpnum_b); + gmp_op(gmpnum_result, gmpnum_a, gmpnum_b); } FREE_GMP_TEMP(temp_a); FREE_GMP_TEMP(temp_b); - - RETVAL_GMP(gmpnum_result); } /* }}} */ /* {{{ gmp_zval_binary_ui_op2 Execute GMP binary operation which returns 2 values. - May return GMP resources or longs if operation allows this. */ -static inline void gmp_zval_binary_ui_op2(zval *return_value, zval **a_arg, zval **b_arg, gmp_binary_op2_t gmp_op, gmp_binary_ui_op2_t gmp_ui_op, int check_b_zero TSRMLS_DC) +static inline void gmp_zval_binary_ui_op2(zval *return_value, zval *a_arg, zval *b_arg, gmp_binary_op2_t gmp_op, gmp_binary_ui_op2_t gmp_ui_op, int check_b_zero TSRMLS_DC) { - mpz_t *gmpnum_a, *gmpnum_b, *gmpnum_result1, *gmpnum_result2; + mpz_ptr gmpnum_a, gmpnum_b, gmpnum_result1, gmpnum_result2; int use_ui = 0; gmp_temp_t temp_a, temp_b; FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a); - if (gmp_ui_op && Z_TYPE_PP(b_arg) == IS_LONG && Z_LVAL_PP(b_arg) >= 0) { + if (gmp_ui_op && Z_TYPE_P(b_arg) == IS_LONG && Z_LVAL_P(b_arg) >= 0) { /* use _ui function */ use_ui = 1; - temp_b = NULL; + temp_b.is_used = 0; } else { FETCH_GMP_ZVAL_DEP(gmpnum_b, b_arg, temp_b, temp_a); } @@ -896,9 +929,9 @@ static inline void gmp_zval_binary_ui_op2(zval *return_value, zval **a_arg, zval if (check_b_zero) { int b_is_zero = 0; if (use_ui) { - b_is_zero = (Z_LVAL_PP(b_arg) == 0); + b_is_zero = (Z_LVAL_P(b_arg) == 0); } else { - b_is_zero = !mpz_cmp_ui(*gmpnum_b, 0); + b_is_zero = !mpz_cmp_ui(gmpnum_b, 0); } if (b_is_zero) { @@ -909,21 +942,18 @@ static inline void gmp_zval_binary_ui_op2(zval *return_value, zval **a_arg, zval } } - INIT_GMP_NUM(gmpnum_result1); - INIT_GMP_NUM(gmpnum_result2); + array_init(return_value); + add_index_zval(return_value, 0, gmp_create(&gmpnum_result1 TSRMLS_CC)); + add_index_zval(return_value, 1, gmp_create(&gmpnum_result2 TSRMLS_CC)); if (use_ui) { - gmp_ui_op(*gmpnum_result1, *gmpnum_result2, *gmpnum_a, (unsigned long)Z_LVAL_PP(b_arg)); + gmp_ui_op(gmpnum_result1, gmpnum_result2, gmpnum_a, (unsigned long) Z_LVAL_P(b_arg)); } else { - gmp_op(*gmpnum_result1, *gmpnum_result2, *gmpnum_a, *gmpnum_b); + gmp_op(gmpnum_result1, gmpnum_result2, gmpnum_a, gmpnum_b); } FREE_GMP_TEMP(temp_a); FREE_GMP_TEMP(temp_b); - - array_init(return_value); - ADD_INDEX_GMP(return_value, 0, gmpnum_result1); - ADD_INDEX_GMP(return_value, 1, gmpnum_result2); } /* }}} */ @@ -931,9 +961,9 @@ static inline void gmp_zval_binary_ui_op2(zval *return_value, zval **a_arg, zval */ static inline void _gmp_binary_ui_op(INTERNAL_FUNCTION_PARAMETERS, gmp_binary_op_t gmp_op, gmp_binary_ui_op_t gmp_ui_op, int check_b_zero) { - zval **a_arg, **b_arg; + zval *a_arg, *b_arg; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ZZ", &a_arg, &b_arg) == FAILURE){ + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zz", &a_arg, &b_arg) == FAILURE){ return; } @@ -945,33 +975,28 @@ static inline void _gmp_binary_ui_op(INTERNAL_FUNCTION_PARAMETERS, gmp_binary_op /* {{{ gmp_zval_unary_op */ -static inline void gmp_zval_unary_op(zval *return_value, zval **a_arg, gmp_unary_op_t gmp_op TSRMLS_DC) +static inline void gmp_zval_unary_op(zval *return_value, zval *a_arg, gmp_unary_op_t gmp_op TSRMLS_DC) { - mpz_t *gmpnum_a, *gmpnum_result; + mpz_ptr gmpnum_a, gmpnum_result; gmp_temp_t temp_a; FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a); - INIT_GMP_NUM(gmpnum_result); - gmp_op(*gmpnum_result, *gmpnum_a); + INIT_GMP_RETVAL(gmpnum_result); + gmp_op(gmpnum_result, gmpnum_a); FREE_GMP_TEMP(temp_a); - RETVAL_GMP(gmpnum_result); } /* }}} */ /* {{{ gmp_zval_unary_ui_op */ -static inline void gmp_zval_unary_ui_op(zval *return_value, zval **a_arg, gmp_unary_ui_op_t gmp_op TSRMLS_DC) +static inline void gmp_zval_unary_ui_op(zval *return_value, zval *a_arg, gmp_unary_ui_op_t gmp_op TSRMLS_DC) { - mpz_t *gmpnum_result; - - convert_to_long_ex(a_arg); - - INIT_GMP_NUM(gmpnum_result); - gmp_op(*gmpnum_result, Z_LVAL_PP(a_arg)); + mpz_ptr gmpnum_result; - RETVAL_GMP(gmpnum_result); + INIT_GMP_RETVAL(gmpnum_result); + gmp_op(gmpnum_result, gmp_get_long(a_arg)); } /* }}} */ @@ -980,9 +1005,9 @@ static inline void gmp_zval_unary_ui_op(zval *return_value, zval **a_arg, gmp_un */ static inline void _gmp_unary_ui_op(INTERNAL_FUNCTION_PARAMETERS, gmp_unary_ui_op_t gmp_op) { - zval **a_arg; + zval *a_arg; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z", &a_arg) == FAILURE){ + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &a_arg) == FAILURE){ return; } @@ -994,9 +1019,9 @@ static inline void _gmp_unary_ui_op(INTERNAL_FUNCTION_PARAMETERS, gmp_unary_ui_o */ static inline void _gmp_unary_op(INTERNAL_FUNCTION_PARAMETERS, gmp_unary_op_t gmp_op) { - zval **a_arg; + zval *a_arg; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z", &a_arg) == FAILURE){ + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &a_arg) == FAILURE){ return; } @@ -1008,16 +1033,16 @@ static inline void _gmp_unary_op(INTERNAL_FUNCTION_PARAMETERS, gmp_unary_op_t gm */ static inline void _gmp_unary_opl(INTERNAL_FUNCTION_PARAMETERS, gmp_unary_opl_t gmp_op) { - zval **a_arg; - mpz_t *gmpnum_a; + zval *a_arg; + mpz_ptr gmpnum_a; gmp_temp_t temp_a; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z", &a_arg) == FAILURE){ + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &a_arg) == FAILURE){ return; } FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a); - RETVAL_LONG(gmp_op(*gmpnum_a)); + RETVAL_LONG(gmp_op(gmpnum_a)); FREE_GMP_TEMP(temp_a); } /* }}} */ @@ -1026,18 +1051,18 @@ static inline void _gmp_unary_opl(INTERNAL_FUNCTION_PARAMETERS, gmp_unary_opl_t */ static inline void _gmp_binary_opl(INTERNAL_FUNCTION_PARAMETERS, gmp_binary_opl_t gmp_op) { - zval **a_arg, **b_arg; - mpz_t *gmpnum_a, *gmpnum_b; + zval *a_arg, *b_arg; + mpz_ptr gmpnum_a, gmpnum_b; gmp_temp_t temp_a, temp_b; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ZZ", &a_arg, &b_arg) == FAILURE){ + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zz", &a_arg, &b_arg) == FAILURE){ return; } FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a); FETCH_GMP_ZVAL_DEP(gmpnum_b, b_arg, temp_b, temp_a); - RETVAL_LONG(gmp_op(*gmpnum_a, *gmpnum_b)); + RETVAL_LONG(gmp_op(gmpnum_a, gmpnum_b)); FREE_GMP_TEMP(temp_a); FREE_GMP_TEMP(temp_b); @@ -1048,11 +1073,11 @@ static inline void _gmp_binary_opl(INTERNAL_FUNCTION_PARAMETERS, gmp_binary_opl_ Initializes GMP number */ ZEND_FUNCTION(gmp_init) { - zval **number_arg; - mpz_t * gmpnumber; - long base=0; + zval *number_arg; + mpz_ptr gmpnumber; + long base = 0; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z|l", &number_arg, &base) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|l", &number_arg, &base) == FAILURE) { return; } @@ -1061,11 +1086,11 @@ ZEND_FUNCTION(gmp_init) RETURN_FALSE; } - if (convert_to_gmp(&gmpnumber, number_arg, base TSRMLS_CC) == FAILURE) { + INIT_GMP_RETVAL(gmpnumber); + if (convert_to_gmp(gmpnumber, number_arg, base TSRMLS_CC) == FAILURE) { + zval_dtor(return_value); RETURN_FALSE; } - - RETVAL_GMP(gmpnumber); } /* }}} */ @@ -1073,19 +1098,16 @@ ZEND_FUNCTION(gmp_init) Gets signed long value of GMP number */ ZEND_FUNCTION(gmp_intval) { - zval **gmpnumber_arg; - mpz_t * gmpnum; + zval *gmpnumber_arg; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z", &gmpnumber_arg) == FAILURE){ + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &gmpnumber_arg) == FAILURE){ return; } - if (IS_GMP_PP(gmpnumber_arg)) { - FETCH_GMP_ZVAL_NO_TEMP(gmpnum, gmpnumber_arg); - RETVAL_LONG(mpz_get_si(*gmpnum)); + if (IS_GMP(gmpnumber_arg)) { + RETVAL_LONG(mpz_get_si(GET_GMP_FROM_ZVAL(gmpnumber_arg))); } else { - convert_to_long_ex(gmpnumber_arg); - RETVAL_LONG(Z_LVAL_PP(gmpnumber_arg)); + RETVAL_LONG(gmp_get_long(gmpnumber_arg)); } } /* }}} */ @@ -1094,12 +1116,12 @@ ZEND_FUNCTION(gmp_intval) Gets string representation of GMP number */ ZEND_FUNCTION(gmp_strval) { - zval **gmpnumber_arg; + zval *gmpnumber_arg; long base = 10; - mpz_t *gmpnum; + mpz_ptr gmpnum; gmp_temp_t temp_a; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z|l", &gmpnumber_arg, &base) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|l", &gmpnumber_arg, &base) == FAILURE) { return; } @@ -1127,7 +1149,7 @@ ZEND_FUNCTION(gmp_strval) Add a and b */ ZEND_FUNCTION(gmp_add) { - gmp_binary_ui_op(mpz_add, (gmp_binary_ui_op_t)mpz_add_ui); + gmp_binary_ui_op(mpz_add, mpz_add_ui); } /* }}} */ @@ -1135,7 +1157,7 @@ ZEND_FUNCTION(gmp_add) Subtract b from a */ ZEND_FUNCTION(gmp_sub) { - gmp_binary_ui_op(mpz_sub, (gmp_binary_ui_op_t)mpz_sub_ui); + gmp_binary_ui_op(mpz_sub, mpz_sub_ui); } /* }}} */ @@ -1143,7 +1165,7 @@ ZEND_FUNCTION(gmp_sub) Multiply a and b */ ZEND_FUNCTION(gmp_mul) { - gmp_binary_ui_op(mpz_mul, (gmp_binary_ui_op_t)mpz_mul_ui); + gmp_binary_ui_op(mpz_mul, mpz_mul_ui); } /* }}} */ @@ -1151,22 +1173,22 @@ ZEND_FUNCTION(gmp_mul) Divide a by b, returns quotient and reminder */ ZEND_FUNCTION(gmp_div_qr) { - zval **a_arg, **b_arg; + zval *a_arg, *b_arg; long round = GMP_ROUND_ZERO; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ZZ|l", &a_arg, &b_arg, &round) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zz|l", &a_arg, &b_arg, &round) == FAILURE) { return; } switch (round) { case GMP_ROUND_ZERO: - gmp_zval_binary_ui_op2(return_value, a_arg, b_arg, mpz_tdiv_qr, (gmp_binary_ui_op2_t)mpz_tdiv_qr_ui, 1 TSRMLS_CC); + gmp_zval_binary_ui_op2(return_value, a_arg, b_arg, mpz_tdiv_qr, (gmp_binary_ui_op2_t) mpz_tdiv_qr_ui, 1 TSRMLS_CC); break; case GMP_ROUND_PLUSINF: - gmp_zval_binary_ui_op2(return_value, a_arg, b_arg, mpz_cdiv_qr, (gmp_binary_ui_op2_t)mpz_cdiv_qr_ui, 1 TSRMLS_CC); + gmp_zval_binary_ui_op2(return_value, a_arg, b_arg, mpz_cdiv_qr, (gmp_binary_ui_op2_t) mpz_cdiv_qr_ui, 1 TSRMLS_CC); break; case GMP_ROUND_MINUSINF: - gmp_zval_binary_ui_op2(return_value, a_arg, b_arg, mpz_fdiv_qr, (gmp_binary_ui_op2_t)mpz_fdiv_qr_ui, 1 TSRMLS_CC); + gmp_zval_binary_ui_op2(return_value, a_arg, b_arg, mpz_fdiv_qr, (gmp_binary_ui_op2_t) mpz_fdiv_qr_ui, 1 TSRMLS_CC); break; default: php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid rounding mode"); @@ -1179,22 +1201,22 @@ ZEND_FUNCTION(gmp_div_qr) Divide a by b, returns reminder only */ ZEND_FUNCTION(gmp_div_r) { - zval **a_arg, **b_arg; + zval *a_arg, *b_arg; long round = GMP_ROUND_ZERO; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ZZ|l", &a_arg, &b_arg, &round) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zz|l", &a_arg, &b_arg, &round) == FAILURE) { return; } switch (round) { case GMP_ROUND_ZERO: - gmp_zval_binary_ui_op(return_value, a_arg, b_arg, mpz_tdiv_r, (gmp_binary_ui_op_t)mpz_tdiv_r_ui, 1 TSRMLS_CC); + gmp_zval_binary_ui_op(return_value, a_arg, b_arg, mpz_tdiv_r, (gmp_binary_ui_op_t) mpz_tdiv_r_ui, 1 TSRMLS_CC); break; case GMP_ROUND_PLUSINF: - gmp_zval_binary_ui_op(return_value, a_arg, b_arg, mpz_cdiv_r, (gmp_binary_ui_op_t)mpz_cdiv_r_ui, 1 TSRMLS_CC); + gmp_zval_binary_ui_op(return_value, a_arg, b_arg, mpz_cdiv_r, (gmp_binary_ui_op_t) mpz_cdiv_r_ui, 1 TSRMLS_CC); break; case GMP_ROUND_MINUSINF: - gmp_zval_binary_ui_op(return_value, a_arg, b_arg, mpz_fdiv_r, (gmp_binary_ui_op_t)mpz_fdiv_r_ui, 1 TSRMLS_CC); + gmp_zval_binary_ui_op(return_value, a_arg, b_arg, mpz_fdiv_r, (gmp_binary_ui_op_t) mpz_fdiv_r_ui, 1 TSRMLS_CC); break; default: php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid rounding mode"); @@ -1207,22 +1229,22 @@ ZEND_FUNCTION(gmp_div_r) Divide a by b, returns quotient only */ ZEND_FUNCTION(gmp_div_q) { - zval **a_arg, **b_arg; + zval *a_arg, *b_arg; long round = GMP_ROUND_ZERO; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ZZ|l", &a_arg, &b_arg, &round) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zz|l", &a_arg, &b_arg, &round) == FAILURE) { return; } switch (round) { case GMP_ROUND_ZERO: - gmp_zval_binary_ui_op(return_value, a_arg, b_arg, mpz_tdiv_q, (gmp_binary_ui_op_t)mpz_tdiv_q_ui, 1 TSRMLS_CC); + gmp_zval_binary_ui_op(return_value, a_arg, b_arg, mpz_tdiv_q, (gmp_binary_ui_op_t) mpz_tdiv_q_ui, 1 TSRMLS_CC); break; case GMP_ROUND_PLUSINF: - gmp_zval_binary_ui_op(return_value, a_arg, b_arg, mpz_cdiv_q, (gmp_binary_ui_op_t)mpz_cdiv_q_ui, 1 TSRMLS_CC); + gmp_zval_binary_ui_op(return_value, a_arg, b_arg, mpz_cdiv_q, (gmp_binary_ui_op_t) mpz_cdiv_q_ui, 1 TSRMLS_CC); break; case GMP_ROUND_MINUSINF: - gmp_zval_binary_ui_op(return_value, a_arg, b_arg, mpz_fdiv_q, (gmp_binary_ui_op_t)mpz_fdiv_q_ui, 1 TSRMLS_CC); + gmp_zval_binary_ui_op(return_value, a_arg, b_arg, mpz_fdiv_q, (gmp_binary_ui_op_t) mpz_fdiv_q_ui, 1 TSRMLS_CC); break; default: php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid rounding mode"); @@ -1236,7 +1258,7 @@ ZEND_FUNCTION(gmp_div_q) Computes a modulo b */ ZEND_FUNCTION(gmp_mod) { - gmp_binary_ui_op_no_zero(mpz_mod, (gmp_binary_ui_op_t)mpz_mod_ui); + gmp_binary_ui_op_no_zero(mpz_mod, (gmp_binary_ui_op_t) mpz_mod_ui); } /* }}} */ @@ -1268,29 +1290,25 @@ ZEND_FUNCTION(gmp_abs) Calculates factorial function */ ZEND_FUNCTION(gmp_fact) { - zval **a_arg; - mpz_t *gmpnum_tmp; + zval *a_arg; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z", &a_arg) == FAILURE){ + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &a_arg) == FAILURE){ return; } - if (IS_GMP_PP(a_arg)) { - FETCH_GMP_ZVAL_NO_TEMP(gmpnum_tmp, a_arg) - if (mpz_sgn(*gmpnum_tmp) < 0) { + if (IS_GMP(a_arg)) { + mpz_ptr gmpnum_tmp = GET_GMP_FROM_ZVAL(a_arg); + if (mpz_sgn(gmpnum_tmp) < 0) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "Number has to be greater than or equal to 0"); RETURN_FALSE; } } else { - convert_to_long_ex(a_arg); - if (Z_LVAL_PP(a_arg) < 0) { + if (gmp_get_long(a_arg) < 0) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "Number has to be greater than or equal to 0"); RETURN_FALSE; } } - /* TODO This one looks like a bug. If you passed a GMP resource it would - * take the factorial of the GMP resource ID rather than the GMP number. */ gmp_zval_unary_ui_op(return_value, a_arg, mpz_fac_ui TSRMLS_CC); } /* }}} */ @@ -1299,13 +1317,12 @@ ZEND_FUNCTION(gmp_fact) Raise base to power exp */ ZEND_FUNCTION(gmp_pow) { - zval **base_arg; - mpz_t *gmpnum_result, *gmpnum_base; - int use_ui = 0; + zval *base_arg; + mpz_ptr gmpnum_result, gmpnum_base; gmp_temp_t temp_base; long exp; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Zl", &base_arg, &exp) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zl", &base_arg, &exp) == FAILURE) { return; } @@ -1314,21 +1331,14 @@ ZEND_FUNCTION(gmp_pow) RETURN_FALSE; } - if (Z_TYPE_PP(base_arg) == IS_LONG && Z_LVAL_PP(base_arg) >= 0) { - use_ui = 1; - temp_base = NULL; + INIT_GMP_RETVAL(gmpnum_result); + if (Z_TYPE_P(base_arg) == IS_LONG && Z_LVAL_P(base_arg) >= 0) { + mpz_ui_pow_ui(gmpnum_result, Z_LVAL_P(base_arg), exp); } else { FETCH_GMP_ZVAL(gmpnum_base, base_arg, temp_base); - } - - INIT_GMP_NUM(gmpnum_result); - if (use_ui) { - mpz_ui_pow_ui(*gmpnum_result, Z_LVAL_PP(base_arg), exp); - } else { - mpz_pow_ui(*gmpnum_result, *gmpnum_base, exp); + mpz_pow_ui(gmpnum_result, gmpnum_base, exp); FREE_GMP_TEMP(temp_base); } - RETVAL_GMP(gmpnum_result); } /* }}} */ @@ -1336,23 +1346,23 @@ ZEND_FUNCTION(gmp_pow) Raise base to power exp and take result modulo mod */ ZEND_FUNCTION(gmp_powm) { - zval **base_arg, **exp_arg, **mod_arg; - mpz_t *gmpnum_base, *gmpnum_exp, *gmpnum_mod, *gmpnum_result; + zval *base_arg, *exp_arg, *mod_arg; + mpz_ptr gmpnum_base, gmpnum_exp, gmpnum_mod, gmpnum_result; int use_ui = 0; gmp_temp_t temp_base, temp_exp, temp_mod; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ZZZ", &base_arg, &exp_arg, &mod_arg) == FAILURE){ + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zzz", &base_arg, &exp_arg, &mod_arg) == FAILURE){ return; } FETCH_GMP_ZVAL(gmpnum_base, base_arg, temp_base); - if (Z_TYPE_PP(exp_arg) == IS_LONG && Z_LVAL_PP(exp_arg) >= 0) { + if (Z_TYPE_P(exp_arg) == IS_LONG && Z_LVAL_P(exp_arg) >= 0) { use_ui = 1; - temp_exp = NULL; + temp_exp.is_used = 0; } else { FETCH_GMP_ZVAL_DEP(gmpnum_exp, exp_arg, temp_exp, temp_base); - if (mpz_sgn(*gmpnum_exp) < 0) { + if (mpz_sgn(gmpnum_exp) < 0) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "Second parameter cannot be less than 0"); FREE_GMP_TEMP(temp_base); FREE_GMP_TEMP(temp_exp); @@ -1361,7 +1371,7 @@ ZEND_FUNCTION(gmp_powm) } FETCH_GMP_ZVAL_DEP_DEP(gmpnum_mod, mod_arg, temp_mod, temp_exp, temp_base); - if (!mpz_cmp_ui(*gmpnum_mod, 0)) { + if (!mpz_cmp_ui(gmpnum_mod, 0)) { FREE_GMP_TEMP(temp_base); if (use_ui) { FREE_GMP_TEMP(temp_exp); @@ -1370,19 +1380,16 @@ ZEND_FUNCTION(gmp_powm) RETURN_FALSE; } - INIT_GMP_NUM(gmpnum_result); + INIT_GMP_RETVAL(gmpnum_result); if (use_ui) { - mpz_powm_ui(*gmpnum_result, *gmpnum_base, (unsigned long)Z_LVAL_PP(exp_arg), *gmpnum_mod); + mpz_powm_ui(gmpnum_result, gmpnum_base, (unsigned long) Z_LVAL_P(exp_arg), gmpnum_mod); } else { - mpz_powm(*gmpnum_result, *gmpnum_base, *gmpnum_exp, *gmpnum_mod); + mpz_powm(gmpnum_result, gmpnum_base, gmpnum_exp, gmpnum_mod); FREE_GMP_TEMP(temp_exp); } FREE_GMP_TEMP(temp_base); FREE_GMP_TEMP(temp_mod); - - RETVAL_GMP(gmpnum_result); - } /* }}} */ @@ -1390,27 +1397,25 @@ ZEND_FUNCTION(gmp_powm) Takes integer part of square root of a */ ZEND_FUNCTION(gmp_sqrt) { - zval **a_arg; - mpz_t *gmpnum_a, *gmpnum_result; + zval *a_arg; + mpz_ptr gmpnum_a, gmpnum_result; gmp_temp_t temp_a; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z", &a_arg) == FAILURE){ + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &a_arg) == FAILURE){ return; } FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a); - if (mpz_sgn(*gmpnum_a) < 0) { + if (mpz_sgn(gmpnum_a) < 0) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "Number has to be greater than or equal to 0"); FREE_GMP_TEMP(temp_a); RETURN_FALSE; } - INIT_GMP_NUM(gmpnum_result); - mpz_sqrt(*gmpnum_result, *gmpnum_a); + INIT_GMP_RETVAL(gmpnum_result); + mpz_sqrt(gmpnum_result, gmpnum_a); FREE_GMP_TEMP(temp_a); - - RETVAL_GMP(gmpnum_result); } /* }}} */ @@ -1418,31 +1423,28 @@ ZEND_FUNCTION(gmp_sqrt) Square root with remainder */ ZEND_FUNCTION(gmp_sqrtrem) { - zval **a_arg; - mpz_t *gmpnum_a, *gmpnum_result1, *gmpnum_result2; + zval *a_arg; + mpz_ptr gmpnum_a, gmpnum_result1, gmpnum_result2; gmp_temp_t temp_a; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z", &a_arg) == FAILURE){ + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &a_arg) == FAILURE){ return; } FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a); - if (mpz_sgn(*gmpnum_a) < 0) { - php_error_docref(NULL TSRMLS_CC, E_WARNING,"Number has to be greater than or equal to 0"); + if (mpz_sgn(gmpnum_a) < 0) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Number has to be greater than or equal to 0"); FREE_GMP_TEMP(temp_a); RETURN_FALSE; } - INIT_GMP_NUM(gmpnum_result1); - INIT_GMP_NUM(gmpnum_result2); + array_init(return_value); + add_index_zval(return_value, 0, gmp_create(&gmpnum_result1 TSRMLS_CC)); + add_index_zval(return_value, 1, gmp_create(&gmpnum_result2 TSRMLS_CC)); - mpz_sqrtrem(*gmpnum_result1, *gmpnum_result2, *gmpnum_a); + mpz_sqrtrem(gmpnum_result1, gmpnum_result2, gmpnum_a); FREE_GMP_TEMP(temp_a); - - array_init(return_value); - ADD_INDEX_GMP(return_value, 0, gmpnum_result1); - ADD_INDEX_GMP(return_value, 1, gmpnum_result2); } /* }}} */ @@ -1450,17 +1452,17 @@ ZEND_FUNCTION(gmp_sqrtrem) Checks if a is an exact square */ ZEND_FUNCTION(gmp_perfect_square) { - zval **a_arg; - mpz_t *gmpnum_a; + zval *a_arg; + mpz_ptr gmpnum_a; gmp_temp_t temp_a; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z", &a_arg) == FAILURE){ + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &a_arg) == FAILURE){ return; } FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a); - RETVAL_BOOL((mpz_perfect_square_p(*gmpnum_a)!=0)); + RETVAL_BOOL((mpz_perfect_square_p(gmpnum_a) != 0)); FREE_GMP_TEMP(temp_a); } /* }}} */ @@ -1469,18 +1471,18 @@ ZEND_FUNCTION(gmp_perfect_square) Checks if a is "probably prime" */ ZEND_FUNCTION(gmp_prob_prime) { - zval **gmpnumber_arg; - mpz_t *gmpnum_a; + zval *gmpnumber_arg; + mpz_ptr gmpnum_a; long reps = 10; gmp_temp_t temp_a; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z|l", &gmpnumber_arg, &reps) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|l", &gmpnumber_arg, &reps) == FAILURE) { return; } FETCH_GMP_ZVAL(gmpnum_a, gmpnumber_arg, temp_a); - RETVAL_LONG(mpz_probab_prime_p(*gmpnum_a, reps)); + RETVAL_LONG(mpz_probab_prime_p(gmpnum_a, reps)); FREE_GMP_TEMP(temp_a); } /* }}} */ @@ -1489,7 +1491,7 @@ ZEND_FUNCTION(gmp_prob_prime) Computes greatest common denominator (gcd) of a and b */ ZEND_FUNCTION(gmp_gcd) { - gmp_binary_ui_op(mpz_gcd, (gmp_binary_ui_op_t)mpz_gcd_ui); + gmp_binary_ui_op(mpz_gcd, (gmp_binary_ui_op_t) mpz_gcd_ui); } /* }}} */ @@ -1497,30 +1499,25 @@ ZEND_FUNCTION(gmp_gcd) Computes G, S, and T, such that AS + BT = G = `gcd' (A, B) */ ZEND_FUNCTION(gmp_gcdext) { - zval **a_arg, **b_arg; - mpz_t *gmpnum_a, *gmpnum_b, *gmpnum_t, *gmpnum_s, *gmpnum_g; + zval *a_arg, *b_arg; + mpz_ptr gmpnum_a, gmpnum_b, gmpnum_t, gmpnum_s, gmpnum_g; gmp_temp_t temp_a, temp_b; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ZZ", &a_arg, &b_arg) == FAILURE){ + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zz", &a_arg, &b_arg) == FAILURE){ return; } FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a); FETCH_GMP_ZVAL_DEP(gmpnum_b, b_arg, temp_b, temp_a); - INIT_GMP_NUM(gmpnum_g); - INIT_GMP_NUM(gmpnum_s); - INIT_GMP_NUM(gmpnum_t); + array_init(return_value); + add_assoc_zval(return_value, "g", gmp_create(&gmpnum_g TSRMLS_CC)); + add_assoc_zval(return_value, "s", gmp_create(&gmpnum_s TSRMLS_CC)); + add_assoc_zval(return_value, "t", gmp_create(&gmpnum_t TSRMLS_CC)); - mpz_gcdext(*gmpnum_g, *gmpnum_s, *gmpnum_t, *gmpnum_a, *gmpnum_b); + mpz_gcdext(gmpnum_g, gmpnum_s, gmpnum_t, gmpnum_a, gmpnum_b); FREE_GMP_TEMP(temp_a); FREE_GMP_TEMP(temp_b); - - array_init(return_value); - - ADD_ASSOC_GMP(return_value, "g", gmpnum_g); - ADD_ASSOC_GMP(return_value, "s", gmpnum_s); - ADD_ASSOC_GMP(return_value, "t", gmpnum_t); } /* }}} */ @@ -1528,26 +1525,24 @@ ZEND_FUNCTION(gmp_gcdext) Computes the inverse of a modulo b */ ZEND_FUNCTION(gmp_invert) { - zval **a_arg, **b_arg; - mpz_t *gmpnum_a, *gmpnum_b, *gmpnum_result; + zval *a_arg, *b_arg; + mpz_ptr gmpnum_a, gmpnum_b, gmpnum_result; gmp_temp_t temp_a, temp_b; int res; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ZZ", &a_arg, &b_arg) == FAILURE){ + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zz", &a_arg, &b_arg) == FAILURE){ return; } FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a); FETCH_GMP_ZVAL_DEP(gmpnum_b, b_arg, temp_b, temp_a); - INIT_GMP_NUM(gmpnum_result); - res=mpz_invert(*gmpnum_result, *gmpnum_a, *gmpnum_b); + INIT_GMP_RETVAL(gmpnum_result); + res = mpz_invert(gmpnum_result, gmpnum_a, gmpnum_b); FREE_GMP_TEMP(temp_a); FREE_GMP_TEMP(temp_b); - if (res) { - RETVAL_GMP(gmpnum_result); - } else { - FREE_GMP_NUM(gmpnum_result); + if (!res) { + zval_dtor(return_value); RETURN_FALSE; } } @@ -1573,9 +1568,9 @@ ZEND_FUNCTION(gmp_legendre) Compares two numbers */ ZEND_FUNCTION(gmp_cmp) { - zval **a_arg, **b_arg; + zval *a_arg, *b_arg; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ZZ", &a_arg, &b_arg) == FAILURE){ + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zz", &a_arg, &b_arg) == FAILURE){ return; } @@ -1587,17 +1582,17 @@ ZEND_FUNCTION(gmp_cmp) Gets the sign of the number */ ZEND_FUNCTION(gmp_sign) { - zval **a_arg; - mpz_t *gmpnum_a; + zval *a_arg; + mpz_ptr gmpnum_a; gmp_temp_t temp_a; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z", &a_arg) == FAILURE){ + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &a_arg) == FAILURE){ return; } FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a); - RETVAL_LONG(mpz_sgn(*gmpnum_a)); + RETVAL_LONG(mpz_sgn(gmpnum_a)); FREE_GMP_TEMP(temp_a); } /* }}} */ @@ -1607,13 +1602,13 @@ ZEND_FUNCTION(gmp_sign) ZEND_FUNCTION(gmp_random) { long limiter = 20; - mpz_t *gmpnum_result; + mpz_ptr gmpnum_result; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &limiter) == FAILURE) { return; } - INIT_GMP_NUM(gmpnum_result); + INIT_GMP_RETVAL(gmpnum_result); if (!GMPG(rand_initialized)) { /* Initialize */ @@ -1625,11 +1620,10 @@ ZEND_FUNCTION(gmp_random) GMPG(rand_initialized) = 1; } #ifdef GMP_LIMB_BITS - mpz_urandomb(*gmpnum_result, GMPG(rand_state), GMP_ABS (limiter) * GMP_LIMB_BITS); + mpz_urandomb(gmpnum_result, GMPG(rand_state), GMP_ABS (limiter) * GMP_LIMB_BITS); #else - mpz_urandomb(*gmpnum_result, GMPG(rand_state), GMP_ABS (limiter) * __GMP_BITS_PER_MP_LIMB); + mpz_urandomb(gmpnum_result, GMPG(rand_state), GMP_ABS (limiter) * __GMP_BITS_PER_MP_LIMB); #endif - RETVAL_GMP(gmpnum_result); } /* }}} */ @@ -1669,8 +1663,9 @@ ZEND_FUNCTION(gmp_nextprime) Calculates logical exclusive OR of a and b */ ZEND_FUNCTION(gmp_xor) { + gmp_binary_op(mpz_xor); /* use formula: a^b = (a|b)&~(a&b) */ - zval **a_arg, **b_arg; + /*zval **a_arg, **b_arg; mpz_t *gmpnum_a, *gmpnum_b, *gmpnum_result, *gmpnum_t; gmp_temp_t temp_a, temp_b; @@ -1694,7 +1689,7 @@ ZEND_FUNCTION(gmp_xor) FREE_GMP_TEMP(temp_a); FREE_GMP_TEMP(temp_b); - RETVAL_GMP(gmpnum_result); + RETVAL_GMP(gmpnum_result);*/ } /* }}} */ @@ -1705,23 +1700,23 @@ ZEND_FUNCTION(gmp_setbit) zval *a_arg; long index; zend_bool set = 1; - mpz_t *gmpnum_a; + mpz_ptr gmpnum_a; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Ol|b", &a_arg, gmp_ce, &index, &set) == FAILURE) { return; } - FETCH_GMP_ZVAL_NO_TEMP(gmpnum_a, &a_arg); - if (index < 0) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "Index must be greater than or equal to zero"); return; } + gmpnum_a = GET_GMP_FROM_ZVAL(a_arg); + if (set) { - mpz_setbit(*gmpnum_a, index); + mpz_setbit(gmpnum_a, index); } else { - mpz_clrbit(*gmpnum_a, index); + mpz_clrbit(gmpnum_a, index); } } /* }}} */ @@ -1732,20 +1727,19 @@ ZEND_FUNCTION(gmp_clrbit) { zval *a_arg; long index; - mpz_t *gmpnum_a; + mpz_ptr gmpnum_a; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Ol", &a_arg, gmp_ce, &index) == FAILURE){ return; } - FETCH_GMP_ZVAL_NO_TEMP(gmpnum_a, &a_arg); - if (index < 0) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "Index must be greater than or equal to zero"); return; } - mpz_clrbit(*gmpnum_a, index); + gmpnum_a = GET_GMP_FROM_ZVAL(a_arg); + mpz_clrbit(gmpnum_a, index); } /* }}} */ @@ -1753,11 +1747,11 @@ ZEND_FUNCTION(gmp_clrbit) Tests if bit is set in a */ ZEND_FUNCTION(gmp_testbit) { - zval **a_arg; + zval *a_arg; long index; - mpz_t *gmpnum_a; + mpz_ptr gmpnum_a; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Zl", &a_arg, &index) == FAILURE){ + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zl", &a_arg, &index) == FAILURE){ return; } @@ -1766,13 +1760,8 @@ ZEND_FUNCTION(gmp_testbit) RETURN_FALSE; } - /* TODO Why NO_TEMP? */ - FETCH_GMP_ZVAL_NO_TEMP(gmpnum_a, a_arg); - - if (mpz_tstbit(*gmpnum_a, index)) { - RETURN_TRUE; - } - RETURN_FALSE; + gmpnum_a = GET_GMP_FROM_ZVAL(a_arg); + RETURN_BOOL(mpz_tstbit(gmpnum_a, index)); } /* }}} */ @@ -1780,17 +1769,17 @@ ZEND_FUNCTION(gmp_testbit) Calculates the population count of a */ ZEND_FUNCTION(gmp_popcount) { - zval **a_arg; - mpz_t *gmpnum_a; + zval *a_arg; + mpz_ptr gmpnum_a; gmp_temp_t temp_a; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z", &a_arg) == FAILURE){ + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &a_arg) == FAILURE){ return; } FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a); - RETVAL_LONG(mpz_popcount(*gmpnum_a)); + RETVAL_LONG(mpz_popcount(gmpnum_a)); FREE_GMP_TEMP(temp_a); } /* }}} */ @@ -1799,18 +1788,18 @@ ZEND_FUNCTION(gmp_popcount) Calculates hamming distance between a and b */ ZEND_FUNCTION(gmp_hamdist) { - zval **a_arg, **b_arg; - mpz_t *gmpnum_a, *gmpnum_b; + zval *a_arg, *b_arg; + mpz_ptr gmpnum_a, gmpnum_b; gmp_temp_t temp_a, temp_b; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ZZ", &a_arg, &b_arg) == FAILURE){ + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zz", &a_arg, &b_arg) == FAILURE){ return; } FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a); FETCH_GMP_ZVAL_DEP(gmpnum_b, b_arg, temp_b, temp_a); - RETVAL_LONG(mpz_hamdist(*gmpnum_a, *gmpnum_b)); + RETVAL_LONG(mpz_hamdist(gmpnum_a, gmpnum_b)); FREE_GMP_TEMP(temp_a); FREE_GMP_TEMP(temp_b); } @@ -1820,12 +1809,12 @@ ZEND_FUNCTION(gmp_hamdist) Finds first zero bit */ ZEND_FUNCTION(gmp_scan0) { - zval **a_arg; - mpz_t *gmpnum_a; + zval *a_arg; + mpz_ptr gmpnum_a; gmp_temp_t temp_a; long start; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Zl", &a_arg, &start) == FAILURE){ + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zl", &a_arg, &start) == FAILURE){ return; } @@ -1836,7 +1825,7 @@ ZEND_FUNCTION(gmp_scan0) FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a); - RETVAL_LONG(mpz_scan0(*gmpnum_a, start)); + RETVAL_LONG(mpz_scan0(gmpnum_a, start)); FREE_GMP_TEMP(temp_a); } /* }}} */ @@ -1845,12 +1834,12 @@ ZEND_FUNCTION(gmp_scan0) Finds first non-zero bit */ ZEND_FUNCTION(gmp_scan1) { - zval **a_arg; - mpz_t *gmpnum_a; + zval *a_arg; + mpz_ptr gmpnum_a; gmp_temp_t temp_a; long start; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Zl", &a_arg, &start) == FAILURE){ + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zl", &a_arg, &start) == FAILURE){ return; } @@ -1861,7 +1850,7 @@ ZEND_FUNCTION(gmp_scan1) FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a); - RETVAL_LONG(mpz_scan1(*gmpnum_a, start)); + RETVAL_LONG(mpz_scan1(gmpnum_a, start)); FREE_GMP_TEMP(temp_a); } /* }}} */ From 05ae4b1025bc680a618f5c15dfb3f7cad71858f8 Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Tue, 14 May 2013 22:16:45 +0200 Subject: [PATCH 08/11] Remove compare_objects_t back to compare_t --- Zend/zend_object_handlers.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Zend/zend_object_handlers.h b/Zend/zend_object_handlers.h index 59421b665e71..07428737ff19 100644 --- a/Zend/zend_object_handlers.h +++ b/Zend/zend_object_handlers.h @@ -99,8 +99,8 @@ typedef zend_object_value (*zend_object_clone_obj_t)(zval *object TSRMLS_DC); typedef zend_class_entry *(*zend_object_get_class_entry_t)(const zval *object TSRMLS_DC); typedef int (*zend_object_get_class_name_t)(const zval *object, const char **class_name, zend_uint *class_name_len, int parent TSRMLS_DC); -typedef int (*zend_object_compare_objects_t)(zval *object1, zval *object2 TSRMLS_DC); -typedef int (*zend_object_compare_t)(zval *resul, zval *op1, zval *op2 TSRMLS_DC); +typedef int (*zend_object_compare_t)(zval *object1, zval *object2 TSRMLS_DC); +typedef int (*zend_object_compare_zvals_t)(zval *resul, zval *op1, zval *op2 TSRMLS_DC); /* Cast an object to some other type */ @@ -139,14 +139,14 @@ struct _zend_object_handlers { zend_object_get_constructor_t get_constructor; zend_object_get_class_entry_t get_class_entry; zend_object_get_class_name_t get_class_name; - zend_object_compare_objects_t compare_objects; + zend_object_compare_t compare_objects; zend_object_cast_t cast_object; zend_object_count_elements_t count_elements; zend_object_get_debug_info_t get_debug_info; zend_object_get_closure_t get_closure; zend_object_get_gc_t get_gc; zend_object_do_operation_t do_operation; - zend_object_compare_t compare; + zend_object_compare_zvals_t compare; }; extern ZEND_API zend_object_handlers std_object_handlers; From 5ff1ef8b67582e31398ace26f20631f7d7a3f6cb Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Fri, 7 Jun 2013 19:05:58 +0200 Subject: [PATCH 09/11] Remove operator overloading code from most likely paths --- Zend/zend_operators.c | 183 ++++++++++++++++++++++-------------------- Zend/zend_operators.h | 26 +++--- 2 files changed, 112 insertions(+), 97 deletions(-) diff --git a/Zend/zend_operators.c b/Zend/zend_operators.c index 1b884d6cbd83..027260583949 100644 --- a/Zend/zend_operators.c +++ b/Zend/zend_operators.c @@ -857,9 +857,7 @@ ZEND_API int add_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ * default: if (!converted) { - if (zend_object_do_operation(ZEND_ADD, result, op1, op2 TSRMLS_CC) == SUCCESS) { - return SUCCESS; - } + ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_ADD); zendi_convert_scalar_to_number(op1, op1_copy, result); zendi_convert_scalar_to_number(op2, op2_copy, result); @@ -908,9 +906,7 @@ ZEND_API int sub_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ * default: if (!converted) { - if (zend_object_do_operation(ZEND_SUB, result, op1, op2 TSRMLS_CC) == SUCCESS) { - return SUCCESS; - } + ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_SUB); zendi_convert_scalar_to_number(op1, op1_copy, result); zendi_convert_scalar_to_number(op2, op2_copy, result); @@ -953,9 +949,7 @@ ZEND_API int mul_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ * default: if (!converted) { - if (zend_object_do_operation(ZEND_MUL, result, op1, op2 TSRMLS_CC) == SUCCESS) { - return SUCCESS; - } + ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_MUL); zendi_convert_scalar_to_number(op1, op1_copy, result); zendi_convert_scalar_to_number(op2, op2_copy, result); @@ -1022,9 +1016,7 @@ ZEND_API int div_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ * default: if (!converted) { - if (zend_object_do_operation(ZEND_DIV, result, op1, op2 TSRMLS_CC) == SUCCESS) { - return SUCCESS; - } + ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_DIV); zendi_convert_scalar_to_number(op1, op1_copy, result); zendi_convert_scalar_to_number(op2, op2_copy, result); @@ -1042,14 +1034,16 @@ ZEND_API int mod_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ * { zval op1_copy, op2_copy; long op1_lval; - - if (zend_object_do_operation(ZEND_MOD, result, op1, op2 TSRMLS_CC) == SUCCESS) { - return SUCCESS; - } - zendi_convert_to_long(op1, op1_copy, result); - op1_lval = Z_LVAL_P(op1); - zendi_convert_to_long(op2, op2_copy, result); + if (Z_TYPE_P(op1) != IS_LONG || Z_TYPE_P(op2) != IS_LONG) { + ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_MOD); + + zendi_convert_to_long(op1, op1_copy, result); + op1_lval = Z_LVAL_P(op1); + zendi_convert_to_long(op2, op2_copy, result); + } else { + op1_lval = Z_LVAL_P(op1); + } if (Z_LVAL_P(op2) == 0) { zend_error(E_WARNING, "Division by zero"); @@ -1073,13 +1067,16 @@ ZEND_API int boolean_xor_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) zval op1_copy, op2_copy; long op1_lval; - if (zend_object_do_operation(ZEND_BOOL_XOR, result, op1, op2 TSRMLS_CC) == SUCCESS) { - return SUCCESS; + if (Z_TYPE_P(op1) != IS_BOOL || Z_TYPE_P(op2) != IS_BOOL) { + ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_BOOL_XOR); + + zendi_convert_to_boolean(op1, op1_copy, result); + op1_lval = Z_LVAL_P(op1); + zendi_convert_to_boolean(op2, op2_copy, result); + } else { + op1_lval = Z_LVAL_P(op1); } - zendi_convert_to_boolean(op1, op1_copy, result); - op1_lval = Z_LVAL_P(op1); - zendi_convert_to_boolean(op2, op2_copy, result); ZVAL_BOOL(result, op1_lval ^ Z_LVAL_P(op2)); return SUCCESS; } @@ -1089,11 +1086,12 @@ ZEND_API int boolean_not_function(zval *result, zval *op1 TSRMLS_DC) /* {{{ */ { zval op1_copy; - if (zend_object_do_operation(ZEND_BOOL_NOT, result, op1, NULL TSRMLS_CC) == SUCCESS) { - return SUCCESS; + if (Z_TYPE_P(op1) != IS_BOOL) { + ZEND_TRY_UNARY_OBJECT_OPERATION(ZEND_BOOL_NOT); + + zendi_convert_to_boolean(op1, op1_copy, result); } - zendi_convert_to_boolean(op1, op1_copy, result); ZVAL_BOOL(result, !Z_LVAL_P(op1)); return SUCCESS; } @@ -1101,33 +1099,32 @@ ZEND_API int boolean_not_function(zval *result, zval *op1 TSRMLS_DC) /* {{{ */ ZEND_API int bitwise_not_function(zval *result, zval *op1 TSRMLS_DC) /* {{{ */ { - zval op1_copy = *op1; - - if (zend_object_do_operation(ZEND_BW_NOT, result, op1, NULL TSRMLS_CC) == SUCCESS) { - return SUCCESS; - } - - op1 = &op1_copy; - if (Z_TYPE_P(op1) == IS_LONG) { - ZVAL_LONG(result, ~Z_LVAL_P(op1)); - return SUCCESS; - } else if (Z_TYPE_P(op1) == IS_DOUBLE) { - ZVAL_LONG(result, ~zend_dval_to_lval(Z_DVAL_P(op1))); - return SUCCESS; - } else if (Z_TYPE_P(op1) == IS_STRING) { - int i; - - Z_TYPE_P(result) = IS_STRING; - Z_STRVAL_P(result) = estrndup(Z_STRVAL_P(op1), Z_STRLEN_P(op1)); - Z_STRLEN_P(result) = Z_STRLEN_P(op1); - for (i = 0; i < Z_STRLEN_P(op1); i++) { - Z_STRVAL_P(result)[i] = ~Z_STRVAL_P(op1)[i]; + switch (Z_TYPE_P(op1)) { + case IS_LONG: + ZVAL_LONG(result, ~Z_LVAL_P(op1)); + return SUCCESS; + case IS_DOUBLE: + ZVAL_LONG(result, ~zend_dval_to_lval(Z_DVAL_P(op1))); + return SUCCESS; + case IS_STRING: { + int i; + zval op1_copy = *op1; + + Z_TYPE_P(result) = IS_STRING; + Z_STRVAL_P(result) = estrndup(Z_STRVAL(op1_copy), Z_STRLEN(op1_copy)); + Z_STRLEN_P(result) = Z_STRLEN(op1_copy); + for (i = 0; i < Z_STRLEN(op1_copy); i++) { + Z_STRVAL_P(result)[i] = ~Z_STRVAL(op1_copy)[i]; + } + return SUCCESS; } - return SUCCESS; + default: + ZEND_TRY_UNARY_OBJECT_OPERATION(ZEND_BW_NOT); + + zend_error(E_ERROR, "Unsupported operand types"); + return FAILURE; } - zend_error(E_ERROR, "Unsupported operand types"); - return FAILURE; /* unknown datatype */ } /* }}} */ @@ -1163,13 +1160,15 @@ ZEND_API int bitwise_or_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) / return SUCCESS; } - if (zend_object_do_operation(ZEND_BW_OR, result, op1, op2 TSRMLS_CC) == SUCCESS) { - return SUCCESS; - } + if (Z_TYPE_P(op1) != IS_LONG || Z_TYPE_P(op2) != IS_LONG) { + ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_BW_OR); - zendi_convert_to_long(op1, op1_copy, result); - op1_lval = Z_LVAL_P(op1); - zendi_convert_to_long(op2, op2_copy, result); + zendi_convert_to_long(op1, op1_copy, result); + op1_lval = Z_LVAL_P(op1); + zendi_convert_to_long(op2, op2_copy, result); + } else { + op1_lval = Z_LVAL_P(op1); + } ZVAL_LONG(result, op1_lval | Z_LVAL_P(op2)); return SUCCESS; @@ -1208,13 +1207,15 @@ ZEND_API int bitwise_and_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) return SUCCESS; } - if (zend_object_do_operation(ZEND_BW_AND, result, op1, op2 TSRMLS_CC) == SUCCESS) { - return SUCCESS; - } + if (Z_TYPE_P(op1) != IS_LONG || Z_TYPE_P(op2) != IS_LONG) { + ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_BW_AND); - zendi_convert_to_long(op1, op1_copy, result); - op1_lval = Z_LVAL_P(op1); - zendi_convert_to_long(op2, op2_copy, result); + zendi_convert_to_long(op1, op1_copy, result); + op1_lval = Z_LVAL_P(op1); + zendi_convert_to_long(op2, op2_copy, result); + } else { + op1_lval = Z_LVAL_P(op1); + } ZVAL_LONG(result, op1_lval & Z_LVAL_P(op2)); return SUCCESS; @@ -1253,13 +1254,15 @@ ZEND_API int bitwise_xor_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) return SUCCESS; } - if (zend_object_do_operation(ZEND_BW_XOR, result, op1, op2 TSRMLS_CC) == SUCCESS) { - return SUCCESS; - } + if (Z_TYPE_P(op1) != IS_LONG || Z_TYPE_P(op2) != IS_LONG) { + ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_BW_XOR); - zendi_convert_to_long(op1, op1_copy, result); - op1_lval = Z_LVAL_P(op1); - zendi_convert_to_long(op2, op2_copy, result); + zendi_convert_to_long(op1, op1_copy, result); + op1_lval = Z_LVAL_P(op1); + zendi_convert_to_long(op2, op2_copy, result); + } else { + op1_lval = Z_LVAL_P(op1); + } ZVAL_LONG(result, op1_lval ^ Z_LVAL_P(op2)); return SUCCESS; @@ -1271,13 +1274,16 @@ ZEND_API int shift_left_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) / zval op1_copy, op2_copy; long op1_lval; - if (zend_object_do_operation(ZEND_SL, result, op1, op2 TSRMLS_CC) == SUCCESS) { - return SUCCESS; + if (Z_TYPE_P(op1) != IS_LONG || Z_TYPE_P(op2) != IS_LONG) { + ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_SL); + + zendi_convert_to_long(op1, op1_copy, result); + op1_lval = Z_LVAL_P(op1); + zendi_convert_to_long(op2, op2_copy, result); + } else { + op1_lval = Z_LVAL_P(op1); } - zendi_convert_to_long(op1, op1_copy, result); - op1_lval = Z_LVAL_P(op1); - zendi_convert_to_long(op2, op2_copy, result); ZVAL_LONG(result, op1_lval << Z_LVAL_P(op2)); return SUCCESS; } @@ -1288,13 +1294,16 @@ ZEND_API int shift_right_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) zval op1_copy, op2_copy; long op1_lval; - if (zend_object_do_operation(ZEND_SR, result, op1, op2 TSRMLS_CC) == SUCCESS) { - return SUCCESS; + if (Z_TYPE_P(op1) != IS_LONG || Z_TYPE_P(op2) != IS_LONG) { + ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_SR); + + zendi_convert_to_long(op1, op1_copy, result); + op1_lval = Z_LVAL_P(op1); + zendi_convert_to_long(op2, op2_copy, result); + } else { + op1_lval = Z_LVAL_P(op1); } - zendi_convert_to_long(op1, op1_copy, result); - op1_lval = Z_LVAL_P(op1); - zendi_convert_to_long(op2, op2_copy, result); ZVAL_LONG(result, op1_lval >> Z_LVAL_P(op2)); return SUCCESS; } @@ -1343,15 +1352,15 @@ ZEND_API int concat_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{ zval op1_copy, op2_copy; int use_copy1 = 0, use_copy2 = 0; - if (zend_object_do_operation(ZEND_CONCAT, result, op1, op2 TSRMLS_CC) == SUCCESS) { - return SUCCESS; - } + if (Z_TYPE_P(op1) != IS_STRING || Z_TYPE_P(op2) != IS_STRING) { + ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_CONCAT); - if (Z_TYPE_P(op1) != IS_STRING) { - zend_make_printable_zval(op1, &op1_copy, &use_copy1); - } - if (Z_TYPE_P(op2) != IS_STRING) { - zend_make_printable_zval(op2, &op2_copy, &use_copy2); + if (Z_TYPE_P(op1) != IS_STRING) { + zend_make_printable_zval(op1, &op1_copy, &use_copy1); + } + if (Z_TYPE_P(op2) != IS_STRING) { + zend_make_printable_zval(op2, &op2_copy, &use_copy2); + } } if (use_copy1) { diff --git a/Zend/zend_operators.h b/Zend/zend_operators.h index 9a0684af18e2..e7ab9bb3fe9e 100644 --- a/Zend/zend_operators.h +++ b/Zend/zend_operators.h @@ -945,17 +945,23 @@ static zend_always_inline int fast_is_smaller_or_equal_function(zval *result, zv return Z_LVAL_P(result) <= 0; } -static inline int zend_object_do_operation(int opcode, zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */ -{ - if (Z_TYPE_P(op1) == IS_OBJECT && Z_OBJ_HANDLER_P(op1, do_operation)) { - return Z_OBJ_HANDLER_P(op1, do_operation)(opcode, result, op1, op2 TSRMLS_CC); - } else if (op2 != NULL && Z_TYPE_P(op2) == IS_OBJECT && Z_OBJ_HANDLER_P(op2, do_operation)) { - return Z_OBJ_HANDLER_P(op2, do_operation)(opcode, result, op1, op2 TSRMLS_CC); - } else { - return FAILURE; +#define ZEND_TRY_BINARY_OBJECT_OPERATION(opcode) \ + if (Z_TYPE_P(op1) == IS_OBJECT && Z_OBJ_HANDLER_P(op1, do_operation)) { \ + if (SUCCESS == Z_OBJ_HANDLER_P(op1, do_operation)(opcode, result, op1, op2 TSRMLS_CC)) { \ + return SUCCESS; \ + } \ + } else if (Z_TYPE_P(op2) == IS_OBJECT && Z_OBJ_HANDLER_P(op2, do_operation)) { \ + if (SUCCESS == Z_OBJ_HANDLER_P(op2, do_operation)(opcode, result, op1, op2 TSRMLS_CC)) { \ + return SUCCESS; \ + } \ + } + +#define ZEND_TRY_UNARY_OBJECT_OPERATION(opcode) \ + if (Z_TYPE_P(op1) == IS_OBJECT && Z_OBJ_HANDLER_P(op1, do_operation) \ + && SUCCESS == Z_OBJ_HANDLER_P(op1, do_operation)(opcode, result, op1, NULL TSRMLS_CC) \ + ) { \ + return SUCCESS; \ } -} -/* }}} */ #endif From 974786d18d5d2116c76700c4e70da1660afc45fb Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Fri, 7 Jun 2013 20:33:40 +0200 Subject: [PATCH 10/11] Add support for shifts on GMP objects >> behaves as an arithmetic shift, i.e. -42 >> 2 == -11 --- ext/gmp/gmp.c | 42 ++++++++++++++++++++++------------ ext/gmp/tests/overloading.phpt | 27 ++++++++++++++++++++++ 2 files changed, 54 insertions(+), 15 deletions(-) diff --git a/ext/gmp/gmp.c b/ext/gmp/gmp.c index 4cd8a6a69616..82d2658638b2 100644 --- a/ext/gmp/gmp.c +++ b/ext/gmp/gmp.c @@ -597,6 +597,29 @@ static zend_object_value gmp_clone_obj(zval *obj TSRMLS_DC) /* {{{ */ } /* }}} */ +static void shift_operator_helper(gmp_binary_ui_op_t op, zval *return_value, zval *op1, zval *op2 TSRMLS_DC) { + zval op2_copy; + if (Z_TYPE_P(op2) != IS_LONG) { + op2_copy = *op2; + zval_copy_ctor(&op2_copy); + convert_to_long(&op2_copy); + op2 = &op2_copy; + } + + if (Z_LVAL_P(op2) < 0) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Shift cannot be negative"); + RETVAL_FALSE; + } else { + mpz_ptr gmpnum_op, gmpnum_result; + gmp_temp_t temp; + + FETCH_GMP_ZVAL(gmpnum_op, op1, temp); + INIT_GMP_RETVAL(gmpnum_result); + op(gmpnum_result, gmpnum_op, (unsigned long) Z_LVAL_P(op2)); + FREE_GMP_TEMP(temp); + } +} + #define DO_BINARY_UI_OP_EX(op, uop, check_b_zero) \ gmp_zval_binary_ui_op( \ result, op1, op2, op, (gmp_binary_ui_op_t) uop, \ @@ -625,22 +648,11 @@ static int gmp_do_operation(zend_uchar opcode, zval *result, zval *op1, zval *op case ZEND_MOD: DO_BINARY_UI_OP_EX(mpz_mod, mpz_mod_ui, 1); case ZEND_SL: - /*convert_to_long_ex(&op2); - if (Z_LVAL_P(op2) < 0) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Shift cannot be negative"); - ZVAL_FALSE(return_value); - } else { - mpz_t *gmpnum, *resultnum; - gmp_temp_t temp; - zval *result_tmp; - FETCH_GMP_ZVAL(gmpnum, &op1, temp); - mpz_mul_2exp(resultnum, gmpnum, (unsigned long) Z_LVAL_P(op2)) - FREE_GMP_TEMP(temp); - RETVAL_GMP(resultnum); - } - return SUCCESS;*/ + shift_operator_helper(mpz_mul_2exp, result, op1, op2 TSRMLS_CC); + return SUCCESS; case ZEND_SR: - return FAILURE; + shift_operator_helper(mpz_fdiv_q_2exp, result, op1, op2 TSRMLS_CC); + return SUCCESS; case ZEND_BW_OR: DO_BINARY_OP(mpz_ior); case ZEND_BW_AND: diff --git a/ext/gmp/tests/overloading.phpt b/ext/gmp/tests/overloading.phpt index 05b6e6729e0f..403769b4ba94 100644 --- a/ext/gmp/tests/overloading.phpt +++ b/ext/gmp/tests/overloading.phpt @@ -38,6 +38,13 @@ var_dump($a ^ $b); var_dump($a ^ 17); var_dump(42 ^ $b); +var_dump($a << $b); +var_dump($a << 17); +var_dump(42 << $b); + +var_dump($a >> 2); +var_dump(-$a >> 2); + var_dump(~$a); var_dump(-$a); var_dump(+$a); @@ -164,6 +171,26 @@ object(GMP)#%d (1) { ["num"]=> string(2) "59" } +object(GMP)#%d (1) { + ["num"]=> + string(7) "5505024" +} +object(GMP)#%d (1) { + ["num"]=> + string(7) "5505024" +} +object(GMP)#%d (1) { + ["num"]=> + string(7) "5505024" +} +object(GMP)#%d (1) { + ["num"]=> + string(2) "10" +} +object(GMP)#%d (1) { + ["num"]=> + string(3) "-11" +} object(GMP)#%d (1) { ["num"]=> string(3) "-43" From 90545f34071563aee398abbe431d59537630737a Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Fri, 7 Jun 2013 20:42:59 +0200 Subject: [PATCH 11/11] Correctly handle errors in GMP comparison --- ext/gmp/gmp.c | 3 +++ ext/gmp/tests/overloading.phpt | 5 +++++ 2 files changed, 8 insertions(+) diff --git a/ext/gmp/gmp.c b/ext/gmp/gmp.c index 82d2658638b2..96e6ecf82aad 100644 --- a/ext/gmp/gmp.c +++ b/ext/gmp/gmp.c @@ -671,6 +671,9 @@ static int gmp_do_operation(zend_uchar opcode, zval *result, zval *op1, zval *op static int gmp_compare(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */ { gmp_cmp(result, op1, op2 TSRMLS_CC); + if (Z_TYPE_P(result) == IS_BOOL) { + ZVAL_LONG(result, 1); + } return SUCCESS; } /* }}} */ diff --git a/ext/gmp/tests/overloading.phpt b/ext/gmp/tests/overloading.phpt index 403769b4ba94..6bea3c49d655 100644 --- a/ext/gmp/tests/overloading.phpt +++ b/ext/gmp/tests/overloading.phpt @@ -66,6 +66,8 @@ var_dump($a <= 42); var_dump($a > 42); var_dump($a >= 42); +var_dump($a == new stdClass); + $a += 1; var_dump($a); $a -= 1; @@ -217,6 +219,9 @@ bool(false) bool(true) bool(false) bool(true) + +Warning: main(): Unable to convert variable to GMP - wrong type in %s on line %d +bool(false) object(GMP)#%d (1) { ["num"]=> string(2) "43"