📄 gmp.c
字号:
/* +----------------------------------------------------------------------+ | PHP Version 4 | +----------------------------------------------------------------------+ | Copyright (c) 1997-2007 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | | available through the world-wide-web at the following url: | | http://www.php.net/license/3_01.txt | | If you did not receive a copy of the PHP license and are unable to | | obtain it through the world-wide-web, please send a note to | | license@php.net so we can mail you a copy immediately. | +----------------------------------------------------------------------+ | Author: Stanislav Malyshev <stas@php.net> | +----------------------------------------------------------------------+ */#ifdef HAVE_CONFIG_H#include "config.h"#endif#include "php.h"#include "php_ini.h"#include "php_gmp.h"#include "ext/standard/info.h"#if HAVE_GMP#include <gmp.h>/* Needed for gmp_random() */#include "ext/standard/php_rand.h"#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;static unsigned char first_of_two_force_ref[] = { 2, BYREF_FORCE, BYREF_NONE };/* {{{ gmp_functions[] */function_entry gmp_functions[] = { ZEND_FE(gmp_init, NULL) ZEND_FE(gmp_intval, NULL) ZEND_FE(gmp_strval, NULL) ZEND_FE(gmp_add, NULL) ZEND_FE(gmp_sub, NULL) ZEND_FE(gmp_mul, NULL) ZEND_FE(gmp_div_qr, NULL) ZEND_FE(gmp_div_q, NULL) ZEND_FE(gmp_div_r, NULL) ZEND_FALIAS(gmp_div, gmp_div_q, NULL) ZEND_FE(gmp_mod, NULL) ZEND_FE(gmp_divexact, NULL) ZEND_FE(gmp_neg, NULL) ZEND_FE(gmp_abs, NULL) ZEND_FE(gmp_fact, NULL) ZEND_FE(gmp_sqrt, NULL) ZEND_FE(gmp_sqrtrem, NULL) ZEND_FE(gmp_pow, NULL) ZEND_FE(gmp_powm, NULL) ZEND_FE(gmp_perfect_square, NULL) ZEND_FE(gmp_prob_prime, NULL) ZEND_FE(gmp_gcd, NULL) ZEND_FE(gmp_gcdext, NULL) ZEND_FE(gmp_invert, NULL) ZEND_FE(gmp_jacobi, NULL) ZEND_FE(gmp_legendre, NULL) ZEND_FE(gmp_cmp, NULL) ZEND_FE(gmp_sign, NULL) ZEND_FE(gmp_random, NULL) ZEND_FE(gmp_and, NULL) ZEND_FE(gmp_or, NULL) ZEND_FE(gmp_com, NULL) ZEND_FE(gmp_xor, NULL) ZEND_FE(gmp_setbit, first_of_two_force_ref) ZEND_FE(gmp_clrbit, first_of_two_force_ref) ZEND_FE(gmp_scan0, NULL) ZEND_FE(gmp_scan1, NULL) ZEND_FE(gmp_popcount, NULL) ZEND_FE(gmp_hamdist, NULL) {NULL, NULL, NULL} /* Must be the last line in gmp_functions[] */};/* }}} *//* {{{ gmp_module_entry */zend_module_entry gmp_module_entry = { STANDARD_MODULE_HEADER, "gmp", gmp_functions, ZEND_MODULE_STARTUP_N(gmp), ZEND_MODULE_SHUTDOWN_N(gmp), NULL, ZEND_MODULE_DEACTIVATE_N(gmp), ZEND_MODULE_INFO_N(gmp), NO_VERSION_YET, STANDARD_MODULE_PROPERTIES};/* }}} */ZEND_DECLARE_MODULE_GLOBALS(gmp)#ifdef COMPILE_DL_GMPZEND_GET_MODULE(gmp)#endifstatic void _php_gmpnum_free(zend_rsrc_list_entry *rsrc TSRMLS_DC);#define GMP_RESOURCE_NAME "GMP integer"#define GMP_ROUND_ZERO 0#define GMP_ROUND_PLUSINF 1#define GMP_ROUND_MINUSINF 2/* {{{ gmp_emalloc */static void *gmp_emalloc(size_t size){ return emalloc(size);}/* }}} *//* {{{ gmp_erealloc */static void *gmp_erealloc(void *ptr, size_t old_size, size_t new_size){ return erealloc(ptr, new_size);}/* }}} *//* {{{ gmp_efree */static void gmp_efree(void *ptr, size_t size){ efree(ptr);}/* }}} *//* {{{ php_gmp_init_globals */static void php_gmp_init_globals(zend_gmp_globals *gmp_globals){ gmp_globals->rand_initialized = 0;}/* }}} *//* {{{ ZEND_MINIT_FUNCTION */ZEND_MODULE_STARTUP_D(gmp){ ZEND_INIT_MODULE_GLOBALS(gmp, php_gmp_init_globals, NULL); le_gmp = zend_register_list_destructors_ex(_php_gmpnum_free, NULL, GMP_RESOURCE_NAME, module_number); 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); mp_set_memory_functions(gmp_emalloc, gmp_erealloc, gmp_efree); return SUCCESS;}/* }}} *//* {{{ ZEND_RSHUTDOWN_FUNCTION */ZEND_MODULE_DEACTIVATE_D(gmp){ if (GMPG(rand_initialized)) { gmp_randclear(GMPG(rand_state)); GMPG(rand_initialized) = 0; } return SUCCESS;}/* }}} *//* {{{ ZEND_MSHUTDOWN_FUNCTION */ZEND_MODULE_SHUTDOWN_D(gmp){ return SUCCESS;}/* }}} *//* {{{ ZEND_MINFO_FUNCTION */ZEND_MODULE_INFO_D(gmp){ php_info_print_table_start(); php_info_print_table_row(2, "gmp support", "enabled"); php_info_print_table_end(); /* Remove comments if you have entries in php.ini DISPLAY_INI_ENTRIES(); */}/* }}} *//* Fetch zval to be GMP number. Initially, zval can be also number or string */#define FETCH_GMP_ZVAL(gmpnumber, zval) \if(Z_TYPE_PP(zval) == IS_RESOURCE) { \ ZEND_FETCH_RESOURCE(gmpnumber, mpz_t *, zval, -1, GMP_RESOURCE_NAME, le_gmp);\} else {\ if(convert_to_gmp(&gmpnumber, zval, 0 TSRMLS_CC) == FAILURE) {\ RETURN_FALSE;\ }\ ZEND_REGISTER_RESOURCE(NULL, gmpnumber, le_gmp);\}/* 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) { 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; } } } 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); return FAILURE; } return SUCCESS;}/* }}} *//* {{{ typedefs */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);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 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 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)/* {{{ gmp_zval_binary_ui_op_ex 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 TSRMLS_DC) { mpz_t *gmpnum_a, *gmpnum_b, *gmpnum_result; unsigned long long_result=0; int use_ui=0; FETCH_GMP_ZVAL(gmpnum_a, a_arg); if(gmp_ui_op && Z_TYPE_PP(b_arg) == IS_LONG && Z_LVAL_PP(b_arg) >= 0) { use_ui=1; } else { FETCH_GMP_ZVAL(gmpnum_b, b_arg); } if(check_b_zero) { int b_is_zero = 0; 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) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "Zero operand not allowed"); RETURN_FALSE; } } 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)); } else { gmp_ui_op(*gmpnum_result, *gmpnum_a, (unsigned long)Z_LVAL_PP(b_arg)); } } else { gmp_op(*gmpnum_result, *gmpnum_a, *gmpnum_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); }}/* }}} *//* {{{ gmp_zval_binary_ui_op2_ex 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){ mpz_t *gmpnum_a, *gmpnum_b, *gmpnum_result1, *gmpnum_result2; zval r; int use_ui=0; unsigned long long_result = 0; FETCH_GMP_ZVAL(gmpnum_a, a_arg); if(gmp_ui_op && Z_TYPE_PP(b_arg) == IS_LONG && Z_LVAL_PP(b_arg) >= 0) { /* use _ui function */ use_ui=1; } else { FETCH_GMP_ZVAL(gmpnum_b, b_arg); } if(check_b_zero) { int b_is_zero = 0; 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) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "Zero operand not allowed"); RETURN_FALSE; } } 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)); } } else { gmp_op(*gmpnum_result1, *gmpnum_result2, *gmpnum_a, *gmpnum_b); } array_init(return_value); ZEND_REGISTER_RESOURCE(&r, gmpnum_result1, le_gmp); add_index_resource(return_value, 0, Z_LVAL(r)); 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)); }}/* }}} *//* {{{ _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) { zval **a_arg, **b_arg; if (ZEND_NUM_ARGS() != 2 || zend_get_parameters_ex(2, &a_arg, &b_arg) == FAILURE){ WRONG_PARAM_COUNT; } gmp_zval_binary_ui_op(return_value, a_arg, b_arg, gmp_op, gmp_ui_op);}/* }}} *//* Unary operations *//* {{{ 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) { mpz_t *gmpnum_a, *gmpnum_result; FETCH_GMP_ZVAL(gmpnum_a, a_arg); INIT_GMP_NUM(gmpnum_result); gmp_op(*gmpnum_result, *gmpnum_a); ZEND_REGISTER_RESOURCE(return_value, gmpnum_result, le_gmp);}/* }}} *//* {{{ 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) { mpz_t *gmpnum_result; convert_to_long_ex(a_arg); INIT_GMP_NUM(gmpnum_result); gmp_op(*gmpnum_result, Z_LVAL_PP(a_arg)); ZEND_REGISTER_RESOURCE(return_value, gmpnum_result, le_gmp);}/* }}} *//* {{{ _gmp_unary_ui_op Execute GMP unary operation.*/static inline void _gmp_unary_ui_op(INTERNAL_FUNCTION_PARAMETERS, gmp_unary_ui_op_t gmp_op) { zval **a_arg; if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &a_arg) == FAILURE){ WRONG_PARAM_COUNT; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -