LCOV - code coverage report
Current view: top level - /ext - colopl_bc_php70.c (source / functions) Coverage Total Hit
Test: Extension code coverage Lines: 78.6 % 276 217
Test Date: 2026-05-18 07:06:36 Functions: 88.9 % 27 24

            Line data    Source code
       1              : /*
       2              :   +----------------------------------------------------------------------+
       3              :   | COLOPL PHP Backwards Compatibility Extension.                        |
       4              :   +----------------------------------------------------------------------+
       5              :   | Copyright (c) COLOPL, Inc.                                           |
       6              :   +----------------------------------------------------------------------+
       7              :   | This source file is subject to the BSD-3-Clause license that is      |
       8              :   | bundled with this package in the file LICENSE.                       |
       9              :   +----------------------------------------------------------------------+
      10              :   | Author: Go Kudo <g-kudo@colopl.co.jp>                                |
      11              :   +----------------------------------------------------------------------+
      12              : */
      13              : 
      14              : #ifdef HAVE_CONFIG_H
      15              : # include "config.h"
      16              : #endif
      17              : 
      18              : #include "php_colopl_bc.h"
      19              : 
      20              : #include "ext/date/php_date.h"
      21              : #include "zend_bitset.h"
      22              : 
      23              : #ifndef RAND_MAX
      24              : # define RAND_MAX (1 << 15)
      25              : #endif
      26              : 
      27              : #if !defined(ZTS) && (defined(HAVE_LRAND48) || defined(HAVE_RANDOM))
      28              : enum {
      29              :         COLOPL_BC_RAND_MAX_VALUE = 2147483647,
      30              :         COLOPL_BC_MT_M = 397,
      31              :         COLOPL_BC_MT_RAND_MAX_VALUE = 0x7FFFFFFF
      32              : };
      33              : #else
      34              : enum {
      35              :         COLOPL_BC_RAND_MAX_VALUE = RAND_MAX,
      36              :         COLOPL_BC_MT_M = 397,
      37              :         COLOPL_BC_MT_RAND_MAX_VALUE = 0x7FFFFFFF
      38              : };
      39              : #endif
      40              : 
      41              : /* Emulate gcc + amd64 undefined behavior results. */
      42      6406256 : static inline zend_long php_colopl_bc_float_to_long_amd64(zend_long min, double value)
      43              : {
      44      6406256 :         if (value > ((double) ZEND_LONG_MAX) || value < ((double) ZEND_LONG_MIN)) {
      45       800766 :                 return 0;
      46              :         }
      47              : 
      48      5605490 :         return min + (zend_long) value;
      49              : }
      50              : 
      51      6406256 : static inline zend_long php_colopl_bc_rand_range(zend_long number, zend_long min, zend_long max, zend_long rand_max)
      52              : {
      53     12812512 :         return php_colopl_bc_float_to_long_amd64(
      54              :                 min,
      55      6406256 :                 ((double) max - (double) min + 1.0) * ((double) number / ((double) rand_max + 1.0))
      56              :         );
      57              : }
      58              : 
      59            0 : static inline zend_long php_colopl_bc_generate_seed(void)
      60              : {
      61              : #ifdef PHP_WIN32
      62              :         return (((zend_long) (time(0) * GetCurrentProcessId())) ^ ((zend_long) (1000000.0 * php_combined_lcg())));
      63              : #else
      64            0 :         return (((zend_long) (time(0) * getpid())) ^ ((zend_long) (1000000.0 * php_combined_lcg())));
      65              : #endif
      66              : }
      67              : 
      68      3217344 : static inline uint32_t php_colopl_bc_mt_hi_bit(uint32_t value)
      69              : {
      70      3217344 :         return value & 0x80000000U;
      71              : }
      72              : 
      73      3217344 : static inline uint32_t php_colopl_bc_mt_lo_bit(uint32_t value)
      74              : {
      75      3217344 :         return value & 0x00000001U;
      76              : }
      77              : 
      78      3217344 : static inline uint32_t php_colopl_bc_mt_lo_bits(uint32_t value)
      79              : {
      80      3217344 :         return value & 0x7FFFFFFFU;
      81              : }
      82              : 
      83      3217344 : static inline uint32_t php_colopl_bc_mt_mix_bits(uint32_t left, uint32_t right)
      84              : {
      85      3217344 :         return php_colopl_bc_mt_hi_bit(left) | php_colopl_bc_mt_lo_bits(right);
      86              : }
      87              : 
      88      3217344 : static inline uint32_t php_colopl_bc_mt_twist(uint32_t m, uint32_t u, uint32_t v)
      89              : {
      90      3217344 :         return m ^ (php_colopl_bc_mt_mix_bits(u, v) >> 1) ^ ((uint32_t) (-(uint32_t) php_colopl_bc_mt_lo_bit(u)) & 0x9908b0dfU);
      91              : }
      92              : 
      93              : /* rand.c */
      94              : 
      95              : #if defined(__clang__)
      96              : __attribute__((no_sanitize("signed-integer-overflow")))
      97              : #endif
      98           48 : void php_colopl_bc_srand(zend_long seed)
      99              : {
     100              : #ifdef ZTS
     101           22 :         COLOPL_BC_G(rand_seed) = (uint32_t) seed;
     102              : #else
     103           26 :         uint32_t s = (uint32_t) seed;
     104           26 :         int i = 0;
     105              : 
     106           26 :         if (s == 0) {
     107            6 :                 s = 1;
     108              :         }
     109              : 
     110           26 :         COLOPL_BC_G(gnurandom_r)[0] = s;
     111          806 :         for (i = 1; i < 31; i++) {
     112          780 :                 COLOPL_BC_G(gnurandom_r)[i] = (16807LL * COLOPL_BC_G(gnurandom_r)[i - 1]) % 2147483647;
     113          780 :                 if (COLOPL_BC_G(gnurandom_r)[i] < 0) {
     114            2 :                         COLOPL_BC_G(gnurandom_r)[i] += 2147483647;
     115              :                 }
     116              :         }
     117          104 :         for (i = 31; i < 34; i++) {
     118           78 :                 COLOPL_BC_G(gnurandom_r)[i] = COLOPL_BC_G(gnurandom_r)[i - 31];
     119              :         }
     120         8086 :         for (i = 34; i < 344; i++) {
     121         8060 :                 COLOPL_BC_G(gnurandom_r)[i] = COLOPL_BC_G(gnurandom_r)[i - 31] + COLOPL_BC_G(gnurandom_r)[i - 3];
     122              :         }
     123              : 
     124           26 :         COLOPL_BC_G(gnurandom_next) = 0;
     125              : #endif
     126           48 :         COLOPL_BC_G(rand_is_seeded) = 1;
     127           48 : }
     128              : 
     129              : #if defined(__clang__)
     130              : __attribute__((no_sanitize("signed-integer-overflow")))
     131              : #endif
     132      3204234 : zend_long php_colopl_bc_rand(void)
     133              : {
     134              :         zend_long ret;
     135              : 
     136      3204234 :         if (!COLOPL_BC_G(rand_is_seeded)) {
     137            0 :                 php_colopl_bc_srand(php_colopl_bc_generate_seed());
     138              :         }
     139              : 
     140              : #ifdef ZTS
     141      1601096 :         uint32_t next = COLOPL_BC_G(rand_seed);
     142              : 
     143      1601096 :         next = (next * 1103515245) + 12345;
     144      1601096 :         ret = (uint32_t) (next / 65536) % 2048;
     145              : 
     146      1601096 :         next = (next * 1103515245) + 12345;
     147      1601096 :         ret <<= 10;
     148      1601096 :         ret ^= (uint32_t) (next / 65536) % 1024;
     149              : 
     150      1601096 :         next = (next * 1103515245) + 12345;
     151      1601096 :         ret <<= 10;
     152      1601096 :         ret ^= (uint32_t) (next / 65536) % 1024;
     153              : 
     154      1601096 :         COLOPL_BC_G(rand_seed) = next;
     155              : #else
     156      1603138 :         COLOPL_BC_G(gnurandom_r)[COLOPL_BC_G(gnurandom_next) % 344] = COLOPL_BC_G(gnurandom_r)[(COLOPL_BC_G(gnurandom_next) + 313) % 344] + COLOPL_BC_G(gnurandom_r)[(COLOPL_BC_G(gnurandom_next) + 341) % 344];
     157      1603138 :         ret = ((uint32_t) COLOPL_BC_G(gnurandom_r)[COLOPL_BC_G(gnurandom_next) % 344] >> 1);
     158      1603138 :         COLOPL_BC_G(gnurandom_next) = (COLOPL_BC_G(gnurandom_next) + 1) % 344;
     159              : #endif
     160      3204234 :         return (zend_long) ret;
     161              : }
     162              : 
     163           48 : PHP_FUNCTION(Colopl_ColoplBc_Php70_srand)
     164              : {
     165           48 :         zend_long seed = 0;
     166              : 
     167           48 :         ZEND_PARSE_PARAMETERS_START(0, 1)
     168           48 :                 Z_PARAM_OPTIONAL
     169           48 :                 Z_PARAM_LONG(seed)
     170           48 :         ZEND_PARSE_PARAMETERS_END();
     171              : 
     172           48 :         if (ZEND_NUM_ARGS() == 0) {
     173            0 :                 seed = php_colopl_bc_generate_seed();
     174              :         }
     175              : 
     176           48 :         php_colopl_bc_srand(seed);
     177              : }
     178              : 
     179      3202044 : PHP_FUNCTION(Colopl_ColoplBc_Php70_rand)
     180              : {
     181              :         zend_long min, max, number;
     182              :         int argc;
     183              : 
     184      3202044 :         number = php_colopl_bc_rand();
     185      3202044 :         argc = ZEND_NUM_ARGS();
     186              : 
     187      3202044 :         if (argc == 0) {
     188            0 :                 RETURN_LONG(number);
     189              :         }
     190              : 
     191      3202044 :         ZEND_PARSE_PARAMETERS_START(2, 2)
     192      3202044 :                 Z_PARAM_LONG(min)
     193      3202044 :                 Z_PARAM_LONG(max)
     194      3202044 :         ZEND_PARSE_PARAMETERS_END();
     195              : 
     196      3202044 :         number = php_colopl_bc_rand_range(number, min, max, COLOPL_BC_RAND_MAX_VALUE);
     197      3202044 :         RETURN_LONG(number);
     198              : }
     199              : 
     200            0 : PHP_FUNCTION(Colopl_ColoplBc_Php70_getrandmax)
     201              : {
     202            0 :         ZEND_PARSE_PARAMETERS_NONE();
     203              : 
     204            0 :         RETURN_LONG(COLOPL_BC_RAND_MAX_VALUE);
     205              : }
     206              : 
     207              : /* mt_rand.c */
     208              : 
     209           36 : static inline void mt_initialize(uint32_t seed, uint32_t *state)
     210              : {
     211           36 :         register uint32_t *s = state;
     212           36 :         register uint32_t *r = state;
     213           36 :         register int i = 1;
     214              : 
     215           36 :         *s++ = seed & 0xffffffffU;
     216        22464 :         for (; i < COLOPL_BC_MT_N; ++i) {
     217        22428 :                 *s++ = ( 1812433253U * ( *r ^ (*r >> 30) ) + i ) & 0xffffffffU;
     218        22428 :                 r++;
     219              :         }
     220           36 : }
     221              : 
     222         5156 : static inline void mt_reload(void)
     223              : {
     224         5156 :         register uint32_t *state = COLOPL_BC_G(mt_state);
     225         5156 :         register uint32_t *p = state;
     226              :         register int i;
     227              : 
     228      1175568 :         for (i = COLOPL_BC_MT_N - COLOPL_BC_MT_M; i--; ++p) {
     229      1170412 :                 *p = php_colopl_bc_mt_twist(p[COLOPL_BC_MT_M], p[0], p[1]);
     230              :         }
     231      2046932 :         for (i = COLOPL_BC_MT_M; --i; ++p) {
     232      2041776 :                 *p = php_colopl_bc_mt_twist(p[COLOPL_BC_MT_M - COLOPL_BC_MT_N], p[0], p[1]);
     233              :         }
     234         5156 :         *p = php_colopl_bc_mt_twist(p[COLOPL_BC_MT_M - COLOPL_BC_MT_N], p[0], state[0]);
     235         5156 :         COLOPL_BC_G(mt_left) = COLOPL_BC_MT_N;
     236         5156 :         COLOPL_BC_G(mt_next) = state;
     237         5156 : }
     238              : 
     239           36 : void php_colopl_bc_mt_srand(uint32_t seed)
     240              : {
     241           36 :         mt_initialize(seed, COLOPL_BC_G(mt_state));
     242           36 :         mt_reload();
     243              : 
     244           36 :         COLOPL_BC_G(mt_rand_is_seeded) = 1;
     245           36 : }
     246              : 
     247      3202040 : uint32_t php_colopl_bc_mt_rand(void)
     248              : {
     249              :         register uint32_t s1;
     250              : 
     251      3202040 :         if (COLOPL_BC_G(mt_left) == 0) {
     252         5120 :                 mt_reload();
     253              :         }
     254      3202040 :         --COLOPL_BC_G(mt_left);
     255              : 
     256      3202040 :         s1 = *COLOPL_BC_G(mt_next)++;
     257      3202040 :         s1 ^= (s1 >> 11);
     258      3202040 :         s1 ^= (s1 <<  7) & 0x9d2c5680U;
     259      3202040 :         s1 ^= (s1 << 15) & 0xefc60000U;
     260      3202040 :         return ( s1 ^ (s1 >> 18) );
     261              : }
     262              : 
     263           36 : PHP_FUNCTION(Colopl_ColoplBc_Php70_mt_srand)
     264              : {
     265           36 :         zend_long seed = 0;
     266              : 
     267           36 :         ZEND_PARSE_PARAMETERS_START(0, 1)
     268           36 :                 Z_PARAM_OPTIONAL
     269           36 :                 Z_PARAM_LONG(seed)
     270           36 :         ZEND_PARSE_PARAMETERS_END();
     271              : 
     272           36 :         if (ZEND_NUM_ARGS() == 0) {
     273            0 :                 seed = php_colopl_bc_generate_seed();
     274              :         }
     275              : 
     276           36 :         php_colopl_bc_mt_srand((uint32_t) seed);
     277              : }
     278              : 
     279      3202040 : PHP_FUNCTION(Colopl_ColoplBc_Php70_mt_rand)
     280              : {
     281              :         zend_long min, max, number;
     282      3202040 :         int argc = ZEND_NUM_ARGS();
     283              : 
     284      3202040 :         if (argc == 0) {
     285            0 :                 if (!COLOPL_BC_G(mt_rand_is_seeded)) {
     286            0 :                         php_colopl_bc_mt_srand(php_colopl_bc_generate_seed());
     287              :                 }
     288            0 :                 RETURN_LONG(php_colopl_bc_mt_rand() >> 1);
     289              :         }
     290              : 
     291      3202040 :         ZEND_PARSE_PARAMETERS_START(2, 2)
     292      3202040 :                 Z_PARAM_LONG(min)
     293      3202040 :                 Z_PARAM_LONG(max)
     294      3202040 :         ZEND_PARSE_PARAMETERS_END();
     295              : 
     296      3202040 :         if (UNEXPECTED(max < min)) {
     297            0 :                 zend_argument_value_error(2, "must be greater than or equal to argument #1 ($min)");
     298            0 :                 RETURN_THROWS();
     299              :         }
     300              : 
     301      3202040 :         if (!COLOPL_BC_G(mt_rand_is_seeded)) {
     302            0 :                 php_colopl_bc_mt_srand(php_colopl_bc_generate_seed());
     303              :         }
     304              : 
     305      3202040 :         number = (zend_long) (php_colopl_bc_mt_rand() >> 1);
     306      3202040 :         number = php_colopl_bc_rand_range(number, min, max, COLOPL_BC_MT_RAND_MAX_VALUE);
     307      3202040 :         RETURN_LONG(number);
     308              : }
     309              : 
     310            0 : PHP_FUNCTION(Colopl_ColoplBc_Php70_mt_getrandmax)
     311              : {
     312            0 :         ZEND_PARSE_PARAMETERS_NONE();
     313              : 
     314            0 :         RETURN_LONG(COLOPL_BC_MT_RAND_MAX_VALUE);
     315              : }
     316              : 
     317              : /* array.c */
     318              : 
     319              : #if PHP_VERSION_ID < 80200
     320              : void php_colopl_bc_array_data_shuffle(zval *array)
     321              : {
     322              :         uint32_t idx, j, n_elems;
     323              :         Bucket *p, temp;
     324              :         HashTable *hash;
     325              :         zend_long rnd_idx;
     326              :         uint32_t n_left;
     327              : 
     328              :         n_elems = zend_hash_num_elements(Z_ARRVAL_P(array));
     329              : 
     330              :         if (n_elems < 1) {
     331              :                 return;
     332              :         }
     333              : 
     334              :         hash = Z_ARRVAL_P(array);
     335              :         n_left = n_elems;
     336              : 
     337              :         if (EXPECTED(hash->u.v.nIteratorsCount == 0)) {
     338              :                 if (hash->nNumUsed != hash->nNumOfElements) {
     339              :                         for (j = 0, idx = 0; idx < hash->nNumUsed; idx++) {
     340              :                                 p = hash->arData + idx;
     341              :                                 if (Z_TYPE(p->val) == IS_UNDEF) continue;
     342              :                                 if (j != idx) {
     343              :                                         hash->arData[j] = *p;
     344              :                                 }
     345              :                                 j++;
     346              :                         }
     347              :                 }
     348              :                 while (--n_left) {
     349              :                         rnd_idx = php_colopl_bc_rand();
     350              :                         rnd_idx = php_colopl_bc_rand_range(rnd_idx, 0, n_left, COLOPL_BC_RAND_MAX_VALUE);
     351              :                         if (rnd_idx != n_left) {
     352              :                                 temp = hash->arData[n_left];
     353              :                                 hash->arData[n_left] = hash->arData[rnd_idx];
     354              :                                 hash->arData[rnd_idx] = temp;
     355              :                         }
     356              :                 }
     357              :         } else {
     358              :                 uint32_t iter_pos = zend_hash_iterators_lower_pos(hash, 0);
     359              : 
     360              :                 if (hash->nNumUsed != hash->nNumOfElements) {
     361              :                         for (j = 0, idx = 0; idx < hash->nNumUsed; idx++) {
     362              :                                 p = hash->arData + idx;
     363              :                                 if (Z_TYPE(p->val) == IS_UNDEF) continue;
     364              :                                 if (j != idx) {
     365              :                                         hash->arData[j] = *p;
     366              :                                         if (idx == iter_pos) {
     367              :                                                 zend_hash_iterators_update(hash, idx, j);
     368              :                                                 iter_pos = zend_hash_iterators_lower_pos(hash, iter_pos + 1);
     369              :                                         }
     370              :                                 }
     371              :                                 j++;
     372              :                         }
     373              :                 }
     374              :                 while (--n_left) {
     375              :                         rnd_idx = php_colopl_bc_rand();
     376              :                         rnd_idx = php_colopl_bc_rand_range(rnd_idx, 0, n_left, COLOPL_BC_RAND_MAX_VALUE);
     377              :                         if (rnd_idx != n_left) {
     378              :                                 temp = hash->arData[n_left];
     379              :                                 hash->arData[n_left] = hash->arData[rnd_idx];
     380              :                                 hash->arData[rnd_idx] = temp;
     381              :                                 zend_hash_iterators_update(hash, (uint32_t)rnd_idx, n_left);
     382              :                         }
     383              :                 }
     384              :         }
     385              :         HANDLE_BLOCK_INTERRUPTIONS();
     386              :         hash->nNumUsed = n_elems;
     387              :         hash->nInternalPointer = 0;
     388              : 
     389              :         for (j = 0; j < n_elems; j++) {
     390              :                 p = hash->arData + j;
     391              :                 if (p->key) {
     392              :                         zend_string_release(p->key);
     393              :                 }
     394              :                 p->h = j;
     395              :                 p->key = NULL;
     396              :         }
     397              :         hash->nNextFreeElement = n_elems;
     398              :         if (!(hash->u.flags & HASH_FLAG_PACKED)) {
     399              :                 zend_hash_to_packed(hash);
     400              :         }
     401              :         HANDLE_UNBLOCK_INTERRUPTIONS();
     402              : }
     403              : #else
     404            4 : void php_colopl_bc_array_data_shuffle(zval *array)
     405              : {
     406              :         int64_t idx, j, n_elems, rnd_idx, n_left;
     407              :         zval *zv, temp;
     408              :         HashTable *hash;
     409              : 
     410            4 :         n_elems = zend_hash_num_elements(Z_ARRVAL_P(array));
     411              : 
     412            4 :         if (n_elems < 1) {
     413            0 :                 return;
     414              :         }
     415              : 
     416            4 :         hash = Z_ARRVAL_P(array);
     417            4 :         n_left = n_elems;
     418              : 
     419            4 :         if (!HT_IS_PACKED(hash)) {
     420            0 :                 if (!HT_HAS_STATIC_KEYS_ONLY(hash)) {
     421            0 :                         Bucket *p = hash->arData;
     422            0 :                         zend_long i = hash->nNumUsed;
     423              : 
     424            0 :                         for (; i > 0; p++, i--) {
     425            0 :                                 if (p->key) {
     426            0 :                                         zend_string_release(p->key);
     427            0 :                                         p->key = NULL;
     428              :                                 }
     429              :                         }
     430              :                 }
     431            0 :                 zend_hash_to_packed(hash);
     432              :         }
     433              : 
     434            4 :         if (EXPECTED(!HT_HAS_ITERATORS(hash))) {
     435            4 :                 if (hash->nNumUsed != hash->nNumOfElements) {
     436            0 :                         for (j = 0, idx = 0; idx < hash->nNumUsed; idx++) {
     437            0 :                                 zv = hash->arPacked + idx;
     438            0 :                                 if (Z_TYPE_P(zv) == IS_UNDEF) continue;
     439            0 :                                 if (j != idx) {
     440            0 :                                         ZVAL_COPY_VALUE(&hash->arPacked[j], zv);
     441              :                                 }
     442            0 :                                 j++;
     443              :                         }
     444              :                 }
     445          400 :                 while (--n_left) {
     446          396 :                         rnd_idx = php_colopl_bc_rand();
     447          396 :                         rnd_idx = php_colopl_bc_rand_range(rnd_idx, 0, n_left, COLOPL_BC_RAND_MAX_VALUE);
     448          396 :                         if (rnd_idx != n_left) {
     449          370 :                                 ZVAL_COPY_VALUE(&temp, &hash->arPacked[n_left]);
     450          370 :                                 ZVAL_COPY_VALUE(&hash->arPacked[n_left], &hash->arPacked[rnd_idx]);
     451          370 :                                 ZVAL_COPY_VALUE(&hash->arPacked[rnd_idx], &temp);
     452              :                         }
     453              :                 }
     454              :         } else {
     455            0 :                 zend_long iter_pos = zend_hash_iterators_lower_pos(hash, 0);
     456              : 
     457            0 :                 if (hash->nNumUsed != hash->nNumOfElements) {
     458            0 :                         for (j = 0, idx = 0; idx < hash->nNumUsed; idx++) {
     459            0 :                                 zv = hash->arPacked + idx;
     460            0 :                                 if (Z_TYPE_P(zv) == IS_UNDEF) continue;
     461            0 :                                 if (j != idx) {
     462            0 :                                         ZVAL_COPY_VALUE(&hash->arPacked[j], zv);
     463            0 :                                         if (idx == iter_pos) {
     464            0 :                                                 zend_hash_iterators_update(hash, idx, j);
     465            0 :                                                 iter_pos = zend_hash_iterators_lower_pos(hash, iter_pos + 1);
     466              :                                         }
     467              :                                 }
     468            0 :                                 j++;
     469              :                         }
     470              :                 }
     471            0 :                 while (--n_left) {
     472            0 :                         rnd_idx = php_colopl_bc_rand();
     473            0 :                         rnd_idx = php_colopl_bc_rand_range(rnd_idx, 0, n_left, COLOPL_BC_RAND_MAX_VALUE);
     474            0 :                         if (rnd_idx != n_left) {
     475            0 :                                 ZVAL_COPY_VALUE(&temp, &hash->arPacked[n_left]);
     476            0 :                                 ZVAL_COPY_VALUE(&hash->arPacked[n_left], &hash->arPacked[rnd_idx]);
     477            0 :                                 ZVAL_COPY_VALUE(&hash->arPacked[rnd_idx], &temp);
     478            0 :                                 zend_hash_iterators_update(hash, (uint32_t)rnd_idx, n_left);
     479              :                         }
     480              :                 }
     481              :         }
     482            4 :         hash->nNumUsed = n_elems;
     483            4 :         hash->nInternalPointer = 0;
     484            4 :         hash->nNextFreeElement = n_elems;
     485              : }
     486              : #endif
     487              : 
     488            4 : PHP_FUNCTION(Colopl_ColoplBc_Php70_shuffle)
     489              : {
     490              :         zval *array;
     491              : 
     492            4 :         ZEND_PARSE_PARAMETERS_START(1, 1)
     493            4 :                 Z_PARAM_ARRAY_EX(array, 0, 1)
     494            4 :         ZEND_PARSE_PARAMETERS_END();
     495              : 
     496            4 :         php_colopl_bc_array_data_shuffle(array);
     497              : 
     498            4 :         RETURN_TRUE;
     499              : }
     500              : 
     501            4 : PHP_FUNCTION(Colopl_ColoplBc_Php70_array_rand)
     502              : {
     503              :         zval *input;
     504            4 :         zend_long randval, num_req = 1;
     505              :         int num_avail;
     506              :         zend_string *string_key;
     507              :         zend_ulong num_key;
     508              : 
     509            4 :         ZEND_PARSE_PARAMETERS_START(1, 2)
     510            4 :                 Z_PARAM_ARRAY(input)
     511            4 :                 Z_PARAM_OPTIONAL
     512            4 :                 Z_PARAM_LONG(num_req)
     513            4 :         ZEND_PARSE_PARAMETERS_END();
     514              : 
     515            4 :         num_avail = zend_hash_num_elements(Z_ARRVAL_P(input));
     516              : 
     517            4 :         if (ZEND_NUM_ARGS() > 1) {
     518            4 :                 if (num_req <= 0 || num_req > num_avail) {
     519            0 :                         zend_argument_value_error(2, "must be between 1 and the number of elements in argument #1 ($array)");
     520            0 :                         RETURN_THROWS();
     521              :                 }
     522              :         }
     523              : 
     524              :         /* Make the return value an array only if we need to pass back more than one result. */
     525            4 :         if (num_req > 1) {
     526            4 :                 array_init_size(return_value, (uint32_t)num_req);
     527              :         }
     528              : 
     529              :         /* We can't use zend_hash_index_find() because the array may have string keys or gaps. */
     530           22 :         ZEND_HASH_FOREACH_KEY(Z_ARRVAL_P(input), num_key, string_key) {
     531           20 :                 if (!num_req) {
     532            2 :                         break;
     533              :                 }
     534              : 
     535           18 :                 randval = php_colopl_bc_rand();
     536              : 
     537           18 :                 if ((double) randval / ((double) COLOPL_BC_RAND_MAX_VALUE + 1.0) < (double) num_req / (double) num_avail) {
     538              :                         /* If we are returning a single result, just do it. */
     539           12 :                         if (Z_TYPE_P(return_value) != IS_ARRAY) {
     540            0 :                                 if (string_key) {
     541            0 :                                         RETURN_STR_COPY(string_key);
     542              :                                 } else {
     543            0 :                                         RETURN_LONG(num_key);
     544              :                                 }
     545              :                         } else {
     546              :                                 /* Append the result to the return value. */
     547           12 :                                 if (string_key) {
     548            0 :                                         add_next_index_str(return_value, zend_string_copy(string_key));
     549              :                                 } else {
     550           12 :                                         add_next_index_long(return_value, num_key);
     551              :                                 }
     552              :                         }
     553           12 :                         num_req--;
     554              :                 }
     555           18 :                 num_avail--;
     556              :         } ZEND_HASH_FOREACH_END();
     557              : 
     558              : }
     559              : 
     560              : /* string.c */
     561            4 : void php_colopl_bc_string_shuffle(char *str, zend_long len)
     562              : {
     563              :         zend_long n_elems, rnd_idx, n_left;
     564              :         char temp;
     565              : 
     566            4 :         n_elems = len;
     567              : 
     568            4 :         if (n_elems <= 1) {
     569            0 :                 return;
     570              :         }
     571              : 
     572            4 :         n_left = n_elems;
     573              : 
     574         1780 :         while (--n_left) {
     575         1776 :                 rnd_idx = php_colopl_bc_rand();
     576         1776 :                 rnd_idx = php_colopl_bc_rand_range(rnd_idx, 0, n_left, COLOPL_BC_RAND_MAX_VALUE);
     577         1776 :                 if (rnd_idx != n_left) {
     578         1744 :                         temp = str[n_left];
     579         1744 :                         str[n_left] = str[rnd_idx];
     580         1744 :                         str[rnd_idx] = temp;
     581              :                 }
     582              :         }
     583              : }
     584              : 
     585            4 : PHP_FUNCTION(Colopl_ColoplBc_Php70_str_shuffle)
     586              : {
     587              :         zend_string *arg;
     588              : 
     589            4 :         ZEND_PARSE_PARAMETERS_START(1, 1)
     590            4 :                 Z_PARAM_STR(arg)
     591            4 :         ZEND_PARSE_PARAMETERS_END();
     592              : 
     593            4 :         RETVAL_STRINGL(ZSTR_VAL(arg), ZSTR_LEN(arg));
     594            4 :         if (Z_STRLEN_P(return_value) > 1) {
     595            4 :                 php_colopl_bc_string_shuffle(Z_STRVAL_P(return_value), (zend_long) Z_STRLEN_P(return_value));
     596              :         }
     597              : }
     598              : 
     599         4004 : PHP_FUNCTION(Colopl_ColoplBc_Php70_date_create)
     600              : {
     601         4004 :         zval *timezone_object = NULL;
     602         4004 :         char *time_str = NULL;
     603         4004 :         size_t time_str_len = 0;
     604              :         php_date_obj *date;
     605              : 
     606         4004 :         ZEND_PARSE_PARAMETERS_START(0, 2)
     607         4004 :                 Z_PARAM_OPTIONAL
     608         4004 :                 Z_PARAM_STRING(time_str, time_str_len)
     609            4 :                 Z_PARAM_OBJECT_OF_CLASS_OR_NULL(timezone_object, php_date_get_timezone_ce())
     610         4008 :         ZEND_PARSE_PARAMETERS_END();
     611              : 
     612         4004 :         php_date_instantiate(php_date_get_date_ce(), return_value);
     613         4004 :         if (!php_date_initialize(Z_PHPDATE_P(return_value), time_str, time_str_len, NULL, timezone_object, 0)) {
     614            4 :                 zval_ptr_dtor(return_value);
     615            4 :                 RETURN_FALSE;
     616              :         }
     617              : 
     618         4000 :         date = Z_PHPDATE_P(return_value);
     619         4000 :         date->time->us = 0;
     620              : }
     621              : 
     622         4004 : PHP_FUNCTION(Colopl_ColoplBc_Php70_date_create_immutable)
     623              : {
     624         4004 :         zval *timezone_object = NULL;
     625         4004 :         char *time_str = NULL;
     626         4004 :         size_t time_str_len = 0;
     627              :         php_date_obj *date;
     628              : 
     629         4004 :         ZEND_PARSE_PARAMETERS_START(0, 2)
     630         4004 :                 Z_PARAM_OPTIONAL
     631         4004 :                 Z_PARAM_STRING(time_str, time_str_len)
     632            4 :                 Z_PARAM_OBJECT_OF_CLASS_OR_NULL(timezone_object, php_date_get_timezone_ce())
     633         4008 :         ZEND_PARSE_PARAMETERS_END();
     634              : 
     635         4004 :         php_date_instantiate(php_date_get_immutable_ce(), return_value);
     636         4004 :         if (!php_date_initialize(Z_PHPDATE_P(return_value), time_str, time_str_len, NULL, timezone_object, 0)) {
     637            4 :                 zval_ptr_dtor(return_value);
     638            4 :                 RETURN_FALSE;
     639              :         }
     640              : 
     641         4000 :         date = Z_PHPDATE_P(return_value);
     642         4000 :         date->time->us = 0;
     643              : }
        

Generated by: LCOV version 2.0-1