php-internal-docs 8.4.8
Unofficial docs for php/php-src
Loading...
Searching...
No Matches
gmp.c
Go to the documentation of this file.
1/*
2 +----------------------------------------------------------------------+
3 | Copyright (c) The PHP Group |
4 +----------------------------------------------------------------------+
5 | This source file is subject to version 3.01 of the PHP license, |
6 | that is bundled with this package in the file LICENSE, and is |
7 | available through the world-wide-web at the following url: |
8 | https://www.php.net/license/3_01.txt |
9 | If you did not receive a copy of the PHP license and are unable to |
10 | obtain it through the world-wide-web, please send a note to |
11 | license@php.net so we can mail you a copy immediately. |
12 +----------------------------------------------------------------------+
13 | Author: Stanislav Malyshev <stas@php.net> |
14 +----------------------------------------------------------------------+
15 */
16
17#ifdef HAVE_CONFIG_H
18#include <config.h>
19#endif
20
21#include "php.h"
22#include "php_gmp.h"
23#include "php_gmp_int.h"
24#include "ext/standard/info.h"
27#include "zend_exceptions.h"
28
29#include <gmp.h>
30
31/* Needed for gmp_random() */
34
35#ifndef mpz_fits_si_p
36# define mpz_fits_si_p mpz_fits_slong_p
37#endif
38
39#define GMP_ROUND_ZERO 0
40#define GMP_ROUND_PLUSINF 1
41#define GMP_ROUND_MINUSINF 2
42
43#ifdef mpir_version
44#define GMP_MPIR_VERSION_STRING ((char *) mpir_version)
45#endif
46#define GMP_VERSION_STRING ((char *) gmp_version)
47
48#define GMP_MSW_FIRST (1 << 0)
49#define GMP_LSW_FIRST (1 << 1)
50#define GMP_LITTLE_ENDIAN (1 << 2)
51#define GMP_BIG_ENDIAN (1 << 3)
52#define GMP_NATIVE_ENDIAN (1 << 4)
53
54#include "gmp_arginfo.h"
55
57static ZEND_GINIT_FUNCTION(gmp);
58
59/* {{{ gmp_module_entry */
76/* }}} */
77
78#ifdef COMPILE_DL_GMP
79#ifdef ZTS
81#endif
83#endif
84
85static zend_class_entry *gmp_ce;
86static zend_object_handlers gmp_object_handlers;
87
89 return gmp_ce;
90}
91
92typedef struct _gmp_temp {
93 mpz_t num;
94 bool is_used;
96
97#define GMP_MAX_BASE 62
98
99#define GMP_51_OR_NEWER \
100 ((__GNU_MP_VERSION >= 6) || (__GNU_MP_VERSION >= 5 && __GNU_MP_VERSION_MINOR >= 1))
101
102#define IS_GMP(zval) \
103 (Z_TYPE_P(zval) == IS_OBJECT && instanceof_function(Z_OBJCE_P(zval), gmp_ce))
104
105#define GET_GMP_OBJECT_FROM_OBJ(obj) \
106 php_gmp_object_from_zend_object(obj)
107#define GET_GMP_OBJECT_FROM_ZVAL(zv) \
108 GET_GMP_OBJECT_FROM_OBJ(Z_OBJ_P(zv))
109
110#define GET_GMP_FROM_ZVAL(zval) \
111 GET_GMP_OBJECT_FROM_OBJ(Z_OBJ_P(zval))->num
112
113/* The FETCH_GMP_ZVAL_* family of macros is used to fetch a gmp number
114 * (mpz_ptr) from a zval. If the zval is not a GMP instance, then we
115 * try to convert the value to a temporary gmp number using convert_to_gmp.
116 * This temporary number is stored in the temp argument, which is of type
117 * gmp_temp_t. This temporary value needs to be freed lateron using the
118 * FREE_GMP_TEMP macro.
119 *
120 * If the conversion to a gmp number fails, the macros RETURN_THROWS() due to TypeError.
121 * The _DEP / _DEP_DEP variants additionally free the temporary values
122 * passed in the last / last two arguments.
123 *
124 * If one zval can sometimes be fetched as a long you have to set the
125 * is_used member of the corresponding gmp_temp_t value to 0, otherwise
126 * the FREE_GMP_TEMP and *_DEP macros will not work properly.
127 *
128 * The three FETCH_GMP_ZVAL_* macros below are mostly copy & paste code
129 * as I couldn't find a way to combine them.
130 */
131
132#define FREE_GMP_TEMP(temp) \
133 if (temp.is_used) { \
134 mpz_clear(temp.num); \
135 }
136
137#define FETCH_GMP_ZVAL_DEP_DEP(gmpnumber, zval, temp, dep1, dep2, arg_pos) \
138if (IS_GMP(zval)) { \
139 gmpnumber = GET_GMP_FROM_ZVAL(zval); \
140 temp.is_used = 0; \
141} else { \
142 mpz_init(temp.num); \
143 if (convert_to_gmp(temp.num, zval, 0, arg_pos) == FAILURE) { \
144 mpz_clear(temp.num); \
145 FREE_GMP_TEMP(dep1); \
146 FREE_GMP_TEMP(dep2); \
147 RETURN_THROWS(); \
148 } \
149 temp.is_used = 1; \
150 gmpnumber = temp.num; \
151}
152
153#define FETCH_GMP_ZVAL_DEP(gmpnumber, zval, temp, dep, arg_pos) \
154if (IS_GMP(zval)) { \
155 gmpnumber = GET_GMP_FROM_ZVAL(zval); \
156 temp.is_used = 0; \
157} else { \
158 mpz_init(temp.num); \
159 if (convert_to_gmp(temp.num, zval, 0, arg_pos) == FAILURE) { \
160 mpz_clear(temp.num); \
161 FREE_GMP_TEMP(dep); \
162 RETURN_THROWS(); \
163 } \
164 temp.is_used = 1; \
165 gmpnumber = temp.num; \
166}
167
168#define FETCH_GMP_ZVAL(gmpnumber, zval, temp, arg_pos) \
169if (IS_GMP(zval)) { \
170 gmpnumber = GET_GMP_FROM_ZVAL(zval); \
171 temp.is_used = 0; \
172} else { \
173 mpz_init(temp.num); \
174 if (convert_to_gmp(temp.num, zval, 0, arg_pos) == FAILURE) { \
175 mpz_clear(temp.num); \
176 RETURN_THROWS(); \
177 } \
178 temp.is_used = 1; \
179 gmpnumber = temp.num; \
180}
181
182#define INIT_GMP_RETVAL(gmpnumber) \
183 gmp_create(return_value, &gmpnumber)
184
185static void gmp_strval(zval *result, mpz_t gmpnum, int base);
186static zend_result convert_zstr_to_gmp(mpz_t gmp_number, const zend_string *val, zend_long base, uint32_t arg_pos);
187static zend_result convert_to_gmp(mpz_t gmpnumber, zval *val, zend_long base, uint32_t arg_pos);
188static void gmp_cmp(zval *return_value, zval *a_arg, zval *b_arg, bool is_operator);
189
190/*
191 * The gmp_*_op functions provide an implementation for several common types
192 * of GMP functions. The gmp_zval_(unary|binary)_*_op functions have to be manually
193 * passed zvals to work on, whereas the gmp_(unary|binary)_*_op macros already
194 * include parameter parsing.
195 */
196typedef void (*gmp_unary_op_t)(mpz_ptr, mpz_srcptr);
197typedef mp_bitcnt_t (*gmp_unary_opl_t)(mpz_srcptr);
198
199typedef void (*gmp_unary_ui_op_t)(mpz_ptr, gmp_ulong);
200
201typedef void (*gmp_binary_op_t)(mpz_ptr, mpz_srcptr, mpz_srcptr);
202
203typedef void (*gmp_binary_ui_op_t)(mpz_ptr, mpz_srcptr, gmp_ulong);
204typedef void (*gmp_binary_op2_t)(mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr);
205typedef gmp_ulong (*gmp_binary_ui_op2_t)(mpz_ptr, mpz_ptr, mpz_srcptr, gmp_ulong);
206
207static 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, bool check_b_zero, bool is_operator);
208static 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);
209static inline void gmp_zval_unary_op(zval *return_value, zval *a_arg, gmp_unary_op_t gmp_op);
210
211static void gmp_mpz_tdiv_q_ui(mpz_ptr a, mpz_srcptr b, gmp_ulong c) {
212 mpz_tdiv_q_ui(a, b, c);
213}
214static void gmp_mpz_tdiv_r_ui(mpz_ptr a, mpz_srcptr b, gmp_ulong c) {
215 mpz_tdiv_r_ui(a, b, c);
216}
217static void gmp_mpz_fdiv_q_ui(mpz_ptr a, mpz_srcptr b, gmp_ulong c) {
218 mpz_fdiv_q_ui(a, b, c);
219}
220static void gmp_mpz_fdiv_r_ui(mpz_ptr a, mpz_srcptr b, gmp_ulong c) {
221 mpz_fdiv_r_ui(a, b, c);
222}
223static void gmp_mpz_cdiv_r_ui(mpz_ptr a, mpz_srcptr b, gmp_ulong c) {
224 mpz_cdiv_r_ui(a, b, c);
225}
226static void gmp_mpz_cdiv_q_ui(mpz_ptr a, mpz_srcptr b, gmp_ulong c) {
227 mpz_cdiv_q_ui(a, b, c);
228}
229static void gmp_mpz_mod_ui(mpz_ptr a, mpz_srcptr b, gmp_ulong c) {
230 mpz_mod_ui(a, b, c);
231}
232static void gmp_mpz_gcd_ui(mpz_ptr a, mpz_srcptr b, gmp_ulong c) {
233 mpz_gcd_ui(a, b, c);
234}
235
236/* Binary operations */
237#define gmp_binary_ui_op(op, uop) _gmp_binary_ui_op(INTERNAL_FUNCTION_PARAM_PASSTHRU, op, uop, 0)
238#define gmp_binary_op(op) _gmp_binary_ui_op(INTERNAL_FUNCTION_PARAM_PASSTHRU, op, NULL, 0)
239#define gmp_binary_ui_op_no_zero(op, uop) \
240 _gmp_binary_ui_op(INTERNAL_FUNCTION_PARAM_PASSTHRU, op, uop, 1)
241
242/* Unary operations */
243#define gmp_unary_op(op) _gmp_unary_op(INTERNAL_FUNCTION_PARAM_PASSTHRU, op)
244#define gmp_unary_opl(op) _gmp_unary_opl(INTERNAL_FUNCTION_PARAM_PASSTHRU, op)
245
246static void gmp_free_object_storage(zend_object *obj) /* {{{ */
247{
248 gmp_object *intern = GET_GMP_OBJECT_FROM_OBJ(obj);
249
250 mpz_clear(intern->num);
251 zend_object_std_dtor(&intern->std);
252}
253/* }}} */
254
255static inline zend_object *gmp_create_object_ex(zend_class_entry *ce, mpz_ptr *gmpnum_target) /* {{{ */
256{
257 gmp_object *intern = emalloc(sizeof(gmp_object) + zend_object_properties_size(ce));
258
259 zend_object_std_init(&intern->std, ce);
260 object_properties_init(&intern->std, ce);
261
262 mpz_init(intern->num);
263 *gmpnum_target = intern->num;
264
265 return &intern->std;
266}
267/* }}} */
268
269static zend_object *gmp_create_object(zend_class_entry *ce) /* {{{ */
270{
271 mpz_ptr gmpnum_dummy;
272 return gmp_create_object_ex(ce, &gmpnum_dummy);
273}
274/* }}} */
275
276static inline void gmp_create(zval *target, mpz_ptr *gmpnum_target) /* {{{ */
277{
278 ZVAL_OBJ(target, gmp_create_object_ex(gmp_ce, gmpnum_target));
279}
280/* }}} */
281
282static zend_result gmp_cast_object(zend_object *readobj, zval *writeobj, int type) /* {{{ */
283{
284 mpz_ptr gmpnum;
285 switch (type) {
286 case IS_STRING:
287 gmpnum = GET_GMP_OBJECT_FROM_OBJ(readobj)->num;
288 gmp_strval(writeobj, gmpnum, 10);
289 return SUCCESS;
290 case IS_LONG:
291 gmpnum = GET_GMP_OBJECT_FROM_OBJ(readobj)->num;
292 ZVAL_LONG(writeobj, mpz_get_si(gmpnum));
293 return SUCCESS;
294 case IS_DOUBLE:
295 gmpnum = GET_GMP_OBJECT_FROM_OBJ(readobj)->num;
296 ZVAL_DOUBLE(writeobj, mpz_get_d(gmpnum));
297 return SUCCESS;
298 case _IS_NUMBER:
299 gmpnum = GET_GMP_OBJECT_FROM_OBJ(readobj)->num;
300 if (mpz_fits_si_p(gmpnum)) {
301 ZVAL_LONG(writeobj, mpz_get_si(gmpnum));
302 } else {
303 ZVAL_DOUBLE(writeobj, mpz_get_d(gmpnum));
304 }
305 return SUCCESS;
306 case _IS_BOOL:
307 gmpnum = GET_GMP_OBJECT_FROM_OBJ(readobj)->num;
308 ZVAL_BOOL(writeobj, mpz_sgn(gmpnum) != 0);
309 return SUCCESS;
310 default:
311 return FAILURE;
312 }
313}
314/* }}} */
315
316static HashTable *gmp_get_debug_info(zend_object *obj, int *is_temp) /* {{{ */
317{
318 HashTable *ht, *props = zend_std_get_properties(obj);
319 mpz_ptr gmpnum = GET_GMP_OBJECT_FROM_OBJ(obj)->num;
320 zval zv;
321
322 *is_temp = 1;
323 ht = zend_array_dup(props);
324
325 gmp_strval(&zv, gmpnum, 10);
326 zend_hash_str_update(ht, "num", sizeof("num")-1, &zv);
327
328 return ht;
329}
330/* }}} */
331
332static zend_object *gmp_clone_obj(zend_object *obj) /* {{{ */
333{
334 gmp_object *old_object = GET_GMP_OBJECT_FROM_OBJ(obj);
335 gmp_object *new_object = GET_GMP_OBJECT_FROM_OBJ(gmp_create_object(obj->ce));
336
337 zend_objects_clone_members( &new_object->std, &old_object->std);
338
339 mpz_set(new_object->num, old_object->num);
340
341 return &new_object->std;
342}
343/* }}} */
344
345static zend_result shift_operator_helper(gmp_binary_ui_op_t op, zval *return_value, zval *op1, zval *op2, uint8_t opcode) {
346 zend_long shift = 0;
347
348 if (UNEXPECTED(Z_TYPE_P(op2) != IS_LONG)) {
349 if (UNEXPECTED(!IS_GMP(op2))) {
350 // For PHP 8.3 and up use zend_try_get_long()
351 switch (Z_TYPE_P(op2)) {
352 case IS_DOUBLE:
353 shift = zval_get_long(op2);
354 if (UNEXPECTED(EG(exception))) {
355 return FAILURE;
356 }
357 break;
358 case IS_STRING:
359 if (is_numeric_str_function(Z_STR_P(op2), &shift, NULL) != IS_LONG) {
360 goto valueof_op_failure;
361 }
362 break;
363 default:
364 goto typeof_op_failure;
365 }
366 } else {
367 // TODO We shouldn't cast the GMP object to int here
368 shift = zval_get_long(op2);
369 }
370 } else {
371 shift = Z_LVAL_P(op2);
372 }
373
374 if (shift < 0) {
376 zend_ce_value_error, "%s must be greater than or equal to 0",
377 opcode == ZEND_POW ? "Exponent" : "Shift"
378 );
380 return FAILURE;
381 } else {
382 mpz_ptr gmpnum_op, gmpnum_result;
383 gmp_temp_t temp;
384
385 /* We do not use FETCH_GMP_ZVAL(...); here as we don't use convert_to_gmp()
386 * as we want to handle the emitted exception ourself. */
387 if (UNEXPECTED(!IS_GMP(op1))) {
388 if (UNEXPECTED(Z_TYPE_P(op1) != IS_LONG)) {
389 goto typeof_op_failure;
390 }
391 mpz_init(temp.num);
392 mpz_set_si(temp.num, Z_LVAL_P(op1));
393 temp.is_used = 1;
394 gmpnum_op = temp.num;
395 } else {
396 gmpnum_op = GET_GMP_FROM_ZVAL(op1);
397 temp.is_used = 0;
398 }
399 INIT_GMP_RETVAL(gmpnum_result);
400 op(gmpnum_result, gmpnum_op, (gmp_ulong) shift);
401 FREE_GMP_TEMP(temp);
402 return SUCCESS;
403 }
404
405typeof_op_failure: ;
406 /* Returning FAILURE without throwing an exception would emit the
407 * Unsupported operand types: GMP OP TypeOfOp2
408 * However, this leads to the engine trying to interpret the GMP object as an integer
409 * and doing the operation that way, which is not something we want. */
410 const char *op_sigil;
411 switch (opcode) {
412 case ZEND_POW:
413 op_sigil = "**";
414 break;
415 case ZEND_SL:
416 op_sigil = "<<";
417 break;
418 case ZEND_SR:
419 op_sigil = ">>";
420 break;
422 }
423 zend_type_error("Unsupported operand types: %s %s %s", zend_zval_type_name(op1), op_sigil, zend_zval_type_name(op2));
424 return FAILURE;
425valueof_op_failure:
426 zend_value_error("Number is not an integer string");
427 return FAILURE;
428}
429
430#define DO_BINARY_UI_OP_EX(op, uop, check_b_zero) \
431 gmp_zval_binary_ui_op( \
432 result, op1, op2, op, uop, check_b_zero, /* is_operator */ true); \
433 if (UNEXPECTED(EG(exception))) { return FAILURE; } \
434 return SUCCESS;
435
436#define DO_BINARY_UI_OP(op) DO_BINARY_UI_OP_EX(op, op ## _ui, 0)
437#define DO_BINARY_OP(op) DO_BINARY_UI_OP_EX(op, NULL, 0)
438
439#define DO_UNARY_OP(op) \
440 gmp_zval_unary_op(result, op1, op); \
441 if (UNEXPECTED(EG(exception))) { \
442 return FAILURE; \
443 } \
444 return SUCCESS;
445
446static zend_result gmp_do_operation_ex(uint8_t opcode, zval *result, zval *op1, zval *op2) /* {{{ */
447{
448 switch (opcode) {
449 case ZEND_ADD:
450 DO_BINARY_UI_OP(mpz_add);
451 case ZEND_SUB:
452 DO_BINARY_UI_OP(mpz_sub);
453 case ZEND_MUL:
454 DO_BINARY_UI_OP(mpz_mul);
455 case ZEND_POW:
456 return shift_operator_helper(mpz_pow_ui, result, op1, op2, opcode);
457 case ZEND_DIV:
458 DO_BINARY_UI_OP_EX(mpz_tdiv_q, gmp_mpz_tdiv_q_ui, 1);
459 case ZEND_MOD:
460 DO_BINARY_UI_OP_EX(mpz_mod, gmp_mpz_mod_ui, 1);
461 case ZEND_SL:
462 return shift_operator_helper(mpz_mul_2exp, result, op1, op2, opcode);
463 case ZEND_SR:
464 return shift_operator_helper(mpz_fdiv_q_2exp, result, op1, op2, opcode);
465 case ZEND_BW_OR:
466 DO_BINARY_OP(mpz_ior);
467 case ZEND_BW_AND:
468 DO_BINARY_OP(mpz_and);
469 case ZEND_BW_XOR:
470 DO_BINARY_OP(mpz_xor);
471 case ZEND_BW_NOT:
472 DO_UNARY_OP(mpz_com);
473
474 default:
475 return FAILURE;
476 }
477}
478/* }}} */
479
480static zend_result gmp_do_operation(uint8_t opcode, zval *result, zval *op1, zval *op2) /* {{{ */
481{
482 zval op1_copy;
483
484 if (result == op1) {
485 ZVAL_COPY_VALUE(&op1_copy, op1);
486 op1 = &op1_copy;
487 }
488
489 zend_result retval = gmp_do_operation_ex(opcode, result, op1, op2);
490
491 if (retval == SUCCESS && op1 == &op1_copy) {
493 }
494
495 return retval;
496}
497/* }}} */
498
499static int gmp_compare(zval *op1, zval *op2) /* {{{ */
500{
501 zval result;
502
503 gmp_cmp(&result, op1, op2, /* is_operator */ true);
504
505 /* An error/exception occurs if one of the operands is not a numeric string
506 * or an object which is different from GMP */
507 if (EG(exception)) {
508 return 1;
509 }
510 /* result can only be a zend_long if gmp_cmp hasn't thrown an Error */
512 return Z_LVAL(result);
513}
514/* }}} */
515
516static int gmp_serialize(zval *object, unsigned char **buffer, size_t *buf_len, zend_serialize_data *data) /* {{{ */
517{
518 mpz_ptr gmpnum = GET_GMP_FROM_ZVAL(object);
519 smart_str buf = {0};
520 zval zv;
521 php_serialize_data_t serialize_data;
522
523 PHP_VAR_SERIALIZE_INIT(serialize_data);
524
525 gmp_strval(&zv, gmpnum, 10);
526 php_var_serialize(&buf, &zv, &serialize_data);
527 zval_ptr_dtor_str(&zv);
528
530 php_var_serialize(&buf, &zv, &serialize_data);
531
532 PHP_VAR_SERIALIZE_DESTROY(serialize_data);
533 *buffer = (unsigned char *) estrndup(ZSTR_VAL(buf.s), ZSTR_LEN(buf.s));
534 *buf_len = ZSTR_LEN(buf.s);
536
537 return SUCCESS;
538}
539/* }}} */
540
541static int gmp_unserialize(zval *object, zend_class_entry *ce, const unsigned char *buf, size_t buf_len, zend_unserialize_data *data) /* {{{ */
542{
543 mpz_ptr gmpnum;
544 const unsigned char *p, *max;
545 zval *zv;
546 int retval = FAILURE;
547 php_unserialize_data_t unserialize_data;
549
550 PHP_VAR_UNSERIALIZE_INIT(unserialize_data);
551 gmp_create(object, &gmpnum);
552
553 zobj = Z_OBJ_P(object);
554
555 p = buf;
556 max = buf + buf_len;
557
558 zv = var_tmp_var(&unserialize_data);
559 if (!php_var_unserialize(zv, &p, max, &unserialize_data)
560 || Z_TYPE_P(zv) != IS_STRING
561 || convert_zstr_to_gmp(gmpnum, Z_STR_P(zv), 10, 0) == FAILURE
562 ) {
563 zend_throw_exception(NULL, "Could not unserialize number", 0);
564 goto exit;
565 }
566
567 zv = var_tmp_var(&unserialize_data);
568 if (!php_var_unserialize(zv, &p, max, &unserialize_data)
569 || Z_TYPE_P(zv) != IS_ARRAY
570 ) {
571 zend_throw_exception(NULL, "Could not unserialize properties", 0);
572 goto exit;
573 }
574
575 if (zend_hash_num_elements(Z_ARRVAL_P(zv)) != 0) {
579 );
580 }
581
582 retval = SUCCESS;
583exit:
584 PHP_VAR_UNSERIALIZE_DESTROY(unserialize_data);
585 return retval;
586}
587/* }}} */
588
589/* {{{ ZEND_GINIT_FUNCTION */
590static ZEND_GINIT_FUNCTION(gmp)
591{
592#if defined(COMPILE_DL_GMP) && defined(ZTS)
594#endif
595 gmp_globals->rand_initialized = 0;
596}
597/* }}} */
598
599/* {{{ ZEND_MINIT_FUNCTION */
601{
602 gmp_ce = register_class_GMP();
603 gmp_ce->create_object = gmp_create_object;
604 gmp_ce->default_object_handlers = &gmp_object_handlers;
605 gmp_ce->serialize = gmp_serialize;
606 gmp_ce->unserialize = gmp_unserialize;
607
608 memcpy(&gmp_object_handlers, &std_object_handlers, sizeof(zend_object_handlers));
609 gmp_object_handlers.offset = XtOffsetOf(gmp_object, std);
610 gmp_object_handlers.free_obj = gmp_free_object_storage;
611 gmp_object_handlers.cast_object = gmp_cast_object;
612 gmp_object_handlers.get_debug_info = gmp_get_debug_info;
613 gmp_object_handlers.clone_obj = gmp_clone_obj;
614 gmp_object_handlers.do_operation = gmp_do_operation;
615 gmp_object_handlers.compare = gmp_compare;
616
617 register_gmp_symbols(module_number);
618
619 return SUCCESS;
620}
621/* }}} */
622
623/* {{{ ZEND_RSHUTDOWN_FUNCTION */
625{
626 if (GMPG(rand_initialized)) {
627 gmp_randclear(GMPG(rand_state));
629 }
630
631 return SUCCESS;
632}
633/* }}} */
634
635/* {{{ ZEND_MINFO_FUNCTION */
637{
639 php_info_print_table_row(2, "gmp support", "enabled");
640#ifdef mpir_version
641 php_info_print_table_row(2, "MPIR version", mpir_version);
642#else
643 php_info_print_table_row(2, "GMP version", gmp_version);
644#endif
646}
647/* }}} */
648
649static zend_result convert_zstr_to_gmp(mpz_t gmp_number, const zend_string *val, zend_long base, uint32_t arg_pos)
650{
651 const char *num_str = ZSTR_VAL(val);
652 bool skip_lead = false;
653
654 size_t num_len = ZSTR_LEN(val);
655 while (isspace(*num_str)) {
656 ++num_str;
657 --num_len;
658 }
659
660 if (num_len >= 2 && num_str[0] == '0') {
661 if ((base == 0 || base == 16) && (num_str[1] == 'x' || num_str[1] == 'X')) {
662 base = 16;
663 skip_lead = true;
664 } else if ((base == 0 || base == 8) && (num_str[1] == 'o' || num_str[1] == 'O')) {
665 base = 8;
666 skip_lead = true;
667 } else if ((base == 0 || base == 2) && (num_str[1] == 'b' || num_str[1] == 'B')) {
668 base = 2;
669 skip_lead = true;
670 }
671 }
672
673 int gmp_ret = mpz_set_str(gmp_number, (skip_lead ? &num_str[2] : num_str), (int) base);
674 if (-1 == gmp_ret) {
675 if (arg_pos == 0) {
676 zend_value_error("Number is not an integer string");
677 } else {
678 zend_argument_value_error(arg_pos, "is not an integer string");
679 }
680 return FAILURE;
681 }
682
683 return SUCCESS;
684}
685
686/* {{{ convert_to_gmp
687 * Convert zval to be gmp number */
688static zend_result convert_to_gmp(mpz_t gmpnumber, zval *val, zend_long base, uint32_t arg_pos)
689{
690 switch (Z_TYPE_P(val)) {
691 case IS_LONG:
692 mpz_set_si(gmpnumber, Z_LVAL_P(val));
693 return SUCCESS;
694 case IS_STRING: {
695 return convert_zstr_to_gmp(gmpnumber, Z_STR_P(val), base, arg_pos);
696 }
697 case IS_NULL:
698 /* Just reject null for operator overloading */
699 if (arg_pos == 0) {
700 zend_type_error("Number must be of type GMP|string|int, %s given", zend_zval_type_name(val));
701 return FAILURE;
702 }
704 default: {
705 zend_long lval;
706 if (!zend_parse_arg_long_slow(val, &lval, arg_pos)) {
707 if (arg_pos == 0) {
709 "Number must be of type GMP|string|int, %s given", zend_zval_value_name(val));
710 } else {
712 "must be of type GMP|string|int, %s given", zend_zval_value_name(val));
713 }
714 return FAILURE;
715 }
716
717 mpz_set_si(gmpnumber, lval);
718 return SUCCESS;
719 }
720 }
721}
722/* }}} */
723
724static void gmp_strval(zval *result, mpz_t gmpnum, int base) /* {{{ */
725{
726 size_t num_len;
727 zend_string *str;
728
729 num_len = mpz_sizeinbase(gmpnum, abs(base));
730 if (mpz_sgn(gmpnum) < 0) {
731 num_len++;
732 }
733
734 str = zend_string_alloc(num_len, 0);
735 mpz_get_str(ZSTR_VAL(str), base, gmpnum);
736
737 /*
738 * From GMP documentation for mpz_sizeinbase():
739 * The returned value will be exact or 1 too big. If base is a power of
740 * 2, the returned value will always be exact.
741 *
742 * So let's check to see if we already have a \0 byte...
743 */
744
745 if (ZSTR_VAL(str)[ZSTR_LEN(str) - 1] == '\0') {
746 ZSTR_LEN(str)--;
747 } else {
748 ZSTR_VAL(str)[ZSTR_LEN(str)] = '\0';
749 }
750
751 ZVAL_NEW_STR(result, str);
752}
753/* }}} */
754
755static void gmp_cmp(zval *return_value, zval *a_arg, zval *b_arg, bool is_operator) /* {{{ */
756{
757 mpz_ptr gmpnum_a, gmpnum_b;
758 gmp_temp_t temp_a, temp_b;
759 bool use_si = 0;
761
762 FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a, is_operator ? 0 : 1);
763
764 if (Z_TYPE_P(b_arg) == IS_LONG) {
765 use_si = 1;
766 temp_b.is_used = 0;
767 } else {
768 FETCH_GMP_ZVAL_DEP(gmpnum_b, b_arg, temp_b, temp_a, is_operator ? 0 : 2);
769 }
770
771 if (use_si) {
772 res = mpz_cmp_si(gmpnum_a, Z_LVAL_P(b_arg));
773 } else {
774 res = mpz_cmp(gmpnum_a, gmpnum_b);
775 }
776
777 FREE_GMP_TEMP(temp_a);
778 FREE_GMP_TEMP(temp_b);
779
781}
782/* }}} */
783
784/* {{{ gmp_zval_binary_ui_op
785 Execute GMP binary operation.
786*/
787static 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, bool check_b_zero, bool is_operator)
788{
789 mpz_ptr gmpnum_a, gmpnum_b, gmpnum_result;
790 gmp_temp_t temp_a, temp_b;
791
792 FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a, is_operator ? 0 : 1);
793
794 if (gmp_ui_op && Z_TYPE_P(b_arg) == IS_LONG && Z_LVAL_P(b_arg) >= 0) {
795 gmpnum_b = NULL;
796 temp_b.is_used = 0;
797 } else {
798 FETCH_GMP_ZVAL_DEP(gmpnum_b, b_arg, temp_b, temp_a, is_operator ? 0 : 2);
799 }
800
801 if (check_b_zero) {
802 int b_is_zero = 0;
803 if (!gmpnum_b) {
804 b_is_zero = (Z_LVAL_P(b_arg) == 0);
805 } else {
806 b_is_zero = !mpz_cmp_ui(gmpnum_b, 0);
807 }
808
809 if (b_is_zero) {
810 if ((gmp_binary_op_t) mpz_mod == gmp_op) {
812 } else {
814 }
815 FREE_GMP_TEMP(temp_a);
816 FREE_GMP_TEMP(temp_b);
818 }
819 }
820
821 INIT_GMP_RETVAL(gmpnum_result);
822
823 if (!gmpnum_b) {
824 gmp_ui_op(gmpnum_result, gmpnum_a, (gmp_ulong) Z_LVAL_P(b_arg));
825 } else {
826 gmp_op(gmpnum_result, gmpnum_a, gmpnum_b);
827 }
828
829 FREE_GMP_TEMP(temp_a);
830 FREE_GMP_TEMP(temp_b);
831}
832/* }}} */
833
834/* {{{ gmp_zval_binary_ui_op2
835 Execute GMP binary operation which returns 2 values.
836*/
837static 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)
838{
839 mpz_ptr gmpnum_a, gmpnum_b, gmpnum_result1, gmpnum_result2;
840 gmp_temp_t temp_a, temp_b;
841 zval result1, result2;
842
843 FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a, 1);
844
845 if (gmp_ui_op && Z_TYPE_P(b_arg) == IS_LONG && Z_LVAL_P(b_arg) >= 0) {
846 gmpnum_b = NULL;
847 temp_b.is_used = 0;
848 } else {
849 FETCH_GMP_ZVAL_DEP(gmpnum_b, b_arg, temp_b, temp_a, 2);
850 }
851
852 if (check_b_zero) {
853 int b_is_zero = 0;
854 if (!gmpnum_b) {
855 b_is_zero = (Z_LVAL_P(b_arg) == 0);
856 } else {
857 b_is_zero = !mpz_cmp_ui(gmpnum_b, 0);
858 }
859
860 if (b_is_zero) {
862 FREE_GMP_TEMP(temp_a);
863 FREE_GMP_TEMP(temp_b);
865 }
866 }
867
868 gmp_create(&result1, &gmpnum_result1);
869 gmp_create(&result2, &gmpnum_result2);
870
872 add_next_index_zval(return_value, &result1);
873 add_next_index_zval(return_value, &result2);
874
875 if (!gmpnum_b) {
876 gmp_ui_op(gmpnum_result1, gmpnum_result2, gmpnum_a, (gmp_ulong) Z_LVAL_P(b_arg));
877 } else {
878 gmp_op(gmpnum_result1, gmpnum_result2, gmpnum_a, gmpnum_b);
879 }
880
881 FREE_GMP_TEMP(temp_a);
882 FREE_GMP_TEMP(temp_b);
883}
884/* }}} */
885
886/* {{{ _gmp_binary_ui_op */
887static 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)
888{
889 zval *a_arg, *b_arg;
890
891 if (zend_parse_parameters(ZEND_NUM_ARGS(), "zz", &a_arg, &b_arg) == FAILURE){
893 }
894
895 gmp_zval_binary_ui_op(
896 return_value, a_arg, b_arg, gmp_op, gmp_ui_op, check_b_zero, /* is_operator */ false);
897}
898/* }}} */
899
900/* Unary operations */
901
902/* {{{ gmp_zval_unary_op */
903static inline void gmp_zval_unary_op(zval *return_value, zval *a_arg, gmp_unary_op_t gmp_op)
904{
905 mpz_ptr gmpnum_a, gmpnum_result;
906 gmp_temp_t temp_a;
907
908 FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a, 1);
909
910 INIT_GMP_RETVAL(gmpnum_result);
911 gmp_op(gmpnum_result, gmpnum_a);
912
913 FREE_GMP_TEMP(temp_a);
914}
915/* }}} */
916
917/* {{{ _gmp_unary_op */
918static inline void _gmp_unary_op(INTERNAL_FUNCTION_PARAMETERS, gmp_unary_op_t gmp_op)
919{
920 zval *a_arg;
921
922 if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &a_arg) == FAILURE){
924 }
925
926 gmp_zval_unary_op(return_value, a_arg, gmp_op);
927}
928/* }}} */
929
930/* {{{ _gmp_unary_opl */
931static inline void _gmp_unary_opl(INTERNAL_FUNCTION_PARAMETERS, gmp_unary_opl_t gmp_op)
932{
933 zval *a_arg;
934 mpz_ptr gmpnum_a;
935 gmp_temp_t temp_a;
936
937 if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &a_arg) == FAILURE){
939 }
940
941 FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a, 1);
942 RETVAL_LONG(gmp_op(gmpnum_a));
943 FREE_GMP_TEMP(temp_a);
944}
945/* }}} */
946
947static bool gmp_verify_base(zend_long base, uint32_t arg_num)
948{
949 if (base && (base < 2 || base > GMP_MAX_BASE)) {
950 zend_argument_value_error(arg_num, "must be 0 or between 2 and %d", GMP_MAX_BASE);
951 return false;
952 }
953
954 return true;
955}
956
957static zend_result gmp_initialize_number(mpz_ptr gmp_number, const zend_string *arg_str, zend_long arg_l, zend_long base)
958{
959 if (arg_str) {
960 return convert_zstr_to_gmp(gmp_number, arg_str, base, 1);
961 }
962
963 mpz_set_si(gmp_number, arg_l);
964 return SUCCESS;
965}
966
967/* {{{ Initializes GMP number */
969{
970 mpz_ptr gmp_number;
971 zend_string *arg_str = NULL;
972 zend_long arg_l = 0;
973 zend_long base = 0;
974
976 Z_PARAM_STR_OR_LONG(arg_str, arg_l)
978 Z_PARAM_LONG(base)
980
981 if (!gmp_verify_base(base, 2)) {
983 }
984
985 INIT_GMP_RETVAL(gmp_number);
986
987 if (gmp_initialize_number(gmp_number, arg_str, arg_l, base) == FAILURE) {
989 }
990}
991/* }}} */
992
993static bool gmp_import_export_validate(zend_long size, zend_long options, int *order, int *endian)
994{
995 if (size < 1) {
996 /* size argument is in second position */
997 zend_argument_value_error(2, "must be greater than or equal to 1");
998 return false;
999 }
1000
1001 switch (options & (GMP_LSW_FIRST | GMP_MSW_FIRST)) {
1002 case GMP_LSW_FIRST:
1003 *order = -1;
1004 break;
1005 case GMP_MSW_FIRST:
1006 case 0: /* default */
1007 *order = 1;
1008 break;
1009 default:
1010 /* options argument is in third position */
1011 zend_argument_value_error(3, "cannot use multiple word order options");
1012 return false;
1013 }
1014
1016 case GMP_LITTLE_ENDIAN:
1017 *endian = -1;
1018 break;
1019 case GMP_BIG_ENDIAN:
1020 *endian = 1;
1021 break;
1022 case GMP_NATIVE_ENDIAN:
1023 case 0: /* default */
1024 *endian = 0;
1025 break;
1026 default:
1027 /* options argument is in third position */
1028 zend_argument_value_error(3, "cannot use multiple endian options");
1029 return false;
1030 }
1031
1032 return true;
1033}
1034
1035/* {{{ Imports a GMP number from a binary string */
1037{
1038 char *data;
1039 size_t data_len;
1040 zend_long size = 1;
1042 int order, endian;
1043 mpz_ptr gmpnumber;
1044
1045 if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|ll", &data, &data_len, &size, &options) == FAILURE) {
1046 RETURN_THROWS();
1047 }
1048
1049 if (!gmp_import_export_validate(size, options, &order, &endian)) {
1050 RETURN_THROWS();
1051 }
1052
1053 if ((data_len % size) != 0) {
1054 zend_argument_value_error(1, "must be a multiple of argument #2 ($word_size)");
1055 RETURN_THROWS();
1056 }
1057
1058 INIT_GMP_RETVAL(gmpnumber);
1059
1060 mpz_import(gmpnumber, data_len / size, order, size, endian, 0, data);
1061}
1062/* }}} */
1063
1064/* {{{ Exports a GMP number to a binary string */
1066{
1067 zval *gmpnumber_arg;
1068 zend_long size = 1;
1070 int order, endian;
1071 mpz_ptr gmpnumber;
1072 gmp_temp_t temp_a;
1073
1074 if (zend_parse_parameters(ZEND_NUM_ARGS(), "z|ll", &gmpnumber_arg, &size, &options) == FAILURE) {
1075 RETURN_THROWS();
1076 }
1077
1078 if (!gmp_import_export_validate(size, options, &order, &endian)) {
1079 RETURN_THROWS();
1080 }
1081
1082 FETCH_GMP_ZVAL(gmpnumber, gmpnumber_arg, temp_a, 1);
1083
1084 if (mpz_sgn(gmpnumber) == 0) {
1086 } else {
1087 ZEND_ASSERT(size > 0);
1088 size_t size_in_base_2 = mpz_sizeinbase(gmpnumber, 2);
1089 if (size > ZEND_LONG_MAX / 4 || size_in_base_2 > SIZE_MAX - (size_t) size * 8 + 1) {
1090 zend_argument_value_error(2, "is too large for argument #1 ($num)");
1091 RETURN_THROWS();
1092 }
1093 size_t bits_per_word = (size_t) size * 8;
1094 size_t count = (size_in_base_2 + bits_per_word - 1) / bits_per_word;
1095
1096 zend_string *out_string = zend_string_safe_alloc(count, size, 0, 0);
1097 mpz_export(ZSTR_VAL(out_string), NULL, order, size, endian, 0, gmpnumber);
1098 ZSTR_VAL(out_string)[ZSTR_LEN(out_string)] = '\0';
1099
1100 RETVAL_NEW_STR(out_string);
1101 }
1102
1103 FREE_GMP_TEMP(temp_a);
1104}
1105/* }}} */
1106
1107/* {{{ Gets signed long value of GMP number */
1109{
1110 zval *gmpnumber_arg;
1111 mpz_ptr gmpnum;
1112 gmp_temp_t temp_a;
1113
1114 if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &gmpnumber_arg) == FAILURE){
1115 RETURN_THROWS();
1116 }
1117
1118 FETCH_GMP_ZVAL(gmpnum, gmpnumber_arg, temp_a, 1);
1119 RETVAL_LONG(mpz_get_si(gmpnum));
1120 FREE_GMP_TEMP(temp_a);
1121}
1122/* }}} */
1123
1124/* {{{ Gets string representation of GMP number */
1125ZEND_FUNCTION(gmp_strval)
1126{
1127 zval *gmpnumber_arg;
1128 zend_long base = 10;
1129 mpz_ptr gmpnum;
1130 gmp_temp_t temp_a;
1131
1132 if (zend_parse_parameters(ZEND_NUM_ARGS(), "z|l", &gmpnumber_arg, &base) == FAILURE) {
1133 RETURN_THROWS();
1134 }
1135
1136 /* Although the maximum base in general in GMP is 62, mpz_get_str()
1137 * is explicitly limited to -36 when dealing with negative bases. */
1138 if ((base < 2 && base > -2) || base > GMP_MAX_BASE || base < -36) {
1139 zend_argument_value_error(2, "must be between 2 and %d, or -2 and -36", GMP_MAX_BASE);
1140 RETURN_THROWS();
1141 }
1142
1143 FETCH_GMP_ZVAL(gmpnum, gmpnumber_arg, temp_a, 1);
1144
1145 gmp_strval(return_value, gmpnum, (int)base);
1146
1147 FREE_GMP_TEMP(temp_a);
1148}
1149/* }}} */
1150
1151/* {{{ Add a and b */
1153{
1154 gmp_binary_ui_op(mpz_add, mpz_add_ui);
1155}
1156/* }}} */
1157
1158/* {{{ Subtract b from a */
1160{
1161 gmp_binary_ui_op(mpz_sub, mpz_sub_ui);
1162}
1163/* }}} */
1164
1165/* {{{ Multiply a and b */
1167{
1168 gmp_binary_ui_op(mpz_mul, mpz_mul_ui);
1169}
1170/* }}} */
1171
1172/* {{{ Divide a by b, returns quotient and reminder */
1174{
1175 zval *a_arg, *b_arg;
1177
1178 if (zend_parse_parameters(ZEND_NUM_ARGS(), "zz|l", &a_arg, &b_arg, &round) == FAILURE) {
1179 RETURN_THROWS();
1180 }
1181
1182 switch (round) {
1183 case GMP_ROUND_ZERO:
1184 gmp_zval_binary_ui_op2(return_value, a_arg, b_arg, mpz_tdiv_qr, mpz_tdiv_qr_ui, 1);
1185 break;
1186 case GMP_ROUND_PLUSINF:
1187 gmp_zval_binary_ui_op2(return_value, a_arg, b_arg, mpz_cdiv_qr, mpz_cdiv_qr_ui, 1);
1188 break;
1189 case GMP_ROUND_MINUSINF:
1190 gmp_zval_binary_ui_op2(return_value, a_arg, b_arg, mpz_fdiv_qr, mpz_fdiv_qr_ui, 1);
1191 break;
1192 default:
1193 zend_argument_value_error(3, "must be one of GMP_ROUND_ZERO, GMP_ROUND_PLUSINF, or GMP_ROUND_MINUSINF");
1194 RETURN_THROWS();
1195 }
1196}
1197/* }}} */
1198
1199/* {{{ Divide a by b, returns reminder only */
1201{
1202 zval *a_arg, *b_arg;
1204
1205 if (zend_parse_parameters(ZEND_NUM_ARGS(), "zz|l", &a_arg, &b_arg, &round) == FAILURE) {
1206 RETURN_THROWS();
1207 }
1208
1209 switch (round) {
1210 case GMP_ROUND_ZERO:
1211 gmp_zval_binary_ui_op(
1212 return_value, a_arg, b_arg, mpz_tdiv_r, gmp_mpz_tdiv_r_ui, 1, /* is_operator */ false);
1213 break;
1214 case GMP_ROUND_PLUSINF:
1215 gmp_zval_binary_ui_op(
1216 return_value, a_arg, b_arg, mpz_cdiv_r, gmp_mpz_cdiv_r_ui, 1, /* is_operator */ false);
1217 break;
1218 case GMP_ROUND_MINUSINF:
1219 gmp_zval_binary_ui_op(
1220 return_value, a_arg, b_arg, mpz_fdiv_r, gmp_mpz_fdiv_r_ui, 1, /* is_operator */ false);
1221 break;
1222 default:
1223 zend_argument_value_error(3, "must be one of GMP_ROUND_ZERO, GMP_ROUND_PLUSINF, or GMP_ROUND_MINUSINF");
1224 RETURN_THROWS();
1225 }
1226}
1227/* }}} */
1228
1229/* {{{ Divide a by b, returns quotient only */
1231{
1232 zval *a_arg, *b_arg;
1234
1235 if (zend_parse_parameters(ZEND_NUM_ARGS(), "zz|l", &a_arg, &b_arg, &round) == FAILURE) {
1236 RETURN_THROWS();
1237 }
1238
1239 switch (round) {
1240 case GMP_ROUND_ZERO:
1241 gmp_zval_binary_ui_op(
1242 return_value, a_arg, b_arg, mpz_tdiv_q, gmp_mpz_tdiv_q_ui, 1, /* is_operator */ false);
1243 break;
1244 case GMP_ROUND_PLUSINF:
1245 gmp_zval_binary_ui_op(
1246 return_value, a_arg, b_arg, mpz_cdiv_q, gmp_mpz_cdiv_q_ui, 1, /* is_operator */ false);
1247 break;
1248 case GMP_ROUND_MINUSINF:
1249 gmp_zval_binary_ui_op(
1250 return_value, a_arg, b_arg, mpz_fdiv_q, gmp_mpz_fdiv_q_ui, 1, /* is_operator */ false);
1251 break;
1252 default:
1253 zend_argument_value_error(3, "must be one of GMP_ROUND_ZERO, GMP_ROUND_PLUSINF, or GMP_ROUND_MINUSINF");
1254 RETURN_THROWS();
1255 }
1256
1257}
1258/* }}} */
1259
1260/* {{{ Computes a modulo b */
1262{
1263 gmp_binary_ui_op_no_zero(mpz_mod, gmp_mpz_mod_ui);
1264}
1265/* }}} */
1266
1267/* {{{ Divide a by b using exact division algorithm */
1272/* }}} */
1273
1274/* {{{ Negates a number */
1276{
1277 gmp_unary_op(mpz_neg);
1278}
1279/* }}} */
1280
1281/* {{{ Calculates absolute value */
1283{
1284 gmp_unary_op(mpz_abs);
1285}
1286/* }}} */
1287
1288/* {{{ Calculates factorial function */
1290{
1291 zval *a_arg;
1292 mpz_ptr gmpnum_result;
1293
1294 if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &a_arg) == FAILURE){
1295 RETURN_THROWS();
1296 }
1297
1298 if (Z_TYPE_P(a_arg) == IS_LONG) {
1299 if (Z_LVAL_P(a_arg) < 0) {
1300 zend_argument_value_error(1, "must be greater than or equal to 0");
1301 RETURN_THROWS();
1302 }
1303 } else {
1304 mpz_ptr gmpnum;
1305 gmp_temp_t temp_a;
1306
1307 FETCH_GMP_ZVAL(gmpnum, a_arg, temp_a, 1);
1308 FREE_GMP_TEMP(temp_a);
1309
1310 if (mpz_sgn(gmpnum) < 0) {
1311 zend_argument_value_error(1, "must be greater than or equal to 0");
1312 RETURN_THROWS();
1313 }
1314 }
1315
1316 INIT_GMP_RETVAL(gmpnum_result);
1317 mpz_fac_ui(gmpnum_result, zval_get_long(a_arg));
1318}
1319/* }}} */
1320
1321/* {{{ Calculates binomial coefficient */
1323{
1324 zval *n_arg;
1325 zend_long k;
1326 mpz_ptr gmpnum_result;
1327
1328 if (zend_parse_parameters(ZEND_NUM_ARGS(), "zl", &n_arg, &k) == FAILURE) {
1329 RETURN_THROWS();
1330 }
1331
1332 if (k < 0) {
1333 zend_argument_value_error(2, "must be greater than or equal to 0");
1334 RETURN_THROWS();
1335 }
1336
1337 INIT_GMP_RETVAL(gmpnum_result);
1338 if (Z_TYPE_P(n_arg) == IS_LONG && Z_LVAL_P(n_arg) >= 0) {
1339 mpz_bin_uiui(gmpnum_result, (gmp_ulong) Z_LVAL_P(n_arg), (gmp_ulong) k);
1340 } else {
1341 mpz_ptr gmpnum_n;
1342 gmp_temp_t temp_n;
1343 FETCH_GMP_ZVAL(gmpnum_n, n_arg, temp_n, 1);
1344 mpz_bin_ui(gmpnum_result, gmpnum_n, (gmp_ulong) k);
1345 FREE_GMP_TEMP(temp_n);
1346 }
1347}
1348/* }}} */
1349
1350/* {{{ Raise base to power exp */
1352{
1353 zval *base_arg;
1354 mpz_ptr gmpnum_result;
1355 gmp_temp_t temp_base;
1356 zend_long exp;
1357
1358 if (zend_parse_parameters(ZEND_NUM_ARGS(), "zl", &base_arg, &exp) == FAILURE) {
1359 RETURN_THROWS();
1360 }
1361
1362 if (exp < 0) {
1363 zend_argument_value_error(2, "must be greater than or equal to 0");
1364 RETURN_THROWS();
1365 }
1366
1367 if (Z_TYPE_P(base_arg) == IS_LONG && Z_LVAL_P(base_arg) >= 0) {
1368 INIT_GMP_RETVAL(gmpnum_result);
1369 mpz_ui_pow_ui(gmpnum_result, Z_LVAL_P(base_arg), exp);
1370 } else {
1371 mpz_ptr gmpnum_base;
1372 FETCH_GMP_ZVAL(gmpnum_base, base_arg, temp_base, 1);
1373 INIT_GMP_RETVAL(gmpnum_result);
1374 mpz_pow_ui(gmpnum_result, gmpnum_base, exp);
1375 FREE_GMP_TEMP(temp_base);
1376 }
1377}
1378/* }}} */
1379
1380/* {{{ Raise base to power exp and take result modulo mod */
1382{
1383 zval *base_arg, *exp_arg, *mod_arg;
1384 mpz_ptr gmpnum_base, gmpnum_exp, gmpnum_mod, gmpnum_result;
1385 int use_ui = 0;
1386 gmp_temp_t temp_base, temp_exp, temp_mod;
1387
1388 if (zend_parse_parameters(ZEND_NUM_ARGS(), "zzz", &base_arg, &exp_arg, &mod_arg) == FAILURE){
1389 RETURN_THROWS();
1390 }
1391
1392 FETCH_GMP_ZVAL(gmpnum_base, base_arg, temp_base, 1);
1393
1394 if (Z_TYPE_P(exp_arg) == IS_LONG && Z_LVAL_P(exp_arg) >= 0) {
1395 use_ui = 1;
1396 temp_exp.is_used = 0;
1397 } else {
1398 FETCH_GMP_ZVAL_DEP(gmpnum_exp, exp_arg, temp_exp, temp_base, 2);
1399 if (mpz_sgn(gmpnum_exp) < 0) {
1400 zend_argument_value_error(2, "must be greater than or equal to 0");
1401 FREE_GMP_TEMP(temp_base);
1402 FREE_GMP_TEMP(temp_exp);
1403 RETURN_THROWS();
1404 }
1405 }
1406 FETCH_GMP_ZVAL_DEP_DEP(gmpnum_mod, mod_arg, temp_mod, temp_exp, temp_base, 3);
1407
1408 if (!mpz_cmp_ui(gmpnum_mod, 0)) {
1410 FREE_GMP_TEMP(temp_base);
1411 FREE_GMP_TEMP(temp_exp);
1412 FREE_GMP_TEMP(temp_mod);
1413 RETURN_THROWS();
1414 }
1415
1416 INIT_GMP_RETVAL(gmpnum_result);
1417 if (use_ui) {
1418 mpz_powm_ui(gmpnum_result, gmpnum_base, (zend_ulong) Z_LVAL_P(exp_arg), gmpnum_mod);
1419 } else {
1420 mpz_powm(gmpnum_result, gmpnum_base, gmpnum_exp, gmpnum_mod);
1421 FREE_GMP_TEMP(temp_exp);
1422 }
1423
1424 FREE_GMP_TEMP(temp_base);
1425 FREE_GMP_TEMP(temp_mod);
1426}
1427/* }}} */
1428
1429/* {{{ Takes integer part of square root of a */
1431{
1432 zval *a_arg;
1433 mpz_ptr gmpnum_a, gmpnum_result;
1434 gmp_temp_t temp_a;
1435
1436 if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &a_arg) == FAILURE){
1437 RETURN_THROWS();
1438 }
1439
1440 FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a, 1);
1441
1442 if (mpz_sgn(gmpnum_a) < 0) {
1443 zend_argument_value_error(1, "must be greater than or equal to 0");
1444 FREE_GMP_TEMP(temp_a);
1445 RETURN_THROWS();
1446 }
1447
1448 INIT_GMP_RETVAL(gmpnum_result);
1449 mpz_sqrt(gmpnum_result, gmpnum_a);
1450 FREE_GMP_TEMP(temp_a);
1451}
1452/* }}} */
1453
1454/* {{{ Square root with remainder */
1456{
1457 zval *a_arg;
1458 mpz_ptr gmpnum_a, gmpnum_result1, gmpnum_result2;
1459 gmp_temp_t temp_a;
1460 zval result1, result2;
1461
1462 if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &a_arg) == FAILURE){
1463 RETURN_THROWS();
1464 }
1465
1466 FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a, 1);
1467
1468 if (mpz_sgn(gmpnum_a) < 0) {
1469 zend_argument_value_error(1, "must be greater than or equal to 0");
1470 FREE_GMP_TEMP(temp_a);
1471 RETURN_THROWS();
1472 }
1473
1474 gmp_create(&result1, &gmpnum_result1);
1475 gmp_create(&result2, &gmpnum_result2);
1476
1478 add_next_index_zval(return_value, &result1);
1479 add_next_index_zval(return_value, &result2);
1480
1481 mpz_sqrtrem(gmpnum_result1, gmpnum_result2, gmpnum_a);
1482 FREE_GMP_TEMP(temp_a);
1483}
1484/* }}} */
1485
1486/* {{{ Takes integer part of nth root */
1488{
1489 zval *a_arg;
1490 zend_long nth;
1491 mpz_ptr gmpnum_a, gmpnum_result;
1492 gmp_temp_t temp_a;
1493
1494 if (zend_parse_parameters(ZEND_NUM_ARGS(), "zl", &a_arg, &nth) == FAILURE) {
1495 RETURN_THROWS();
1496 }
1497
1498 if (nth <= 0) {
1499 zend_argument_value_error(2, "must be greater than 0");
1500 RETURN_THROWS();
1501 }
1502
1503 FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a, 1);
1504
1505 if (nth % 2 == 0 && mpz_sgn(gmpnum_a) < 0) {
1506 zend_argument_value_error(2, "must be odd if argument #1 ($a) is negative");
1507 FREE_GMP_TEMP(temp_a);
1508 RETURN_THROWS();
1509 }
1510
1511 INIT_GMP_RETVAL(gmpnum_result);
1512 mpz_root(gmpnum_result, gmpnum_a, (gmp_ulong) nth);
1513 FREE_GMP_TEMP(temp_a);
1514}
1515/* }}} */
1516
1517/* {{{ Calculates integer part of nth root and remainder */
1519{
1520 zval *a_arg;
1521 zend_long nth;
1522 mpz_ptr gmpnum_a, gmpnum_result1, gmpnum_result2;
1523 gmp_temp_t temp_a;
1524 zval result1, result2;
1525
1526 if (zend_parse_parameters(ZEND_NUM_ARGS(), "zl", &a_arg, &nth) == FAILURE) {
1527 RETURN_THROWS();
1528 }
1529
1530 if (nth <= 0) {
1531 zend_argument_value_error(2, "must be greater than or equal to 1");
1532 RETURN_THROWS();
1533 }
1534
1535 FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a, 1);
1536
1537 if (nth % 2 == 0 && mpz_sgn(gmpnum_a) < 0) {
1538 zend_argument_value_error(2, "must be odd if argument #1 ($a) is negative");
1539 FREE_GMP_TEMP(temp_a);
1540 RETURN_THROWS();
1541 }
1542
1543 gmp_create(&result1, &gmpnum_result1);
1544 gmp_create(&result2, &gmpnum_result2);
1545
1547 add_next_index_zval(return_value, &result1);
1548 add_next_index_zval(return_value, &result2);
1549
1550#if GMP_51_OR_NEWER
1551 /* mpz_rootrem() is supported since GMP 4.2, but buggy wrt odd roots
1552 * of negative numbers */
1553 mpz_rootrem(gmpnum_result1, gmpnum_result2, gmpnum_a, (gmp_ulong) nth);
1554#else
1555 mpz_root(gmpnum_result1, gmpnum_a, (gmp_ulong) nth);
1556 mpz_pow_ui(gmpnum_result2, gmpnum_result1, (gmp_ulong) nth);
1557 mpz_sub(gmpnum_result2, gmpnum_a, gmpnum_result2);
1558#endif
1559
1560 FREE_GMP_TEMP(temp_a);
1561}
1562/* }}} */
1563
1564/* {{{ Checks if a is an exact square */
1566{
1567 zval *a_arg;
1568 mpz_ptr gmpnum_a;
1569 gmp_temp_t temp_a;
1570
1571 if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &a_arg) == FAILURE){
1572 RETURN_THROWS();
1573 }
1574
1575 FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a, 1);
1576
1577 RETVAL_BOOL((mpz_perfect_square_p(gmpnum_a) != 0));
1578 FREE_GMP_TEMP(temp_a);
1579}
1580/* }}} */
1581
1582/* {{{ Checks if a is a perfect power */
1584{
1585 zval *a_arg;
1586 mpz_ptr gmpnum_a;
1587 gmp_temp_t temp_a;
1588
1589 if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &a_arg) == FAILURE){
1590 RETURN_THROWS();
1591 }
1592
1593 FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a, 1);
1594
1595 RETVAL_BOOL((mpz_perfect_power_p(gmpnum_a) != 0));
1596 FREE_GMP_TEMP(temp_a);
1597}
1598/* }}} */
1599
1600/* {{{ Checks if a is "probably prime" */
1602{
1603 zval *gmpnumber_arg;
1604 mpz_ptr gmpnum_a;
1605 zend_long reps = 10;
1606 gmp_temp_t temp_a;
1607
1608 if (zend_parse_parameters(ZEND_NUM_ARGS(), "z|l", &gmpnumber_arg, &reps) == FAILURE) {
1609 RETURN_THROWS();
1610 }
1611
1612 FETCH_GMP_ZVAL(gmpnum_a, gmpnumber_arg, temp_a, 1);
1613
1614 RETVAL_LONG(mpz_probab_prime_p(gmpnum_a, (int)reps));
1615 FREE_GMP_TEMP(temp_a);
1616}
1617/* }}} */
1618
1619/* {{{ Computes greatest common denominator (gcd) of a and b */
1621{
1622 gmp_binary_ui_op(mpz_gcd, gmp_mpz_gcd_ui);
1623}
1624/* }}} */
1625
1626/* {{{ Computes least common multiple (lcm) of a and b */
1628{
1629 gmp_binary_ui_op(mpz_lcm, mpz_lcm_ui);
1630}
1631/* }}} */
1632
1633/* {{{ Computes G, S, and T, such that AS + BT = G = `gcd' (A, B) */
1635{
1636 zval *a_arg, *b_arg;
1637 mpz_ptr gmpnum_a, gmpnum_b, gmpnum_t, gmpnum_s, gmpnum_g;
1638 gmp_temp_t temp_a, temp_b;
1639 zval result_g, result_s, result_t;
1640
1641 if (zend_parse_parameters(ZEND_NUM_ARGS(), "zz", &a_arg, &b_arg) == FAILURE){
1642 RETURN_THROWS();
1643 }
1644
1645 FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a, 1);
1646 FETCH_GMP_ZVAL_DEP(gmpnum_b, b_arg, temp_b, temp_a, 2);
1647
1648 gmp_create(&result_g, &gmpnum_g);
1649 gmp_create(&result_s, &gmpnum_s);
1650 gmp_create(&result_t, &gmpnum_t);
1651
1653 add_assoc_zval(return_value, "g", &result_g);
1654 add_assoc_zval(return_value, "s", &result_s);
1655 add_assoc_zval(return_value, "t", &result_t);
1656
1657 mpz_gcdext(gmpnum_g, gmpnum_s, gmpnum_t, gmpnum_a, gmpnum_b);
1658 FREE_GMP_TEMP(temp_a);
1659 FREE_GMP_TEMP(temp_b);
1660}
1661/* }}} */
1662
1663/* {{{ Computes the inverse of a modulo b */
1665{
1666 zval *a_arg, *b_arg;
1667 mpz_ptr gmpnum_a, gmpnum_b, gmpnum_result;
1668 gmp_temp_t temp_a, temp_b;
1669 int res;
1670
1671 if (zend_parse_parameters(ZEND_NUM_ARGS(), "zz", &a_arg, &b_arg) == FAILURE){
1672 RETURN_THROWS();
1673 }
1674
1675 if (Z_TYPE_P(b_arg) == IS_LONG && Z_LVAL_P(b_arg) == 0) {
1677 RETURN_THROWS();
1678 }
1679
1680 FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a, 1);
1681 FETCH_GMP_ZVAL_DEP(gmpnum_b, b_arg, temp_b, temp_a, 2);
1682
1683 if (!mpz_cmp_ui(gmpnum_b, 0)) {
1685 FREE_GMP_TEMP(temp_a);
1686 FREE_GMP_TEMP(temp_b);
1687 RETURN_THROWS();
1688 }
1689
1690 INIT_GMP_RETVAL(gmpnum_result);
1691 res = mpz_invert(gmpnum_result, gmpnum_a, gmpnum_b);
1692 FREE_GMP_TEMP(temp_a);
1693 FREE_GMP_TEMP(temp_b);
1694 if (!res) {
1697 }
1698}
1699/* }}} */
1700
1701/* {{{ Computes Jacobi symbol */
1703{
1704 zval *a_arg, *b_arg;
1705 mpz_ptr gmpnum_a, gmpnum_b;
1706 gmp_temp_t temp_a, temp_b;
1707
1708 if (zend_parse_parameters(ZEND_NUM_ARGS(), "zz", &a_arg, &b_arg) == FAILURE){
1709 RETURN_THROWS();
1710 }
1711
1712 FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a, 1);
1713 FETCH_GMP_ZVAL_DEP(gmpnum_b, b_arg, temp_b, temp_a, 2);
1714
1715 RETVAL_LONG(mpz_jacobi(gmpnum_a, gmpnum_b));
1716
1717 FREE_GMP_TEMP(temp_a);
1718 FREE_GMP_TEMP(temp_b);
1719}
1720/* }}} */
1721
1722/* {{{ Computes Legendre symbol */
1724{
1725 zval *a_arg, *b_arg;
1726 mpz_ptr gmpnum_a, gmpnum_b;
1727 gmp_temp_t temp_a, temp_b;
1728
1729 if (zend_parse_parameters(ZEND_NUM_ARGS(), "zz", &a_arg, &b_arg) == FAILURE){
1730 RETURN_THROWS();
1731 }
1732
1733 FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a, 1);
1734 FETCH_GMP_ZVAL_DEP(gmpnum_b, b_arg, temp_b, temp_a, 2);
1735
1736 RETVAL_LONG(mpz_legendre(gmpnum_a, gmpnum_b));
1737
1738 FREE_GMP_TEMP(temp_a);
1739 FREE_GMP_TEMP(temp_b);
1740}
1741/* }}} */
1742
1743/* {{{ Computes the Kronecker symbol */
1745{
1746 zval *a_arg, *b_arg;
1747 mpz_ptr gmpnum_a, gmpnum_b;
1748 gmp_temp_t temp_a, temp_b;
1749 bool use_a_si = 0, use_b_si = 0;
1750 int result;
1751
1752 if (zend_parse_parameters(ZEND_NUM_ARGS(), "zz", &a_arg, &b_arg) == FAILURE){
1753 RETURN_THROWS();
1754 }
1755
1756 if (Z_TYPE_P(a_arg) == IS_LONG && Z_TYPE_P(b_arg) != IS_LONG) {
1757 use_a_si = 1;
1758 temp_a.is_used = 0;
1759 } else {
1760 FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a, 1);
1761 }
1762
1763 if (Z_TYPE_P(b_arg) == IS_LONG) {
1764 use_b_si = 1;
1765 temp_b.is_used = 0;
1766 } else {
1767 FETCH_GMP_ZVAL_DEP(gmpnum_b, b_arg, temp_b, temp_a, 2);
1768 }
1769
1770 if (use_a_si) {
1771 ZEND_ASSERT(use_b_si == 0);
1772 result = mpz_si_kronecker((gmp_long) Z_LVAL_P(a_arg), gmpnum_b);
1773 } else if (use_b_si) {
1774 result = mpz_kronecker_si(gmpnum_a, (gmp_long) Z_LVAL_P(b_arg));
1775 } else {
1776 result = mpz_kronecker(gmpnum_a, gmpnum_b);
1777 }
1778
1779 FREE_GMP_TEMP(temp_a);
1780 FREE_GMP_TEMP(temp_b);
1781
1783}
1784/* }}} */
1785
1786/* {{{ Compares two numbers */
1788{
1789 zval *a_arg, *b_arg;
1790
1791 if (zend_parse_parameters(ZEND_NUM_ARGS(), "zz", &a_arg, &b_arg) == FAILURE){
1792 RETURN_THROWS();
1793 }
1794
1795 gmp_cmp(return_value, a_arg, b_arg, /* is_operator */ false);
1796}
1797/* }}} */
1798
1799/* {{{ Gets the sign of the number */
1801{
1802 /* Can't use gmp_unary_opl here, because mpz_sgn is a macro */
1803 zval *a_arg;
1804 mpz_ptr gmpnum_a;
1805 gmp_temp_t temp_a;
1806
1807 if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &a_arg) == FAILURE){
1808 RETURN_THROWS();
1809 }
1810
1811 FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a, 1);
1812
1813 RETVAL_LONG(mpz_sgn(gmpnum_a));
1814 FREE_GMP_TEMP(temp_a);
1815}
1816/* }}} */
1817
1818static void gmp_init_random(void)
1819{
1820 if (!GMPG(rand_initialized)) {
1821 /* Initialize */
1822 gmp_randinit_mt(GMPG(rand_state));
1823 /* Seed */
1824 unsigned long int seed = 0;
1825 if (php_random_bytes_silent(&seed, sizeof(seed)) == FAILURE) {
1826 seed = (unsigned long int)php_random_generate_fallback_seed();
1827 }
1828 gmp_randseed_ui(GMPG(rand_state), seed);
1829
1831 }
1832}
1833
1834/* {{{ Seed the RNG */
1836{
1837 zval *seed;
1838 gmp_temp_t temp_a;
1839
1840 if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &seed) == FAILURE) {
1841 RETURN_THROWS();
1842 }
1843
1844 gmp_init_random();
1845
1846 if (Z_TYPE_P(seed) == IS_LONG && Z_LVAL_P(seed) >= 0) {
1847 gmp_randseed_ui(GMPG(rand_state), Z_LVAL_P(seed));
1848 }
1849 else {
1850 mpz_ptr gmpnum_seed;
1851
1852 FETCH_GMP_ZVAL(gmpnum_seed, seed, temp_a, 1);
1853
1854 gmp_randseed(GMPG(rand_state), gmpnum_seed);
1855
1856 FREE_GMP_TEMP(temp_a);
1857 }
1858}
1859/* }}} */
1860
1861/* {{{ Gets a random number in the range 0 to (2 ** n) - 1 */
1863{
1864 zend_long bits;
1865 mpz_ptr gmpnum_result;
1866
1867 if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &bits) == FAILURE) {
1868 RETURN_THROWS();
1869 }
1870
1871#if SIZEOF_SIZE_T == 4
1872 const zend_long maxbits = ULONG_MAX / GMP_NUMB_BITS;
1873#else
1874 const zend_long maxbits = INT_MAX;
1875#endif
1876
1877 if (bits <= 0 || bits > maxbits) {
1878 zend_argument_value_error(1, "must be between 1 and " ZEND_LONG_FMT, maxbits);
1879 RETURN_THROWS();
1880 }
1881
1882 INIT_GMP_RETVAL(gmpnum_result);
1883 gmp_init_random();
1884
1885 mpz_urandomb(gmpnum_result, GMPG(rand_state), (mp_bitcnt_t)bits);
1886}
1887/* }}} */
1888
1889/* {{{ Gets a random number in the range min to max */
1891{
1892 zval *min_arg, *max_arg;
1893 mpz_ptr gmpnum_max, gmpnum_result;
1894 mpz_t gmpnum_range;
1895 gmp_temp_t temp_a, temp_b;
1896
1897 if (zend_parse_parameters(ZEND_NUM_ARGS(), "zz", &min_arg, &max_arg) == FAILURE) {
1898 RETURN_THROWS();
1899 }
1900
1901 gmp_init_random();
1902
1903 FETCH_GMP_ZVAL(gmpnum_max, max_arg, temp_a, 2);
1904
1905 if (Z_TYPE_P(min_arg) == IS_LONG && Z_LVAL_P(min_arg) >= 0) {
1906 if (mpz_cmp_ui(gmpnum_max, Z_LVAL_P(min_arg)) <= 0) {
1907 FREE_GMP_TEMP(temp_a);
1908 zend_argument_value_error(1, "must be less than argument #2 ($maximum)");
1909 RETURN_THROWS();
1910 }
1911
1912 INIT_GMP_RETVAL(gmpnum_result);
1913 mpz_init(gmpnum_range);
1914
1915 if (Z_LVAL_P(min_arg) != 0) {
1916 mpz_sub_ui(gmpnum_range, gmpnum_max, Z_LVAL_P(min_arg) - 1);
1917 } else {
1918 mpz_add_ui(gmpnum_range, gmpnum_max, 1);
1919 }
1920
1921 mpz_urandomm(gmpnum_result, GMPG(rand_state), gmpnum_range);
1922
1923 if (Z_LVAL_P(min_arg) != 0) {
1924 mpz_add_ui(gmpnum_result, gmpnum_result, Z_LVAL_P(min_arg));
1925 }
1926
1927 mpz_clear(gmpnum_range);
1928 FREE_GMP_TEMP(temp_a);
1929 } else {
1930 mpz_ptr gmpnum_min;
1931
1932 FETCH_GMP_ZVAL_DEP(gmpnum_min, min_arg, temp_b, temp_a, 1);
1933
1934 if (mpz_cmp(gmpnum_max, gmpnum_min) <= 0) {
1935 FREE_GMP_TEMP(temp_b);
1936 FREE_GMP_TEMP(temp_a);
1937 zend_argument_value_error(1, "must be less than argument #2 ($maximum)");
1938 RETURN_THROWS();
1939 }
1940
1941 INIT_GMP_RETVAL(gmpnum_result);
1942 mpz_init(gmpnum_range);
1943
1944 mpz_sub(gmpnum_range, gmpnum_max, gmpnum_min);
1945 mpz_add_ui(gmpnum_range, gmpnum_range, 1);
1946 mpz_urandomm(gmpnum_result, GMPG(rand_state), gmpnum_range);
1947 mpz_add(gmpnum_result, gmpnum_result, gmpnum_min);
1948
1949 mpz_clear(gmpnum_range);
1950 FREE_GMP_TEMP(temp_b);
1951 FREE_GMP_TEMP(temp_a);
1952 }
1953}
1954/* }}} */
1955
1956/* {{{ Calculates logical AND of a and b */
1958{
1959 gmp_binary_op(mpz_and);
1960}
1961/* }}} */
1962
1963/* {{{ Calculates logical OR of a and b */
1965{
1966 gmp_binary_op(mpz_ior);
1967}
1968/* }}} */
1969
1970/* {{{ Calculates one's complement of a */
1972{
1973 gmp_unary_op(mpz_com);
1974}
1975/* }}} */
1976
1977/* {{{ Finds next prime of a */
1979{
1980 gmp_unary_op(mpz_nextprime);
1981}
1982/* }}} */
1983
1984/* {{{ Calculates logical exclusive OR of a and b */
1986{
1987 gmp_binary_op(mpz_xor);
1988}
1989/* }}} */
1990
1991/* {{{ Sets or clear bit in a */
1993{
1994 zval *a_arg;
1995 zend_long index;
1996 bool set = 1;
1997 mpz_ptr gmpnum_a;
1998
1999 if (zend_parse_parameters(ZEND_NUM_ARGS(), "Ol|b", &a_arg, gmp_ce, &index, &set) == FAILURE) {
2000 RETURN_THROWS();
2001 }
2002
2003 if (index < 0) {
2004 zend_argument_value_error(2, "must be greater than or equal to 0");
2005 RETURN_THROWS();
2006 }
2007 if (index / GMP_NUMB_BITS >= INT_MAX) {
2008 zend_argument_value_error(2, "must be less than %d * %d", INT_MAX, GMP_NUMB_BITS);
2009 RETURN_THROWS();
2010 }
2011
2012 gmpnum_a = GET_GMP_FROM_ZVAL(a_arg);
2013
2014 if (set) {
2015 mpz_setbit(gmpnum_a, index);
2016 } else {
2017 mpz_clrbit(gmpnum_a, index);
2018 }
2019}
2020/* }}} */
2021
2022/* {{{ Clears bit in a */
2024{
2025 zval *a_arg;
2026 zend_long index;
2027 mpz_ptr gmpnum_a;
2028
2029 if (zend_parse_parameters(ZEND_NUM_ARGS(), "Ol", &a_arg, gmp_ce, &index) == FAILURE){
2030 RETURN_THROWS();
2031 }
2032
2033 if (index < 0) {
2034 zend_argument_value_error(2, "must be greater than or equal to 0");
2035 RETURN_THROWS();
2036 }
2037
2038 gmpnum_a = GET_GMP_FROM_ZVAL(a_arg);
2039 mpz_clrbit(gmpnum_a, index);
2040}
2041/* }}} */
2042
2043/* {{{ Tests if bit is set in a */
2045{
2046 zval *a_arg;
2047 zend_long index;
2048 mpz_ptr gmpnum_a;
2049 gmp_temp_t temp_a;
2050
2051 if (zend_parse_parameters(ZEND_NUM_ARGS(), "zl", &a_arg, &index) == FAILURE){
2052 RETURN_THROWS();
2053 }
2054
2055 if (index < 0) {
2056 zend_argument_value_error(2, "must be greater than or equal to 0");
2057 RETURN_THROWS();
2058 }
2059
2060 FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a, 1);
2061 RETVAL_BOOL(mpz_tstbit(gmpnum_a, index));
2062 FREE_GMP_TEMP(temp_a);
2063}
2064/* }}} */
2065
2066/* {{{ Calculates the population count of a */
2068{
2069 gmp_unary_opl(mpz_popcount);
2070}
2071/* }}} */
2072
2073/* {{{ Calculates hamming distance between a and b */
2075{
2076 zval *a_arg, *b_arg;
2077 mpz_ptr gmpnum_a, gmpnum_b;
2078 gmp_temp_t temp_a, temp_b;
2079
2080 if (zend_parse_parameters(ZEND_NUM_ARGS(), "zz", &a_arg, &b_arg) == FAILURE){
2081 RETURN_THROWS();
2082 }
2083
2084 FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a, 1);
2085 FETCH_GMP_ZVAL_DEP(gmpnum_b, b_arg, temp_b, temp_a, 2);
2086
2087 RETVAL_LONG(mpz_hamdist(gmpnum_a, gmpnum_b));
2088
2089 FREE_GMP_TEMP(temp_a);
2090 FREE_GMP_TEMP(temp_b);
2091}
2092/* }}} */
2093
2094/* {{{ Finds first zero bit */
2096{
2097 zval *a_arg;
2098 mpz_ptr gmpnum_a;
2099 gmp_temp_t temp_a;
2101
2102 if (zend_parse_parameters(ZEND_NUM_ARGS(), "zl", &a_arg, &start) == FAILURE){
2103 RETURN_THROWS();
2104 }
2105
2106 if (start < 0) {
2107 zend_argument_value_error(2, "must be greater than or equal to 0");
2108 RETURN_THROWS();
2109 }
2110
2111 FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a, 1);
2112
2113 RETVAL_LONG(mpz_scan0(gmpnum_a, start));
2114 FREE_GMP_TEMP(temp_a);
2115}
2116/* }}} */
2117
2118/* {{{ Finds first non-zero bit */
2120{
2121 zval *a_arg;
2122 mpz_ptr gmpnum_a;
2123 gmp_temp_t temp_a;
2125
2126 if (zend_parse_parameters(ZEND_NUM_ARGS(), "zl", &a_arg, &start) == FAILURE){
2127 RETURN_THROWS();
2128 }
2129
2130 if (start < 0) {
2131 zend_argument_value_error(2, "must be greater than or equal to 0");
2132 RETURN_THROWS();
2133 }
2134
2135 FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a, 1);
2136
2137 RETVAL_LONG(mpz_scan1(gmpnum_a, start));
2138 FREE_GMP_TEMP(temp_a);
2139}
2140/* }}} */
2141
2142ZEND_METHOD(GMP, __construct)
2143{
2144 zend_string *arg_str = NULL;
2145 zend_long arg_l = 0;
2146 zend_long base = 0;
2147
2150 Z_PARAM_STR_OR_LONG(arg_str, arg_l)
2151 Z_PARAM_LONG(base)
2153
2154 if (!gmp_verify_base(base, 2)) {
2155 RETURN_THROWS();
2156 }
2157
2159 mpz_ptr gmp_number = GET_GMP_FROM_ZVAL(ZEND_THIS);
2160
2161 if (gmp_initialize_number(gmp_number, arg_str, arg_l, base) == FAILURE) {
2162 RETURN_THROWS();
2163 }
2164}
2165
2166ZEND_METHOD(GMP, __serialize)
2167{
2169
2170 zval zv;
2172
2173 mpz_ptr gmpnum = GET_GMP_FROM_ZVAL(ZEND_THIS);
2174 gmp_strval(&zv, gmpnum, 16);
2176
2177 HashTable *props = Z_OBJ_P(ZEND_THIS)->properties;
2178 if (props && zend_hash_num_elements(props) != 0) {
2180 zend_std_get_properties(Z_OBJ_P(ZEND_THIS)), /* always duplicate */ 1));
2182 }
2183}
2184
2185ZEND_METHOD(GMP, __unserialize)
2186{
2187 HashTable *data;
2188
2192
2193 zval *num = zend_hash_index_find(data, 0);
2194 if (!num || Z_TYPE_P(num) != IS_STRING ||
2195 convert_zstr_to_gmp(GET_GMP_FROM_ZVAL(ZEND_THIS), Z_STR_P(num), 16, /* arg_pos */ 0) == FAILURE) {
2196 zend_throw_exception(NULL, "Could not unserialize number", 0);
2197 RETURN_THROWS();
2198 }
2199
2200 zval *props = zend_hash_index_find(data, 1);
2201 if (props) {
2202 if (Z_TYPE_P(props) != IS_ARRAY) {
2203 zend_throw_exception(NULL, "Could not unserialize properties", 0);
2204 RETURN_THROWS();
2205 }
2206
2208 }
2209}
bool exception
Definition assert.c:30
abs(int|float $num)
count(Countable|array $value, int $mode=COUNT_NORMAL)
exp(float $num)
#define max(a, b)
Definition exif.c:60
zend_ffi_type * type
Definition ffi.c:3812
zval * zv
Definition ffi.c:3975
new_type size
Definition ffi.c:4365
zend_string * res
Definition ffi.c:4692
memcpy(ptr1, ptr2, size)
zval * val
Definition ffi.c:4262
HashTable * ht
Definition ffi.c:4838
buf start
Definition ffi.c:4687
zend_ffi_ctype_name_buf buf
Definition ffi.c:4685
#define SIZE_MAX
Definition funcs.c:51
#define maxbits
Definition gd_gif_out.c:42
#define NULL
Definition gdcache.h:45
#define FETCH_GMP_ZVAL_DEP_DEP(gmpnumber, zval, temp, dep1, dep2, arg_pos)
Definition gmp.c:137
void(* gmp_binary_op2_t)(mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr)
Definition gmp.c:204
void(* gmp_unary_ui_op_t)(mpz_ptr, gmp_ulong)
Definition gmp.c:199
#define GMP_BIG_ENDIAN
Definition gmp.c:51
#define gmp_binary_ui_op_no_zero(op, uop)
Definition gmp.c:239
gmp_ulong(* gmp_binary_ui_op2_t)(mpz_ptr, mpz_ptr, mpz_srcptr, gmp_ulong)
Definition gmp.c:205
#define GET_GMP_OBJECT_FROM_OBJ(obj)
Definition gmp.c:105
#define GMP_ROUND_ZERO
Definition gmp.c:39
#define gmp_unary_op(op)
Definition gmp.c:243
#define GMP_LSW_FIRST
Definition gmp.c:49
void(* gmp_binary_ui_op_t)(mpz_ptr, mpz_srcptr, gmp_ulong)
Definition gmp.c:203
#define GMP_LITTLE_ENDIAN
Definition gmp.c:50
#define gmp_binary_op(op)
Definition gmp.c:238
#define GMP_NATIVE_ENDIAN
Definition gmp.c:52
#define GMP_ROUND_PLUSINF
Definition gmp.c:40
mp_bitcnt_t(* gmp_unary_opl_t)(mpz_srcptr)
Definition gmp.c:197
#define gmp_unary_opl(op)
Definition gmp.c:244
#define FETCH_GMP_ZVAL_DEP(gmpnumber, zval, temp, dep, arg_pos)
Definition gmp.c:153
#define IS_GMP(zval)
Definition gmp.c:102
void(* gmp_binary_op_t)(mpz_ptr, mpz_srcptr, mpz_srcptr)
Definition gmp.c:201
#define GMP_ROUND_MINUSINF
Definition gmp.c:41
#define FETCH_GMP_ZVAL(gmpnumber, zval, temp, arg_pos)
Definition gmp.c:168
void(* gmp_unary_op_t)(mpz_ptr, mpz_srcptr)
Definition gmp.c:196
PHP_GMP_API zend_class_entry * php_gmp_class_entry(void)
Definition gmp.c:88
#define DO_BINARY_UI_OP_EX(op, uop, check_b_zero)
Definition gmp.c:430
struct _gmp_temp gmp_temp_t
#define GMP_MAX_BASE
Definition gmp.c:97
#define GMP_MSW_FIRST
Definition gmp.c:48
#define INIT_GMP_RETVAL(gmpnumber)
Definition gmp.c:182
#define gmp_binary_ui_op(op, uop)
Definition gmp.c:237
#define DO_UNARY_OP(op)
Definition gmp.c:439
#define mpz_fits_si_p
Definition gmp.c:36
zend_module_entry gmp_module_entry
Definition gmp.c:60
#define DO_BINARY_UI_OP(op)
Definition gmp.c:436
#define DO_BINARY_OP(op)
Definition gmp.c:437
#define GET_GMP_FROM_ZVAL(zval)
Definition gmp.c:110
#define FREE_GMP_TEMP(temp)
Definition gmp.c:132
gmp_divexact(GMP|int|string $num1, GMP|int|string $num2)
Definition gmp.stub.php:100
gmp_sqrtrem(GMP|int|string $num)
Definition gmp.stub.php:114
gmp_init(int|string $num, int $base=0)
Definition gmp.stub.php:69
gmp_random_bits(int $bits)
Definition gmp.stub.php:158
gmp_com(GMP|int|string $num)
Definition gmp.stub.php:166
gmp_legendre(GMP|int|string $num1, GMP|int|string $num2)
Definition gmp.stub.php:148
gmp_popcount(GMP|int|string $num)
Definition gmp.stub.php:180
gmp_scan1(GMP|int|string $num1, int $start)
Definition gmp.stub.php:178
gmp_hamdist(GMP|int|string $num1, GMP|int|string $num2)
Definition gmp.stub.php:182
gmp_nextprime(GMP|int|string $num)
Definition gmp.stub.php:184
gmp_div_q(GMP|int|string $num1, GMP|int|string $num2, int $rounding_mode=GMP_ROUND_ZERO)
Definition gmp.stub.php:91
gmp_prob_prime(GMP|int|string $num, int $repetitions=10)
Definition gmp.stub.php:132
gmp_div_qr(GMP|int|string $num1, GMP|int|string $num2, int $rounding_mode=GMP_ROUND_ZERO)
Definition gmp.stub.php:89
gmp_gcd(GMP|int|string $num1, GMP|int|string $num2)
Definition gmp.stub.php:134
gmp_export(GMP|int|string $num, int $word_size=1, int $flags=GMP_MSW_FIRST|GMP_NATIVE_ENDIAN)
Definition gmp.stub.php:73
gmp_mul(GMP|int|string $num1, GMP|int|string $num2)
Definition gmp.stub.php:83
gmp_sign(GMP|int|string $num)
Definition gmp.stub.php:154
gmp_scan0(GMP|int|string $num1, int $start)
Definition gmp.stub.php:176
gmp_mod(GMP|int|string $num1, GMP|int|string $num2)
Definition gmp.stub.php:98
gmp_setbit(GMP $num, int $index, bool $value=true)
Definition gmp.stub.php:170
gmp_sub(GMP|int|string $num1, GMP|int|string $num2)
Definition gmp.stub.php:81
gmp_powm(GMP|int|string $num, GMP|int|string $exponent, GMP|int|string $modulus)
Definition gmp.stub.php:126
gmp_jacobi(GMP|int|string $num1, GMP|int|string $num2)
Definition gmp.stub.php:146
gmp_kronecker(GMP|int|string $num1, GMP|int|string $num2)
Definition gmp.stub.php:150
gmp_binomial(GMP|int|string $n, int $k)
Definition gmp.stub.php:186
gmp_clrbit(GMP $num, int $index)
Definition gmp.stub.php:172
gmp_lcm(GMP|int|string $num1, GMP|int|string $num2)
Definition gmp.stub.php:142
gmp_abs(GMP|int|string $num)
Definition gmp.stub.php:104
gmp_add(GMP|int|string $num1, GMP|int|string $num2)
Definition gmp.stub.php:79
gmp_and(GMP|int|string $num1, GMP|int|string $num2)
Definition gmp.stub.php:162
gmp_sqrt(GMP|int|string $num)
Definition gmp.stub.php:108
gmp_intval(GMP|int|string $num)
Definition gmp.stub.php:75
gmp_invert(GMP|int|string $num1, GMP|int|string $num2)
Definition gmp.stub.php:144
gmp_xor(GMP|int|string $num1, GMP|int|string $num2)
Definition gmp.stub.php:168
gmp_root(GMP|int|string $num, int $nth)
Definition gmp.stub.php:116
gmp_import(string $data, int $word_size=1, int $flags=GMP_MSW_FIRST|GMP_NATIVE_ENDIAN)
Definition gmp.stub.php:71
gmp_fact(GMP|int|string $num)
Definition gmp.stub.php:106
gmp_or(GMP|int|string $num1, GMP|int|string $num2)
Definition gmp.stub.php:164
gmp_perfect_square(GMP|int|string $num)
Definition gmp.stub.php:128
gmp_div_r(GMP|int|string $num1, GMP|int|string $num2, int $rounding_mode=GMP_ROUND_ZERO)
Definition gmp.stub.php:93
gmp_testbit(GMP|int|string $num, int $index)
Definition gmp.stub.php:174
gmp_random_range(GMP|int|string $min, GMP|int|string $max)
Definition gmp.stub.php:160
gmp_random_seed(GMP|int|string $seed)
Definition gmp.stub.php:156
gmp_pow(GMP|int|string $num, int $exponent)
Definition gmp.stub.php:124
gmp_rootrem(GMP|int|string $num, int $nth)
Definition gmp.stub.php:122
gmp_perfect_power(GMP|int|string $num)
Definition gmp.stub.php:130
gmp_neg(GMP|int|string $num)
Definition gmp.stub.php:102
gmp_gcdext(GMP|int|string $num1, GMP|int|string $num2)
Definition gmp.stub.php:140
#define round(tables, k1, k2)
Definition hash_gost.c:26
#define SUCCESS
Definition hash_sha3.c:261
php_info_print_table_start()
Definition info.c:1064
php_info_print_table_row(2, "PDO Driver for Firebird", "enabled")
php_info_print_table_end()
Definition info.c:1074
#define INT_MAX
Definition php.h:237
gmp_randstate_t rand_state
Definition php_gmp.h:34
#define PHP_GMP_VERSION
Definition php_gmp.h:26
#define GMPG(v)
Definition php_gmp.h:37
bool rand_initialized
Definition php_gmp.h:33
long gmp_long
Definition php_gmp_int.h:37
unsigned long gmp_ulong
Definition php_gmp_int.h:38
struct _gmp_object gmp_object
#define PHP_GMP_API
Definition php_gmp_int.h:18
PHP_JSON_API size_t int options
Definition php_json.h:102
PHPAPI uint64_t php_random_generate_fallback_seed(void)
Definition random.c:716
#define PHP_VAR_UNSERIALIZE_DESTROY(d)
Definition php_var.h:59
struct php_unserialize_data * php_unserialize_data_t
Definition php_var.h:32
struct php_serialize_data * php_serialize_data_t
Definition php_var.h:31
#define PHP_VAR_UNSERIALIZE_INIT(d)
Definition php_var.h:56
PHPAPI zval * var_tmp_var(php_unserialize_data_t *var_hashx)
PHPAPI int php_var_unserialize(zval *rval, const unsigned char **p, const unsigned char *max, php_unserialize_data_t *var_hash)
#define PHP_VAR_SERIALIZE_INIT(d)
Definition php_var.h:50
PHPAPI void php_var_serialize(smart_str *buf, zval *struc, php_serialize_data_t *data)
Definition var.c:1319
#define PHP_VAR_SERIALIZE_DESTROY(d)
Definition php_var.h:53
zend_constant * data
p
Definition session.c:1105
zend_object std
Definition php_gmp_int.h:23
bool is_used
Definition gmp.c:94
mpz_t num
Definition gmp.c:93
zend_class_entry * ce
Definition zend_types.h:560
Definition file.h:177
$obj a
Definition test.php:84
ZEND_API ZEND_COLD void zend_throw_error(zend_class_entry *exception_ce, const char *format,...)
Definition zend.c:1772
ZEND_API ZEND_COLD void zend_type_error(const char *format,...)
Definition zend.c:1824
ZEND_API ZEND_COLD void zend_value_error(const char *format,...)
Definition zend.c:1849
#define ZEND_TSRMLS_CACHE_UPDATE()
Definition zend.h:69
struct _zend_unserialize_data zend_unserialize_data
Definition zend.h:83
#define INTERNAL_FUNCTION_PARAMETERS
Definition zend.h:49
#define ZEND_TSRMLS_CACHE_DEFINE()
Definition zend.h:68
struct _zend_serialize_data zend_serialize_data
Definition zend.h:82
ZEND_API const char * zend_zval_value_name(const zval *arg)
Definition zend_API.c:148
ZEND_API const char * zend_zval_type_name(const zval *arg)
Definition zend_API.c:167
ZEND_API bool ZEND_FASTCALL zend_parse_arg_long_slow(const zval *arg, zend_long *dest, uint32_t arg_num)
Definition zend_API.c:627
ZEND_API zend_result zend_parse_parameters(uint32_t num_args, const char *type_spec,...)
Definition zend_API.c:1300
ZEND_API void object_properties_init(zend_object *object, zend_class_entry *class_type)
Definition zend_API.c:1688
ZEND_API ZEND_COLD void zend_argument_value_error(uint32_t arg_num, const char *format,...)
Definition zend_API.c:433
ZEND_API ZEND_COLD void zend_argument_type_error(uint32_t arg_num, const char *format,...)
Definition zend_API.c:423
ZEND_API void object_properties_load(zend_object *object, HashTable *properties)
Definition zend_API.c:1728
#define ZEND_NUM_ARGS()
Definition zend_API.h:530
#define ZEND_PARSE_PARAMETERS_END()
Definition zend_API.h:1641
#define RETURN_FALSE
Definition zend_API.h:1058
#define ZEND_PARSE_PARAMETERS_NONE()
Definition zend_API.h:1623
#define ZEND_MINIT_FUNCTION
Definition zend_API.h:1074
#define ZEND_DECLARE_MODULE_GLOBALS(module_name)
Definition zend_API.h:268
#define RETVAL_NEW_STR(s)
Definition zend_API.h:1015
#define Z_PARAM_OPTIONAL
Definition zend_API.h:1667
#define ZEND_MODULE_INFO_D(module)
Definition zend_API.h:237
#define ZEND_GET_MODULE(name)
Definition zend_API.h:241
#define ZEND_PARSE_PARAMETERS_START(min_num_args, max_num_args)
Definition zend_API.h:1620
#define ZEND_MODULE_INFO_N(module)
Definition zend_API.h:227
#define RETVAL_EMPTY_STRING()
Definition zend_API.h:1021
#define Z_PARAM_LONG(dest)
Definition zend_API.h:1896
#define RETURN_LONG(l)
Definition zend_API.h:1037
#define ZEND_MODULE_DEACTIVATE_N(module)
Definition zend_API.h:225
#define ZEND_METHOD(classname, name)
Definition zend_API.h:76
#define RETURN_THROWS()
Definition zend_API.h:1060
#define Z_PARAM_ARRAY_HT(dest)
Definition zend_API.h:1852
#define ZEND_THIS
Definition zend_API.h:523
#define RETVAL_BOOL(b)
Definition zend_API.h:1009
#define ZEND_GINIT(module)
Definition zend_API.h:1071
#define ZEND_MODULE_DEACTIVATE_D(module)
Definition zend_API.h:235
#define Z_PARAM_STR_OR_LONG(dest_str, dest_long)
Definition zend_API.h:2165
#define RETVAL_LONG(l)
Definition zend_API.h:1011
#define ZEND_GINIT_FUNCTION
Definition zend_API.h:1079
#define ZEND_FUNCTION(name)
Definition zend_API.h:75
#define ZEND_MODULE_STARTUP_N(module)
Definition zend_API.h:222
#define array_init(arg)
Definition zend_API.h:537
#define estrndup(s, length)
Definition zend_alloc.h:165
#define emalloc(size)
Definition zend_alloc.h:151
struct _zval_struct zval
exit(string|int $status=0)
zend_string_release_ex(func->internal_function.function_name, 0)
ZEND_API zend_class_entry * zend_ce_value_error
ZEND_API ZEND_COLD zend_object * zend_throw_exception(zend_class_entry *exception_ce, const char *message, zend_long code)
ZEND_API zend_class_entry * zend_ce_division_by_zero_error
ZEND_API ZEND_COLD zend_object * zend_throw_exception_ex(zend_class_entry *exception_ce, zend_long code, const char *format,...)
ZEND_API void(ZEND_FASTCALL *zend_touch_vm_stack_data)(void *vm_stack_data)
#define EG(v)
ZEND_API HashTable *ZEND_FASTCALL zend_proptable_to_symtable(HashTable *ht, bool always_duplicate)
Definition zend_hash.c:3387
ZEND_API zval *ZEND_FASTCALL zend_hash_next_index_insert(HashTable *ht, zval *pData)
Definition zend_hash.c:1224
ZEND_API zval *ZEND_FASTCALL zend_hash_str_update(HashTable *ht, const char *str, size_t len, zval *pData)
Definition zend_hash.c:1031
ZEND_API void ZEND_FASTCALL zend_hash_copy(HashTable *target, HashTable *source, copy_ctor_func_t pCopyConstructor)
Definition zend_hash.c:2240
ZEND_API HashTable *ZEND_FASTCALL zend_array_dup(HashTable *source)
Definition zend_hash.c:2438
ZEND_API zval *ZEND_FASTCALL zend_hash_index_find(const HashTable *ht, zend_ulong h)
Definition zend_hash.c:2701
int32_t zend_long
Definition zend_long.h:42
uint32_t zend_ulong
Definition zend_long.h:43
#define ZEND_LONG_FMT
Definition zend_long.h:87
#define ZEND_LONG_MAX
Definition zend_long.h:45
struct _zend_string zend_string
#define STANDARD_MODULE_HEADER
#define ZEND_MODULE_GLOBALS(module_name)
struct _zend_module_entry zend_module_entry
#define STANDARD_MODULE_PROPERTIES_EX
ZEND_API HashTable * zend_std_get_properties(zend_object *zobj)
ZEND_API const zend_object_handlers std_object_handlers
ZEND_API void ZEND_FASTCALL zend_objects_clone_members(zend_object *new_object, zend_object *old_object)
ZEND_API void ZEND_FASTCALL zend_object_std_init(zend_object *object, zend_class_entry *ce)
ZEND_API void zend_object_std_dtor(zend_object *object)
ZEND_API uint8_t ZEND_FASTCALL is_numeric_str_function(const zend_string *str, zend_long *lval, double *dval)
#define ZEND_FALLTHROUGH
#define XtOffsetOf(s_type, field)
#define ZEND_ASSERT(c)
#define EMPTY_SWITCH_DEFAULT_CASE()
#define UNEXPECTED(condition)
struct _zend_class_entry zend_class_entry
struct _zend_object zend_object
#define ZSTR_VAL(zstr)
Definition zend_string.h:68
#define ZSTR_LEN(zstr)
Definition zend_string.h:69
#define Z_TYPE_P(zval_p)
Definition zend_types.h:660
#define ZVAL_UNDEF(z)
#define Z_ARRVAL_P(zval_p)
Definition zend_types.h:987
#define ZVAL_LONG(z, l)
#define IS_STRING
Definition zend_types.h:606
struct _zend_array HashTable
Definition zend_types.h:386
#define Z_OBJ_P(zval_p)
Definition zend_types.h:990
#define IS_ARRAY
Definition zend_types.h:607
#define IS_DOUBLE
Definition zend_types.h:605
#define Z_STR_P(zval_p)
Definition zend_types.h:972
#define IS_NULL
Definition zend_types.h:601
#define ZVAL_OBJ(z, o)
@ FAILURE
Definition zend_types.h:61
#define IS_LONG
Definition zend_types.h:604
#define ZVAL_ARR(z, a)
void(* copy_ctor_func_t)(zval *pElement)
Definition zend_types.h:108
#define ZVAL_NEW_STR(z, s)
#define _IS_BOOL
Definition zend_types.h:629
#define ZVAL_DOUBLE(z, d)
ZEND_RESULT_CODE zend_result
Definition zend_types.h:64
#define _IS_NUMBER
Definition zend_types.h:630
struct _zend_object_handlers zend_object_handlers
Definition zend_types.h:88
#define Z_TYPE(zval)
Definition zend_types.h:659
#define Z_LVAL_P(zval_p)
Definition zend_types.h:966
#define ZVAL_COPY_VALUE(z, v)
#define ZVAL_BOOL(z, b)
#define Z_LVAL(zval)
Definition zend_types.h:965
ZEND_API void zval_ptr_dtor(zval *zval_ptr)
ZEND_API void zval_add_ref(zval *p)
zval retval
zval * return_value
uint32_t arg_num
bool result
op2
op1
zend_object * zobj
#define ZEND_SL
#define ZEND_POW
#define ZEND_SUB
#define ZEND_BW_XOR
#define ZEND_DIV
#define ZEND_BW_OR
#define ZEND_MUL
#define ZEND_BW_NOT
#define ZEND_BW_AND
#define ZEND_SR
#define ZEND_MOD
#define ZEND_ADD