PHP  
 PHP: Test and Code Coverage Analysis
downloads | QA | documentation | faq | getting help | mailing lists | reporting bugs | php.net sites | links | my php.net 
 

LCOV - code coverage report
Current view: top level - ext/standard - array.c (source / functions) Hit Total Coverage
Test: PHP Code Coverage Lines: 2530 2708 93.4 %
Date: 2016-09-18 Functions: 131 136 96.3 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :    +----------------------------------------------------------------------+
       3             :    | PHP Version 7                                                        |
       4             :    +----------------------------------------------------------------------+
       5             :    | Copyright (c) 1997-2016 The PHP Group                                |
       6             :    +----------------------------------------------------------------------+
       7             :    | This source file is subject to version 3.01 of the PHP license,      |
       8             :    | that is bundled with this package in the file LICENSE, and is        |
       9             :    | available through the world-wide-web at the following url:           |
      10             :    | http://www.php.net/license/3_01.txt                                  |
      11             :    | If you did not receive a copy of the PHP license and are unable to   |
      12             :    | obtain it through the world-wide-web, please send a note to          |
      13             :    | license@php.net so we can mail you a copy immediately.               |
      14             :    +----------------------------------------------------------------------+
      15             :    | Authors: Andi Gutmans <andi@zend.com>                                |
      16             :    |          Zeev Suraski <zeev@zend.com>                                |
      17             :    |          Rasmus Lerdorf <rasmus@php.net>                             |
      18             :    |          Andrei Zmievski <andrei@php.net>                            |
      19             :    |          Stig Venaas <venaas@php.net>                                |
      20             :    |          Jason Greene <jason@php.net>                                |
      21             :    +----------------------------------------------------------------------+
      22             : */
      23             : 
      24             : /* $Id$ */
      25             : 
      26             : #include "php.h"
      27             : #include "php_ini.h"
      28             : #include <stdarg.h>
      29             : #include <stdlib.h>
      30             : #include <math.h>
      31             : #include <time.h>
      32             : #include <stdio.h>
      33             : #if HAVE_STRING_H
      34             : #include <string.h>
      35             : #else
      36             : #include <strings.h>
      37             : #endif
      38             : #ifdef PHP_WIN32
      39             : #include "win32/unistd.h"
      40             : #endif
      41             : #include "zend_globals.h"
      42             : #include "zend_interfaces.h"
      43             : #include "php_globals.h"
      44             : #include "php_array.h"
      45             : #include "basic_functions.h"
      46             : #include "php_string.h"
      47             : #include "php_rand.h"
      48             : #include "php_math.h"
      49             : #include "zend_smart_str.h"
      50             : #include "zend_bitset.h"
      51             : #include "ext/spl/spl_array.h"
      52             : 
      53             : /* {{{ defines */
      54             : #define EXTR_OVERWRITE                  0
      55             : #define EXTR_SKIP                               1
      56             : #define EXTR_PREFIX_SAME                2
      57             : #define EXTR_PREFIX_ALL                 3
      58             : #define EXTR_PREFIX_INVALID             4
      59             : #define EXTR_PREFIX_IF_EXISTS   5
      60             : #define EXTR_IF_EXISTS                  6
      61             : 
      62             : #define EXTR_REFS                               0x100
      63             : 
      64             : #define CASE_LOWER                              0
      65             : #define CASE_UPPER                              1
      66             : 
      67             : #define DIFF_NORMAL                     1
      68             : #define DIFF_KEY                        2
      69             : #define DIFF_ASSOC                      6
      70             : #define DIFF_COMP_DATA_NONE    -1
      71             : #define DIFF_COMP_DATA_INTERNAL 0
      72             : #define DIFF_COMP_DATA_USER     1
      73             : #define DIFF_COMP_KEY_INTERNAL  0
      74             : #define DIFF_COMP_KEY_USER      1
      75             : 
      76             : #define INTERSECT_NORMAL                1
      77             : #define INTERSECT_KEY                   2
      78             : #define INTERSECT_ASSOC                 6
      79             : #define INTERSECT_COMP_DATA_NONE    -1
      80             : #define INTERSECT_COMP_DATA_INTERNAL 0
      81             : #define INTERSECT_COMP_DATA_USER     1
      82             : #define INTERSECT_COMP_KEY_INTERNAL  0
      83             : #define INTERSECT_COMP_KEY_USER      1
      84             : /* }}} */
      85             : 
      86             : ZEND_DECLARE_MODULE_GLOBALS(array)
      87             : 
      88             : /* {{{ php_array_init_globals
      89             : */
      90       23922 : static void php_array_init_globals(zend_array_globals *array_globals)
      91             : {
      92       23922 :         memset(array_globals, 0, sizeof(zend_array_globals));
      93       23922 : }
      94             : /* }}} */
      95             : 
      96       23922 : PHP_MINIT_FUNCTION(array) /* {{{ */
      97             : {
      98       23922 :         ZEND_INIT_MODULE_GLOBALS(array, php_array_init_globals, NULL);
      99             : 
     100       23922 :         REGISTER_LONG_CONSTANT("EXTR_OVERWRITE", EXTR_OVERWRITE, CONST_CS | CONST_PERSISTENT);
     101       23922 :         REGISTER_LONG_CONSTANT("EXTR_SKIP", EXTR_SKIP, CONST_CS | CONST_PERSISTENT);
     102       23922 :         REGISTER_LONG_CONSTANT("EXTR_PREFIX_SAME", EXTR_PREFIX_SAME, CONST_CS | CONST_PERSISTENT);
     103       23922 :         REGISTER_LONG_CONSTANT("EXTR_PREFIX_ALL", EXTR_PREFIX_ALL, CONST_CS | CONST_PERSISTENT);
     104       23922 :         REGISTER_LONG_CONSTANT("EXTR_PREFIX_INVALID", EXTR_PREFIX_INVALID, CONST_CS | CONST_PERSISTENT);
     105       23922 :         REGISTER_LONG_CONSTANT("EXTR_PREFIX_IF_EXISTS", EXTR_PREFIX_IF_EXISTS, CONST_CS | CONST_PERSISTENT);
     106       23922 :         REGISTER_LONG_CONSTANT("EXTR_IF_EXISTS", EXTR_IF_EXISTS, CONST_CS | CONST_PERSISTENT);
     107       23922 :         REGISTER_LONG_CONSTANT("EXTR_REFS", EXTR_REFS, CONST_CS | CONST_PERSISTENT);
     108             : 
     109       23922 :         REGISTER_LONG_CONSTANT("SORT_ASC", PHP_SORT_ASC, CONST_CS | CONST_PERSISTENT);
     110       23922 :         REGISTER_LONG_CONSTANT("SORT_DESC", PHP_SORT_DESC, CONST_CS | CONST_PERSISTENT);
     111             : 
     112       23922 :         REGISTER_LONG_CONSTANT("SORT_REGULAR", PHP_SORT_REGULAR, CONST_CS | CONST_PERSISTENT);
     113       23922 :         REGISTER_LONG_CONSTANT("SORT_NUMERIC", PHP_SORT_NUMERIC, CONST_CS | CONST_PERSISTENT);
     114       23922 :         REGISTER_LONG_CONSTANT("SORT_STRING", PHP_SORT_STRING, CONST_CS | CONST_PERSISTENT);
     115       23922 :         REGISTER_LONG_CONSTANT("SORT_LOCALE_STRING", PHP_SORT_LOCALE_STRING, CONST_CS | CONST_PERSISTENT);
     116       23922 :         REGISTER_LONG_CONSTANT("SORT_NATURAL", PHP_SORT_NATURAL, CONST_CS | CONST_PERSISTENT);
     117       23922 :         REGISTER_LONG_CONSTANT("SORT_FLAG_CASE", PHP_SORT_FLAG_CASE, CONST_CS | CONST_PERSISTENT);
     118             : 
     119       23922 :         REGISTER_LONG_CONSTANT("CASE_LOWER", CASE_LOWER, CONST_CS | CONST_PERSISTENT);
     120       23922 :         REGISTER_LONG_CONSTANT("CASE_UPPER", CASE_UPPER, CONST_CS | CONST_PERSISTENT);
     121             : 
     122       23922 :         REGISTER_LONG_CONSTANT("COUNT_NORMAL", COUNT_NORMAL, CONST_CS | CONST_PERSISTENT);
     123       23922 :         REGISTER_LONG_CONSTANT("COUNT_RECURSIVE", COUNT_RECURSIVE, CONST_CS | CONST_PERSISTENT);
     124             : 
     125       23922 :         REGISTER_LONG_CONSTANT("ARRAY_FILTER_USE_BOTH", ARRAY_FILTER_USE_BOTH, CONST_CS | CONST_PERSISTENT);
     126       23922 :         REGISTER_LONG_CONSTANT("ARRAY_FILTER_USE_KEY", ARRAY_FILTER_USE_KEY, CONST_CS | CONST_PERSISTENT);
     127             : 
     128       23922 :         return SUCCESS;
     129             : }
     130             : /* }}} */
     131             : 
     132       23963 : PHP_MSHUTDOWN_FUNCTION(array) /* {{{ */
     133             : {
     134             : #ifdef ZTS
     135             :         ts_free_id(array_globals_id);
     136             : #endif
     137             : 
     138       23963 :         return SUCCESS;
     139             : }
     140             : /* }}} */
     141             : 
     142        1968 : static int php_array_key_compare(const void *a, const void *b) /* {{{ */
     143             : {
     144        1968 :         Bucket *f = (Bucket *) a;
     145        1968 :         Bucket *s = (Bucket *) b;
     146             :         zend_uchar t;
     147             :         zend_long l1, l2;
     148             :         double d;
     149             : 
     150        1968 :         if (f->key == NULL) {
     151        1324 :                 if (s->key == NULL) {
     152        1275 :                         return (zend_long)f->h > (zend_long)s->h ? 1 : -1;
     153             :                 } else {
     154          49 :                         l1 = (zend_long)f->h;
     155          98 :                         t = is_numeric_string(s->key->val, s->key->len, &l2, &d, 1);
     156          49 :                         if (t == IS_LONG) {
     157             :                                 /* pass */
     158          49 :                         } else if (t == IS_DOUBLE) {
     159           4 :                                 return ZEND_NORMALIZE_BOOL((double)l1 - d);
     160             :                         } else {
     161          45 :                                 l2 = 0;
     162             :                         }
     163             :                 }
     164             :         } else {
     165         644 :                 if (s->key) {
     166         608 :                         return zendi_smart_strcmp(f->key, s->key);
     167             :                 } else {
     168          36 :                         l2 = (zend_long)s->h;
     169          72 :                         t = is_numeric_string(f->key->val, f->key->len, &l1, &d, 1);
     170          36 :                         if (t == IS_LONG) {
     171             :                                 /* pass */
     172          36 :                         } else if (t == IS_DOUBLE) {
     173           4 :                                 return ZEND_NORMALIZE_BOOL(d - (double)l2);
     174             :                         } else {
     175          32 :                                 l1 = 0;
     176             :                         }
     177             :                 }
     178             :         }
     179          77 :         return l1 > l2 ? 1 : (l1 < l2 ? -1 : 0);
     180             : }
     181             : /* }}} */
     182             : 
     183         930 : static int php_array_reverse_key_compare(const void *a, const void *b) /* {{{ */
     184             : {
     185         930 :         return php_array_key_compare(b, a);
     186             : }
     187             : /* }}} */
     188             : 
     189         226 : static int php_array_key_compare_numeric(const void *a, const void *b) /* {{{ */
     190             : {
     191         226 :         Bucket *f = (Bucket *) a;
     192         226 :         Bucket *s = (Bucket *) b;
     193             : 
     194         226 :         if (f->key == NULL && s->key == NULL) {
     195         222 :                 return (zend_long)f->h > (zend_long)s->h ? 1 : -1;
     196             :         } else {
     197             :                 double d1, d2;
     198           4 :                 if (f->key) {
     199           2 :                         d1 = zend_strtod(f->key->val, NULL);
     200             :                 } else {
     201           2 :                         d1 = (double)(zend_long)f->h;
     202             :                 }
     203           4 :                 if (s->key) {
     204           2 :                         d2 = zend_strtod(s->key->val, NULL);
     205             :                 } else {
     206           2 :                         d2 = (double)(zend_long)s->h;
     207             :                 }
     208           4 :                 return ZEND_NORMALIZE_BOOL(d1 - d2);
     209             :         }
     210             : }
     211             : /* }}} */
     212             : 
     213         108 : static int php_array_reverse_key_compare_numeric(const void *a, const void *b) /* {{{ */
     214             : {
     215         108 :         return php_array_key_compare_numeric(b, a);
     216             : }
     217             : /* }}} */
     218             : 
     219          24 : static int php_array_key_compare_string_case(const void *a, const void *b) /* {{{ */
     220             : {
     221          24 :         Bucket *f = (Bucket *) a;
     222          24 :         Bucket *s = (Bucket *) b;
     223             :         char *s1, *s2;
     224             :         size_t l1, l2;
     225             :         char buf1[MAX_LENGTH_OF_LONG + 1];
     226             :         char buf2[MAX_LENGTH_OF_LONG + 1];
     227             : 
     228          24 :         if (f->key) {
     229          20 :                 s1 = f->key->val;
     230          20 :                 l1 = f->key->len;
     231             :         } else {
     232           8 :                 s1 = zend_print_long_to_buf(buf1 + sizeof(buf1) - 1, f->h);
     233           4 :                 l1 = buf1 + sizeof(buf1) - 1 - s1;
     234             :         }
     235          24 :         if (s->key) {
     236          20 :                 s2 = s->key->val;
     237          20 :                 l2 = s->key->len;
     238             :         } else {
     239           8 :                 s2 = zend_print_long_to_buf(buf2 + sizeof(buf2) - 1, s->h);
     240           4 :                 l2 = buf2 + sizeof(buf2) - 1 - s1;
     241             :         }
     242          24 :         return zend_binary_strcasecmp_l(s1, l1, s2, l2);
     243             : }
     244             : /* }}} */
     245             : 
     246          22 : static int php_array_reverse_key_compare_string_case(const void *a, const void *b) /* {{{ */
     247             : {
     248          22 :         return php_array_key_compare_string_case(b, a);
     249             : }
     250             : /* }}} */
     251             : 
     252         506 : static int php_array_key_compare_string(const void *a, const void *b) /* {{{ */
     253             : {
     254         506 :         Bucket *f = (Bucket *) a;
     255         506 :         Bucket *s = (Bucket *) b;
     256             :         char *s1, *s2;
     257             :         size_t l1, l2;
     258             :         char buf1[MAX_LENGTH_OF_LONG + 1];
     259             :         char buf2[MAX_LENGTH_OF_LONG + 1];
     260             : 
     261         506 :         if (f->key) {
     262         478 :                 s1 = f->key->val;
     263         478 :                 l1 = f->key->len;
     264             :         } else {
     265          56 :                 s1 = zend_print_long_to_buf(buf1 + sizeof(buf1) - 1, f->h);
     266          28 :                 l1 = buf1 + sizeof(buf1) - 1 - s1;
     267             :         }
     268         506 :         if (s->key) {
     269         469 :                 s2 = s->key->val;
     270         469 :                 l2 = s->key->len;
     271             :         } else {
     272          74 :                 s2 = zend_print_long_to_buf(buf2 + sizeof(buf2) - 1, s->h);
     273          37 :                 l2 = buf2 + sizeof(buf2) - 1 - s2;
     274             :         }
     275         506 :         return zend_binary_strcmp(s1, l1, s2, l2);
     276             : }
     277             : /* }}} */
     278             : 
     279         103 : static int php_array_reverse_key_compare_string(const void *a, const void *b) /* {{{ */
     280             : {
     281         103 :         return php_array_key_compare_string(b, a);
     282             : }
     283             : /* }}} */
     284             : 
     285          39 : static int php_array_key_compare_string_natural_general(const void *a, const void *b, int fold_case) /* {{{ */
     286             : {
     287          39 :         Bucket *f = (Bucket *) a;
     288          39 :         Bucket *s = (Bucket *) b;
     289             :         char *s1, *s2;
     290             :         size_t l1, l2;
     291             :         char buf1[MAX_LENGTH_OF_LONG + 1];
     292             :         char buf2[MAX_LENGTH_OF_LONG + 1];
     293             : 
     294          39 :         if (f->key) {
     295          39 :                 s1 = f->key->val;
     296          39 :                 l1 = f->key->len;
     297             :         } else {
     298           0 :                 s1 = zend_print_long_to_buf(buf1 + sizeof(buf1) - 1, f->h);
     299           0 :                 l1 = buf1 + sizeof(buf1) - 1 - s1;
     300             :         }
     301          39 :         if (s->key) {
     302          39 :                 s2 = s->key->val;
     303          39 :                 l2 = s->key->len;
     304             :         } else {
     305           0 :                 s2 = zend_print_long_to_buf(buf2 + sizeof(buf2) - 1, s->h);
     306           0 :                 l2 = buf2 + sizeof(buf2) - 1 - s1;
     307             :         }
     308          39 :         return strnatcmp_ex(s1, l1, s2, l2, fold_case);
     309             : }
     310             : /* }}} */
     311             : 
     312           0 : static int php_array_key_compare_string_natural_case(const void *a, const void *b) /* {{{ */
     313             : {
     314           0 :         return php_array_key_compare_string_natural_general(a, b, 1);
     315             : }
     316             : /* }}} */
     317             : 
     318          20 : static int php_array_reverse_key_compare_string_natural_case(const void *a, const void *b) /* {{{ */
     319             : {
     320          20 :         return php_array_key_compare_string_natural_general(b, a, 1);
     321             : }
     322             : /* }}} */
     323             : 
     324           0 : static int php_array_key_compare_string_natural(const void *a, const void *b) /* {{{ */
     325             : {
     326           0 :         return php_array_key_compare_string_natural_general(a, b, 0);
     327             : }
     328             : /* }}} */
     329             : 
     330          19 : static int php_array_reverse_key_compare_string_natural(const void *a, const void *b) /* {{{ */
     331             : {
     332          19 :         return php_array_key_compare_string_natural_general(b, a, 0);
     333             : }
     334             : /* }}} */
     335             : 
     336             : #if HAVE_STRCOLL
     337           0 : static int php_array_key_compare_string_locale(const void *a, const void *b) /* {{{ */
     338             : {
     339           0 :         Bucket *f = (Bucket *) a;
     340           0 :         Bucket *s = (Bucket *) b;
     341             :         char *s1, *s2;
     342             :         char buf1[MAX_LENGTH_OF_LONG + 1];
     343             :         char buf2[MAX_LENGTH_OF_LONG + 1];
     344             : 
     345           0 :         if (f->key) {
     346           0 :                 s1 = f->key->val;
     347             :         } else {
     348           0 :                 s1 = zend_print_long_to_buf(buf1 + sizeof(buf1) - 1, f->h);
     349             :         }
     350           0 :         if (s->key) {
     351           0 :                 s2 = s->key->val;
     352             :         } else {
     353           0 :                 s2 = zend_print_long_to_buf(buf2 + sizeof(buf2) - 1, s->h);
     354             :         }
     355           0 :         return strcoll(s1, s2);
     356             : }
     357             : /* }}} */
     358             : 
     359           0 : static int php_array_reverse_key_compare_string_locale(const void *a, const void *b) /* {{{ */
     360             : {
     361           0 :         return php_array_key_compare_string_locale(b, a);
     362             : }
     363             : /* }}} */
     364             : #endif
     365             : 
     366             : /* Numbers are always smaller than strings int this function as it
     367             :  * anyway doesn't make much sense to compare two different data types.
     368             :  * This keeps it consistent and simple.
     369             :  *
     370             :  * This is not correct any more, depends on what compare_func is set to.
     371             :  */
     372       31452 : static int php_array_data_compare(const void *a, const void *b) /* {{{ */
     373             : {
     374             :         Bucket *f;
     375             :         Bucket *s;
     376             :         zval result;
     377             :         zval *first;
     378             :         zval *second;
     379             : 
     380       31452 :         f = (Bucket *) a;
     381       31452 :         s = (Bucket *) b;
     382             : 
     383       31452 :         first = &f->val;
     384       31452 :         second = &s->val;
     385             : 
     386       31452 :         if (UNEXPECTED(Z_TYPE_P(first) == IS_INDIRECT)) {
     387           0 :                 first = Z_INDIRECT_P(first);
     388             :         }
     389       31452 :         if (UNEXPECTED(Z_TYPE_P(second) == IS_INDIRECT)) {
     390           0 :                 second = Z_INDIRECT_P(second);
     391             :         }
     392       31452 :         if (compare_function(&result, first, second) == FAILURE) {
     393           0 :                 return 0;
     394             :         }
     395             : 
     396             :         ZEND_ASSERT(Z_TYPE(result) == IS_LONG);
     397       31452 :         return Z_LVAL(result);
     398             : }
     399             : /* }}} */
     400             : 
     401        1265 : static int php_array_reverse_data_compare(const void *a, const void *b) /* {{{ */
     402             : {
     403        1265 :         return php_array_data_compare(a, b) * -1;
     404             : }
     405             : /* }}} */
     406             : 
     407         565 : static int php_array_data_compare_numeric(const void *a, const void *b) /* {{{ */
     408             : {
     409             :         Bucket *f;
     410             :         Bucket *s;
     411             :         zval *first;
     412             :         zval *second;
     413             : 
     414         565 :         f = (Bucket *) a;
     415         565 :         s = (Bucket *) b;
     416             : 
     417         565 :         first = &f->val;
     418         565 :         second = &s->val;
     419             : 
     420         565 :         if (UNEXPECTED(Z_TYPE_P(first) == IS_INDIRECT)) {
     421           0 :                 first = Z_INDIRECT_P(first);
     422             :         }
     423         565 :         if (UNEXPECTED(Z_TYPE_P(second) == IS_INDIRECT)) {
     424           0 :                 second = Z_INDIRECT_P(second);
     425             :         }
     426             : 
     427         565 :         return numeric_compare_function(first, second);
     428             : }
     429             : /* }}} */
     430             : 
     431         208 : static int php_array_reverse_data_compare_numeric(const void *a, const void *b) /* {{{ */
     432             : {
     433         208 :         return php_array_data_compare_numeric(b, a);
     434             : }
     435             : /* }}} */
     436             : 
     437          99 : static int php_array_data_compare_string_case(const void *a, const void *b) /* {{{ */
     438             : {
     439             :         Bucket *f;
     440             :         Bucket *s;
     441             :         zval *first;
     442             :         zval *second;
     443             : 
     444          99 :         f = (Bucket *) a;
     445          99 :         s = (Bucket *) b;
     446             : 
     447          99 :         first = &f->val;
     448          99 :         second = &s->val;
     449             : 
     450          99 :         if (UNEXPECTED(Z_TYPE_P(first) == IS_INDIRECT)) {
     451           0 :                 first = Z_INDIRECT_P(first);
     452             :         }
     453          99 :         if (UNEXPECTED(Z_TYPE_P(second) == IS_INDIRECT)) {
     454           0 :                 second = Z_INDIRECT_P(second);
     455             :         }
     456             : 
     457          99 :         return string_case_compare_function(first, second);
     458             : }
     459             : /* }}} */
     460             : 
     461          49 : static int php_array_reverse_data_compare_string_case(const void *a, const void *b) /* {{{ */
     462             : {
     463          49 :         return php_array_data_compare_string_case(b, a);
     464             : }
     465             : /* }}} */
     466             : 
     467      239360 : static int php_array_data_compare_string(const void *a, const void *b) /* {{{ */
     468             : {
     469             :         Bucket *f;
     470             :         Bucket *s;
     471             :         zval *first;
     472             :         zval *second;
     473             : 
     474      239360 :         f = (Bucket *) a;
     475      239360 :         s = (Bucket *) b;
     476             : 
     477      239360 :         first = &f->val;
     478      239360 :         second = &s->val;
     479             : 
     480      239360 :         if (UNEXPECTED(Z_TYPE_P(first) == IS_INDIRECT)) {
     481           2 :                 first = Z_INDIRECT_P(first);
     482             :         }
     483      239360 :         if (UNEXPECTED(Z_TYPE_P(second) == IS_INDIRECT)) {
     484           4 :                 second = Z_INDIRECT_P(second);
     485             :         }
     486             : 
     487      239360 :         return string_compare_function(first, second);
     488             : }
     489             : /* }}} */
     490             : 
     491         218 : static int php_array_reverse_data_compare_string(const void *a, const void *b) /* {{{ */
     492             : {
     493         218 :         return php_array_data_compare_string(b, a);
     494             : }
     495             : /* }}} */
     496             : 
     497         583 : static int php_array_natural_general_compare(const void *a, const void *b, int fold_case) /* {{{ */
     498             : {
     499         583 :         Bucket *f = (Bucket *) a;
     500         583 :         Bucket *s = (Bucket *) b;
     501        1166 :         zend_string *str1 = zval_get_string(&f->val);
     502        1166 :         zend_string *str2 = zval_get_string(&s->val);
     503             : 
     504         583 :         int result = strnatcmp_ex(ZSTR_VAL(str1), ZSTR_LEN(str1), ZSTR_VAL(str2), ZSTR_LEN(str2), fold_case);
     505             : 
     506             :         zend_string_release(str1);
     507             :         zend_string_release(str2);
     508         583 :         return result;
     509             : }
     510             : /* }}} */
     511             : 
     512         134 : static int php_array_natural_compare(const void *a, const void *b) /* {{{ */
     513             : {
     514         134 :         return php_array_natural_general_compare(a, b, 0);
     515             : }
     516             : /* }}} */
     517             : 
     518          38 : static int php_array_reverse_natural_compare(const void *a, const void *b) /* {{{ */
     519             : {
     520          38 :         return php_array_natural_general_compare(b, a, 0);
     521             : }
     522             : /* }}} */
     523             : 
     524         371 : static int php_array_natural_case_compare(const void *a, const void *b) /* {{{ */
     525             : {
     526         371 :         return php_array_natural_general_compare(a, b, 1);
     527             : }
     528             : /* }}} */
     529             : 
     530          40 : static int php_array_reverse_natural_case_compare(const void *a, const void *b) /* {{{ */
     531             : {
     532          40 :         return php_array_natural_general_compare(b, a, 1);
     533             : }
     534             : /* }}} */
     535             : 
     536             : #if HAVE_STRCOLL
     537          29 : static int php_array_data_compare_string_locale(const void *a, const void *b) /* {{{ */
     538             : {
     539             :         Bucket *f;
     540             :         Bucket *s;
     541             :         zval *first;
     542             :         zval *second;
     543             : 
     544          29 :         f = (Bucket *) a;
     545          29 :         s = (Bucket *) b;
     546             : 
     547          29 :         first = &f->val;
     548          29 :         second = &s->val;
     549             : 
     550          29 :         if (UNEXPECTED(Z_TYPE_P(first) == IS_INDIRECT)) {
     551           0 :                 first = Z_INDIRECT_P(first);
     552             :         }
     553          29 :         if (UNEXPECTED(Z_TYPE_P(second) == IS_INDIRECT)) {
     554           0 :                 second = Z_INDIRECT_P(second);
     555             :         }
     556             : 
     557          29 :         return string_locale_compare_function(first, second);
     558             : }
     559             : /* }}} */
     560             : 
     561           0 : static int php_array_reverse_data_compare_string_locale(const void *a, const void *b) /* {{{ */
     562             : {
     563           0 :         return php_array_data_compare_string_locale(b, a);
     564             : }
     565             : /* }}} */
     566             : #endif
     567             : 
     568         475 : static compare_func_t php_get_key_compare_func(zend_long sort_type, int reverse) /* {{{ */
     569             : {
     570         475 :         switch (sort_type & ~PHP_SORT_FLAG_CASE) {
     571             :                 case PHP_SORT_NUMERIC:
     572          20 :                         if (reverse) {
     573          10 :                                 return php_array_reverse_key_compare_numeric;
     574             :                         } else {
     575          10 :                                 return php_array_key_compare_numeric;
     576             :                         }
     577             :                         break;
     578             : 
     579             :                 case PHP_SORT_STRING:
     580          27 :                         if (sort_type & PHP_SORT_FLAG_CASE) {
     581           3 :                                 if (reverse) {
     582           2 :                                         return php_array_reverse_key_compare_string_case;
     583             :                                 } else {
     584           1 :                                         return php_array_key_compare_string_case;
     585             :                                 }
     586             :                         } else {
     587          24 :                                 if (reverse) {
     588           6 :                                         return php_array_reverse_key_compare_string;
     589             :                                 } else {
     590          18 :                                         return php_array_key_compare_string;
     591             :                                 }
     592             :                         }
     593             :                         break;
     594             : 
     595             :                 case PHP_SORT_NATURAL:
     596           2 :                         if (sort_type & PHP_SORT_FLAG_CASE) {
     597           1 :                                 if (reverse) {
     598           1 :                                         return php_array_reverse_key_compare_string_natural_case;
     599             :                                 } else {
     600           0 :                                         return php_array_key_compare_string_natural_case;
     601             :                                 }
     602             :                         } else {
     603           1 :                                 if (reverse) {
     604           1 :                                         return php_array_reverse_key_compare_string_natural;
     605             :                                 } else {
     606           0 :                                         return php_array_key_compare_string_natural;
     607             :                                 }
     608             :                         }
     609             :                         break;
     610             : 
     611             : #if HAVE_STRCOLL
     612             :                 case PHP_SORT_LOCALE_STRING:
     613           0 :                         if (reverse) {
     614           0 :                                 return php_array_reverse_key_compare_string_locale;
     615             :                         } else {
     616           0 :                                 return php_array_key_compare_string_locale;
     617             :                         }
     618             :                         break;
     619             : #endif
     620             : 
     621             :                 case PHP_SORT_REGULAR:
     622             :                 default:
     623         426 :                         if (reverse) {
     624          75 :                                 return php_array_reverse_key_compare;
     625             :                         } else {
     626         351 :                                 return php_array_key_compare;
     627             :                         }
     628             :                         break;
     629             :         }
     630             :         return NULL;
     631             : }
     632             : /* }}} */
     633             : 
     634         534 : static compare_func_t php_get_data_compare_func(zend_long sort_type, int reverse) /* {{{ */
     635             : {
     636         534 :         switch (sort_type & ~PHP_SORT_FLAG_CASE) {
     637             :                 case PHP_SORT_NUMERIC:
     638          51 :                         if (reverse) {
     639          22 :                                 return php_array_reverse_data_compare_numeric;
     640             :                         } else {
     641          29 :                                 return php_array_data_compare_numeric;
     642             :                         }
     643             :                         break;
     644             : 
     645             :                 case PHP_SORT_STRING:
     646          80 :                         if (sort_type & PHP_SORT_FLAG_CASE) {
     647          10 :                                 if (reverse) {
     648           4 :                                         return php_array_reverse_data_compare_string_case;
     649             :                                 } else {
     650           6 :                                         return php_array_data_compare_string_case;
     651             :                                 }
     652             :                         } else {
     653          70 :                                 if (reverse) {
     654          12 :                                         return php_array_reverse_data_compare_string;
     655             :                                 } else {
     656          58 :                                         return php_array_data_compare_string;
     657             :                                 }
     658             :                         }
     659             :                         break;
     660             : 
     661             :                 case PHP_SORT_NATURAL:
     662          13 :                         if (sort_type & PHP_SORT_FLAG_CASE) {
     663           6 :                                 if (reverse) {
     664           2 :                                         return php_array_reverse_natural_case_compare;
     665             :                                 } else {
     666           4 :                                         return php_array_natural_case_compare;
     667             :                                 }
     668             :                         } else {
     669           7 :                                 if (reverse) {
     670           2 :                                         return php_array_reverse_natural_compare;
     671             :                                 } else {
     672           5 :                                         return php_array_natural_compare;
     673             :                                 }
     674             :                         }
     675             :                         break;
     676             : 
     677             : #if HAVE_STRCOLL
     678             :                 case PHP_SORT_LOCALE_STRING:
     679           1 :                         if (reverse) {
     680           0 :                                 return php_array_reverse_data_compare_string_locale;
     681             :                         } else {
     682           1 :                                 return php_array_data_compare_string_locale;
     683             :                         }
     684             :                         break;
     685             : #endif
     686             : 
     687             :                 case PHP_SORT_REGULAR:
     688             :                 default:
     689         389 :                         if (reverse) {
     690         120 :                                 return php_array_reverse_data_compare;
     691             :                         } else {
     692         269 :                                 return php_array_data_compare;
     693             :                         }
     694             :                         break;
     695             :         }
     696             :         return NULL;
     697             : }
     698             : /* }}} */
     699             : 
     700             : /* {{{ proto bool krsort(array &array_arg [, int sort_flags])
     701             :    Sort an array by key value in reverse order */
     702         199 : PHP_FUNCTION(krsort)
     703             : {
     704             :         zval *array;
     705         199 :         zend_long sort_type = PHP_SORT_REGULAR;
     706             :         compare_func_t cmp;
     707             : 
     708         199 :         ZEND_PARSE_PARAMETERS_START(1, 2)
     709         774 :                 Z_PARAM_ARRAY_EX(array, 0, 1)
     710         103 :                 Z_PARAM_OPTIONAL
     711         229 :                 Z_PARAM_LONG(sort_type)
     712         199 :         ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE);
     713             : 
     714          95 :         cmp = php_get_key_compare_func(sort_type, 1);
     715             : 
     716          95 :         if (zend_hash_sort(Z_ARRVAL_P(array), cmp, 0) == FAILURE) {
     717           0 :                 RETURN_FALSE;
     718             :         }
     719          95 :         RETURN_TRUE;
     720             : }
     721             : /* }}} */
     722             : 
     723             : /* {{{ proto bool ksort(array &array_arg [, int sort_flags])
     724             :    Sort an array by key */
     725         485 : PHP_FUNCTION(ksort)
     726             : {
     727             :         zval *array;
     728         485 :         zend_long sort_type = PHP_SORT_REGULAR;
     729             :         compare_func_t cmp;
     730             : 
     731         485 :         ZEND_PARSE_PARAMETERS_START(1, 2)
     732        1927 :                 Z_PARAM_ARRAY_EX(array, 0, 1)
     733         389 :                 Z_PARAM_OPTIONAL
     734         535 :                 Z_PARAM_LONG(sort_type)
     735         485 :         ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE);
     736             : 
     737         380 :         cmp = php_get_key_compare_func(sort_type, 0);
     738             : 
     739         380 :         if (zend_hash_sort(Z_ARRVAL_P(array), cmp, 0) == FAILURE) {
     740           0 :                 RETURN_FALSE;
     741             :         }
     742         380 :         RETURN_TRUE;
     743             : }
     744             : /* }}} */
     745             : 
     746         275 : PHPAPI zend_long php_count_recursive(zval *array, zend_long mode) /* {{{ */
     747             : {
     748         275 :         zend_long cnt = 0;
     749             :         zval *element;
     750             : 
     751         275 :         if (Z_TYPE_P(array) == IS_ARRAY) {
     752          68 :                 if (Z_ARRVAL_P(array)->u.v.nApplyCount > 1) {
     753           1 :                         php_error_docref(NULL, E_WARNING, "recursion detected");
     754           1 :                         return 0;
     755             :                 }
     756             : 
     757          67 :                 cnt = zend_array_count(Z_ARRVAL_P(array));
     758          67 :                 if (mode == COUNT_RECURSIVE) {
     759          67 :                     if (ZEND_HASH_APPLY_PROTECTION(Z_ARRVAL_P(array))) {
     760          67 :                                 Z_ARRVAL_P(array)->u.v.nApplyCount++;
     761             :                         }
     762         315 :                         ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(array), element) {
     763         124 :                                 ZVAL_DEREF(element);
     764         124 :                                 cnt += php_count_recursive(element, COUNT_RECURSIVE);
     765             :                         } ZEND_HASH_FOREACH_END();
     766          67 :                     if (ZEND_HASH_APPLY_PROTECTION(Z_ARRVAL_P(array))) {
     767          67 :                                 Z_ARRVAL_P(array)->u.v.nApplyCount--;
     768             :                         }
     769             :                 }
     770             :         }
     771             : 
     772         274 :         return cnt;
     773             : }
     774             : /* }}} */
     775             : 
     776             : /* {{{ proto int count(mixed var [, int mode])
     777             :    Count the number of elements in a variable (usually an array) */
     778      235459 : PHP_FUNCTION(count)
     779             : {
     780             :         zval *array;
     781      235459 :         zend_long mode = COUNT_NORMAL;
     782             :         zend_long cnt;
     783             :         zval *element;
     784             : 
     785      235459 :         ZEND_PARSE_PARAMETERS_START(1, 2)
     786      235452 :                 Z_PARAM_ZVAL(array)
     787      235452 :                 Z_PARAM_OPTIONAL
     788      235906 :                 Z_PARAM_LONG(mode)
     789      235459 :         ZEND_PARSE_PARAMETERS_END();
     790             : 
     791      470872 :         switch (Z_TYPE_P(array)) {
     792             :                 case IS_NULL:
     793      183942 :                         RETURN_LONG(0);
     794             :                         break;
     795             :                 case IS_ARRAY:
     796       20049 :                         cnt = zend_array_count(Z_ARRVAL_P(array));
     797       20049 :                         if (mode == COUNT_RECURSIVE) {
     798         352 :                                 ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(array), element) {
     799         151 :                                         ZVAL_DEREF(element);
     800         151 :                                         cnt += php_count_recursive(element, COUNT_RECURSIVE);
     801             :                                 } ZEND_HASH_FOREACH_END();
     802             :                         }
     803       20049 :                         RETURN_LONG(cnt);
     804             :                         break;
     805             :                 case IS_OBJECT: {
     806             :                         zval retval;
     807             :                         /* first, we check if the handler is defined */
     808         107 :                         if (Z_OBJ_HT_P(array)->count_elements) {
     809          66 :                                 RETVAL_LONG(1);
     810          66 :                                 if (SUCCESS == Z_OBJ_HT(*array)->count_elements(array, &Z_LVAL_P(return_value))) {
     811          65 :                                         return;
     812             :                                 }
     813             :                         }
     814             :                         /* if not and the object implements Countable we call its count() method */
     815          42 :                         if (instanceof_function(Z_OBJCE_P(array), spl_ce_Countable)) {
     816          26 :                                 zend_call_method_with_0_params(array, NULL, NULL, "count", &retval);
     817          26 :                                 if (Z_TYPE(retval) != IS_UNDEF) {
     818          48 :                                         RETVAL_LONG(zval_get_long(&retval));
     819          24 :                                         zval_ptr_dtor(&retval);
     820             :                                 }
     821          26 :                                 return;
     822             :                         }
     823             :                 }
     824             :                 default:
     825       31354 :                         RETURN_LONG(1);
     826             :                         break;
     827             :         }
     828             : }
     829             : /* }}} */
     830             : 
     831          73 : static void php_natsort(INTERNAL_FUNCTION_PARAMETERS, int fold_case) /* {{{ */
     832             : {
     833             :         zval *array;
     834             : 
     835          73 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "a/", &array) == FAILURE) {
     836          26 :                 return;
     837             :         }
     838             : 
     839          47 :         if (fold_case) {
     840          42 :                 if (zend_hash_sort(Z_ARRVAL_P(array), php_array_natural_case_compare, 0) == FAILURE) {
     841           0 :                         return;
     842             :                 }
     843             :         } else {
     844           5 :                 if (zend_hash_sort(Z_ARRVAL_P(array), php_array_natural_compare, 0) == FAILURE) {
     845           0 :                         return;
     846             :                 }
     847             :         }
     848             : 
     849          47 :         RETURN_TRUE;
     850             : }
     851             : /* }}} */
     852             : 
     853             : /* {{{ proto void natsort(array &array_arg)
     854             :    Sort an array using natural sort */
     855           5 : PHP_FUNCTION(natsort)
     856             : {
     857           5 :         php_natsort(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
     858           5 : }
     859             : /* }}} */
     860             : 
     861             : /* {{{ proto void natcasesort(array &array_arg)
     862             :    Sort an array using case-insensitive natural sort */
     863          68 : PHP_FUNCTION(natcasesort)
     864             : {
     865          68 :         php_natsort(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
     866          68 : }
     867             : /* }}} */
     868             : 
     869             : /* {{{ proto bool asort(array &array_arg [, int sort_flags])
     870             :    Sort an array and maintain index association */
     871         246 : PHP_FUNCTION(asort)
     872             : {
     873             :         zval *array;
     874         246 :         zend_long sort_type = PHP_SORT_REGULAR;
     875             :         compare_func_t cmp;
     876             : 
     877         246 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "a/|l", &array, &sort_type) == FAILURE) {
     878         105 :                 RETURN_FALSE;
     879             :         }
     880             : 
     881         141 :         cmp = php_get_data_compare_func(sort_type, 0);
     882             : 
     883         141 :         if (zend_hash_sort(Z_ARRVAL_P(array), cmp, 0) == FAILURE) {
     884           0 :                 RETURN_FALSE;
     885             :         }
     886         141 :         RETURN_TRUE;
     887             : }
     888             : /* }}} */
     889             : 
     890             : /* {{{ proto bool arsort(array &array_arg [, int sort_flags])
     891             :    Sort an array in reverse order and maintain index association */
     892         184 : PHP_FUNCTION(arsort)
     893             : {
     894             :         zval *array;
     895         184 :         zend_long sort_type = PHP_SORT_REGULAR;
     896             :         compare_func_t cmp;
     897             : 
     898         184 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "a/|l", &array, &sort_type) == FAILURE) {
     899         104 :                 RETURN_FALSE;
     900             :         }
     901             : 
     902          80 :         cmp = php_get_data_compare_func(sort_type, 1);
     903             : 
     904          80 :         if (zend_hash_sort(Z_ARRVAL_P(array), cmp, 0) == FAILURE) {
     905           0 :                 RETURN_FALSE;
     906             :         }
     907          80 :         RETURN_TRUE;
     908             : }
     909             : /* }}} */
     910             : 
     911             : /* {{{ proto bool sort(array &array_arg [, int sort_flags])
     912             :    Sort an array */
     913         239 : PHP_FUNCTION(sort)
     914             : {
     915             :         zval *array;
     916         239 :         zend_long sort_type = PHP_SORT_REGULAR;
     917             :         compare_func_t cmp;
     918             : 
     919         239 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "a/|l", &array, &sort_type) == FAILURE) {
     920         104 :                 RETURN_FALSE;
     921             :         }
     922             : 
     923         135 :         cmp = php_get_data_compare_func(sort_type, 0);
     924             : 
     925         135 :         if (zend_hash_sort(Z_ARRVAL_P(array), cmp, 1) == FAILURE) {
     926           0 :                 RETURN_FALSE;
     927             :         }
     928         135 :         RETURN_TRUE;
     929             : }
     930             : /* }}} */
     931             : 
     932             : /* {{{ proto bool rsort(array &array_arg [, int sort_flags])
     933             :    Sort an array in reverse order */
     934         182 : PHP_FUNCTION(rsort)
     935             : {
     936             :         zval *array;
     937         182 :         zend_long sort_type = PHP_SORT_REGULAR;
     938             :         compare_func_t cmp;
     939             : 
     940         182 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "a/|l", &array, &sort_type) == FAILURE) {
     941         105 :                 RETURN_FALSE;
     942             :         }
     943             : 
     944          77 :         cmp = php_get_data_compare_func(sort_type, 1);
     945             : 
     946          77 :         if (zend_hash_sort(Z_ARRVAL_P(array), cmp, 1) == FAILURE) {
     947           0 :                 RETURN_FALSE;
     948             :         }
     949          77 :         RETURN_TRUE;
     950             : }
     951             : /* }}} */
     952             : 
     953      217218 : static int php_array_user_compare(const void *a, const void *b) /* {{{ */
     954             : {
     955             :         Bucket *f;
     956             :         Bucket *s;
     957             :         zval args[2];
     958             :         zval retval;
     959             : 
     960      217218 :         f = (Bucket *) a;
     961      217218 :         s = (Bucket *) b;
     962             : 
     963      217218 :         ZVAL_COPY(&args[0], &f->val);
     964      217218 :         ZVAL_COPY(&args[1], &s->val);
     965             : 
     966      217218 :         BG(user_compare_fci).param_count = 2;
     967      217218 :         BG(user_compare_fci).params = args;
     968      217218 :         BG(user_compare_fci).retval = &retval;
     969      217218 :         BG(user_compare_fci).no_separation = 0;
     970      434433 :         if (zend_call_function(&BG(user_compare_fci), &BG(user_compare_fci_cache)) == SUCCESS && Z_TYPE(retval) != IS_UNDEF) {
     971      217213 :                 zend_long ret = zval_get_long(&retval);
     972      217213 :                 zval_ptr_dtor(&retval);
     973      217213 :                 zval_ptr_dtor(&args[1]);
     974      217213 :                 zval_ptr_dtor(&args[0]);
     975      217213 :                 return ret < 0 ? -1 : ret > 0 ? 1 : 0;
     976             :         } else {
     977           5 :                 zval_ptr_dtor(&args[1]);
     978           5 :                 zval_ptr_dtor(&args[0]);
     979           5 :                 return 0;
     980             :         }
     981             : }
     982             : /* }}} */
     983             : 
     984             : /* check if comparison function is valid */
     985             : #define PHP_ARRAY_CMP_FUNC_CHECK(func_name)     \
     986             :         if (!zend_is_callable(*func_name, 0, NULL)) {   \
     987             :                 php_error_docref(NULL, E_WARNING, "Invalid comparison function");     \
     988             :                 BG(user_compare_fci) = old_user_compare_fci; \
     989             :                 BG(user_compare_fci_cache) = old_user_compare_fci_cache; \
     990             :                 RETURN_FALSE;   \
     991             :         }       \
     992             : 
     993             :         /* Clear FCI cache otherwise : for example the same or other array with
     994             :          * (partly) the same key values has been sorted with uasort() or
     995             :          * other sorting function the comparison is cached, however the name
     996             :          * of the function for comparison is not respected. see bug #28739 AND #33295
     997             :          *
     998             :          * Following defines will assist in backup / restore values. */
     999             : 
    1000             : #define PHP_ARRAY_CMP_FUNC_VARS \
    1001             :         zend_fcall_info old_user_compare_fci; \
    1002             :         zend_fcall_info_cache old_user_compare_fci_cache \
    1003             : 
    1004             : #define PHP_ARRAY_CMP_FUNC_BACKUP() \
    1005             :         old_user_compare_fci = BG(user_compare_fci); \
    1006             :         old_user_compare_fci_cache = BG(user_compare_fci_cache); \
    1007             :         BG(user_compare_fci_cache) = empty_fcall_info_cache; \
    1008             : 
    1009             : #define PHP_ARRAY_CMP_FUNC_RESTORE() \
    1010             :         BG(user_compare_fci) = old_user_compare_fci; \
    1011             :         BG(user_compare_fci_cache) = old_user_compare_fci_cache; \
    1012             : 
    1013         271 : static void php_usort(INTERNAL_FUNCTION_PARAMETERS, compare_func_t compare_func, zend_bool renumber) /* {{{ */
    1014             : {
    1015             :         zval *array;
    1016             :         zend_array *arr;
    1017             :         zend_bool retval;
    1018             :         PHP_ARRAY_CMP_FUNC_VARS;
    1019             : 
    1020         271 :         PHP_ARRAY_CMP_FUNC_BACKUP();
    1021             : 
    1022         271 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "af", &array, &BG(user_compare_fci), &BG(user_compare_fci_cache)) == FAILURE) {
    1023         168 :                 PHP_ARRAY_CMP_FUNC_RESTORE();
    1024         168 :                 return;
    1025             :         }
    1026             : 
    1027         103 :         arr = Z_ARR_P(array);
    1028         103 :         if (zend_hash_num_elements(arr) == 0)  {
    1029           4 :                 PHP_ARRAY_CMP_FUNC_RESTORE();
    1030           4 :                 RETURN_TRUE;
    1031             :         }
    1032             : 
    1033             :         /* Copy array, so the in-place modifications will not be visible to the callback function */
    1034          99 :         arr = zend_array_dup(arr);
    1035             : 
    1036          99 :         retval = zend_hash_sort(arr, compare_func, renumber) != FAILURE;
    1037             : 
    1038          99 :         zval_ptr_dtor(array);
    1039          99 :         ZVAL_ARR(array, arr);
    1040             : 
    1041          99 :         PHP_ARRAY_CMP_FUNC_RESTORE();
    1042          99 :         RETURN_BOOL(retval);
    1043             : }
    1044             : /* }}} */
    1045             : 
    1046             : /* {{{ proto bool usort(array array_arg, string cmp_function)
    1047             :    Sort an array by values using a user-defined comparison function */
    1048         107 : PHP_FUNCTION(usort)
    1049             : {
    1050         107 :         php_usort(INTERNAL_FUNCTION_PARAM_PASSTHRU, php_array_user_compare, 1);
    1051         107 : }
    1052             : /* }}} */
    1053             : 
    1054             : /* {{{ proto bool uasort(array array_arg, string cmp_function)
    1055             :    Sort an array with a user-defined comparison function and maintain index association */
    1056         101 : PHP_FUNCTION(uasort)
    1057             : {
    1058         101 :         php_usort(INTERNAL_FUNCTION_PARAM_PASSTHRU, php_array_user_compare, 0);
    1059         101 : }
    1060             : /* }}} */
    1061             : 
    1062        5092 : static int php_array_user_key_compare(const void *a, const void *b) /* {{{ */
    1063             : {
    1064             :         Bucket *f;
    1065             :         Bucket *s;
    1066             :         zval args[2];
    1067             :         zval retval;
    1068             :         zend_long result;
    1069             : 
    1070        5092 :         ZVAL_NULL(&args[0]);
    1071        5092 :         ZVAL_NULL(&args[1]);
    1072             : 
    1073        5092 :         f = (Bucket *) a;
    1074        5092 :         s = (Bucket *) b;
    1075             : 
    1076        5092 :         if (f->key == NULL) {
    1077        1803 :                 ZVAL_LONG(&args[0], f->h);
    1078             :         } else {
    1079        3289 :                 ZVAL_STR_COPY(&args[0], f->key);
    1080             :         }
    1081        5092 :         if (s->key == NULL) {
    1082        2030 :                 ZVAL_LONG(&args[1], s->h);
    1083             :         } else {
    1084        3062 :                 ZVAL_STR_COPY(&args[1], s->key);
    1085             :         }
    1086             : 
    1087        5092 :         BG(user_compare_fci).param_count = 2;
    1088        5092 :         BG(user_compare_fci).params = args;
    1089        5092 :         BG(user_compare_fci).retval = &retval;
    1090        5092 :         BG(user_compare_fci).no_separation = 0;
    1091       15272 :         if (zend_call_function(&BG(user_compare_fci), &BG(user_compare_fci_cache)) == SUCCESS && Z_TYPE(retval) != IS_UNDEF) {
    1092        5089 :                 result = zval_get_long(&retval);
    1093        5089 :                 zval_ptr_dtor(&retval);
    1094             :         } else {
    1095           3 :                 result = 0;
    1096             :         }
    1097             : 
    1098        5092 :         zval_ptr_dtor(&args[0]);
    1099        5092 :         zval_ptr_dtor(&args[1]);
    1100             : 
    1101        5092 :         return result < 0 ? -1 : result > 0 ? 1 : 0;
    1102             : }
    1103             : /* }}} */
    1104             : 
    1105             : /* {{{ proto bool uksort(array array_arg, string cmp_function)
    1106             :    Sort an array by keys using a user-defined comparison function */
    1107          63 : PHP_FUNCTION(uksort)
    1108             : {
    1109          63 :         php_usort(INTERNAL_FUNCTION_PARAM_PASSTHRU, php_array_user_key_compare, 0);
    1110          63 : }
    1111             : /* }}} */
    1112             : 
    1113             : /* {{{ proto mixed end(array array_arg)
    1114             :    Advances array argument's internal pointer to the last element and return it */
    1115          76 : PHP_FUNCTION(end)
    1116             : {
    1117             :         HashTable *array;
    1118             :         zval *entry;
    1119             : 
    1120          76 :         ZEND_PARSE_PARAMETERS_START(1, 1)
    1121         292 :                 Z_PARAM_ARRAY_OR_OBJECT_HT_EX(array, 0, 1)
    1122          76 :         ZEND_PARSE_PARAMETERS_END();
    1123             : 
    1124          47 :         zend_hash_internal_pointer_end(array);
    1125             : 
    1126          47 :         if (USED_RET()) {
    1127          34 :                 if ((entry = zend_hash_get_current_data(array)) == NULL) {
    1128           2 :                         RETURN_FALSE;
    1129             :                 }
    1130             : 
    1131          32 :                 if (Z_TYPE_P(entry) == IS_INDIRECT) {
    1132           1 :                         entry = Z_INDIRECT_P(entry);
    1133             :                 }
    1134             : 
    1135          32 :                 ZVAL_DEREF(entry);
    1136          32 :                 ZVAL_COPY(return_value, entry);
    1137             :         }
    1138             : }
    1139             : /* }}} */
    1140             : 
    1141             : /* {{{ proto mixed prev(array array_arg)
    1142             :    Move array argument's internal pointer to the previous element and return it */
    1143          46 : PHP_FUNCTION(prev)
    1144             : {
    1145             :         HashTable *array;
    1146             :         zval *entry;
    1147             : 
    1148          46 :         ZEND_PARSE_PARAMETERS_START(1, 1)
    1149         154 :                 Z_PARAM_ARRAY_OR_OBJECT_HT_EX(array, 0, 1)
    1150          46 :         ZEND_PARSE_PARAMETERS_END();
    1151             : 
    1152          21 :         zend_hash_move_backwards(array);
    1153             : 
    1154          21 :         if (USED_RET()) {
    1155          19 :                 if ((entry = zend_hash_get_current_data(array)) == NULL) {
    1156           6 :                         RETURN_FALSE;
    1157             :                 }
    1158             : 
    1159          13 :                 if (Z_TYPE_P(entry) == IS_INDIRECT) {
    1160           0 :                         entry = Z_INDIRECT_P(entry);
    1161             :                 }
    1162             : 
    1163          13 :                 ZVAL_DEREF(entry);
    1164          13 :                 ZVAL_COPY(return_value, entry);
    1165             :         }
    1166             : }
    1167             : /* }}} */
    1168             : 
    1169             : /* {{{ proto mixed next(array array_arg)
    1170             :    Move array argument's internal pointer to the next element and return it */
    1171        1511 : PHP_FUNCTION(next)
    1172             : {
    1173             :         HashTable *array;
    1174             :         zval *entry;
    1175             : 
    1176        1511 :         ZEND_PARSE_PARAMETERS_START(1, 1)
    1177        6046 :                 Z_PARAM_ARRAY_OR_OBJECT_HT_EX(array, 0, 1)
    1178        1511 :         ZEND_PARSE_PARAMETERS_END();
    1179             : 
    1180        1480 :         zend_hash_move_forward(array);
    1181             : 
    1182        1480 :         if (USED_RET()) {
    1183        1431 :                 if ((entry = zend_hash_get_current_data(array)) == NULL) {
    1184         347 :                         RETURN_FALSE;
    1185             :                 }
    1186             : 
    1187        1084 :                 if (Z_TYPE_P(entry) == IS_INDIRECT) {
    1188           0 :                         entry = Z_INDIRECT_P(entry);
    1189             :                 }
    1190             : 
    1191        1084 :                 ZVAL_DEREF(entry);
    1192        1084 :                 ZVAL_COPY(return_value, entry);
    1193             :         }
    1194             : }
    1195             : /* }}} */
    1196             : 
    1197             : /* {{{ proto mixed reset(array array_arg)
    1198             :    Set array argument's internal pointer to the first element and return it */
    1199         475 : PHP_FUNCTION(reset)
    1200             : {
    1201             :         HashTable *array;
    1202             :         zval *entry;
    1203             : 
    1204         475 :         ZEND_PARSE_PARAMETERS_START(1, 1)
    1205        1906 :                 Z_PARAM_ARRAY_OR_OBJECT_HT_EX(array, 0, 1)
    1206         475 :         ZEND_PARSE_PARAMETERS_END();
    1207             : 
    1208         444 :         zend_hash_internal_pointer_reset(array);
    1209             : 
    1210         444 :         if (USED_RET()) {
    1211          70 :                 if ((entry = zend_hash_get_current_data(array)) == NULL) {
    1212           3 :                         RETURN_FALSE;
    1213             :                 }
    1214             : 
    1215          67 :                 if (Z_TYPE_P(entry) == IS_INDIRECT) {
    1216           0 :                         entry = Z_INDIRECT_P(entry);
    1217             :                 }
    1218             : 
    1219          67 :                 ZVAL_DEREF(entry);
    1220          67 :                 ZVAL_COPY(return_value, entry);
    1221             :         }
    1222             : }
    1223             : /* }}} */
    1224             : 
    1225             : /* {{{ proto mixed current(array array_arg)
    1226             :    Return the element currently pointed to by the internal array pointer */
    1227        1655 : PHP_FUNCTION(current)
    1228             : {
    1229             :         HashTable *array;
    1230             :         zval *entry;
    1231             : 
    1232        1655 :         ZEND_PARSE_PARAMETERS_START(1, 1)
    1233        4953 :                 Z_PARAM_ARRAY_OR_OBJECT_HT(array)
    1234        1655 :         ZEND_PARSE_PARAMETERS_END();
    1235             : 
    1236        1624 :         if ((entry = zend_hash_get_current_data(array)) == NULL) {
    1237          24 :                 RETURN_FALSE;
    1238             :         }
    1239             : 
    1240        1600 :         if (Z_TYPE_P(entry) == IS_INDIRECT) {
    1241           1 :                 entry = Z_INDIRECT_P(entry);
    1242             :         }
    1243             : 
    1244        1600 :         ZVAL_DEREF(entry);
    1245        1600 :         ZVAL_COPY(return_value, entry);
    1246             : }
    1247             : /* }}} */
    1248             : 
    1249             : /* {{{ proto mixed key(array array_arg)
    1250             :    Return the key of the element currently pointed to by the internal array pointer */
    1251        1612 : PHP_FUNCTION(key)
    1252             : {
    1253             :         HashTable *array;
    1254             : 
    1255        1612 :         ZEND_PARSE_PARAMETERS_START(1, 1)
    1256        4824 :                 Z_PARAM_ARRAY_OR_OBJECT_HT(array)
    1257        1612 :         ZEND_PARSE_PARAMETERS_END();
    1258             : 
    1259        1581 :         zend_hash_get_current_key_zval(array, return_value);
    1260             : }
    1261             : /* }}} */
    1262             : 
    1263             : /* {{{ proto mixed min(mixed arg1 [, mixed arg2 [, mixed ...]])
    1264             :    Return the lowest value in an array or a series of arguments */
    1265         667 : PHP_FUNCTION(min)
    1266             : {
    1267             :         int argc;
    1268         667 :         zval *args = NULL;
    1269             : 
    1270         667 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "+", &args, &argc) == FAILURE) {
    1271           2 :                 return;
    1272             :         }
    1273             : 
    1274             :         /* mixed min ( array $values ) */
    1275         665 :         if (argc == 1) {
    1276             :                 zval *result;
    1277             : 
    1278          46 :                 if (Z_TYPE(args[0]) != IS_ARRAY) {
    1279           4 :                         php_error_docref(NULL, E_WARNING, "When only one parameter is given, it must be an array");
    1280           4 :                         RETVAL_NULL();
    1281             :                 } else {
    1282          19 :                         if ((result = zend_hash_minmax(Z_ARRVAL(args[0]), php_array_data_compare, 0)) != NULL) {
    1283          17 :                                 ZVAL_DEREF(result);
    1284          17 :                                 ZVAL_COPY(return_value, result);
    1285             :                         } else {
    1286           2 :                                 php_error_docref(NULL, E_WARNING, "Array must contain at least one element");
    1287           2 :                                 RETVAL_FALSE;
    1288             :                         }
    1289             :                 }
    1290             :         } else {
    1291             :                 /* mixed min ( mixed $value1 , mixed $value2 [, mixed $value3... ] ) */
    1292             :                 zval *min, result;
    1293             :                 int i;
    1294             : 
    1295         642 :                 min = &args[0];
    1296             : 
    1297        2535 :                 for (i = 1; i < argc; i++) {
    1298        1893 :                         is_smaller_function(&result, &args[i], min);
    1299        1893 :                         if (Z_TYPE(result) == IS_TRUE) {
    1300         583 :                                 min = &args[i];
    1301             :                         }
    1302             :                 }
    1303             : 
    1304         642 :                 ZVAL_DEREF(min);
    1305         642 :                 ZVAL_COPY(return_value, min);
    1306             :         }
    1307             : }
    1308             : /* }}} */
    1309             : 
    1310             : /* {{{ proto mixed max(mixed arg1 [, mixed arg2 [, mixed ...]])
    1311             :    Return the highest value in an array or a series of arguments */
    1312          96 : PHP_FUNCTION(max)
    1313             : {
    1314          96 :         zval *args = NULL;
    1315             :         int argc;
    1316             : 
    1317          96 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "+", &args, &argc) == FAILURE) {
    1318           2 :                 return;
    1319             :         }
    1320             : 
    1321             :         /* mixed max ( array $values ) */
    1322          94 :         if (argc == 1) {
    1323             :                 zval *result;
    1324             : 
    1325         134 :                 if (Z_TYPE(args[0]) != IS_ARRAY) {
    1326           4 :                         php_error_docref(NULL, E_WARNING, "When only one parameter is given, it must be an array");
    1327           4 :                         RETVAL_NULL();
    1328             :                 } else {
    1329          63 :                         if ((result = zend_hash_minmax(Z_ARRVAL(args[0]), php_array_data_compare, 1)) != NULL) {
    1330          61 :                                 ZVAL_DEREF(result);
    1331          61 :                                 ZVAL_COPY(return_value, result);
    1332             :                         } else {
    1333           2 :                                 php_error_docref(NULL, E_WARNING, "Array must contain at least one element");
    1334           2 :                                 RETVAL_FALSE;
    1335             :                         }
    1336             :                 }
    1337             :         } else {
    1338             :                 /* mixed max ( mixed $value1 , mixed $value2 [, mixed $value3... ] ) */
    1339             :                 zval *max, result;
    1340             :                 int i;
    1341             : 
    1342          27 :                 max = &args[0];
    1343             : 
    1344        1305 :                 for (i = 1; i < argc; i++) {
    1345        1278 :                         is_smaller_or_equal_function(&result, &args[i], max);
    1346        1278 :                         if (Z_TYPE(result) == IS_FALSE) {
    1347          43 :                                 max = &args[i];
    1348             :                         }
    1349             :                 }
    1350             : 
    1351          27 :                 ZVAL_DEREF(max);
    1352          27 :                 ZVAL_COPY(return_value, max);
    1353             :         }
    1354             : }
    1355             : /* }}} */
    1356             : 
    1357         267 : static int php_array_walk(zval *array, zval *userdata, int recursive) /* {{{ */
    1358             : {
    1359             :         zval args[3],           /* Arguments to userland function */
    1360             :                  retval,                /* Return value - unused */
    1361             :                  *zv;
    1362         273 :         HashTable *target_hash = HASH_OF(array);
    1363             :         HashPosition pos;
    1364             :         uint32_t ht_iter;
    1365         267 :         int result = SUCCESS;
    1366             : 
    1367             :         /* Set up known arguments */
    1368         267 :         ZVAL_UNDEF(&args[1]);
    1369         267 :         if (userdata) {
    1370         151 :                 ZVAL_COPY(&args[2], userdata);
    1371             :         }
    1372             : 
    1373         267 :         BG(array_walk_fci).retval = &retval;
    1374         267 :         BG(array_walk_fci).param_count = userdata ? 3 : 2;
    1375         267 :         BG(array_walk_fci).params = args;
    1376         267 :         BG(array_walk_fci).no_separation = 0;
    1377             : 
    1378         267 :         zend_hash_internal_pointer_reset_ex(target_hash, &pos);
    1379         267 :         ht_iter = zend_hash_iterator_add(target_hash, pos);
    1380             : 
    1381             :         /* Iterate through hash */
    1382             :         do {
    1383             :                 /* Retrieve value */
    1384        1284 :                 zv = zend_hash_get_current_data_ex(target_hash, &pos);
    1385        1284 :                 if (zv == NULL) {
    1386         252 :                         break;
    1387             :                 }
    1388             : 
    1389             :                 /* Skip undefined indirect elements */
    1390        1032 :                 if (Z_TYPE_P(zv) == IS_INDIRECT) {
    1391          12 :                         zv = Z_INDIRECT_P(zv);
    1392          12 :                         if (Z_TYPE_P(zv) == IS_UNDEF) {
    1393           0 :                                 zend_hash_move_forward_ex(target_hash, &pos);
    1394           0 :                                 continue;
    1395             :                         }
    1396             :                 }
    1397             : 
    1398             :                 /* Ensure the value is a reference. Otherwise the location of the value may be freed. */
    1399        2064 :                 ZVAL_MAKE_REF(zv);
    1400             : 
    1401             :                 /* Retrieve key */
    1402        1032 :                 zend_hash_get_current_key_zval_ex(target_hash, &args[1], &pos);
    1403             : 
    1404             :                 /* Move to next element already now -- this mirrors the approach used by foreach
    1405             :                  * and ensures proper behavior with regard to modifications. */
    1406        1032 :                 zend_hash_move_forward_ex(target_hash, &pos);
    1407             : 
    1408             :                 /* Back up hash position, as it may change */
    1409        1032 :                 EG(ht_iterators)[ht_iter].pos = pos;
    1410             : 
    1411        1585 :                 if (recursive && Z_TYPE_P(Z_REFVAL_P(zv)) == IS_ARRAY) {
    1412             :                         HashTable *thash;
    1413             :                         zend_fcall_info orig_array_walk_fci;
    1414             :                         zend_fcall_info_cache orig_array_walk_fci_cache;
    1415             :                         zval ref;
    1416         111 :                         ZVAL_COPY_VALUE(&ref, zv);
    1417             : 
    1418         111 :                         ZVAL_DEREF(zv);
    1419         111 :                         SEPARATE_ARRAY(zv);
    1420         111 :                         thash = Z_ARRVAL_P(zv);
    1421         111 :                         if (thash->u.v.nApplyCount > 1) {
    1422           0 :                                 php_error_docref(NULL, E_WARNING, "recursion detected");
    1423           0 :                                 result = FAILURE;
    1424           0 :                                 break;
    1425             :                         }
    1426             : 
    1427             :                         /* backup the fcall info and cache */
    1428         111 :                         orig_array_walk_fci = BG(array_walk_fci);
    1429         111 :                         orig_array_walk_fci_cache = BG(array_walk_fci_cache);
    1430             : 
    1431             :                         Z_ADDREF(ref);
    1432         111 :                         thash->u.v.nApplyCount++;
    1433         111 :                         result = php_array_walk(zv, userdata, recursive);
    1434         222 :                         if (Z_TYPE_P(Z_REFVAL(ref)) == IS_ARRAY && thash == Z_ARRVAL_P(Z_REFVAL(ref))) {
    1435             :                                 /* If the hashtable changed in the meantime, we'll "leak" this apply count
    1436             :                                  * increment -- our reference to thash is no longer valid. */
    1437         111 :                                 thash->u.v.nApplyCount--;
    1438             :                         }
    1439         111 :                         zval_ptr_dtor(&ref);
    1440             : 
    1441             :                         /* restore the fcall info and cache */
    1442         111 :                         BG(array_walk_fci) = orig_array_walk_fci;
    1443         111 :                         BG(array_walk_fci_cache) = orig_array_walk_fci_cache;
    1444             :                 } else {
    1445         921 :                         ZVAL_COPY(&args[0], zv);
    1446             : 
    1447             :                         /* Call the userland function */
    1448         921 :                         result = zend_call_function(&BG(array_walk_fci), &BG(array_walk_fci_cache));
    1449         920 :                         if (result == SUCCESS) {
    1450         920 :                                 zval_ptr_dtor(&retval);
    1451             :                         }
    1452             : 
    1453         920 :                         zval_ptr_dtor(&args[0]);
    1454             :                 }
    1455             : 
    1456        1031 :                 if (Z_TYPE(args[1]) != IS_UNDEF) {
    1457        1031 :                         zval_ptr_dtor(&args[1]);
    1458        1031 :                         ZVAL_UNDEF(&args[1]);
    1459             :                 }
    1460             : 
    1461        1031 :                 if (result == FAILURE) {
    1462           0 :                         break;
    1463             :                 }
    1464             : 
    1465             :                 /* Reload array and position -- both may have changed */
    1466        1031 :                 if (Z_TYPE_P(array) == IS_ARRAY) {
    1467        1014 :                         pos = zend_hash_iterator_pos_ex(ht_iter, array);
    1468        1014 :                         target_hash = Z_ARRVAL_P(array);
    1469          17 :                 } else if (Z_TYPE_P(array) == IS_OBJECT) {
    1470          16 :                         target_hash = Z_OBJPROP_P(array);
    1471          16 :                         pos = zend_hash_iterator_pos(ht_iter, target_hash);
    1472             :                 } else {
    1473           1 :                         php_error_docref(NULL, E_WARNING, "Iterated value is no longer an array or object");
    1474           1 :                         result = FAILURE;
    1475           1 :                         break;
    1476             :                 }
    1477        1030 :         } while (!EG(exception));
    1478             : 
    1479         266 :         if (userdata) {
    1480         150 :                 zval_ptr_dtor(&args[2]);
    1481             :         }
    1482         266 :         zend_hash_iterator_del(ht_iter);
    1483         266 :         return result;
    1484             : }
    1485             : /* }}} */
    1486             : 
    1487             : /* {{{ proto bool array_walk(array input, string funcname [, mixed userdata])
    1488             :    Apply a user function to every member of an array */
    1489         212 : PHP_FUNCTION(array_walk)
    1490             : {
    1491             :         zval *array;
    1492         212 :         zval *userdata = NULL;
    1493             :         zend_fcall_info orig_array_walk_fci;
    1494             :         zend_fcall_info_cache orig_array_walk_fci_cache;
    1495             : 
    1496         212 :         orig_array_walk_fci = BG(array_walk_fci);
    1497         212 :         orig_array_walk_fci_cache = BG(array_walk_fci_cache);
    1498             : 
    1499         212 :         ZEND_PARSE_PARAMETERS_START(2, 3)
    1500         850 :                 Z_PARAM_ARRAY_OR_OBJECT_EX(array, 0, 1)
    1501         474 :                 Z_PARAM_FUNC(BG(array_walk_fci), BG(array_walk_fci_cache))
    1502         104 :                 Z_PARAM_OPTIONAL
    1503         213 :                 Z_PARAM_ZVAL_EX(userdata, 0, 1)
    1504         212 :         ZEND_PARSE_PARAMETERS_END_EX(
    1505             :                 BG(array_walk_fci) = orig_array_walk_fci;
    1506             :                 BG(array_walk_fci_cache) = orig_array_walk_fci_cache;
    1507             :                 return
    1508             :         );
    1509             : 
    1510         104 :         php_array_walk(array, userdata, 0);
    1511         103 :         BG(array_walk_fci) = orig_array_walk_fci;
    1512         103 :         BG(array_walk_fci_cache) = orig_array_walk_fci_cache;
    1513         103 :         RETURN_TRUE;
    1514             : }
    1515             : /* }}} */
    1516             : 
    1517             : /* {{{ proto bool array_walk_recursive(array input, string funcname [, mixed userdata])
    1518             :    Apply a user function recursively to every member of an array */
    1519         156 : PHP_FUNCTION(array_walk_recursive)
    1520             : {
    1521             :         zval *array;
    1522         156 :         zval *userdata = NULL;
    1523             :         zend_fcall_info orig_array_walk_fci;
    1524             :         zend_fcall_info_cache orig_array_walk_fci_cache;
    1525             : 
    1526         156 :         orig_array_walk_fci = BG(array_walk_fci);
    1527         156 :         orig_array_walk_fci_cache = BG(array_walk_fci_cache);
    1528             : 
    1529         156 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "A/f|z/", &array, &BG(array_walk_fci), &BG(array_walk_fci_cache), &userdata) == FAILURE) {
    1530         104 :                 BG(array_walk_fci) = orig_array_walk_fci;
    1531         104 :                 BG(array_walk_fci_cache) = orig_array_walk_fci_cache;
    1532         104 :                 return;
    1533             :         }
    1534             : 
    1535          52 :         php_array_walk(array, userdata, 1);
    1536          52 :         BG(array_walk_fci) = orig_array_walk_fci;
    1537          52 :         BG(array_walk_fci_cache) = orig_array_walk_fci_cache;
    1538          52 :         RETURN_TRUE;
    1539             : }
    1540             : /* }}} */
    1541             : 
    1542             : /* void php_search_array(INTERNAL_FUNCTION_PARAMETERS, int behavior)
    1543             :  * 0 = return boolean
    1544             :  * 1 = return key
    1545             :  */
    1546        7301 : static inline void php_search_array(INTERNAL_FUNCTION_PARAMETERS, int behavior) /* {{{ */
    1547             : {
    1548             :         zval *value,                            /* value to check for */
    1549             :                  *array,                                /* array to check in */
    1550             :                  *entry;                                /* pointer to array entry */
    1551             :         zend_ulong num_idx;
    1552             :         zend_string *str_idx;
    1553        7301 :         zend_bool strict = 0;           /* strict comparison or not */
    1554             : 
    1555        7301 :         ZEND_PARSE_PARAMETERS_START(2, 3)
    1556        7294 :                 Z_PARAM_ZVAL(value)
    1557       21882 :                 Z_PARAM_ARRAY(array)
    1558        7285 :                 Z_PARAM_OPTIONAL
    1559        8563 :                 Z_PARAM_BOOL(strict)
    1560        7301 :         ZEND_PARSE_PARAMETERS_END();
    1561             : 
    1562        7285 :         if (strict) {
    1563        2814 :                 ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(array), num_idx, str_idx, entry) {
    1564        1262 :                         ZVAL_DEREF(entry);
    1565        2524 :                         if (fast_is_identical_function(value, entry)) {
    1566          36 :                                 if (behavior == 0) {
    1567          18 :                                         RETURN_TRUE;
    1568             :                                 } else {
    1569          18 :                                         if (str_idx) {
    1570           4 :                                                 RETVAL_STR_COPY(str_idx);
    1571             :                                         } else {
    1572          14 :                                                 RETVAL_LONG(num_idx);
    1573             :                                         }
    1574          18 :                                         return;
    1575             :                                 }
    1576             :                         }
    1577             :                 } ZEND_HASH_FOREACH_END();
    1578             :         } else {
    1579       13918 :                 if (Z_TYPE_P(value) == IS_LONG) {
    1580       17663 :                         ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(array), num_idx, str_idx, entry) {
    1581       16504 :                                 if (fast_equal_check_long(value, entry)) {
    1582         218 :                                         if (behavior == 0) {
    1583         183 :                                                 RETURN_TRUE;
    1584             :                                         } else {
    1585          35 :                                                 if (str_idx) {
    1586           5 :                                                         RETVAL_STR_COPY(str_idx);
    1587             :                                                 } else {
    1588          30 :                                                         RETVAL_LONG(num_idx);
    1589             :                                                 }
    1590          35 :                                                 return;
    1591             :                                         }
    1592             :                                 }
    1593             :                         } ZEND_HASH_FOREACH_END();
    1594       11164 :                 } else if (Z_TYPE_P(value) == IS_STRING) {
    1595      962902 :                         ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(array), num_idx, str_idx, entry) {
    1596      961480 :                                 if (fast_equal_check_string(value, entry)) {
    1597        2984 :                                         if (behavior == 0) {
    1598        2905 :                                                 RETURN_TRUE;
    1599             :                                         } else {
    1600          79 :                                                 if (str_idx) {
    1601           8 :                                                         RETVAL_STR_COPY(str_idx);
    1602             :                                                 } else {
    1603          71 :                                                         RETVAL_LONG(num_idx);
    1604             :                                                 }
    1605          79 :                                                 return;
    1606             :                                         }
    1607             :                                 }
    1608             :                         } ZEND_HASH_FOREACH_END();
    1609             :                 } else {
    1610       28391 :                         ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(array), num_idx, str_idx, entry) {
    1611       28254 :                                 if (fast_equal_check_function(value, entry)) {
    1612        1057 :                                         if (behavior == 0) {
    1613         995 :                                                 RETURN_TRUE;
    1614             :                                         } else {
    1615          62 :                                                 if (str_idx) {
    1616          12 :                                                         RETVAL_STR_COPY(str_idx);
    1617             :                                                 } else {
    1618          50 :                                                         RETVAL_LONG(num_idx);
    1619             :                                                 }
    1620          62 :                                                 return;
    1621             :                                         }
    1622             :                                 }
    1623             :                         } ZEND_HASH_FOREACH_END();
    1624             :                 }
    1625             :         }
    1626             : 
    1627        2990 :         RETURN_FALSE;
    1628             : }
    1629             : /* }}} */
    1630             : 
    1631             : /* {{{ proto bool in_array(mixed needle, array haystack [, bool strict])
    1632             :    Checks if the given value exists in the array */
    1633        6776 : PHP_FUNCTION(in_array)
    1634             : {
    1635        6776 :         php_search_array(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
    1636        6776 : }
    1637             : /* }}} */
    1638             : 
    1639             : /* {{{ proto mixed array_search(mixed needle, array haystack [, bool strict])
    1640             :    Searches the array for a given value and returns the corresponding key if successful */
    1641         525 : PHP_FUNCTION(array_search)
    1642             : {
    1643         525 :         php_search_array(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
    1644         525 : }
    1645             : /* }}} */
    1646             : 
    1647             : static zend_always_inline int php_valid_var_name(char *var_name, size_t var_name_len) /* {{{ */
    1648             : {
    1649             : #if 1
    1650             :         /* first 256 bits for first character, and second 256 bits for the next */
    1651             :         static const uint32_t charset[16] = {
    1652             :              /*  31      0   63     32   95     64   127    96 */
    1653             :                         0x00000000, 0x00000000, 0x87fffffe, 0x07fffffe,
    1654             :                         0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
    1655             :              /*  31      0   63     32   95     64   127    96 */
    1656             :                         0x00000000, 0x03ff0000, 0x87fffffe, 0x07fffffe,
    1657             :                         0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff
    1658             :                 };
    1659             : #endif
    1660             :         size_t i;
    1661             :         uint32_t ch;
    1662             : 
    1663         431 :         if (UNEXPECTED(!var_name_len)) {
    1664           4 :                 return 0;
    1665             :         }
    1666             : 
    1667             :         /* These are allowed as first char: [a-zA-Z_\x7f-\xff] */
    1668         427 :         ch = (uint32_t)((unsigned char *)var_name)[0];
    1669             : #if 1
    1670         427 :         if (UNEXPECTED(!(charset[ch >> 5] & (1 << (ch & 0x1f))))) {
    1671             : #else
    1672             :         if (var_name[0] != '_' &&
    1673             :                 (ch < 65  /* A    */ || /* Z    */ ch > 90)  &&
    1674             :                 (ch < 97  /* a    */ || /* z    */ ch > 122) &&
    1675             :                 (ch < 127 /* 0x7f */ || /* 0xff */ ch > 255)
    1676             :         ) {
    1677             : #endif
    1678          15 :                 return 0;
    1679             :         }
    1680             : 
    1681             :         /* And these as the rest: [a-zA-Z0-9_\x7f-\xff] */
    1682         412 :         if (var_name_len > 1) {
    1683         359 :                 i = 1;
    1684             :                 do {
    1685        1122 :                         ch = (uint32_t)((unsigned char *)var_name)[i];
    1686             : #if 1
    1687        1122 :                         if (UNEXPECTED(!(charset[8 + (ch >> 5)] & (1 << (ch & 0x1f))))) {
    1688             : #else
    1689             :                         if (var_name[i] != '_' &&
    1690             :                                 (ch < 48  /* 0    */ || /* 9    */ ch > 57)  &&
    1691             :                                 (ch < 65  /* A    */ || /* Z    */ ch > 90)  &&
    1692             :                                 (ch < 97  /* a    */ || /* z    */ ch > 122) &&
    1693             :                                 (ch < 127 /* 0x7f */ || /* 0xff */ ch > 255)
    1694             :                         ) {
    1695             : #endif
    1696           6 :                                 return 0;
    1697             :                         }
    1698        1116 :                 } while (++i < var_name_len);
    1699             :         }
    1700         406 :         return 1;
    1701             : }
    1702             : /* }}} */
    1703             : 
    1704         237 : PHPAPI int php_prefix_varname(zval *result, zval *prefix, char *var_name, size_t var_name_len, zend_bool add_underscore) /* {{{ */
    1705             : {
    1706         474 :         ZVAL_NEW_STR(result, zend_string_alloc(Z_STRLEN_P(prefix) + (add_underscore ? 1 : 0) + var_name_len, 0));
    1707         237 :         memcpy(Z_STRVAL_P(result), Z_STRVAL_P(prefix), Z_STRLEN_P(prefix));
    1708             : 
    1709         237 :         if (add_underscore) {
    1710         237 :                 Z_STRVAL_P(result)[Z_STRLEN_P(prefix)] = '_';
    1711             :         }
    1712             : 
    1713         237 :         memcpy(Z_STRVAL_P(result) + Z_STRLEN_P(prefix) + (add_underscore ? 1 : 0), var_name, var_name_len + 1);
    1714             : 
    1715         237 :         return SUCCESS;
    1716             : }
    1717             : /* }}} */
    1718             : 
    1719             : /* {{{ proto int extract(array var_array [, int extract_type [, string prefix]])
    1720             :    Imports variables into symbol table from an array */
    1721         146 : PHP_FUNCTION(extract)
    1722             : {
    1723         146 :         zval *var_array_param, *prefix = NULL;
    1724         146 :         zend_long extract_type = EXTR_OVERWRITE;
    1725             :         zval *entry;
    1726             :         zend_string *var_name;
    1727             :         zend_ulong num_key;
    1728         146 :         int var_exists, count = 0;
    1729         146 :         int extract_refs = 0;
    1730         146 :         int exception_thrown = 0;
    1731             :         zend_array *symbol_table;
    1732             :         zval var_array;
    1733             : 
    1734         146 :         ZEND_PARSE_PARAMETERS_START(1, 3)
    1735         432 :                 Z_PARAM_ARRAY(var_array_param)
    1736         142 :                 Z_PARAM_OPTIONAL
    1737         372 :                 Z_PARAM_LONG(extract_type)
    1738         179 :                 Z_PARAM_ZVAL_EX(prefix, 0, 1)
    1739         146 :         ZEND_PARSE_PARAMETERS_END();
    1740             : 
    1741         142 :         extract_refs = (extract_type & EXTR_REFS);
    1742         142 :         if (extract_refs) {
    1743          38 :                 SEPARATE_ZVAL(var_array_param);
    1744             :         }
    1745         142 :         extract_type &= 0xff;
    1746             : 
    1747         142 :         if (extract_type < EXTR_OVERWRITE || extract_type > EXTR_IF_EXISTS) {
    1748           2 :                 php_error_docref(NULL, E_WARNING, "Invalid extract type");
    1749           2 :                 return;
    1750             :         }
    1751             : 
    1752         140 :         if (extract_type > EXTR_SKIP && extract_type <= EXTR_PREFIX_IF_EXISTS && ZEND_NUM_ARGS() < 3) {
    1753           1 :                 php_error_docref(NULL, E_WARNING, "specified extract type requires the prefix parameter");
    1754           1 :                 return;
    1755             :         }
    1756             : 
    1757         139 :         if (prefix) {
    1758         126 :                 convert_to_string(prefix);
    1759         115 :                 if (Z_STRLEN_P(prefix) && !php_valid_var_name(Z_STRVAL_P(prefix), Z_STRLEN_P(prefix))) {
    1760           0 :                         php_error_docref(NULL, E_WARNING, "prefix is not a valid identifier");
    1761           0 :                         return;
    1762             :                 }
    1763             :         }
    1764             : 
    1765         139 :         if (zend_forbid_dynamic_call("extract()") == FAILURE) {
    1766           6 :                 return;
    1767             :         }
    1768             : 
    1769         133 :         symbol_table = zend_rebuild_symbol_table();
    1770             : 
    1771             :         /* The array might be stored in a local variable that will be overwritten. To avoid losing the
    1772             :          * reference in that case we work on a copy. */
    1773         133 :         ZVAL_COPY(&var_array, var_array_param);
    1774             : 
    1775        2296 :         ZEND_HASH_FOREACH_KEY_VAL_IND(Z_ARRVAL(var_array), num_key, var_name, entry) {
    1776             :                 zval final_name;
    1777             : 
    1778         702 :                 ZVAL_NULL(&final_name);
    1779         702 :                 var_exists = 0;
    1780             : 
    1781         702 :                 if (var_name) {
    1782         222 :                         var_exists = zend_hash_exists_ind(symbol_table, var_name);
    1783         651 :                 } else if (extract_type == EXTR_PREFIX_ALL || extract_type == EXTR_PREFIX_INVALID) {
    1784         171 :                         zend_string *str = zend_long_to_str(num_key);
    1785         171 :                         php_prefix_varname(&final_name, prefix, ZSTR_VAL(str), ZSTR_LEN(str), 1);
    1786             :                         zend_string_release(str);
    1787             :                 } else {
    1788         309 :                         continue;
    1789             :                 }
    1790             : 
    1791         393 :                 switch (extract_type) {
    1792             :                         case EXTR_IF_EXISTS:
    1793          15 :                                 if (!var_exists) break;
    1794             :                                 /* break omitted intentionally */
    1795             : 
    1796             :                         case EXTR_OVERWRITE:
    1797             :                                 /* GLOBALS protection */
    1798         112 :                                 if (var_exists && ZSTR_LEN(var_name) == sizeof("GLOBALS")-1 && !strcmp(ZSTR_VAL(var_name), "GLOBALS")) {
    1799           3 :                                         break;
    1800             :                                 }
    1801         109 :                                 ZVAL_STR_COPY(&final_name, var_name);
    1802         109 :                                 break;
    1803             : 
    1804             :                         case EXTR_PREFIX_IF_EXISTS:
    1805          15 :                                 if (var_exists) {
    1806          11 :                                         php_prefix_varname(&final_name, prefix, ZSTR_VAL(var_name), ZSTR_LEN(var_name), 1);
    1807             :                                 }
    1808          15 :                                 break;
    1809             : 
    1810             :                         case EXTR_PREFIX_SAME:
    1811          17 :                                 if (!var_exists && ZSTR_LEN(var_name) != 0) {
    1812           3 :                                         ZVAL_STR_COPY(&final_name, var_name);
    1813             :                                 }
    1814             :                                 /* break omitted intentionally */
    1815             : 
    1816             :                         case EXTR_PREFIX_ALL:
    1817         181 :                                 if (Z_TYPE(final_name) == IS_NULL && ZSTR_LEN(var_name) != 0) {
    1818          51 :                                         php_prefix_varname(&final_name, prefix, ZSTR_VAL(var_name), ZSTR_LEN(var_name), 1);
    1819             :                                 }
    1820         181 :                                 break;
    1821             : 
    1822             :                         case EXTR_PREFIX_INVALID:
    1823          66 :                                 if (Z_TYPE(final_name) == IS_NULL) {
    1824          30 :                                         if (!php_valid_var_name(ZSTR_VAL(var_name), ZSTR_LEN(var_name))) {
    1825           4 :                                                 php_prefix_varname(&final_name, prefix, ZSTR_VAL(var_name), ZSTR_LEN(var_name), 1);
    1826             :                                         } else {
    1827          11 :                                                 ZVAL_STR_COPY(&final_name, var_name);
    1828             :                                         }
    1829             :                                 }
    1830          66 :                                 break;
    1831             : 
    1832             :                         default:
    1833          15 :                                 if (!var_exists) {
    1834           4 :                                         ZVAL_STR_COPY(&final_name, var_name);
    1835             :                                 }
    1836             :                                 break;
    1837             :                 }
    1838             : 
    1839         757 :                 if (Z_TYPE(final_name) == IS_STRING && php_valid_var_name(Z_STRVAL(final_name), Z_STRLEN(final_name))) {
    1840             :                         zval *orig_var;
    1841             : 
    1842         343 :                         if (Z_STRLEN(final_name) == sizeof("this")-1  && !strcmp(Z_STRVAL(final_name), "this")) {
    1843           1 :                                 if (!exception_thrown) {
    1844           1 :                                         exception_thrown = 1;
    1845           1 :                                         zend_throw_error(NULL, "Cannot re-assign $this");
    1846             :                                 }
    1847             :                                 zval_dtor(&final_name);
    1848           1 :                                 continue;
    1849             :                         }
    1850         342 :                         if (extract_refs) {
    1851             : 
    1852         108 :                                 ZVAL_MAKE_REF(entry);
    1853             :                                 Z_ADDREF_P(entry);
    1854             : 
    1855          54 :                                 if ((orig_var = zend_hash_find(symbol_table, Z_STR(final_name))) != NULL) {
    1856          31 :                                         if (Z_TYPE_P(orig_var) == IS_INDIRECT) {
    1857          17 :                                                 orig_var = Z_INDIRECT_P(orig_var);
    1858             :                                         }
    1859          31 :                                         zval_ptr_dtor(orig_var);
    1860          31 :                                         ZVAL_COPY_VALUE(orig_var, entry);
    1861             :                                 } else {
    1862          23 :                                         zend_hash_update(symbol_table, Z_STR(final_name), entry);
    1863             :                                 }
    1864             :                         } else {
    1865         288 :                                 ZVAL_DEREF(entry);
    1866         288 :                                 if (Z_REFCOUNTED_P(entry)) Z_ADDREF_P(entry);
    1867         288 :                                 if ((orig_var = zend_hash_find(symbol_table, Z_STR(final_name))) != NULL) {
    1868         117 :                                         if (Z_TYPE_P(orig_var) == IS_INDIRECT) {
    1869           8 :                                                 orig_var = Z_INDIRECT_P(orig_var);
    1870             :                                         }
    1871         117 :                                         ZVAL_DEREF(orig_var);
    1872         117 :                                         zval_ptr_dtor(orig_var);
    1873         117 :                                         ZVAL_COPY_VALUE(orig_var, entry);
    1874             :                                 } else {
    1875         171 :                                         zend_hash_update(symbol_table, Z_STR(final_name), entry);
    1876             :                                 }
    1877             :                         }
    1878         342 :                         count++;
    1879             :                 }
    1880             :                 zval_dtor(&final_name);
    1881             :         } ZEND_HASH_FOREACH_END();
    1882         133 :         zval_ptr_dtor(&var_array);
    1883             : 
    1884         133 :         RETURN_LONG(count);
    1885             : }
    1886             : /* }}} */
    1887             : 
    1888          86 : static void php_compact_var(HashTable *eg_active_symbol_table, zval *return_value, zval *entry) /* {{{ */
    1889             : {
    1890             :         zval *value_ptr, data;
    1891             : 
    1892          86 :         ZVAL_DEREF(entry);
    1893          86 :         if (Z_TYPE_P(entry) == IS_STRING) {
    1894          90 :                 if ((value_ptr = zend_hash_find_ind(eg_active_symbol_table, Z_STR_P(entry))) != NULL) {
    1895          34 :                         ZVAL_DEREF(value_ptr);
    1896          34 :                         ZVAL_COPY(&data, value_ptr);
    1897          34 :                         zend_hash_update(Z_ARRVAL_P(return_value), Z_STR_P(entry), &data);
    1898             :                 }
    1899          45 :                 if (zend_string_equals_literal(Z_STR_P(entry), "this")) {
    1900           6 :                         zend_object *object = zend_get_this_object(EG(current_execute_data));
    1901           6 :                         if (object) {
    1902           3 :                                 GC_REFCOUNT(object)++;
    1903           3 :                                 ZVAL_OBJ(&data, object);
    1904           3 :                                 zend_hash_update(Z_ARRVAL_P(return_value), Z_STR_P(entry), &data);
    1905             :                         }
    1906             :                 }
    1907          41 :         } else if (Z_TYPE_P(entry) == IS_ARRAY) {
    1908          30 :                 if ((Z_ARRVAL_P(entry)->u.v.nApplyCount > 1)) {
    1909           5 :                         php_error_docref(NULL, E_WARNING, "recursion detected");
    1910           5 :                         return;
    1911             :                 }
    1912             : 
    1913          25 :             if (ZEND_HASH_APPLY_PROTECTION(Z_ARRVAL_P(entry))) {
    1914          25 :                         Z_ARRVAL_P(entry)->u.v.nApplyCount++;
    1915             :                 }
    1916         175 :                 ZEND_HASH_FOREACH_VAL_IND(Z_ARRVAL_P(entry), value_ptr) {
    1917          50 :                         php_compact_var(eg_active_symbol_table, return_value, value_ptr);
    1918             :                 } ZEND_HASH_FOREACH_END();
    1919          25 :             if (ZEND_HASH_APPLY_PROTECTION(Z_ARRVAL_P(entry))) {
    1920          25 :                         Z_ARRVAL_P(entry)->u.v.nApplyCount--;
    1921             :                 }
    1922             :         }
    1923             : }
    1924             : /* }}} */
    1925             : 
    1926             : /* {{{ proto array compact(mixed var_names [, mixed ...])
    1927             :    Creates a hash containing variables and their values */
    1928          25 : PHP_FUNCTION(compact)
    1929             : {
    1930          25 :         zval *args = NULL;      /* function arguments array */
    1931             :         uint32_t num_args, i;
    1932             :         zend_array *symbol_table;
    1933             : 
    1934          25 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "+", &args, &num_args) == FAILURE) {
    1935           1 :                 return;
    1936             :         }
    1937             : 
    1938          24 :         if (zend_forbid_dynamic_call("compact()") == FAILURE) {
    1939           2 :                 return;
    1940             :         }
    1941             : 
    1942          22 :         symbol_table = zend_rebuild_symbol_table();
    1943          22 :         if (UNEXPECTED(symbol_table == NULL)) {
    1944           0 :                 return;
    1945             :         }
    1946             : 
    1947             :         /* compact() is probably most used with a single array of var_names
    1948             :            or multiple string names, rather than a combination of both.
    1949             :            So quickly guess a minimum result size based on that */
    1950          47 :         if (ZEND_NUM_ARGS() == 1 && Z_TYPE(args[0]) == IS_ARRAY) {
    1951           9 :                 array_init_size(return_value, zend_hash_num_elements(Z_ARRVAL(args[0])));
    1952             :         } else {
    1953          13 :                 array_init_size(return_value, ZEND_NUM_ARGS());
    1954             :         }
    1955             : 
    1956          58 :         for (i=0; i<ZEND_NUM_ARGS(); i++) {
    1957          36 :                 php_compact_var(symbol_table, return_value, &args[i]);
    1958             :         }
    1959             : }
    1960             : /* }}} */
    1961             : 
    1962             : /* {{{ proto array array_fill(int start_key, int num, mixed val)
    1963             :    Create an array containing num elements starting with index start_key each initialized to val */
    1964         172 : PHP_FUNCTION(array_fill)
    1965             : {
    1966             :         zval *val;
    1967             :         zend_long start_key, num;
    1968             : 
    1969         172 :         ZEND_PARSE_PARAMETERS_START(3, 3)
    1970         507 :                 Z_PARAM_LONG(start_key)
    1971         474 :                 Z_PARAM_LONG(num)
    1972         148 :                 Z_PARAM_ZVAL(val)
    1973         172 :         ZEND_PARSE_PARAMETERS_END();
    1974             : 
    1975         148 :         if (EXPECTED(num > 0)) {
    1976         120 :                 if (sizeof(num) > 4 && UNEXPECTED(EXPECTED(num > 0x7fffffff))) {
    1977           0 :                         php_error_docref(NULL, E_WARNING, "Too many elements");
    1978           0 :                         RETURN_FALSE;
    1979         120 :                 } else if (UNEXPECTED(start_key > ZEND_LONG_MAX - num + 1)) {
    1980           1 :                         php_error_docref(NULL, E_WARNING, "Cannot add element to the array as the next element is already occupied");
    1981           1 :                         RETURN_FALSE;
    1982         217 :                 } else if (EXPECTED(start_key >= 0) && EXPECTED(start_key < num)) {
    1983             :                         /* create packed array */
    1984             :                         Bucket *p;
    1985             :                         zend_long n;
    1986             : 
    1987          98 :                         array_init_size(return_value, (uint32_t)(start_key + num));
    1988          98 :                         zend_hash_real_init(Z_ARRVAL_P(return_value), 1);
    1989          98 :                         Z_ARRVAL_P(return_value)->nNumUsed = start_key + num;
    1990          98 :                         Z_ARRVAL_P(return_value)->nNumOfElements = num;
    1991          98 :                         Z_ARRVAL_P(return_value)->nInternalPointer = start_key;
    1992          98 :                         Z_ARRVAL_P(return_value)->nNextFreeElement = start_key + num;
    1993             : 
    1994          98 :                         if (Z_REFCOUNTED_P(val)) {
    1995          41 :                                 GC_REFCOUNT(Z_COUNTED_P(val)) += num;
    1996             :                         }
    1997             : 
    1998          98 :                         p = Z_ARRVAL_P(return_value)->arData;
    1999          98 :                         n = start_key;
    2000             : 
    2001         204 :                         while (start_key--) {
    2002           8 :                                 ZVAL_UNDEF(&p->val);
    2003           8 :                                 p++;
    2004             :                         }
    2005      231277 :                         while (num--) {
    2006      231081 :                                 ZVAL_COPY_VALUE(&p->val, val);
    2007      231081 :                                 p->h = n++;
    2008      231081 :                                 p->key = NULL;
    2009      231081 :                                 p++;
    2010             :                         }
    2011             :                 } else {
    2012             :                         /* create hash */
    2013          21 :                         array_init_size(return_value, (uint32_t)num);
    2014          21 :                         zend_hash_real_init(Z_ARRVAL_P(return_value), 0);
    2015          21 :                         if (Z_REFCOUNTED_P(val)) {
    2016           9 :                                 GC_REFCOUNT(Z_COUNTED_P(val)) += num;
    2017             :                         }
    2018          21 :                         zend_hash_index_add_new(Z_ARRVAL_P(return_value), start_key, val);
    2019          51 :                         while (--num) {
    2020           9 :                                 zend_hash_next_index_insert_new(Z_ARRVAL_P(return_value), val);
    2021           9 :                                 start_key++;
    2022             :                         }
    2023             :                 }
    2024          28 :         } else if (EXPECTED(num == 0)) {
    2025          26 :                 array_init(return_value);
    2026          26 :                 return;
    2027             :         } else {
    2028           2 :                 php_error_docref(NULL, E_WARNING, "Number of elements can't be negative");
    2029           2 :                 RETURN_FALSE;
    2030             :         }
    2031             : }
    2032             : /* }}} */
    2033             : 
    2034             : /* {{{ proto array array_fill_keys(array keys, mixed val)
    2035             :    Create an array using the elements of the first parameter as keys each initialized to val */
    2036          38 : PHP_FUNCTION(array_fill_keys)
    2037             : {
    2038             :         zval *keys, *val, *entry;
    2039             : 
    2040          38 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "az", &keys, &val) == FAILURE) {
    2041           6 :                 return;
    2042             :         }
    2043             : 
    2044             :         /* Initialize return array */
    2045          32 :         array_init_size(return_value, zend_hash_num_elements(Z_ARRVAL_P(keys)));
    2046             : 
    2047         150 :         ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(keys), entry) {
    2048          59 :                 ZVAL_DEREF(entry);
    2049          59 :                 Z_TRY_ADDREF_P(val);
    2050          59 :                 if (Z_TYPE_P(entry) == IS_LONG) {
    2051           8 :                         zend_hash_index_update(Z_ARRVAL_P(return_value), Z_LVAL_P(entry), val);
    2052             :                 } else {
    2053          51 :                         zend_string *key = zval_get_string(entry);
    2054          51 :                         zend_symtable_update(Z_ARRVAL_P(return_value), key, val);
    2055             :                         zend_string_release(key);
    2056             :                 }
    2057             :         } ZEND_HASH_FOREACH_END();
    2058             : }
    2059             : /* }}} */
    2060             : 
    2061             : #define RANGE_CHECK_DOUBLE_INIT_ARRAY(start, end) do { \
    2062             :                 double __calc_size = ((start - end) / step) + 1; \
    2063             :                 if (__calc_size >= (double)HT_MAX_SIZE) { \
    2064             :                         php_error_docref(NULL, E_WARNING, "The supplied range exceeds the maximum array size: start=%0.0f end=%0.0f", end, start); \
    2065             :                         RETURN_FALSE; \
    2066             :                 } \
    2067             :                 size = (uint32_t)_php_math_round(__calc_size, 0, PHP_ROUND_HALF_UP); \
    2068             :                 array_init_size(return_value, size); \
    2069             :                 zend_hash_real_init(Z_ARRVAL_P(return_value), 1); \
    2070             :         } while (0)
    2071             : 
    2072             : #define RANGE_CHECK_LONG_INIT_ARRAY(start, end) do { \
    2073             :                 zend_ulong __calc_size = (start - end) / lstep; \
    2074             :                 if (__calc_size >= HT_MAX_SIZE - 1) { \
    2075             :                         php_error_docref(NULL, E_WARNING, "The supplied range exceeds the maximum array size: start=" ZEND_LONG_FMT " end=" ZEND_LONG_FMT, end, start); \
    2076             :                         RETURN_FALSE; \
    2077             :                 } \
    2078             :                 size = (uint32_t)(__calc_size + 1); \
    2079             :                 array_init_size(return_value, size); \
    2080             :                 zend_hash_real_init(Z_ARRVAL_P(return_value), 1); \
    2081             :         } while (0)
    2082             : 
    2083             : /* {{{ proto array range(mixed low, mixed high[, int step])
    2084             :    Create an array containing the range of integers or characters from low to high (inclusive) */
    2085      100274 : PHP_FUNCTION(range)
    2086             : {
    2087      100274 :         zval *zlow, *zhigh, *zstep = NULL, tmp;
    2088      100274 :         int err = 0, is_step_double = 0;
    2089      100274 :         double step = 1.0;
    2090             : 
    2091      100274 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "zz|z", &zlow, &zhigh, &zstep) == FAILURE) {
    2092           3 :                 RETURN_FALSE;
    2093             :         }
    2094             : 
    2095      100271 :         if (zstep) {
    2096          79 :                 if (Z_TYPE_P(zstep) == IS_DOUBLE ||
    2097          23 :                         (Z_TYPE_P(zstep) == IS_STRING && is_numeric_string(Z_STRVAL_P(zstep), Z_STRLEN_P(zstep), NULL, NULL, 0) == IS_DOUBLE)
    2098             :                 ) {
    2099          11 :                         is_step_double = 1;
    2100             :                 }
    2101             : 
    2102          56 :                 step = zval_get_double(zstep);
    2103             : 
    2104             :                 /* We only want positive step values. */
    2105          28 :                 if (step < 0.0) {
    2106           0 :                         step *= -1;
    2107             :                 }
    2108             :         }
    2109             : 
    2110             :         /* If the range is given as strings, generate an array of characters. */
    2111      200670 :         if (Z_TYPE_P(zlow) == IS_STRING && Z_TYPE_P(zhigh) == IS_STRING && Z_STRLEN_P(zlow) >= 1 && Z_STRLEN_P(zhigh) >= 1) {
    2112             :                 int type1, type2;
    2113             :                 unsigned char low, high;
    2114          63 :                 zend_long lstep = (zend_long) step;
    2115             : 
    2116         126 :                 type1 = is_numeric_string(Z_STRVAL_P(zlow), Z_STRLEN_P(zlow), NULL, NULL, 0);
    2117         126 :                 type2 = is_numeric_string(Z_STRVAL_P(zhigh), Z_STRLEN_P(zhigh), NULL, NULL, 0);
    2118             : 
    2119          63 :                 if (type1 == IS_DOUBLE || type2 == IS_DOUBLE || is_step_double) {
    2120             :                         goto double_str;
    2121          59 :                 } else if (type1 == IS_LONG || type2 == IS_LONG) {
    2122             :                         goto long_str;
    2123             :                 }
    2124             : 
    2125          54 :                 low = (unsigned char)Z_STRVAL_P(zlow)[0];
    2126          54 :                 high = (unsigned char)Z_STRVAL_P(zhigh)[0];
    2127             : 
    2128          54 :                 if (low > high) {            /* Negative Steps */
    2129           2 :                         if (lstep <= 0) {
    2130           1 :                                 err = 1;
    2131           1 :                                 goto err;
    2132             :                         }
    2133             :                         /* Initialize the return_value as an array. */
    2134           1 :                         array_init_size(return_value, (uint32_t)(((low - high) / lstep) + 1));
    2135           1 :                         zend_hash_real_init(Z_ARRVAL_P(return_value), 1);
    2136           1 :                         ZEND_HASH_FILL_PACKED(Z_ARRVAL_P(return_value)) {
    2137          27 :                                 for (; low >= high; low -= (unsigned int)lstep) {
    2138          26 :                                         if (CG(one_char_string)[low]) {
    2139           0 :                                                 ZVAL_INTERNED_STR(&tmp, CG(one_char_string)[low]);
    2140             :                                         } else {
    2141          52 :                                                 ZVAL_STRINGL(&tmp, (char*)&low, 1);
    2142             :                                         }
    2143          26 :                                         ZEND_HASH_FILL_ADD(&tmp);
    2144          26 :                                         if (((signed int)low - lstep) < 0) {
    2145           0 :                                                 break;
    2146             :                                         }
    2147             :                                 }
    2148           1 :                         } ZEND_HASH_FILL_END();
    2149          52 :                 } else if (high > low) {     /* Positive Steps */
    2150          50 :                         if (lstep <= 0) {
    2151           2 :                                 err = 1;
    2152           2 :                                 goto err;
    2153             :                         }
    2154          48 :                         array_init_size(return_value, (uint32_t)(((high - low) / lstep) + 1));
    2155          48 :                         zend_hash_real_init(Z_ARRVAL_P(return_value), 1);
    2156          48 :                         ZEND_HASH_FILL_PACKED(Z_ARRVAL_P(return_value)) {
    2157        1242 :                                 for (; low <= high; low += (unsigned int)lstep) {
    2158        1194 :                                         if (CG(one_char_string)[low]) {
    2159           0 :                                                 ZVAL_INTERNED_STR(&tmp, CG(one_char_string)[low]);
    2160             :                                         } else {
    2161        2388 :                                                 ZVAL_STRINGL(&tmp, (char*)&low, 1);
    2162             :                                         }
    2163        1194 :                                         ZEND_HASH_FILL_ADD(&tmp);
    2164        1194 :                                         if (((signed int)low + lstep) > 255) {
    2165           0 :                                                 break;
    2166             :                                         }
    2167             :                                 }
    2168          48 :                         } ZEND_HASH_FILL_END();
    2169             :                 } else {
    2170           2 :                         array_init(return_value);
    2171           2 :                         if (CG(one_char_string)[low]) {
    2172           0 :                                 ZVAL_INTERNED_STR(&tmp, CG(one_char_string)[low]);
    2173             :                         } else {
    2174           4 :                                 ZVAL_STRINGL(&tmp, (char*)&low, 1);
    2175             :                         }
    2176           2 :                         zend_hash_next_index_insert_new(Z_ARRVAL_P(return_value), &tmp);
    2177             :                 }
    2178      300637 :         } else if (Z_TYPE_P(zlow) == IS_DOUBLE || Z_TYPE_P(zhigh) == IS_DOUBLE || is_step_double) {
    2179             :                 double low, high, element;
    2180             :                 uint32_t i, size;
    2181             : double_str:
    2182          60 :                 low = zval_get_double(zlow);
    2183          60 :                 high = zval_get_double(zhigh);
    2184             : 
    2185          30 :                 if (zend_isinf(high) || zend_isinf(low)) {
    2186           2 :                         php_error_docref(NULL, E_WARNING, "Invalid range supplied: start=%0.0f end=%0.0f", low, high);
    2187           2 :                         RETURN_FALSE;
    2188             :                 }
    2189             : 
    2190          28 :                 Z_TYPE_INFO(tmp) = IS_DOUBLE;
    2191          28 :                 if (low > high) {            /* Negative steps */
    2192          12 :                         if (low - high < step || step <= 0) {
    2193           1 :                                 err = 1;
    2194           1 :                                 goto err;
    2195             :                         }
    2196             : 
    2197          11 :                         RANGE_CHECK_DOUBLE_INIT_ARRAY(low, high);
    2198             : 
    2199          11 :                         ZEND_HASH_FILL_PACKED(Z_ARRVAL_P(return_value)) {
    2200      102507 :                                 for (i = 0, element = low; i < size && element >= high; ++i, element = low - (i * step)) {
    2201      102496 :                                         Z_DVAL(tmp) = element;
    2202      102496 :                                         ZEND_HASH_FILL_ADD(&tmp);
    2203             :                                 }
    2204          11 :                         } ZEND_HASH_FILL_END();
    2205          16 :                 } else if (high > low) {     /* Positive steps */
    2206          15 :                         if (high - low < step || step <= 0) {
    2207           1 :                                 err = 1;
    2208           1 :                                 goto err;
    2209             :                         }
    2210             : 
    2211          14 :                         RANGE_CHECK_DOUBLE_INIT_ARRAY(high, low);
    2212             : 
    2213          14 :                         ZEND_HASH_FILL_PACKED(Z_ARRVAL_P(return_value)) {
    2214      102730 :                                 for (i = 0, element = low; i < size && element <= high; ++i, element = low + (i * step)) {
    2215      102716 :                                         Z_DVAL(tmp) = element;
    2216      102716 :                                         ZEND_HASH_FILL_ADD(&tmp);
    2217             :                                 }
    2218          14 :                         } ZEND_HASH_FILL_END();
    2219             :                 } else {
    2220           1 :                         array_init(return_value);
    2221           1 :                         Z_DVAL(tmp) = low;
    2222           1 :                         zend_hash_next_index_insert_new(Z_ARRVAL_P(return_value), &tmp);
    2223             :                 }
    2224             :         } else {
    2225             :                 zend_long low, high;
    2226             :                 /* lstep is a ulong so that comparisons to it don't overflow, i.e. low - high < lstep */
    2227             :                 zend_ulong lstep;
    2228             :                 uint32_t i, size;
    2229             : long_str:
    2230      200374 :                 low = zval_get_long(zlow);
    2231      200374 :                 high = zval_get_long(zhigh);
    2232             : 
    2233      100187 :                 if (step <= 0) {
    2234           7 :                         err = 1;
    2235           7 :                         goto err;
    2236             :                 }
    2237             : 
    2238      100180 :                 lstep = step;
    2239             : 
    2240      100180 :                 Z_TYPE_INFO(tmp) = IS_LONG;
    2241      100180 :                 if (low > high) {            /* Negative steps */
    2242          14 :                         if ((zend_ulong)(low - high) < lstep) {
    2243           1 :                                 err = 1;
    2244           1 :                                 goto err;
    2245             :                         }
    2246             : 
    2247          13 :                         RANGE_CHECK_LONG_INIT_ARRAY(low, high);
    2248             : 
    2249          13 :                         ZEND_HASH_FILL_PACKED(Z_ARRVAL_P(return_value)) {
    2250         583 :                                 for (i = 0; i < size; ++i) {
    2251         570 :                                         Z_LVAL(tmp) = low - (i * lstep);
    2252         570 :                                         ZEND_HASH_FILL_ADD(&tmp);
    2253             :                                 }
    2254          13 :                         } ZEND_HASH_FILL_END();
    2255      100166 :                 } else if (high > low) {     /* Positive steps */
    2256      100145 :                         if ((zend_ulong)(high - low) < lstep) {
    2257           0 :                                 err = 1;
    2258           0 :                                 goto err;
    2259             :                         }
    2260             : 
    2261      100145 :                         RANGE_CHECK_LONG_INIT_ARRAY(high, low);
    2262             : 
    2263      100143 :                         ZEND_HASH_FILL_PACKED(Z_ARRVAL_P(return_value)) {
    2264      559722 :                                 for (i = 0; i < size; ++i) {
    2265      459579 :                                         Z_LVAL(tmp) = low + (i * lstep);
    2266      459579 :                                         ZEND_HASH_FILL_ADD(&tmp);
    2267             :                                 }
    2268      100143 :                         } ZEND_HASH_FILL_END();
    2269             :                 } else {
    2270          21 :                         array_init(return_value);
    2271          21 :                         Z_LVAL(tmp) = low;
    2272          21 :                         zend_hash_next_index_insert_new(Z_ARRVAL_P(return_value), &tmp);
    2273             :                 }
    2274             :         }
    2275             : err:
    2276      100267 :         if (err) {
    2277          13 :                 php_error_docref(NULL, E_WARNING, "step exceeds the specified range");
    2278          13 :                 RETURN_FALSE;
    2279             :         }
    2280             : }
    2281             : /* }}} */
    2282             : 
    2283             : #undef RANGE_CHECK_DOUBLE_INIT_ARRAY
    2284             : #undef RANGE_CHECK_LONG_INIT_ARRAY
    2285             : 
    2286       90054 : static void php_array_data_shuffle(zval *array) /* {{{ */
    2287             : {
    2288             :         uint32_t idx, j, n_elems;
    2289             :         Bucket *p, temp;
    2290             :         HashTable *hash;
    2291             :         zend_long rnd_idx;
    2292             :         zend_long n_left;
    2293             : 
    2294       90054 :         n_elems = zend_hash_num_elements(Z_ARRVAL_P(array));
    2295             : 
    2296       90054 :         if (n_elems < 1) {
    2297           1 :                 return;
    2298             :         }
    2299             : 
    2300       90053 :         hash = Z_ARRVAL_P(array);
    2301       90053 :         n_left = n_elems;
    2302             : 
    2303       90053 :         if (EXPECTED(hash->u.v.nIteratorsCount == 0)) {
    2304       90053 :                 if (hash->nNumUsed != hash->nNumOfElements) {
    2305           7 :                         for (j = 0, idx = 0; idx < hash->nNumUsed; idx++) {
    2306           5 :                                 p = hash->arData + idx;
    2307          10 :                                 if (Z_TYPE(p->val) == IS_UNDEF) continue;
    2308           2 :                                 if (j != idx) {
    2309           2 :                                         hash->arData[j] = *p;
    2310             :                                 }
    2311           2 :                                 j++;
    2312             :                         }
    2313             :                 }
    2314      451493 :                 while (--n_left) {
    2315      271387 :                         RAND_RANGE(rnd_idx, 0, n_left, PHP_RAND_MAX);
    2316      271387 :                         if (rnd_idx != n_left) {
    2317      174052 :                                 temp = hash->arData[n_left];
    2318      174052 :                                 hash->arData[n_left] = hash->arData[rnd_idx];
    2319      174052 :                                 hash->arData[rnd_idx] = temp;
    2320             :                         }
    2321             :                 }
    2322             :         } else {
    2323           0 :                 uint32_t iter_pos = zend_hash_iterators_lower_pos(hash, 0);
    2324             : 
    2325           0 :                 if (hash->nNumUsed != hash->nNumOfElements) {
    2326           0 :                         for (j = 0, idx = 0; idx < hash->nNumUsed; idx++) {
    2327           0 :                                 p = hash->arData + idx;
    2328           0 :                                 if (Z_TYPE(p->val) == IS_UNDEF) continue;
    2329           0 :                                 if (j != idx) {
    2330           0 :                                         hash->arData[j] = *p;
    2331           0 :                                         if (idx == iter_pos) {
    2332             :                                                 zend_hash_iterators_update(hash, idx, j);
    2333           0 :                                                 iter_pos = zend_hash_iterators_lower_pos(hash, iter_pos + 1);
    2334             :                                         }
    2335             :                                 }
    2336           0 :                                 j++;
    2337             :                         }
    2338             :                 }
    2339           0 :                 while (--n_left) {
    2340           0 :                         RAND_RANGE(rnd_idx, 0, n_left, PHP_RAND_MAX);
    2341           0 :                         if (rnd_idx != n_left) {
    2342           0 :                                 temp = hash->arData[n_left];
    2343           0 :                                 hash->arData[n_left] = hash->arData[rnd_idx];
    2344           0 :                                 hash->arData[rnd_idx] = temp;
    2345           0 :                                 zend_hash_iterators_update(hash, (uint32_t)rnd_idx, n_left);
    2346             :                         }
    2347             :                 }
    2348             :         }
    2349       90053 :         hash->nNumUsed = n_elems;
    2350       90053 :         hash->nInternalPointer = 0;
    2351             : 
    2352      451493 :         for (j = 0; j < n_elems; j++) {
    2353      361440 :                 p = hash->arData + j;
    2354      361440 :                 if (p->key) {
    2355          41 :                         zend_string_release(p->key);
    2356             :                 }
    2357      361440 :                 p->h = j;
    2358      361440 :                 p->key = NULL;
    2359             :         }
    2360       90053 :         hash->nNextFreeElement = n_elems;
    2361       90053 :         if (!(hash->u.flags & HASH_FLAG_PACKED)) {
    2362          15 :                 zend_hash_to_packed(hash);
    2363             :         }
    2364             : }
    2365             : /* }}} */
    2366             : 
    2367             : /* {{{ proto bool shuffle(array array_arg)
    2368             :    Randomly shuffle the contents of an array */
    2369       90079 : PHP_FUNCTION(shuffle)
    2370             : {
    2371             :         zval *array;
    2372             : 
    2373       90079 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "a/", &array) == FAILURE) {
    2374          25 :                 RETURN_FALSE;
    2375             :         }
    2376             : 
    2377       90054 :         php_array_data_shuffle(array);
    2378             : 
    2379       90054 :         RETURN_TRUE;
    2380             : }
    2381             : /* }}} */
    2382             : 
    2383          64 : static void php_splice(HashTable *in_hash, zend_long offset, zend_long length, HashTable *replace, HashTable *removed) /* {{{ */
    2384             : {
    2385             :         HashTable        out_hash;                      /* Output hashtable */
    2386             :         zend_long        num_in;                        /* Number of entries in the input hashtable */
    2387             :         zend_long        pos;                           /* Current position in the hashtable */
    2388             :         uint32_t     idx;
    2389             :         Bucket          *p;                                     /* Pointer to hash bucket */
    2390             :         zval            *entry;                         /* Hash entry */
    2391          64 :         uint32_t    iter_pos = zend_hash_iterators_lower_pos(in_hash, 0);
    2392             : 
    2393             :         /* Get number of entries in the input hash */
    2394          64 :         num_in = zend_hash_num_elements(in_hash);
    2395             : 
    2396             :         /* Clamp the offset.. */
    2397          64 :         if (offset > num_in) {
    2398           0 :                 offset = num_in;
    2399          64 :         } else if (offset < 0 && (offset = (num_in + offset)) < 0) {
    2400           0 :                 offset = 0;
    2401             :         }
    2402             : 
    2403             :         /* ..and the length */
    2404          64 :         if (length < 0) {
    2405          15 :                 length = num_in - offset + length;
    2406          49 :         } else if (((unsigned)offset + (unsigned)length) > (unsigned)num_in) {
    2407          10 :                 length = num_in - offset;
    2408             :         }
    2409             : 
    2410             :         /* Create and initialize output hash */
    2411          64 :         zend_hash_init(&out_hash, (length > 0 ? num_in - length : 0) + (replace ? zend_hash_num_elements(replace) : 0), NULL, ZVAL_PTR_DTOR, 0);
    2412             : 
    2413             :         /* Start at the beginning of the input hash and copy entries to output hash until offset is reached */
    2414         167 :         for (pos = 0, idx = 0; pos < offset && idx < in_hash->nNumUsed; idx++) {
    2415         103 :                 p = in_hash->arData + idx;
    2416         206 :                 if (Z_TYPE(p->val) == IS_UNDEF) continue;
    2417             :                 /* Get entry and increase reference count */
    2418         103 :                 entry = &p->val;
    2419             : 
    2420             :                 /* Update output hash depending on key type */
    2421         103 :                 if (p->key == NULL) {
    2422         102 :                         zend_hash_next_index_insert_new(&out_hash, entry);
    2423             :                 } else {
    2424           1 :                         zend_hash_add_new(&out_hash, p->key, entry);
    2425             :                 }
    2426         103 :                 if (idx == iter_pos) {
    2427           2 :                         if ((zend_long)idx != pos) {
    2428           0 :                                 zend_hash_iterators_update(in_hash, idx, pos);
    2429             :                         }
    2430           2 :                         iter_pos = zend_hash_iterators_lower_pos(in_hash, iter_pos + 1);
    2431             :                 }
    2432         103 :                 pos++;
    2433             :         }
    2434             : 
    2435             :         /* If hash for removed entries exists, go until offset+length and copy the entries to it */
    2436          64 :         if (removed != NULL) {
    2437         145 :                 for ( ; pos < offset + length && idx < in_hash->nNumUsed; idx++) {
    2438          93 :                         p = in_hash->arData + idx;
    2439         186 :                         if (Z_TYPE(p->val) == IS_UNDEF) continue;
    2440          93 :                         pos++;
    2441          93 :                         entry = &p->val;
    2442          93 :                         if (Z_REFCOUNTED_P(entry)) {
    2443             :                                 Z_ADDREF_P(entry);
    2444             :                         }
    2445          93 :                         if (p->key == NULL) {
    2446          92 :                                 zend_hash_next_index_insert_new(removed, entry);
    2447          92 :                                 zend_hash_index_del(in_hash, p->h);
    2448             :                         } else {
    2449           1 :                                 zend_hash_add_new(removed, p->key, entry);
    2450           1 :                                 if (in_hash == &EG(symbol_table)) {
    2451           0 :                                         zend_delete_global_variable(p->key);
    2452             :                                 } else {
    2453           1 :                                         zend_hash_del(in_hash, p->key);
    2454             :                                 }
    2455             :                         }
    2456             :                 }
    2457             :         } else { /* otherwise just skip those entries */
    2458          12 :                 int pos2 = pos;
    2459             : 
    2460          44 :                 for ( ; pos2 < offset + length && idx < in_hash->nNumUsed; idx++) {
    2461          32 :                         p = in_hash->arData + idx;
    2462          64 :                         if (Z_TYPE(p->val) == IS_UNDEF) continue;
    2463          32 :                         pos2++;
    2464          32 :                         if (p->key == NULL) {
    2465          23 :                                 zend_hash_index_del(in_hash, p->h);
    2466             :                         } else {
    2467           9 :                                 if (in_hash == &EG(symbol_table)) {
    2468           9 :                                         zend_delete_global_variable(p->key);
    2469             :                                 } else {
    2470           0 :                                         zend_hash_del(in_hash, p->key);
    2471             :                                 }
    2472             :                         }
    2473             :                 }
    2474             :         }
    2475          64 :         iter_pos = zend_hash_iterators_lower_pos(in_hash, iter_pos);
    2476             : 
    2477             :         /* If there are entries to insert.. */
    2478          64 :         if (replace) {
    2479         266 :                 ZEND_HASH_FOREACH_VAL_IND(replace, entry) {
    2480          78 :                         if (Z_REFCOUNTED_P(entry)) Z_ADDREF_P(entry);
    2481          78 :                         zend_hash_next_index_insert_new(&out_hash, entry);
    2482          78 :                         pos++;
    2483             :                 } ZEND_HASH_FOREACH_END();
    2484             :         }
    2485             : 
    2486             :         /* Copy the remaining input hash entries to the output hash */
    2487         176 :         for ( ; idx < in_hash->nNumUsed ; idx++) {
    2488         112 :                 p = in_hash->arData + idx;
    2489         224 :                 if (Z_TYPE(p->val) == IS_UNDEF) continue;
    2490         112 :                 entry = &p->val;
    2491         112 :                 if (p->key == NULL) {
    2492         111 :                         zend_hash_next_index_insert_new(&out_hash, entry);
    2493             :                 } else {
    2494           1 :                         zend_hash_add_new(&out_hash, p->key, entry);
    2495             :                 }
    2496         112 :                 if (idx == iter_pos) {
    2497           4 :                         if ((zend_long)idx != pos) {
    2498           3 :                                 zend_hash_iterators_update(in_hash, idx, pos);
    2499             :                         }
    2500           4 :                         iter_pos = zend_hash_iterators_lower_pos(in_hash, iter_pos + 1);
    2501             :                 }
    2502         112 :                 pos++;
    2503             :         }
    2504             : 
    2505             :         /* replace HashTable data */
    2506          64 :         in_hash->u.v.nIteratorsCount = 0;
    2507          64 :         in_hash->pDestructor = NULL;
    2508          64 :         zend_hash_destroy(in_hash);
    2509             : 
    2510          64 :         in_hash->u.v.flags         = out_hash.u.v.flags;
    2511          64 :         in_hash->nTableSize        = out_hash.nTableSize;
    2512          64 :         in_hash->nTableMask        = out_hash.nTableMask;
    2513          64 :         in_hash->nNumUsed          = out_hash.nNumUsed;
    2514          64 :         in_hash->nNumOfElements    = out_hash.nNumOfElements;
    2515          64 :         in_hash->nNextFreeElement  = out_hash.nNextFreeElement;
    2516          64 :         in_hash->arData            = out_hash.arData;
    2517          64 :         in_hash->pDestructor       = out_hash.pDestructor;
    2518             : 
    2519          64 :         zend_hash_internal_pointer_reset(in_hash);
    2520          64 : }
    2521             : /* }}} */
    2522             : 
    2523             : /* {{{ proto int array_push(array stack, mixed var [, mixed ...])
    2524             :    Pushes elements onto the end of the array */
    2525         804 : PHP_FUNCTION(array_push)
    2526             : {
    2527             :         zval   *args,           /* Function arguments array */
    2528             :                    *stack,              /* Input array */
    2529             :                     new_var;    /* Variable to be pushed */
    2530             :         int i,                          /* Loop counter */
    2531             :                 argc;                   /* Number of function arguments */
    2532             : 
    2533             : 
    2534         804 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "a/+", &stack, &args, &argc) == FAILURE) {
    2535          28 :                 return;
    2536             :         }
    2537             : 
    2538             :         /* For each subsequent argument, make it a reference, increase refcount, and add it to the end of the array */
    2539        1567 :         for (i = 0; i < argc; i++) {
    2540         792 :                 ZVAL_COPY(&new_var, &args[i]);
    2541             : 
    2542         792 :                 if (zend_hash_next_index_insert(Z_ARRVAL_P(stack), &new_var) == NULL) {
    2543           1 :                         if (Z_REFCOUNTED(new_var)) Z_DELREF(new_var);
    2544           1 :                         php_error_docref(NULL, E_WARNING, "Cannot add element to the array as the next element is already occupied");
    2545           1 :                         RETURN_FALSE;
    2546             :                 }
    2547             :         }
    2548             : 
    2549             :         /* Clean up and return the number of values in the stack */
    2550         775 :         RETVAL_LONG(zend_hash_num_elements(Z_ARRVAL_P(stack)));
    2551             : }
    2552             : /* }}} */
    2553             : 
    2554             : /* {{{ proto mixed array_pop(array stack)
    2555             :    Pops an element off the end of the array */
    2556          78 : PHP_FUNCTION(array_pop)
    2557             : {
    2558             :         zval *stack,    /* Input stack */
    2559             :                  *val;          /* Value to be popped */
    2560             :         uint32_t idx;
    2561             :         Bucket *p;
    2562             : 
    2563          78 :         ZEND_PARSE_PARAMETERS_START(1, 1)
    2564         330 :                 Z_PARAM_ARRAY_EX(stack, 0, 1)
    2565          78 :         ZEND_PARSE_PARAMETERS_END();
    2566             : 
    2567          74 :         if (zend_hash_num_elements(Z_ARRVAL_P(stack)) == 0) {
    2568           2 :                 return;
    2569             :         }
    2570             : 
    2571             :         /* Get the last value and copy it into the return value */
    2572          72 :         idx = Z_ARRVAL_P(stack)->nNumUsed;
    2573             :         while (1) {
    2574          81 :                 if (idx == 0) {
    2575           0 :                         return;
    2576             :                 }
    2577          81 :                 idx--;
    2578          81 :                 p = Z_ARRVAL_P(stack)->arData + idx;
    2579          81 :                 val = &p->val;
    2580          81 :                 if (Z_TYPE_P(val) == IS_INDIRECT) {
    2581          10 :                         val = Z_INDIRECT_P(val);
    2582             :                 }
    2583          81 :                 if (Z_TYPE_P(val) != IS_UNDEF) {
    2584          72 :                         break;
    2585             :                 }
    2586           9 :         }
    2587          72 :         ZVAL_DEREF(val);
    2588          72 :         ZVAL_COPY(return_value, val);
    2589             : 
    2590          72 :         if (!p->key && Z_ARRVAL_P(stack)->nNextFreeElement > 0 && p->h >= (zend_ulong)(Z_ARRVAL_P(stack)->nNextFreeElement - 1)) {
    2591          63 :                 Z_ARRVAL_P(stack)->nNextFreeElement = Z_ARRVAL_P(stack)->nNextFreeElement - 1;
    2592             :         }
    2593             : 
    2594             :         /* Delete the last value */
    2595          72 :         if (p->key) {
    2596           7 :                 if (Z_ARRVAL_P(stack) == &EG(symbol_table)) {
    2597           3 :                         zend_delete_global_variable(p->key);
    2598             :                 } else {
    2599           4 :                         zend_hash_del(Z_ARRVAL_P(stack), p->key);
    2600             :                 }
    2601             :         } else {
    2602          65 :                 zend_hash_index_del(Z_ARRVAL_P(stack), p->h);
    2603             :         }
    2604             : 
    2605          72 :         zend_hash_internal_pointer_reset(Z_ARRVAL_P(stack));
    2606             : }
    2607             : /* }}} */
    2608             : 
    2609             : /* {{{ proto mixed array_shift(array stack)
    2610             :    Pops an element off the beginning of the array */
    2611         228 : PHP_FUNCTION(array_shift)
    2612             : {
    2613             :         zval *stack,    /* Input stack */
    2614             :                  *val;          /* Value to be popped */
    2615             :         uint32_t idx;
    2616             :         Bucket *p;
    2617             : 
    2618         228 :         ZEND_PARSE_PARAMETERS_START(1, 1)
    2619         961 :                 Z_PARAM_ARRAY_EX(stack, 0, 1)
    2620         228 :         ZEND_PARSE_PARAMETERS_END();
    2621             : 
    2622         198 :         if (zend_hash_num_elements(Z_ARRVAL_P(stack)) == 0) {
    2623           3 :                 return;
    2624             :         }
    2625             : 
    2626             :         /* Get the first value and copy it into the return value */
    2627         195 :         idx = 0;
    2628             :         while (1) {
    2629         203 :                 if (idx == Z_ARRVAL_P(stack)->nNumUsed) {
    2630           0 :                         return;
    2631             :                 }
    2632         203 :                 p = Z_ARRVAL_P(stack)->arData + idx;
    2633         203 :                 val = &p->val;
    2634         203 :                 if (Z_TYPE_P(val) == IS_INDIRECT) {
    2635           0 :                         val = Z_INDIRECT_P(val);
    2636             :                 }
    2637         203 :                 if (Z_TYPE_P(val) != IS_UNDEF) {
    2638         195 :                         break;
    2639             :                 }
    2640           8 :                 idx++;
    2641           8 :         }
    2642         195 :         ZVAL_DEREF(val);
    2643         195 :         ZVAL_COPY(return_value, val);
    2644             : 
    2645             :         /* Delete the first value */
    2646         195 :         if (p->key) {
    2647          26 :                 if (Z_ARRVAL_P(stack) == &EG(symbol_table)) {
    2648           1 :                         zend_delete_global_variable(p->key);
    2649             :                 } else {
    2650          25 :                         zend_hash_del(Z_ARRVAL_P(stack), p->key);
    2651             :                 }
    2652             :         } else {
    2653         169 :                 zend_hash_index_del(Z_ARRVAL_P(stack), p->h);
    2654             :         }
    2655             : 
    2656             :         /* re-index like it did before */
    2657         195 :         if (Z_ARRVAL_P(stack)->u.flags & HASH_FLAG_PACKED) {
    2658         163 :                 uint32_t k = 0;
    2659             : 
    2660         163 :                 if (EXPECTED(Z_ARRVAL_P(stack)->u.v.nIteratorsCount == 0)) {
    2661         583 :                         for (idx = 0; idx < Z_ARRVAL_P(stack)->nNumUsed; idx++) {
    2662         444 :                                 p = Z_ARRVAL_P(stack)->arData + idx;
    2663         888 :                                 if (Z_TYPE(p->val) == IS_UNDEF) continue;
    2664         328 :                                 if (idx != k) {
    2665         328 :                                         Bucket *q = Z_ARRVAL_P(stack)->arData + k;
    2666         328 :                                         q->h = k;
    2667         328 :                                         q->key = NULL;
    2668         328 :                                         ZVAL_COPY_VALUE(&q->val, &p->val);
    2669         328 :                                         ZVAL_UNDEF(&p->val);
    2670             :                                 }
    2671         328 :                                 k++;
    2672             :                         }
    2673             :                 } else {
    2674          24 :                         uint32_t iter_pos = zend_hash_iterators_lower_pos(Z_ARRVAL_P(stack), 0);
    2675             : 
    2676          65 :                         for (idx = 0; idx < Z_ARRVAL_P(stack)->nNumUsed; idx++) {
    2677          41 :                                 p = Z_ARRVAL_P(stack)->arData + idx;
    2678          82 :                                 if (Z_TYPE(p->val) == IS_UNDEF) continue;
    2679          26 :                                 if (idx != k) {
    2680          26 :                                         Bucket *q = Z_ARRVAL_P(stack)->arData + k;
    2681          26 :                                         q->h = k;
    2682          26 :                                         q->key = NULL;
    2683          26 :                                         ZVAL_COPY_VALUE(&q->val, &p->val);
    2684          26 :                                         ZVAL_UNDEF(&p->val);
    2685          26 :                                         if (idx == iter_pos) {
    2686          15 :                                                 zend_hash_iterators_update(Z_ARRVAL_P(stack), idx, k);
    2687          15 :                                                 iter_pos = zend_hash_iterators_lower_pos(Z_ARRVAL_P(stack), iter_pos + 1);
    2688             :                                         }
    2689             :                                 }
    2690          26 :                                 k++;
    2691             :                         }
    2692             :                 }
    2693         163 :                 Z_ARRVAL_P(stack)->nNumUsed = k;
    2694         163 :                 Z_ARRVAL_P(stack)->nNextFreeElement = k;
    2695             :         } else {
    2696          32 :                 uint32_t k = 0;
    2697          32 :                 int should_rehash = 0;
    2698             : 
    2699         501 :                 for (idx = 0; idx < Z_ARRVAL_P(stack)->nNumUsed; idx++) {
    2700         469 :                         p = Z_ARRVAL_P(stack)->arData + idx;
    2701         938 :                         if (Z_TYPE(p->val) == IS_UNDEF) continue;
    2702         437 :                         if (p->key == NULL) {
    2703          22 :                                 if (p->h != k) {
    2704          15 :                                         p->h = k++;
    2705          15 :                                         should_rehash = 1;
    2706             :                                 } else {
    2707           7 :                                         k++;
    2708             :                                 }
    2709             :                         }
    2710             :                 }
    2711          32 :                 Z_ARRVAL_P(stack)->nNextFreeElement = k;
    2712          32 :                 if (should_rehash) {
    2713           5 :                         zend_hash_rehash(Z_ARRVAL_P(stack));
    2714             :                 }
    2715             :         }
    2716             : 
    2717         195 :         zend_hash_internal_pointer_reset(Z_ARRVAL_P(stack));
    2718             : }
    2719             : /* }}} */
    2720             : 
    2721             : /* {{{ proto int array_unshift(array stack, mixed var [, mixed ...])
    2722             :    Pushes elements onto the beginning of the array */
    2723         277 : PHP_FUNCTION(array_unshift)
    2724             : {
    2725             :         zval   *args,                   /* Function arguments array */
    2726             :                    *stack;                      /* Input stack */
    2727             :         HashTable new_hash;             /* New hashtable for the stack */
    2728             :         int argc;                               /* Number of function arguments */
    2729             :         int i;
    2730             :         zend_string *key;
    2731             :         zval *value;
    2732             : 
    2733         277 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "a/+", &stack, &args, &argc) == FAILURE) {
    2734          51 :                 return;
    2735             :         }
    2736             : 
    2737         226 :         zend_hash_init(&new_hash, zend_hash_num_elements(Z_ARRVAL_P(stack)) + argc, NULL, ZVAL_PTR_DTOR, 0);
    2738         647 :         for (i = 0; i < argc; i++) {
    2739         421 :                 if (Z_REFCOUNTED(args[i])) {
    2740          79 :                         Z_ADDREF(args[i]);
    2741             :                 }
    2742         421 :                 zend_hash_next_index_insert_new(&new_hash, &args[i]);
    2743             :         }
    2744         226 :         if (EXPECTED(Z_ARRVAL_P(stack)->u.v.nIteratorsCount == 0)) {
    2745        1755 :                 ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(stack), key, value) {
    2746         755 :                         if (key) {
    2747         310 :                                 zend_hash_add_new(&new_hash, key, value);
    2748             :                         } else {
    2749         445 :                                 zend_hash_next_index_insert_new(&new_hash, value);
    2750             :                         }
    2751             :                 } ZEND_HASH_FOREACH_END();
    2752             :         } else {
    2753             :                 uint32_t old_idx;
    2754           9 :                 uint32_t new_idx = i;
    2755           9 :                 uint32_t iter_pos = zend_hash_iterators_lower_pos(Z_ARRVAL_P(stack), 0);
    2756             : 
    2757          55 :                 ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(stack), key, value) {
    2758          23 :                         if (key) {
    2759           0 :                                 zend_hash_add_new(&new_hash, key, value);
    2760             :                         } else {
    2761          23 :                                 zend_hash_next_index_insert_new(&new_hash, value);
    2762             :                         }
    2763          23 :                         old_idx = (Bucket*)value - Z_ARRVAL_P(stack)->arData;
    2764          23 :                         if (old_idx == iter_pos) {
    2765          13 :                                 zend_hash_iterators_update(Z_ARRVAL_P(stack), old_idx, new_idx);
    2766          13 :                                 iter_pos = zend_hash_iterators_lower_pos(Z_ARRVAL_P(stack), iter_pos + 1);
    2767             :                         }
    2768          23 :                         new_idx++;
    2769             :                 } ZEND_HASH_FOREACH_END();
    2770             :         }
    2771             : 
    2772             :         /* replace HashTable data */
    2773         226 :         Z_ARRVAL_P(stack)->u.v.nIteratorsCount = 0;
    2774         226 :         Z_ARRVAL_P(stack)->pDestructor = NULL;
    2775         226 :         zend_hash_destroy(Z_ARRVAL_P(stack));
    2776             : 
    2777         226 :         Z_ARRVAL_P(stack)->u.v.flags         = new_hash.u.v.flags;
    2778         226 :         Z_ARRVAL_P(stack)->nTableSize        = new_hash.nTableSize;
    2779         226 :         Z_ARRVAL_P(stack)->nTableMask        = new_hash.nTableMask;
    2780         226 :         Z_ARRVAL_P(stack)->nNumUsed          = new_hash.nNumUsed;
    2781         226 :         Z_ARRVAL_P(stack)->nNumOfElements    = new_hash.nNumOfElements;
    2782         226 :         Z_ARRVAL_P(stack)->nNextFreeElement  = new_hash.nNextFreeElement;
    2783         226 :         Z_ARRVAL_P(stack)->arData            = new_hash.arData;
    2784         226 :         Z_ARRVAL_P(stack)->pDestructor       = new_hash.pDestructor;
    2785             :         
    2786         226 :         zend_hash_internal_pointer_reset(Z_ARRVAL_P(stack));
    2787             : 
    2788             :         /* Clean up and return the number of elements in the stack */
    2789         226 :         RETVAL_LONG(zend_hash_num_elements(Z_ARRVAL_P(stack)));
    2790             : }
    2791             : /* }}} */
    2792             : 
    2793             : /* {{{ proto array array_splice(array input, int offset [, int length [, array replacement]])
    2794             :    Removes the elements designated by offset and length and replace them with supplied array */
    2795          70 : PHP_FUNCTION(array_splice)
    2796             : {
    2797             :         zval *array,                            /* Input array */
    2798          70 :                  *repl_array = NULL;    /* Replacement array */
    2799          70 :         HashTable  *rem_hash = NULL;
    2800             :         zend_long offset,
    2801          70 :                         length = 0;
    2802             :         int             num_in;                         /* Number of elements in the input array */
    2803             : 
    2804          70 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "a/l|lz/", &array, &offset, &length, &repl_array) == FAILURE) {
    2805           6 :                 return;
    2806             :         }
    2807             : 
    2808          64 :         num_in = zend_hash_num_elements(Z_ARRVAL_P(array));
    2809             : 
    2810          64 :         if (ZEND_NUM_ARGS() < 3) {
    2811           1 :                 length = num_in;
    2812             :         }
    2813             : 
    2814          64 :         if (ZEND_NUM_ARGS() == 4) {
    2815             :                 /* Make sure the last argument, if passed, is an array */
    2816          64 :                 convert_to_array_ex(repl_array);
    2817             :         }
    2818             : 
    2819             :         /* Don't create the array of removed elements if it's not going
    2820             :          * to be used; e.g. only removing and/or replacing elements */
    2821          64 :         if (USED_RET()) {
    2822          52 :                 zend_long size = length;
    2823             : 
    2824             :                 /* Clamp the offset.. */
    2825          52 :                 if (offset > num_in) {
    2826           0 :                         offset = num_in;
    2827          52 :                 } else if (offset < 0 && (offset = (num_in + offset)) < 0) {
    2828           0 :                         offset = 0;
    2829             :                 }
    2830             : 
    2831             :                 /* ..and the length */
    2832          52 :                 if (length < 0) {
    2833          15 :                         size = num_in - offset + length;
    2834          37 :                 } else if (((zend_ulong) offset + (zend_ulong) length) > (uint32_t) num_in) {
    2835          10 :                         size = num_in - offset;
    2836             :                 }
    2837             : 
    2838             :                 /* Initialize return value */
    2839          52 :                 array_init_size(return_value, size > 0 ? (uint32_t)size : 0);
    2840          52 :                 rem_hash = Z_ARRVAL_P(return_value);
    2841             :         }
    2842             : 
    2843             :         /* Perform splice */
    2844          64 :         php_splice(Z_ARRVAL_P(array), offset, length, repl_array ? Z_ARRVAL_P(repl_array) : NULL, rem_hash);
    2845             : }
    2846             : /* }}} */
    2847             : 
    2848             : /* {{{ proto array array_slice(array input, int offset [, int length [, bool preserve_keys]])
    2849             :    Returns elements specified by offset and length */
    2850         381 : PHP_FUNCTION(array_slice)
    2851             : {
    2852             :         zval     *input,                /* Input array */
    2853         381 :                          *z_length = NULL, /* How many elements to get */
    2854             :                          *entry;                /* An array entry */
    2855             :         zend_long        offset,                /* Offset to get elements from */
    2856         381 :                          length = 0;
    2857         381 :         zend_bool preserve_keys = 0; /* Whether to preserve keys while copying to the new array or not */
    2858             :         int              num_in,                /* Number of elements in the input array */
    2859             :                          pos;                   /* Current position in the array */
    2860             :         zend_string *string_key;
    2861             :         zend_ulong num_key;
    2862             : 
    2863         381 :         ZEND_PARSE_PARAMETERS_START(2, 4)
    2864        1128 :                 Z_PARAM_ARRAY(input)
    2865        1050 :                 Z_PARAM_LONG(offset)
    2866         350 :                 Z_PARAM_OPTIONAL
    2867         350 :                 Z_PARAM_ZVAL(z_length)
    2868         602 :                 Z_PARAM_BOOL(preserve_keys)
    2869         381 :         ZEND_PARSE_PARAMETERS_END();
    2870             : 
    2871             :         /* Get number of entries in the input hash */
    2872         348 :         num_in = zend_hash_num_elements(Z_ARRVAL_P(input));
    2873             : 
    2874             :         /* We want all entries from offset to the end if length is not passed or is null */
    2875         706 :         if (ZEND_NUM_ARGS() < 3 || Z_TYPE_P(z_length) == IS_NULL) {
    2876          62 :                 length = num_in;
    2877             :         } else {
    2878         572 :                 length = zval_get_long(z_length);
    2879             :         }
    2880             : 
    2881             :         /* Clamp the offset.. */
    2882         348 :         if (offset > num_in) {
    2883          11 :                 array_init(return_value);
    2884          11 :                 return;
    2885         337 :         } else if (offset < 0 && (offset = (num_in + offset)) < 0) {
    2886          10 :                 offset = 0;
    2887             :         }
    2888             : 
    2889             :         /* ..and the length */
    2890         337 :         if (length < 0) {
    2891          71 :                 length = num_in - offset + length;
    2892         266 :         } else if (((zend_ulong) offset + (zend_ulong) length) > (unsigned) num_in) {
    2893          95 :                 length = num_in - offset;
    2894             :         }
    2895             : 
    2896         337 :         if (length <= 0) {
    2897         117 :                 array_init(return_value);
    2898         117 :                 return;
    2899             :         }
    2900             : 
    2901             :         /* Initialize returned array */
    2902         220 :         array_init_size(return_value, (uint32_t)length);
    2903             : 
    2904             :         /* Start at the beginning and go until we hit offset */
    2905         220 :         pos = 0;
    2906         288 :         if ((Z_ARRVAL_P(input)->u.flags & HASH_FLAG_PACKED) && !preserve_keys) {
    2907          68 :                 zend_hash_real_init(Z_ARRVAL_P(return_value), 1);
    2908          68 :                 ZEND_HASH_FILL_PACKED(Z_ARRVAL_P(return_value)) {
    2909         878 :                         ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(input), entry) {
    2910         402 :                                 pos++;
    2911         402 :                                 if (pos <= offset) {
    2912          80 :                                         continue;
    2913             :                                 }
    2914         322 :                                 if (pos > offset + length) {
    2915          26 :                                         break;
    2916             :                                 }
    2917         298 :                                 if (UNEXPECTED(Z_ISREF_P(entry)) &&
    2918           2 :                                         UNEXPECTED(Z_REFCOUNT_P(entry) == 1)) {
    2919           2 :                                         ZVAL_UNREF(entry);
    2920             :                                 }
    2921         296 :                                 Z_TRY_ADDREF_P(entry);
    2922         296 :                                 ZEND_HASH_FILL_ADD(entry);
    2923             :                         } ZEND_HASH_FOREACH_END();
    2924          68 :                 } ZEND_HASH_FILL_END();
    2925             :         } else {
    2926        1361 :                 ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(input), num_key, string_key, entry) {
    2927         630 :                         pos++;
    2928         630 :                         if (pos <= offset) {
    2929         149 :                                 continue;
    2930             :                         }
    2931         481 :                         if (pos > offset + length) {
    2932          71 :                                 break;
    2933             :                         }
    2934             : 
    2935         410 :                         if (string_key) {
    2936         136 :                                 entry = zend_hash_add_new(Z_ARRVAL_P(return_value), string_key, entry);
    2937             :                         } else {
    2938         274 :                                 if (preserve_keys) {
    2939         150 :                                         entry = zend_hash_index_add_new(Z_ARRVAL_P(return_value), num_key, entry);
    2940             :                                 } else {
    2941         124 :                                         entry = zend_hash_next_index_insert_new(Z_ARRVAL_P(return_value), entry);
    2942             :                                 }
    2943             :                         }
    2944         410 :                         zval_add_ref(entry);
    2945             :                 } ZEND_HASH_FOREACH_END();
    2946             :         }
    2947             : }
    2948             : /* }}} */
    2949             : 
    2950          85 : PHPAPI int php_array_merge_recursive(HashTable *dest, HashTable *src) /* {{{ */
    2951             : {
    2952             :         zval *src_entry, *dest_entry;
    2953             :         zend_string *string_key;
    2954             : 
    2955         539 :         ZEND_HASH_FOREACH_STR_KEY_VAL(src, string_key, src_entry) {
    2956         232 :                 if (string_key) {
    2957         116 :                         if ((dest_entry = zend_hash_find(dest, string_key)) != NULL) {
    2958          39 :                                 zval *src_zval = src_entry;
    2959          39 :                                 zval *dest_zval = dest_entry;
    2960             :                                 HashTable *thash;
    2961             :                                 zval tmp;
    2962             :                                 int ret;
    2963             : 
    2964          39 :                                 ZVAL_DEREF(src_zval);
    2965          39 :                                 ZVAL_DEREF(dest_zval);
    2966          39 :                                 thash = Z_TYPE_P(dest_zval) == IS_ARRAY ? Z_ARRVAL_P(dest_zval) : NULL;
    2967          39 :                                 if ((thash && thash->u.v.nApplyCount > 1) || (src_entry == dest_entry && Z_ISREF_P(dest_entry) && (Z_REFCOUNT_P(dest_entry) % 2))) {
    2968           2 :                                         php_error_docref(NULL, E_WARNING, "recursion detected");
    2969           2 :                                         return 0;
    2970             :                                 }
    2971             : 
    2972          37 :                                 if (Z_ISREF_P(dest_entry)) {
    2973           5 :                                         if (Z_REFCOUNT_P(dest_entry) == 1) {
    2974           0 :                                                 ZVAL_UNREF(dest_entry);
    2975             :                                         } else {
    2976             :                                                 Z_DELREF_P(dest_entry);
    2977           5 :                                                 ZVAL_DUP(dest_entry, dest_zval);
    2978             :                                         }
    2979           5 :                                         dest_zval = dest_entry;
    2980             :                                 } else {
    2981          76 :                                         SEPARATE_ZVAL(dest_zval);
    2982             :                                 }
    2983          37 :                                 if (Z_TYPE_P(dest_zval) == IS_NULL) {
    2984           2 :                                         convert_to_array_ex(dest_zval);
    2985           2 :                                         add_next_index_null(dest_zval);
    2986          35 :                                 } else if (Z_TYPE_P(dest_zval) == IS_ARRAY) {
    2987          17 :                                         if (UNEXPECTED(Z_ARRVAL_P(dest_zval)->nNextFreeElement > (zend_long)Z_ARRVAL_P(dest_zval)->nNumUsed)) {
    2988           1 :                                                 Z_ARRVAL_P(dest_zval)->nNextFreeElement = Z_ARRVAL_P(dest_zval)->nNumUsed;
    2989             :                                         }
    2990             :                                 } else {
    2991          18 :                                         convert_to_array_ex(dest_zval);
    2992             :                                 }
    2993          37 :                                 ZVAL_UNDEF(&tmp);
    2994          37 :                                 if (Z_TYPE_P(src_zval) == IS_OBJECT) {
    2995           0 :                                         ZVAL_COPY(&tmp, src_zval);
    2996           0 :                                         convert_to_array(&tmp);
    2997           0 :                                         src_zval = &tmp;
    2998             :                                 }
    2999          37 :                                 if (Z_TYPE_P(src_zval) == IS_ARRAY) {
    3000          19 :                                         if (thash && ZEND_HASH_APPLY_PROTECTION(thash)) {
    3001          17 :                                                 thash->u.v.nApplyCount++;
    3002             :                                         }
    3003          19 :                                         ret = php_array_merge_recursive(Z_ARRVAL_P(dest_zval), Z_ARRVAL_P(src_zval));
    3004          19 :                                         if (thash && ZEND_HASH_APPLY_PROTECTION(thash)) {
    3005          17 :                                                 thash->u.v.nApplyCount--;
    3006             :                                         }
    3007          19 :                                         if (!ret) {
    3008           8 :                                                 return 0;
    3009             :                                         }
    3010             :                                 } else {
    3011          18 :                                         if (Z_REFCOUNTED_P(src_entry)) {
    3012             :                                                 Z_ADDREF_P(src_entry);
    3013             :                                         }
    3014          18 :                                         zend_hash_next_index_insert(Z_ARRVAL_P(dest_zval), src_zval);
    3015             :                                 }
    3016          29 :                                 zval_ptr_dtor(&tmp);
    3017             :                         } else {
    3018          77 :                                 zval *zv = zend_hash_add_new(dest, string_key, src_entry);
    3019          77 :                                 zval_add_ref(zv);
    3020             :                         }
    3021             :                 } else {
    3022         116 :                         zval *zv = zend_hash_next_index_insert_new(dest, src_entry);
    3023         116 :                         zval_add_ref(zv);
    3024             :                 }
    3025             :         } ZEND_HASH_FOREACH_END();
    3026          75 :         return 1;
    3027             : }
    3028             : /* }}} */
    3029             : 
    3030         208 : PHPAPI int php_array_merge(HashTable *dest, HashTable *src) /* {{{ */
    3031             : {
    3032             :         zval *src_entry;
    3033             :         zend_string *string_key;
    3034             : 
    3035         306 :         if ((dest->u.flags & HASH_FLAG_PACKED) && (src->u.flags & HASH_FLAG_PACKED)) {
    3036          98 :                 zend_hash_extend(dest, zend_hash_num_elements(dest) + zend_hash_num_elements(src), 1);
    3037          98 :                 ZEND_HASH_FILL_PACKED(dest) {
    3038       35322 :                         ZEND_HASH_FOREACH_VAL(src, src_entry) {
    3039       17604 :                                 if (UNEXPECTED(Z_ISREF_P(src_entry)) &&
    3040           0 :                                         UNEXPECTED(Z_REFCOUNT_P(src_entry) == 1)) {
    3041           0 :                                         ZVAL_UNREF(src_entry);
    3042             :                                 }
    3043       17604 :                                 Z_TRY_ADDREF_P(src_entry);
    3044       17604 :                                 ZEND_HASH_FILL_ADD(src_entry);
    3045             :                         } ZEND_HASH_FOREACH_END();
    3046          98 :                 } ZEND_HASH_FILL_END();
    3047             :         } else {
    3048         794 :                 ZEND_HASH_FOREACH_STR_KEY_VAL(src, string_key, src_entry) {
    3049         345 :                         if (UNEXPECTED(Z_ISREF_P(src_entry) &&
    3050             :                                 Z_REFCOUNT_P(src_entry) == 1)) {
    3051           1 :                                 ZVAL_UNREF(src_entry);
    3052             :                         }
    3053         338 :                         Z_TRY_ADDREF_P(src_entry);
    3054         338 :                         if (string_key) {
    3055         125 :                                 zend_hash_update(dest, string_key, src_entry);
    3056             :                         } else {
    3057         213 :                                 zend_hash_next_index_insert_new(dest, src_entry);
    3058             :                         }
    3059             :                 } ZEND_HASH_FOREACH_END();
    3060             :         }
    3061         208 :         return 1;
    3062             : }
    3063             : /* }}} */
    3064             : 
    3065           8 : PHPAPI int php_array_replace_recursive(HashTable *dest, HashTable *src) /* {{{ */
    3066             : {
    3067             :         zval *src_entry, *dest_entry, *src_zval, *dest_zval;
    3068             :         zend_string *string_key;
    3069             :         zend_ulong num_key;
    3070             :         int ret;
    3071             : 
    3072          25 :         ZEND_HASH_FOREACH_KEY_VAL(src, num_key, string_key, src_entry) {
    3073          10 :                 src_zval = src_entry;
    3074          10 :                 ZVAL_DEREF(src_zval);
    3075          10 :                 if (string_key) {
    3076           7 :                         if (Z_TYPE_P(src_zval) != IS_ARRAY ||
    3077           2 :                                 (dest_entry = zend_hash_find(dest, string_key)) == NULL ||
    3078             :                                 (Z_TYPE_P(dest_entry) != IS_ARRAY &&
    3079           0 :                                  (!Z_ISREF_P(dest_entry) || Z_TYPE_P(Z_REFVAL_P(dest_entry)) != IS_ARRAY))) {
    3080             : 
    3081           3 :                                 zval *zv = zend_hash_update(dest, string_key, src_entry);
    3082           3 :                                 zval_add_ref(zv);
    3083           3 :                                 continue;
    3084             :                         }
    3085             :                 } else {
    3086          14 :                         if (Z_TYPE_P(src_zval) != IS_ARRAY ||
    3087           4 :                                 (dest_entry = zend_hash_index_find(dest, num_key)) == NULL ||
    3088             :                                 (Z_TYPE_P(dest_entry) != IS_ARRAY &&
    3089           0 :                                  (!Z_ISREF_P(dest_entry) || Z_TYPE_P(Z_REFVAL_P(dest_entry)) != IS_ARRAY))) {
    3090             : 
    3091           2 :                                 zval *zv = zend_hash_index_update(dest, num_key, src_entry);
    3092           2 :                                 zval_add_ref(zv);
    3093           2 :                                 continue;
    3094             :                         }
    3095             :                 }
    3096             : 
    3097           5 :                 dest_zval = dest_entry;
    3098           5 :                 ZVAL_DEREF(dest_zval);
    3099          16 :                 if (Z_ARRVAL_P(dest_zval)->u.v.nApplyCount > 1 ||
    3100           5 :                     Z_ARRVAL_P(src_zval)->u.v.nApplyCount > 1 ||
    3101           0 :                     (Z_ISREF_P(src_entry) && Z_ISREF_P(dest_entry) && Z_REF_P(src_entry) == Z_REF_P(dest_entry) && (Z_REFCOUNT_P(dest_entry) % 2))) {
    3102           1 :                         php_error_docref(NULL, E_WARNING, "recursion detected");
    3103           1 :                         return 0;
    3104             :                 }
    3105          12 :                 SEPARATE_ZVAL(dest_zval);
    3106             : 
    3107           4 :                 if (ZEND_HASH_APPLY_PROTECTION(Z_ARRVAL_P(dest_zval))) {
    3108           4 :                         Z_ARRVAL_P(dest_zval)->u.v.nApplyCount++;
    3109             :                 }
    3110           4 :                 if (ZEND_HASH_APPLY_PROTECTION(Z_ARRVAL_P(src_zval))) {
    3111           4 :                         Z_ARRVAL_P(src_zval)->u.v.nApplyCount++;
    3112             :                 }
    3113             : 
    3114           4 :                 ret = php_array_replace_recursive(Z_ARRVAL_P(dest_zval), Z_ARRVAL_P(src_zval));
    3115             : 
    3116           4 :                 if (ZEND_HASH_APPLY_PROTECTION(Z_ARRVAL_P(dest_zval))) {
    3117           4 :                         Z_ARRVAL_P(dest_zval)->u.v.nApplyCount--;
    3118             :                 }
    3119           4 :                 if (ZEND_HASH_APPLY_PROTECTION(Z_ARRVAL_P(src_zval))) {
    3120           4 :                         Z_ARRVAL_P(src_zval)->u.v.nApplyCount--;
    3121             :                 }
    3122             : 
    3123           4 :                 if (!ret) {
    3124           2 :                         return 0;
    3125             :                 }
    3126             :         } ZEND_HASH_FOREACH_END();
    3127             : 
    3128           5 :         return 1;
    3129             : }
    3130             : /* }}} */
    3131             : 
    3132         446 : static inline void php_array_merge_or_replace_wrapper(INTERNAL_FUNCTION_PARAMETERS, int recursive, int replace) /* {{{ */
    3133             : {
    3134         446 :         zval *args = NULL;
    3135             :         zval *arg;
    3136             :         int argc, i;
    3137             : 
    3138         446 :         ZEND_PARSE_PARAMETERS_START(1, -1)
    3139         443 :                 Z_PARAM_VARIADIC('+', args, argc)
    3140         446 :         ZEND_PARSE_PARAMETERS_END();
    3141             : 
    3142        1094 :         for (i = 0; i < argc; i++) {
    3143         774 :                 zval *arg = args + i;
    3144             : 
    3145         774 :                 ZVAL_DEREF(arg);
    3146         774 :                 if (Z_TYPE_P(arg) != IS_ARRAY) {
    3147         123 :                         php_error_docref(NULL, E_WARNING, "Argument #%d is not an array", i + 1);
    3148         123 :                         RETURN_NULL();
    3149             :                 }
    3150             :         }
    3151             : 
    3152             : 
    3153         320 :         if (replace) {
    3154             :                 HashTable *dest;
    3155             : 
    3156             :                 /* copy first array */
    3157           5 :                 arg = args;
    3158           5 :                 ZVAL_DEREF(arg);
    3159           5 :                 dest = zend_array_dup(Z_ARRVAL_P(arg));
    3160           5 :                 ZVAL_ARR(return_value, dest);
    3161           5 :                 if (recursive) {
    3162           8 :                         for (i = 1; i < argc; i++) {
    3163           4 :                                 arg = args + i;
    3164           4 :                                 ZVAL_DEREF(arg);
    3165           4 :                                 php_array_replace_recursive(dest, Z_ARRVAL_P(arg));
    3166             :                         }
    3167             :                 } else {
    3168           2 :                         for (i = 1; i < argc; i++) {
    3169           1 :                                 arg = args + i;
    3170           1 :                                 ZVAL_DEREF(arg);
    3171           1 :                                 zend_hash_merge(dest, Z_ARRVAL_P(arg), zval_add_ref, 1);
    3172             :                         }
    3173             :                 }
    3174             :         } else {
    3175             :                 zval *src_entry;
    3176             :                 HashTable *src, *dest;
    3177             : 
    3178         315 :                 arg = args;
    3179         315 :                 ZVAL_DEREF(arg);
    3180         315 :                 src  = Z_ARRVAL_P(arg);
    3181             :                 /* copy first array */
    3182         315 :                 array_init_size(return_value, zend_hash_num_elements(src));
    3183         315 :                 dest = Z_ARRVAL_P(return_value);
    3184         315 :                 if (src->u.flags & HASH_FLAG_PACKED) {
    3185         143 :                         zend_hash_real_init(dest, 1);
    3186         143 :                         ZEND_HASH_FILL_PACKED(dest) {
    3187       15661 :                                 ZEND_HASH_FOREACH_VAL(src, src_entry) {
    3188        7744 :                                         if (UNEXPECTED(Z_ISREF_P(src_entry) &&
    3189             :                                                 Z_REFCOUNT_P(src_entry) == 1)) {
    3190           1 :                                                 ZVAL_UNREF(src_entry);
    3191             :                                         }
    3192        7737 :                                         Z_TRY_ADDREF_P(src_entry);
    3193        7737 :                                         ZEND_HASH_FILL_ADD(src_entry);
    3194             :                                 } ZEND_HASH_FOREACH_END();
    3195         143 :                         } ZEND_HASH_FILL_END();
    3196             :                 } else {
    3197             :                         zend_string *string_key;
    3198        2252 :                         ZEND_HASH_FOREACH_STR_KEY_VAL(src, string_key, src_entry) {
    3199        1049 :                                 if (UNEXPECTED(Z_ISREF_P(src_entry) &&
    3200             :                                         Z_REFCOUNT_P(src_entry) == 1)) {
    3201           0 :                                         ZVAL_UNREF(src_entry);
    3202             :                                 }
    3203        1040 :                                 Z_TRY_ADDREF_P(src_entry);
    3204        1040 :                                 if (string_key) {
    3205         854 :                                         zend_hash_add_new(dest, string_key, src_entry);
    3206             :                                 } else {
    3207         186 :                                         zend_hash_next_index_insert_new(dest, src_entry);
    3208             :                                 }
    3209             :                         } ZEND_HASH_FOREACH_END();
    3210             :                 }
    3211         315 :                 if (recursive) {
    3212         173 :                         for (i = 1; i < argc; i++) {
    3213          66 :                                 arg = args + i;
    3214          66 :                                 ZVAL_DEREF(arg);
    3215          66 :                                 php_array_merge_recursive(dest, Z_ARRVAL_P(arg));
    3216             :                         }
    3217             :                 } else {
    3218         416 :                         for (i = 1; i < argc; i++) {
    3219         208 :                                 arg = args + i;
    3220         208 :                                 ZVAL_DEREF(arg);
    3221         208 :                                 php_array_merge(dest, Z_ARRVAL_P(arg));
    3222             :                         }
    3223             :                 }
    3224             :         }
    3225             : }
    3226             : /* }}} */
    3227             : 
    3228             : /* {{{ proto array array_merge(array arr1, array arr2 [, array ...])
    3229             :    Merges elements from passed arrays into one array */
    3230         261 : PHP_FUNCTION(array_merge)
    3231             : {
    3232         261 :         php_array_merge_or_replace_wrapper(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0, 0);
    3233         261 : }
    3234             : /* }}} */
    3235             : 
    3236             : /* {{{ proto array array_merge_recursive(array arr1, array arr2 [, array ...])
    3237             :    Recursively merges elements from passed arrays into one array */
    3238         180 : PHP_FUNCTION(array_merge_recursive)
    3239             : {
    3240         180 :         php_array_merge_or_replace_wrapper(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1, 0);
    3241         180 : }
    3242             : /* }}} */
    3243             : 
    3244             : /* {{{ proto array array_replace(array arr1, array arr2 [, array ...])
    3245             :    Replaces elements from passed arrays into one array */
    3246           1 : PHP_FUNCTION(array_replace)
    3247             : {
    3248           1 :         php_array_merge_or_replace_wrapper(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0, 1);
    3249           1 : }
    3250             : /* }}} */
    3251             : 
    3252             : /* {{{ proto array array_replace_recursive(array arr1, array arr2 [, array ...])
    3253             :    Recursively replaces elements from passed arrays into one array */
    3254           4 : PHP_FUNCTION(array_replace_recursive)
    3255             : {
    3256           4 :         php_array_merge_or_replace_wrapper(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1, 1);
    3257           4 : }
    3258             : /* }}} */
    3259             : 
    3260             : /* {{{ proto array array_keys(array input [, mixed search_value[, bool strict]])
    3261             :    Return just the keys from the input array, optionally only for the specified search_value */
    3262         475 : PHP_FUNCTION(array_keys)
    3263             : {
    3264             :         zval *input,                            /* Input array */
    3265         475 :              *search_value = NULL,      /* Value to search for */
    3266             :              *entry,                            /* An entry in the input array */
    3267             :                new_val;                         /* New value */
    3268         475 :         zend_bool strict = 0;           /* do strict comparison */
    3269             :         zend_ulong num_idx;
    3270             :         zend_string *str_idx;
    3271             : 
    3272         475 :         ZEND_PARSE_PARAMETERS_START(1, 3)
    3273        1419 :                 Z_PARAM_ARRAY(input)
    3274         470 :                 Z_PARAM_OPTIONAL
    3275         470 :                 Z_PARAM_ZVAL(search_value)
    3276          80 :                 Z_PARAM_BOOL(strict)
    3277         475 :         ZEND_PARSE_PARAMETERS_END();
    3278             : 
    3279             :         /* Initialize return array */
    3280         470 :         if (search_value != NULL) {
    3281          36 :                 array_init(return_value);
    3282             : 
    3283          36 :                 if (strict) {
    3284         478 :                         ZEND_HASH_FOREACH_KEY_VAL_IND(Z_ARRVAL_P(input), num_idx, str_idx, entry) {
    3285         152 :                                 ZVAL_DEREF(entry);
    3286         304 :                                 if (fast_is_identical_function(search_value, entry)) {
    3287          17 :                                         if (str_idx) {
    3288           2 :                                                 ZVAL_STR_COPY(&new_val, str_idx);
    3289             :                                         } else {
    3290          15 :                                                 ZVAL_LONG(&new_val, num_idx);
    3291             :                                         }
    3292          17 :                                         zend_hash_next_index_insert_new(Z_ARRVAL_P(return_value), &new_val);
    3293             :                                 }
    3294             :                         } ZEND_HASH_FOREACH_END();
    3295             :                 } else {
    3296         278 :                         ZEND_HASH_FOREACH_KEY_VAL_IND(Z_ARRVAL_P(input), num_idx, str_idx, entry) {
    3297         176 :                                 if (fast_equal_check_function(search_value, entry)) {
    3298          26 :                                         if (str_idx) {
    3299           7 :                                                 ZVAL_STR_COPY(&new_val, str_idx);
    3300             :                                         } else {
    3301          19 :                                                 ZVAL_LONG(&new_val, num_idx);
    3302             :                                         }
    3303          26 :                                         zend_hash_next_index_insert_new(Z_ARRVAL_P(return_value), &new_val);
    3304             :                                 }
    3305             :                         } ZEND_HASH_FOREACH_END();
    3306             :                 }
    3307             :         } else {
    3308         434 :                 array_init_size(return_value, zend_hash_num_elements(Z_ARRVAL_P(input)));
    3309         434 :                 if (!zend_hash_num_elements(Z_ARRVAL_P(input))) {
    3310           4 :                         return;
    3311             :                 }
    3312         430 :                 zend_hash_real_init(Z_ARRVAL_P(return_value), 1);
    3313         430 :                 ZEND_HASH_FILL_PACKED(Z_ARRVAL_P(return_value)) {
    3314             :                         /* Go through input array and add keys to the return array */
    3315       21883 :                         ZEND_HASH_FOREACH_KEY_VAL_IND(Z_ARRVAL_P(input), num_idx, str_idx, entry) {
    3316        7146 :                                 if (str_idx) {
    3317        5264 :                                         ZVAL_STR_COPY(&new_val, str_idx);
    3318             :                                 } else {
    3319        1882 :                                         ZVAL_LONG(&new_val, num_idx);
    3320             :                                 }
    3321        7146 :                                 ZEND_HASH_FILL_ADD(&new_val);
    3322             :                         } ZEND_HASH_FOREACH_END();
    3323         430 :                 } ZEND_HASH_FILL_END();
    3324             :         }
    3325             : }
    3326             : /* }}} */
    3327             : 
    3328             : /* {{{ proto array array_values(array input)
    3329             :    Return just the values from the input array */
    3330          91 : PHP_FUNCTION(array_values)
    3331             : {
    3332             :         zval     *input,                /* Input array */
    3333             :                          *entry;                /* An entry in the input array */
    3334             : 
    3335          91 :         ZEND_PARSE_PARAMETERS_START(1, 1)
    3336         261 :                 Z_PARAM_ARRAY(input)
    3337          91 :         ZEND_PARSE_PARAMETERS_END();
    3338             : 
    3339             :         /* Initialize return array */
    3340          60 :         array_init_size(return_value, zend_hash_num_elements(Z_ARRVAL_P(input)));
    3341             : 
    3342          60 :         if (!zend_hash_num_elements(Z_ARRVAL_P(input))) {
    3343           4 :                 return;
    3344             :         }
    3345             : 
    3346          56 :         zend_hash_real_init(Z_ARRVAL_P(return_value), 1);
    3347             : 
    3348             :         /* Go through input array and add values to the return array */
    3349          56 :         ZEND_HASH_FILL_PACKED(Z_ARRVAL_P(return_value)) {
    3350         396 :                 ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(input), entry) {
    3351         178 :                         if (UNEXPECTED(Z_ISREF_P(entry) && Z_REFCOUNT_P(entry) == 1)) {
    3352           3 :                                 entry = Z_REFVAL_P(entry);
    3353             :                         }
    3354         170 :                         Z_TRY_ADDREF_P(entry);
    3355         170 :                         ZEND_HASH_FILL_ADD(entry);
    3356             :                 } ZEND_HASH_FOREACH_END();
    3357          56 :         } ZEND_HASH_FILL_END();
    3358             : }
    3359             : /* }}} */
    3360             : 
    3361             : /* {{{ proto array array_count_values(array input)
    3362             :    Return the value as key and the frequency of that value in input as value */
    3363          20 : PHP_FUNCTION(array_count_values)
    3364             : {
    3365             :         zval    *input,         /* Input array */
    3366             :                         *entry,         /* An entry in the input array */
    3367             :                         *tmp;
    3368             :         HashTable *myht;
    3369             : 
    3370          20 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "a", &input) == FAILURE) {
    3371           3 :                 return;
    3372             :         }
    3373             : 
    3374             :         /* Initialize return array */
    3375          17 :         array_init(return_value);
    3376             : 
    3377             :         /* Go through input array and add values to the return array */
    3378          17 :         myht = Z_ARRVAL_P(input);
    3379         135 :         ZEND_HASH_FOREACH_VAL(myht, entry) {
    3380          59 :                 ZVAL_DEREF(entry);
    3381          59 :                 if (Z_TYPE_P(entry) == IS_LONG) {
    3382          17 :                         if ((tmp = zend_hash_index_find(Z_ARRVAL_P(return_value), Z_LVAL_P(entry))) == NULL) {
    3383             :                                 zval data;
    3384          13 :                                 ZVAL_LONG(&data, 1);
    3385          13 :                                 zend_hash_index_update(Z_ARRVAL_P(return_value), Z_LVAL_P(entry), &data);
    3386             :                         } else {
    3387           4 :                                 Z_LVAL_P(tmp)++;
    3388             :                         }
    3389          42 :                 } else if (Z_TYPE_P(entry) == IS_STRING) {
    3390          66 :                         if ((tmp = zend_symtable_find(Z_ARRVAL_P(return_value), Z_STR_P(entry))) == NULL) {
    3391             :                                 zval data;
    3392          24 :                                 ZVAL_LONG(&data, 1);
    3393          24 :                                 zend_symtable_update(Z_ARRVAL_P(return_value), Z_STR_P(entry), &data);
    3394             :                         } else {
    3395           9 :                                 Z_LVAL_P(tmp)++;
    3396             :                         }
    3397             :                 } else {
    3398           9 :                         php_error_docref(NULL, E_WARNING, "Can only count STRING and INTEGER values!");
    3399             :                 }
    3400             :         } ZEND_HASH_FOREACH_END();
    3401             : }
    3402             : /* }}} */
    3403             : 
    3404             : /* {{{ array_column_param_helper
    3405             :  * Specialized conversion rules for array_column() function
    3406             :  */
    3407             : static inline
    3408          65 : zend_bool array_column_param_helper(zval *param,
    3409             :                                     const char *name) {
    3410          65 :         switch (Z_TYPE_P(param)) {
    3411             :                 case IS_DOUBLE:
    3412           2 :                         convert_to_long_ex(param);
    3413             :                         /* fallthrough */
    3414             :                 case IS_LONG:
    3415          18 :                         return 1;
    3416             : 
    3417             :                 case IS_OBJECT:
    3418          10 :                         convert_to_string_ex(param);
    3419             :                         /* fallthrough */
    3420             :                 case IS_STRING:
    3421          43 :                         return 1;
    3422             : 
    3423             :                 default:
    3424           4 :                         php_error_docref(NULL, E_WARNING, "The %s key should be either a string or an integer", name);
    3425           4 :                         return 0;
    3426             :         }
    3427             : }
    3428             : /* }}} */
    3429             : 
    3430         213 : static inline zval *array_column_fetch_prop(zval *data, zval *name, zval *rv) /* {{{ */
    3431             : {
    3432         213 :         zval *prop = NULL;
    3433             : 
    3434         213 :         if (Z_TYPE_P(data) == IS_OBJECT) {
    3435          78 :                 if (!Z_OBJ_HANDLER_P(data, has_property) || !Z_OBJ_HANDLER_P(data, read_property)) {
    3436           0 :                         return NULL;
    3437             :                 }
    3438             : 
    3439             :                 /* The has_property check is first performed in "exists" mode (which returns true for
    3440             :                  * properties that are null but exist) and then in "has" mode to handle objects that
    3441             :                  * implement __isset (which is not called in "exists" mode). */
    3442         189 :                 if (Z_OBJ_HANDLER_P(data, has_property)(data, name, 2, NULL)
    3443         111 :                                 || Z_OBJ_HANDLER_P(data, has_property)(data, name, 0, NULL)) {
    3444          47 :                         prop = Z_OBJ_HANDLER_P(data, read_property)(data, name, BP_VAR_R, NULL, rv);
    3445             :                 }
    3446         135 :         } else if (Z_TYPE_P(data) == IS_ARRAY) {
    3447         132 :                 if (Z_TYPE_P(name) == IS_STRING) {
    3448         200 :                         prop = zend_symtable_find(Z_ARRVAL_P(data), Z_STR_P(name));
    3449          32 :                 } else if (Z_TYPE_P(name) == IS_LONG) {
    3450          32 :                         prop = zend_hash_index_find(Z_ARRVAL_P(data), Z_LVAL_P(name));
    3451             :                 }
    3452             :         }
    3453             : 
    3454         213 :         if (prop) {
    3455         154 :                 ZVAL_DEREF(prop);
    3456             :         }
    3457             : 
    3458         213 :         return prop;
    3459             : }
    3460             : /* }}} */
    3461             : 
    3462             : /* {{{ proto array array_column(array input, mixed column_key[, mixed index_key])
    3463             :    Return the values from a single column in the input array, identified by the
    3464             :    value_key and optionally indexed by the index_key */
    3465          50 : PHP_FUNCTION(array_column)
    3466             : {
    3467          50 :         zval *zcolumn = NULL, *zkey = NULL, *data;
    3468             :         HashTable *arr_hash;
    3469          50 :         zval *zcolval = NULL, *zkeyval = NULL, rvc, rvk;
    3470             : 
    3471          50 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "hz!|z!", &arr_hash, &zcolumn, &zkey) == FAILURE) {
    3472           4 :                 return;
    3473             :         }
    3474             : 
    3475         112 :         if ((zcolumn && !array_column_param_helper(zcolumn, "column")) ||
    3476          66 :             (zkey && !array_column_param_helper(zkey, "index"))) {
    3477           4 :                 RETURN_FALSE;
    3478             :         }
    3479             : 
    3480          42 :         array_init_size(return_value, zend_hash_num_elements(arr_hash));
    3481          42 :         if (!zkey) {
    3482          22 :                 zend_hash_real_init(Z_ARRVAL_P(return_value), 1);
    3483          22 :                 ZEND_HASH_FILL_PACKED(Z_ARRVAL_P(return_value)) {
    3484         194 :                         ZEND_HASH_FOREACH_VAL(arr_hash, data) {
    3485          86 :                                 ZVAL_DEREF(data);
    3486          86 :                                 if (!zcolumn) {
    3487           2 :                                         zcolval = data;
    3488           2 :                                         Z_TRY_ADDREF_P(zcolval);
    3489          84 :                                 } else if ((zcolval = array_column_fetch_prop(data, zcolumn, &rvc)) == NULL) {
    3490          30 :                                         continue;
    3491          54 :                                 } else if (zcolval != &rvc) {
    3492          52 :                                         Z_TRY_ADDREF_P(zcolval);
    3493             :                                 }
    3494          56 :                                 ZEND_HASH_FILL_ADD(zcolval);
    3495             :                         } ZEND_HASH_FOREACH_END();
    3496          22 :                 } ZEND_HASH_FILL_END();
    3497             :         } else {
    3498         172 :                 ZEND_HASH_FOREACH_VAL(arr_hash, data) {
    3499          76 :                         ZVAL_DEREF(data);
    3500             : 
    3501          76 :                         if (!zcolumn) {
    3502           4 :                                 zcolval = data;
    3503           4 :                                 Z_TRY_ADDREF_P(zcolval);
    3504          72 :                         } else if ((zcolval = array_column_fetch_prop(data, zcolumn, &rvc)) == NULL) {
    3505          19 :                                 continue;
    3506          53 :                         } else if (zcolval != &rvc) {
    3507          53 :                                 Z_TRY_ADDREF_P(zcolval);
    3508             :                         }
    3509             : 
    3510             :                         /* Failure will leave zkeyval alone which will land us on the final else block below
    3511             :                          * which is to append the value as next_index
    3512             :                          */
    3513          57 :                         if (zkey) {
    3514          57 :                                 zkeyval = array_column_fetch_prop(data, zkey, &rvk);
    3515             :                         }
    3516          57 :                         if (zkeyval) {
    3517          47 :                                 if (Z_TYPE_P(zkeyval) == IS_STRING) {
    3518          27 :                                         zend_symtable_update(Z_ARRVAL_P(return_value), Z_STR_P(zkeyval), zcolval);
    3519          20 :                                 } else if (Z_TYPE_P(zkeyval) == IS_LONG) {
    3520          19 :                                         add_index_zval(return_value, Z_LVAL_P(zkeyval), zcolval);
    3521           1 :                                 } else if (Z_TYPE_P(zkeyval) == IS_OBJECT) {
    3522           1 :                                         zend_string *key = zval_get_string(zkeyval);
    3523           1 :                                         zend_symtable_update(Z_ARRVAL_P(return_value), key, zcolval);
    3524             :                                         zend_string_release(key);
    3525             :                                 } else {
    3526           0 :                                         add_next_index_zval(return_value, zcolval);
    3527             :                                 }
    3528          47 :                                 if (zkeyval == &rvk) {
    3529           0 :                                         zval_ptr_dtor(&rvk);
    3530             :                                 }
    3531             :                         } else {
    3532          10 :                                 add_next_index_zval(return_value, zcolval);
    3533             :                         }
    3534             :                 } ZEND_HASH_FOREACH_END();
    3535             :         }
    3536             : }
    3537             : /* }}} */
    3538             : 
    3539             : /* {{{ proto array array_reverse(array input [, bool preserve keys])
    3540             :    Return input as a new array with the order of the entries reversed */
    3541         235 : PHP_FUNCTION(array_reverse)
    3542             : {
    3543             :         zval     *input,                                /* Input array */
    3544             :                          *entry;                                /* An entry in the input array */
    3545             :         zend_string *string_key;
    3546             :         zend_ulong        num_key;
    3547         235 :         zend_bool preserve_keys = 0;    /* whether to preserve keys */
    3548             : 
    3549         235 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "a|b", &input, &preserve_keys) == FAILURE) {
    3550          82 :                 return;
    3551             :         }
    3552             : 
    3553             :         /* Initialize return array */
    3554         153 :         array_init_size(return_value, zend_hash_num_elements(Z_ARRVAL_P(input)));
    3555         189 :         if ((Z_ARRVAL_P(input)->u.flags & HASH_FLAG_PACKED) && !preserve_keys) {
    3556          36 :                 zend_hash_real_init(Z_ARRVAL_P(return_value), 1);
    3557          36 :                 ZEND_HASH_FILL_PACKED(Z_ARRVAL_P(return_value)) {
    3558         270 :                         ZEND_HASH_REVERSE_FOREACH_VAL(Z_ARRVAL_P(input), entry) {
    3559         107 :                                 if (UNEXPECTED(Z_ISREF_P(entry) &&
    3560             :                                         Z_REFCOUNT_P(entry) == 1)) {
    3561           3 :                                         ZVAL_UNREF(entry);
    3562             :                                 }
    3563         103 :                                 Z_TRY_ADDREF_P(entry);
    3564         103 :                                 ZEND_HASH_FILL_ADD(entry);
    3565             :                         } ZEND_HASH_FOREACH_END();
    3566          36 :                 } ZEND_HASH_FILL_END();
    3567             :         } else {
    3568         957 :                 ZEND_HASH_REVERSE_FOREACH_KEY_VAL(Z_ARRVAL_P(input), num_key, string_key, entry) {
    3569         413 :                         if (string_key) {
    3570         175 :                                 entry = zend_hash_add_new(Z_ARRVAL_P(return_value), string_key, entry);
    3571             :                         } else {
    3572         238 :                                 if (preserve_keys) {
    3573         129 :                                         entry = zend_hash_index_add_new(Z_ARRVAL_P(return_value), num_key, entry);
    3574             :                                 } else {
    3575         109 :                                         entry = zend_hash_next_index_insert_new(Z_ARRVAL_P(return_value), entry);
    3576             :                                 }
    3577             :                         }
    3578         413 :                         zval_add_ref(entry);
    3579             :                 } ZEND_HASH_FOREACH_END();
    3580             :         }
    3581             : }
    3582             : /* }}} */
    3583             : 
    3584             : /* {{{ proto array array_pad(array input, int pad_size, mixed pad_value)
    3585             :    Returns a copy of input array padded with pad_value to size pad_size */
    3586         199 : PHP_FUNCTION(array_pad)
    3587             : {
    3588             :         zval  *input;           /* Input array */
    3589             :         zval  *pad_value;       /* Padding value obviously */
    3590             :         zend_long pad_size;             /* Size to pad to */
    3591             :         zend_long pad_size_abs; /* Absolute value of pad_size */
    3592             :         zend_long input_size;           /* Size of the input array */
    3593             :         zend_long num_pads;             /* How many pads do we need */
    3594             :         zend_long i;
    3595             :         zend_string *key;
    3596             :         zval *value;
    3597             : 
    3598         199 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "alz", &input, &pad_size, &pad_value) == FAILURE) {
    3599          66 :                 return;
    3600             :         }
    3601             : 
    3602             :         /* Do some initial calculations */
    3603         133 :         input_size = zend_hash_num_elements(Z_ARRVAL_P(input));
    3604         133 :         pad_size_abs = ZEND_ABS(pad_size);
    3605         133 :         if (pad_size_abs < 0 || pad_size_abs - input_size > Z_L(1048576)) {
    3606           3 :                 php_error_docref(NULL, E_WARNING, "You may only pad up to 1048576 elements at a time");
    3607           3 :                 RETURN_FALSE;
    3608             :         }
    3609             : 
    3610         130 :         if (input_size >= pad_size_abs) {
    3611             :                 /* Copy the original array */
    3612          15 :                 ZVAL_COPY(return_value, input);
    3613          15 :                 return;
    3614             :         }
    3615             : 
    3616         115 :         num_pads = pad_size_abs - input_size;
    3617         115 :         if (Z_REFCOUNTED_P(pad_value)) {
    3618          18 :                 GC_REFCOUNT(Z_COUNTED_P(pad_value)) += num_pads;
    3619             :         }
    3620             : 
    3621         115 :         array_init_size(return_value, pad_size_abs);
    3622         115 :         if (Z_ARRVAL_P(input)->u.flags & HASH_FLAG_PACKED) {
    3623          91 :                 zend_hash_real_init(Z_ARRVAL_P(return_value), 1);
    3624             : 
    3625          91 :                 if (pad_size < 0) {
    3626          45 :                         ZEND_HASH_FILL_PACKED(Z_ARRVAL_P(return_value)) {
    3627         152 :                                 for (i = 0; i < num_pads; i++) {
    3628         107 :                                         ZEND_HASH_FILL_ADD(pad_value);
    3629             :                                 }
    3630          45 :                         } ZEND_HASH_FILL_END();
    3631             :                 }
    3632             : 
    3633          91 :                 ZEND_HASH_FILL_PACKED(Z_ARRVAL_P(return_value)) {
    3634         493 :                         ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(input), value) {
    3635         199 :                                 Z_TRY_ADDREF_P(value);
    3636         199 :                                 ZEND_HASH_FILL_ADD(value);
    3637             :                         } ZEND_HASH_FOREACH_END();
    3638          91 :                 } ZEND_HASH_FILL_END();
    3639             : 
    3640          91 :                 if (pad_size > 0) {
    3641          46 :                         ZEND_HASH_FILL_PACKED(Z_ARRVAL_P(return_value)) {
    3642         156 :                                 for (i = 0; i < num_pads; i++) {
    3643         110 :                                         ZEND_HASH_FILL_ADD(pad_value);
    3644             :                                 }
    3645          46 :                         } ZEND_HASH_FILL_END();
    3646             :                 }
    3647             :         } else {
    3648          24 :                 if (pad_size < 0) {
    3649          46 :                         for (i = 0; i < num_pads; i++) {
    3650          34 :                                 zend_hash_next_index_insert_new(Z_ARRVAL_P(return_value), pad_value);
    3651             :                         }
    3652             :                 }
    3653             : 
    3654         222 :                 ZEND_HASH_FOREACH_STR_KEY_VAL_IND(Z_ARRVAL_P(input), key, value) {
    3655          66 :                         Z_TRY_ADDREF_P(value);
    3656          66 :                         if (key) {
    3657          44 :                                 zend_hash_add_new(Z_ARRVAL_P(return_value), key, value);
    3658             :                         } else {
    3659          22 :                                 zend_hash_next_index_insert_new(Z_ARRVAL_P(return_value), value);
    3660             :                         }
    3661             :                 } ZEND_HASH_FOREACH_END();
    3662             : 
    3663          24 :                 if (pad_size > 0) {
    3664          46 :                         for (i = 0; i < num_pads; i++) {
    3665          34 :                                 zend_hash_next_index_insert_new(Z_ARRVAL_P(return_value), pad_value);
    3666             :                         }
    3667             :                 }
    3668             :         }
    3669             : }
    3670             : /* }}} */
    3671             : 
    3672             : /* {{{ proto array array_flip(array input)
    3673             :    Return array with key <-> value flipped */
    3674          69 : PHP_FUNCTION(array_flip)
    3675             : {
    3676             :         zval *array, *entry, data;
    3677             :         zend_ulong num_idx;
    3678             :         zend_string *str_idx;
    3679             : 
    3680          69 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "a", &array) == FAILURE) {
    3681          25 :                 return;
    3682             :         }
    3683             : 
    3684          44 :         array_init_size(return_value, zend_hash_num_elements(Z_ARRVAL_P(array)));
    3685             : 
    3686         402 :         ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(array), num_idx, str_idx, entry) {
    3687         177 :                 ZVAL_DEREF(entry);
    3688         177 :                 if (Z_TYPE_P(entry) == IS_LONG) {
    3689          80 :                         if (str_idx) {
    3690          17 :                                 ZVAL_STR_COPY(&data, str_idx);
    3691             :                         } else {
    3692          63 :                                 ZVAL_LONG(&data, num_idx);
    3693             :                         }
    3694          80 :                         zend_hash_index_update(Z_ARRVAL_P(return_value), Z_LVAL_P(entry), &data);
    3695          97 :                 } else if (Z_TYPE_P(entry) == IS_STRING) {
    3696          82 :                         if (str_idx) {
    3697          35 :                                 ZVAL_STR_COPY(&data, str_idx);
    3698             :                         } else {
    3699          47 :                                 ZVAL_LONG(&data, num_idx);
    3700             :                         }
    3701          82 :                         zend_symtable_update(Z_ARRVAL_P(return_value), Z_STR_P(entry), &data);
    3702             :                 } else {
    3703          15 :                         php_error_docref(NULL, E_WARNING, "Can only flip STRING and INTEGER values!");
    3704             :                 }
    3705             :         } ZEND_HASH_FOREACH_END();
    3706             : }
    3707             : /* }}} */
    3708             : 
    3709             : /* {{{ proto array array_change_key_case(array input [, int case=CASE_LOWER])
    3710             :    Retuns an array with all string keys lowercased [or uppercased] */
    3711         200 : PHP_FUNCTION(array_change_key_case)
    3712             : {
    3713             :         zval *array, *entry;
    3714             :         zend_string *string_key;
    3715             :         zend_string *new_key;
    3716             :         zend_ulong num_key;
    3717         200 :         zend_long change_to_upper=0;
    3718             : 
    3719         200 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "a|l", &array, &change_to_upper) == FAILURE) {
    3720          36 :                 return;
    3721             :         }
    3722             : 
    3723         164 :         array_init_size(return_value, zend_hash_num_elements(Z_ARRVAL_P(array)));
    3724             : 
    3725         970 :         ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(array), num_key, string_key, entry) {
    3726         403 :                 if (!string_key) {
    3727          64 :                         entry = zend_hash_index_update(Z_ARRVAL_P(return_value), num_key, entry);
    3728             :                 } else {
    3729         339 :                         if (change_to_upper) {
    3730         166 :                                 new_key = php_string_toupper(string_key);
    3731             :                         } else {
    3732         173 :                                 new_key = php_string_tolower(string_key);
    3733             :                         }
    3734         339 :                         entry = zend_hash_update(Z_ARRVAL_P(return_value), new_key, entry);
    3735             :                         zend_string_release(new_key);
    3736             :                 }
    3737             : 
    3738         403 :                 zval_add_ref(entry);
    3739             :         } ZEND_HASH_FOREACH_END();
    3740             : }
    3741             : /* }}} */
    3742             : 
    3743             : struct bucketindex {
    3744             :         Bucket b;
    3745             :         unsigned int i;
    3746             : };
    3747             : 
    3748       75000 : static void array_bucketindex_swap(void *p, void *q) /* {{{ */
    3749             : {
    3750       75000 :         struct bucketindex *f = (struct bucketindex *)p;
    3751       75000 :         struct bucketindex *g = (struct bucketindex *)q;
    3752             :         struct bucketindex t;
    3753       75000 :         t = *f;
    3754       75000 :         *f = *g;
    3755       75000 :         *g = t;
    3756       75000 : }
    3757             : /* }}} */
    3758             : 
    3759             : /* {{{ proto array array_unique(array input [, int sort_flags])
    3760             :    Removes duplicate values from array */
    3761          72 : PHP_FUNCTION(array_unique)
    3762             : {
    3763             :         zval *array;
    3764             :         uint idx;
    3765             :         Bucket *p;
    3766             :         struct bucketindex *arTmp, *cmpdata, *lastkept;
    3767             :         unsigned int i;
    3768          72 :         zend_long sort_type = PHP_SORT_STRING;
    3769             :         compare_func_t cmp;
    3770             : 
    3771          72 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "a|l", &array, &sort_type) == FAILURE) {
    3772          27 :                 return;
    3773             :         }
    3774             : 
    3775          45 :         cmp = php_get_data_compare_func(sort_type, 0);
    3776             : 
    3777             : 
    3778          45 :         if (Z_ARRVAL_P(array)->nNumOfElements <= 1) {     /* nothing to do */
    3779           2 :                 ZVAL_COPY(return_value, array);
    3780           2 :                 return;
    3781             :         }
    3782             : 
    3783          43 :         RETVAL_ARR(zend_array_dup(Z_ARRVAL_P(array)));
    3784             : 
    3785             :         /* create and sort array with pointers to the target_hash buckets */
    3786          43 :         arTmp = (struct bucketindex *) pemalloc((Z_ARRVAL_P(array)->nNumOfElements + 1) * sizeof(struct bucketindex), Z_ARRVAL_P(array)->u.flags & HASH_FLAG_PERSISTENT);
    3787          43 :         if (!arTmp) {
    3788             :                 zval_dtor(return_value);
    3789           0 :                 RETURN_FALSE;
    3790             :         }
    3791       15337 :         for (i = 0, idx = 0; idx < Z_ARRVAL_P(array)->nNumUsed; idx++) {
    3792       15294 :                 p = Z_ARRVAL_P(array)->arData + idx;
    3793       30588 :                 if (Z_TYPE(p->val) == IS_UNDEF) continue;
    3794       30574 :                 if (Z_TYPE(p->val) == IS_INDIRECT && Z_TYPE_P(Z_INDIRECT(p->val)) == IS_UNDEF) continue;
    3795       15286 :                 arTmp[i].b = *p;
    3796       15286 :                 arTmp[i].i = i;
    3797       15286 :                 i++;
    3798             :         }
    3799          43 :         ZVAL_UNDEF(&arTmp[i].b.val);
    3800          43 :         zend_sort((void *) arTmp, i, sizeof(struct bucketindex),
    3801             :                         cmp, (swap_func_t)array_bucketindex_swap);
    3802             :         /* go through the sorted array and delete duplicates from the copy */
    3803          43 :         lastkept = arTmp;
    3804       30572 :         for (cmpdata = arTmp + 1; Z_TYPE(cmpdata->b.val) != IS_UNDEF; cmpdata++) {
    3805       15243 :                 if (cmp(lastkept, cmpdata)) {
    3806       15142 :                         lastkept = cmpdata;
    3807             :                 } else {
    3808         101 :                         if (lastkept->i > cmpdata->i) {
    3809          10 :                                 p = &lastkept->b;
    3810          10 :                                 lastkept = cmpdata;
    3811             :                         } else {
    3812          91 :                                 p = &cmpdata->b;
    3813             :                         }
    3814         101 :                         if (p->key == NULL) {
    3815          85 :                                 zend_hash_index_del(Z_ARRVAL_P(return_value), p->h);
    3816             :                         } else {
    3817          16 :                                 if (Z_ARRVAL_P(return_value) == &EG(symbol_table)) {
    3818           0 :                                         zend_delete_global_variable(p->key);
    3819             :                                 } else {
    3820          16 :                                         zend_hash_del(Z_ARRVAL_P(return_value), p->key);
    3821             :                                 }
    3822             :                         }
    3823             :                 }
    3824             :         }
    3825          43 :         pefree(arTmp, Z_ARRVAL_P(array)->u.flags & HASH_FLAG_PERSISTENT);
    3826             : }
    3827             : /* }}} */
    3828             : 
    3829        1110 : static int zval_compare(zval *first, zval *second) /* {{{ */
    3830             : {
    3831        1110 :         return string_compare_function(first, second);
    3832             : }
    3833             : /* }}} */
    3834             : 
    3835          44 : static int zval_user_compare(zval *a, zval *b) /* {{{ */
    3836             : {
    3837             :         zval args[2];
    3838             :         zval retval;
    3839             : 
    3840          44 :         ZVAL_COPY_VALUE(&args[0], a);
    3841          44 :         ZVAL_COPY_VALUE(&args[1], b);
    3842             : 
    3843          44 :         BG(user_compare_fci).param_count = 2;
    3844          44 :         BG(user_compare_fci).params = args;
    3845          44 :         BG(user_compare_fci).retval = &retval;
    3846          44 :         BG(user_compare_fci).no_separation = 0;
    3847             : 
    3848          88 :         if (zend_call_function(&BG(user_compare_fci), &BG(user_compare_fci_cache)) == SUCCESS && Z_TYPE(retval) != IS_UNDEF) {
    3849          42 :                 zend_long ret = zval_get_long(&retval);
    3850          42 :                 zval_ptr_dtor(&retval);
    3851          42 :                 return ret < 0 ? -1 : ret > 0 ? 1 : 0;;
    3852             :         } else {
    3853           2 :                 return 0;
    3854             :         }
    3855             : }
    3856             : /* }}} */
    3857             : 
    3858         572 : static void php_array_intersect_key(INTERNAL_FUNCTION_PARAMETERS, int data_compare_type) /* {{{ */
    3859             : {
    3860             :     uint idx;
    3861             :         Bucket *p;
    3862             :         int argc, i;
    3863             :         zval *args;
    3864         572 :         int (*intersect_data_compare_func)(zval *, zval *) = NULL;
    3865             :         zend_bool ok;
    3866             :         zval *val, *data;
    3867             :         int req_args;
    3868             :         char *param_spec;
    3869             : 
    3870             :         /* Get the argument count */
    3871         572 :         argc = ZEND_NUM_ARGS();
    3872         572 :         if (data_compare_type == INTERSECT_COMP_DATA_USER) {
    3873             :                 /* INTERSECT_COMP_DATA_USER - array_uintersect_assoc() */
    3874         112 :                 req_args = 3;
    3875         112 :                 param_spec = "+f";
    3876         112 :                 intersect_data_compare_func = zval_user_compare;
    3877             :         } else {
    3878             :                 /*      INTERSECT_COMP_DATA_NONE - array_intersect_key()
    3879             :                         INTERSECT_COMP_DATA_INTERNAL - array_intersect_assoc() */
    3880         460 :                 req_args = 2;
    3881         460 :                 param_spec = "+";
    3882             : 
    3883         460 :                 if (data_compare_type == INTERSECT_COMP_DATA_INTERNAL) {
    3884         279 :                         intersect_data_compare_func = zval_compare;
    3885             :                 }
    3886             :         }
    3887             : 
    3888         572 :         if (argc < req_args) {
    3889           5 :                 php_error_docref(NULL, E_WARNING, "at least %d parameters are required, %d given", req_args, argc);
    3890           5 :                 return;
    3891             :         }
    3892             : 
    3893         567 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), param_spec, &args, &argc, &BG(user_compare_fci), &BG(user_compare_fci_cache)) == FAILURE) {
    3894          30 :                 return;
    3895             :         }
    3896             : 
    3897        1332 :         for (i = 0; i < argc; i++) {
    3898        2192 :                 if (Z_TYPE(args[i]) != IS_ARRAY) {
    3899         301 :                         php_error_docref(NULL, E_WARNING, "Argument #%d is not an array", i + 1);
    3900         301 :                         RETURN_NULL();
    3901             :                 }
    3902             :         }
    3903             : 
    3904         236 :         array_init(return_value);
    3905             : 
    3906        2443 :         for (idx = 0; idx < Z_ARRVAL(args[0])->nNumUsed; idx++) {
    3907        2207 :                 p = Z_ARRVAL(args[0])->arData + idx;
    3908        2207 :                 val = &p->val;
    3909        2207 :                 if (Z_TYPE_P(val) == IS_UNDEF) continue;
    3910        2193 :                 if (UNEXPECTED(Z_TYPE_P(val) == IS_INDIRECT)) {
    3911           0 :                         val = Z_INDIRECT_P(val);
    3912           0 :                         if (Z_TYPE_P(val) == IS_UNDEF) continue;
    3913             :                 }
    3914        2214 :                 if (Z_ISREF_P(val) && Z_REFCOUNT_P(val) == 1) {
    3915          12 :                         ZVAL_UNREF(val);
    3916             :                 }
    3917        2193 :                 if (p->key == NULL) {
    3918        1141 :                         ok = 1;
    3919        1346 :                         for (i = 1; i < argc; i++) {
    3920        1562 :                                 if ((data = zend_hash_index_find(Z_ARRVAL(args[i]), p->h)) == NULL ||
    3921             :                                         (intersect_data_compare_func &&
    3922         354 :                                         intersect_data_compare_func(val, data) != 0)
    3923             :                                 ) {
    3924        1003 :                                         ok = 0;
    3925        1003 :                                         break;
    3926             :                                 }
    3927             :                         }
    3928        1141 :                         if (ok) {
    3929         138 :                                 if (Z_REFCOUNTED_P(val)) {
    3930             :                                         Z_ADDREF_P(val);
    3931             :                                 }
    3932         138 :                                 zend_hash_index_update(Z_ARRVAL_P(return_value), p->h, val);
    3933             :                         }
    3934             :                 } else {
    3935        1052 :                         ok = 1;
    3936        1191 :                         for (i = 1; i < argc; i++) {
    3937        2337 :                                 if ((data = zend_hash_find_ind(Z_ARRVAL(args[i]), p->key)) == NULL ||
    3938             :                                         (intersect_data_compare_func &&
    3939         153 :                                         intersect_data_compare_func(val, data) != 0)
    3940             :                                 ) {
    3941         953 :                                         ok = 0;
    3942         953 :                                         break;
    3943             :                                 }
    3944             :                         }
    3945        1052 :                         if (ok) {
    3946          99 :                                 if (Z_REFCOUNTED_P(val)) {
    3947             :                                         Z_ADDREF_P(val);
    3948             :                                 }
    3949          99 :                                 zend_hash_update(Z_ARRVAL_P(return_value), p->key, val);
    3950             :                         }
    3951             :                 }
    3952             :         }
    3953             : }
    3954             : /* }}} */
    3955             : 
    3956         965 : static void php_array_intersect(INTERNAL_FUNCTION_PARAMETERS, int behavior, int data_compare_type, int key_compare_type) /* {{{ */
    3957             : {
    3958         965 :         zval *args = NULL;
    3959             :         HashTable *hash;
    3960         965 :         int arr_argc, i, c = 0;
    3961             :         uint idx;
    3962             :         Bucket **lists, *list, **ptrs, *p;
    3963             :         uint32_t req_args;
    3964             :         char *param_spec;
    3965             :         zend_fcall_info fci1, fci2;
    3966         965 :         zend_fcall_info_cache fci1_cache = empty_fcall_info_cache, fci2_cache = empty_fcall_info_cache;
    3967         965 :         zend_fcall_info *fci_key = NULL, *fci_data;
    3968         965 :         zend_fcall_info_cache *fci_key_cache = NULL, *fci_data_cache;
    3969             :         PHP_ARRAY_CMP_FUNC_VARS;
    3970             : 
    3971             :         int (*intersect_key_compare_func)(const void *, const void *);
    3972             :         int (*intersect_data_compare_func)(const void *, const void *);
    3973             : 
    3974         965 :         if (behavior == INTERSECT_NORMAL) {
    3975         397 :                 intersect_key_compare_func = php_array_key_compare_string;
    3976             : 
    3977         397 :                 if (data_compare_type == INTERSECT_COMP_DATA_INTERNAL) {
    3978             :                         /* array_intersect() */
    3979         283 :                         req_args = 2;
    3980         283 :                         param_spec = "+";
    3981         283 :                         intersect_data_compare_func = php_array_data_compare_string;
    3982         114 :                 } else if (data_compare_type == INTERSECT_COMP_DATA_USER) {
    3983             :                         /* array_uintersect() */
    3984         114 :                         req_args = 3;
    3985         114 :                         param_spec = "+f";
    3986         114 :                         intersect_data_compare_func = php_array_user_compare;
    3987             :                 } else {
    3988           0 :                         php_error_docref(NULL, E_WARNING, "data_compare_type is %d. This should never happen. Please report as a bug", data_compare_type);
    3989           0 :                         return;
    3990             :                 }
    3991             : 
    3992         397 :                 if (ZEND_NUM_ARGS() < req_args) {
    3993           3 :                         php_error_docref(NULL, E_WARNING, "at least %d parameters are required, %d given", req_args, ZEND_NUM_ARGS());
    3994           3 :                         return;
    3995             :                 }
    3996             : 
    3997         394 :                 if (zend_parse_parameters(ZEND_NUM_ARGS(), param_spec, &args, &arr_argc, &fci1, &fci1_cache) == FAILURE) {
    3998          30 :                         return;
    3999             :                 }
    4000         364 :                 fci_data = &fci1;
    4001         364 :                 fci_data_cache = &fci1_cache;
    4002             : 
    4003         568 :         } else if (behavior & INTERSECT_ASSOC) { /* triggered also when INTERSECT_KEY */
    4004             :                 /* INTERSECT_KEY is subset of INTERSECT_ASSOC. When having the former
    4005             :                  * no comparison of the data is done (part of INTERSECT_ASSOC) */
    4006         568 :                 intersect_key_compare_func = php_array_key_compare_string;
    4007             : 
    4008         568 :                 if (data_compare_type == INTERSECT_COMP_DATA_INTERNAL && key_compare_type == INTERSECT_COMP_KEY_INTERNAL) {
    4009             :                         /* array_intersect_assoc() or array_intersect_key() */
    4010           0 :                         req_args = 2;
    4011           0 :                         param_spec = "+";
    4012           0 :                         intersect_key_compare_func = php_array_key_compare_string;
    4013           0 :                         intersect_data_compare_func = php_array_data_compare_string;
    4014         568 :                 } else if (data_compare_type == INTERSECT_COMP_DATA_USER && key_compare_type == INTERSECT_COMP_KEY_INTERNAL) {
    4015             :                         /* array_uintersect_assoc() */
    4016           0 :                         req_args = 3;
    4017           0 :                         param_spec = "+f";
    4018           0 :                         intersect_key_compare_func = php_array_key_compare_string;
    4019           0 :                         intersect_data_compare_func = php_array_user_compare;
    4020           0 :                         fci_data = &fci1;
    4021           0 :                         fci_data_cache = &fci1_cache;
    4022         995 :                 } else if (data_compare_type == INTERSECT_COMP_DATA_INTERNAL && key_compare_type == INTERSECT_COMP_KEY_USER) {
    4023             :                         /* array_intersect_uassoc() or array_intersect_ukey() */
    4024         427 :                         req_args = 3;
    4025         427 :                         param_spec = "+f";
    4026         427 :                         intersect_key_compare_func = php_array_user_key_compare;
    4027         427 :                         intersect_data_compare_func = php_array_data_compare_string;
    4028         427 :                         fci_key = &fci1;
    4029         427 :                         fci_key_cache = &fci1_cache;
    4030         282 :                 } else if (data_compare_type == INTERSECT_COMP_DATA_USER && key_compare_type == INTERSECT_COMP_KEY_USER) {
    4031             :                         /* array_uintersect_uassoc() */
    4032         141 :                         req_args = 4;
    4033         141 :                         param_spec = "+ff";
    4034         141 :                         intersect_key_compare_func = php_array_user_key_compare;
    4035         141 :                         intersect_data_compare_func = php_array_user_compare;
    4036         141 :                         fci_data = &fci1;
    4037         141 :                         fci_data_cache = &fci1_cache;
    4038         141 :                         fci_key = &fci2;
    4039         141 :                         fci_key_cache = &fci2_cache;
    4040             :                 } else {
    4041           0 :                         php_error_docref(NULL, E_WARNING, "data_compare_type is %d. key_compare_type is %d. This should never happen. Please report as a bug", data_compare_type, key_compare_type);
    4042           0 :                         return;
    4043             :                 }
    4044             : 
    4045         568 :                 if (ZEND_NUM_ARGS() < req_args) {
    4046           5 :                         php_error_docref(NULL, E_WARNING, "at least %d parameters are required, %d given", req_args, ZEND_NUM_ARGS());
    4047           5 :                         return;
    4048             :                 }
    4049             : 
    4050         563 :                 if (zend_parse_parameters(ZEND_NUM_ARGS(), param_spec, &args, &arr_argc, &fci1, &fci1_cache, &fci2, &fci2_cache) == FAILURE) {
    4051         160 :                         return;
    4052             :                 }
    4053             : 
    4054             :         } else {
    4055           0 :                 php_error_docref(NULL, E_WARNING, "behavior is %d. This should never happen. Please report as a bug", behavior);
    4056           0 :                 return;
    4057             :         }
    4058             : 
    4059         767 :         PHP_ARRAY_CMP_FUNC_BACKUP();
    4060             : 
    4061             :         /* for each argument, create and sort list with pointers to the hash buckets */
    4062         767 :         lists = (Bucket **)safe_emalloc(arr_argc, sizeof(Bucket *), 0);
    4063         767 :         ptrs = (Bucket **)safe_emalloc(arr_argc, sizeof(Bucket *), 0);
    4064             : 
    4065         850 :         if (behavior == INTERSECT_NORMAL && data_compare_type == INTERSECT_COMP_DATA_USER) {
    4066          83 :                 BG(user_compare_fci) = *fci_data;
    4067          83 :                 BG(user_compare_fci_cache) = *fci_data_cache;
    4068         684 :         } else if (behavior & INTERSECT_ASSOC && key_compare_type == INTERSECT_COMP_KEY_USER) {
    4069         403 :                 BG(user_compare_fci) = *fci_key;
    4070         403 :                 BG(user_compare_fci_cache) = *fci_key_cache;
    4071             :         }
    4072             : 
    4073        1795 :         for (i = 0; i < arr_argc; i++) {
    4074        3120 :                 if (Z_TYPE(args[i]) != IS_ARRAY) {
    4075         532 :                         php_error_docref(NULL, E_WARNING, "Argument #%d is not an array", i + 1);
    4076         532 :                         arr_argc = i; /* only free up to i - 1 */
    4077         532 :                         goto out;
    4078             :                 }
    4079        1028 :                 hash = Z_ARRVAL(args[i]);
    4080        1028 :                 list = (Bucket *) pemalloc((hash->nNumOfElements + 1) * sizeof(Bucket), hash->u.flags & HASH_FLAG_PERSISTENT);
    4081        1028 :                 if (!list) {
    4082           0 :                         PHP_ARRAY_CMP_FUNC_RESTORE();
    4083             : 
    4084           0 :                         efree(ptrs);
    4085           0 :                         efree(lists);
    4086           0 :                         RETURN_FALSE;
    4087             :                 }
    4088        1028 :                 lists[i] = list;
    4089        1028 :                 ptrs[i] = list;
    4090        6593 :                 for (idx = 0; idx < hash->nNumUsed; idx++) {
    4091        5565 :                         p = hash->arData + idx;
    4092       11130 :                         if (Z_TYPE(p->val) == IS_UNDEF) continue;
    4093        5530 :                         *list++ = *p;
    4094             :                 }
    4095        1028 :                 ZVAL_UNDEF(&list->val);
    4096        1028 :                 if (hash->nNumOfElements > 1) {
    4097         967 :                         if (behavior == INTERSECT_NORMAL) {
    4098         546 :                                 zend_sort((void *) lists[i], hash->nNumOfElements, 
    4099             :                                                 sizeof(Bucket), intersect_data_compare_func, (swap_func_t)zend_hash_bucket_swap);
    4100         421 :                         } else if (behavior & INTERSECT_ASSOC) { /* triggered also when INTERSECT_KEY */
    4101         421 :                                 zend_sort((void *) lists[i], hash->nNumOfElements,
    4102             :                                                 sizeof(Bucket), intersect_key_compare_func, (swap_func_t)zend_hash_bucket_swap);
    4103             :                         }
    4104             :                 }
    4105             :         }
    4106             : 
    4107             :         /* copy the argument array */
    4108         235 :         RETVAL_ARR(zend_array_dup(Z_ARRVAL(args[0])));
    4109             : 
    4110             :         /* go through the lists and look for common values */
    4111        1741 :         while (Z_TYPE(ptrs[0]->val) != IS_UNDEF) {
    4112         747 :                 if ((behavior & INTERSECT_ASSOC) /* triggered also when INTERSECT_KEY */
    4113             :                         && key_compare_type == INTERSECT_COMP_KEY_USER) {
    4114         148 :                         BG(user_compare_fci) = *fci_key;
    4115         148 :                         BG(user_compare_fci_cache) = *fci_key_cache;
    4116             :                 }
    4117             : 
    4118        1252 :                 for (i = 1; i < arr_argc; i++) {
    4119         906 :                         if (behavior & INTERSECT_NORMAL) {
    4120        3970 :                                 while (Z_TYPE(ptrs[i]->val) != IS_UNDEF && (0 < (c = intersect_data_compare_func(ptrs[0], ptrs[i])))) {
    4121         872 :                                         ptrs[i]++;
    4122             :                                 }
    4123         164 :                         } else if (behavior & INTERSECT_ASSOC) { /* triggered also when INTERSECT_KEY */
    4124         636 :                                 while (Z_TYPE(ptrs[i]->val) != IS_UNDEF && (0 < (c = intersect_key_compare_func(ptrs[0], ptrs[i])))) {
    4125          72 :                                         ptrs[i]++;
    4126             :                                 }
    4127         267 :                                 if ((!c && Z_TYPE(ptrs[i]->val) != IS_UNDEF) && (behavior == INTERSECT_ASSOC)) { /* only when INTERSECT_ASSOC */
    4128             :                                         /* this means that ptrs[i] is not NULL so we can compare
    4129             :                                          * and "c==0" is from last operation
    4130             :                                          * in this branch of code we enter only when INTERSECT_ASSOC
    4131             :                                          * since when we have INTERSECT_KEY compare of data is not wanted. */
    4132          41 :                                         if (data_compare_type == INTERSECT_COMP_DATA_USER) {
    4133          13 :                                                 BG(user_compare_fci) = *fci_data;
    4134          13 :                                                 BG(user_compare_fci_cache) = *fci_data_cache;
    4135             :                                         }
    4136          41 :                                         if (intersect_data_compare_func(ptrs[0], ptrs[i]) != 0) {
    4137          19 :                                                 c = 1;
    4138          19 :                                                 if (key_compare_type == INTERSECT_COMP_KEY_USER) {
    4139          19 :                                                         BG(user_compare_fci) = *fci_key;
    4140          19 :                                                         BG(user_compare_fci_cache) = *fci_key_cache;
    4141             :                                                         /* When KEY_USER, the last parameter is always the callback */
    4142             :                                                 }
    4143             :                                                 /* we are going to the break */
    4144             :                                         } else {
    4145             :                                                 /* continue looping */
    4146             :                                         }
    4147             :                                 }
    4148             :                         }
    4149        1812 :                         if (Z_TYPE(ptrs[i]->val) == IS_UNDEF) {
    4150             :                                 /* delete any values corresponding to remains of ptrs[0] */
    4151             :                                 /* and exit because they do not present in at least one of */
    4152             :                                 /* the other arguments */
    4153             :                                 for (;;) {
    4154         694 :                                         p = ptrs[0]++;
    4155        1388 :                                         if (Z_TYPE(p->val) == IS_UNDEF) {
    4156         107 :                                                 goto out;
    4157             :                                         }
    4158         587 :                                         if (p->key == NULL) {
    4159         520 :                                                 zend_hash_index_del(Z_ARRVAL_P(return_value), p->h);
    4160             :                                         } else {
    4161          67 :                                                 zend_hash_del(Z_ARRVAL_P(return_value), p->key);
    4162             :                                         }
    4163         587 :                                 }
    4164             :                         }
    4165         799 :                         if (c) /* here we get if not all are equal */
    4166         294 :                                 break;
    4167         505 :                         ptrs[i]++;
    4168             :                 }
    4169         640 :                 if (c) {
    4170             :                         /* Value of ptrs[0] not in all arguments, delete all entries */
    4171             :                         /* with value < value of ptrs[i] */
    4172             :                         for (;;) {
    4173         678 :                                 p = ptrs[0];
    4174         678 :                                 if (p->key == NULL) {
    4175         564 :                                         zend_hash_index_del(Z_ARRVAL_P(return_value), p->h);
    4176             :                                 } else {
    4177         114 :                                         zend_hash_del(Z_ARRVAL_P(return_value), p->key);
    4178             :                                 }
    4179        1356 :                                 if (Z_TYPE((++ptrs[0])->val) == IS_UNDEF) {
    4180          54 :                                         goto out;
    4181             :                                 }
    4182         624 :                                 if (behavior == INTERSECT_NORMAL) {
    4183         567 :                                         if (0 <= intersect_data_compare_func(ptrs[0], ptrs[i])) {
    4184         183 :                                                 break;
    4185             :                                         }
    4186          57 :                                 } else if (behavior & INTERSECT_ASSOC) { /* triggered also when INTERSECT_KEY */
    4187             :                                         /* no need of looping because indexes are unique */
    4188          57 :                                         break;
    4189             :                                 }
    4190         384 :                         }
    4191             :                 } else {
    4192             :                         /* ptrs[0] is present in all the arguments */
    4193             :                         /* Skip all entries with same value as ptrs[0] */
    4194             :                         for (;;) {
    4195         808 :                                 if (Z_TYPE((++ptrs[0])->val) == IS_UNDEF) {
    4196          68 :                                         goto out;
    4197             :                                 }
    4198         336 :                                 if (behavior == INTERSECT_NORMAL) {
    4199         287 :                                         if (intersect_data_compare_func(ptrs[0] - 1, ptrs[0])) {
    4200         229 :                                                 break;
    4201             :                                         }
    4202          49 :                                 } else if (behavior & INTERSECT_ASSOC) { /* triggered also when INTERSECT_KEY */
    4203             :                                         /* no need of looping because indexes are unique */
    4204          49 :                                         break;
    4205             :                                 }
    4206          58 :                         }
    4207             :                 }
    4208             :         }
    4209             : out:
    4210        1795 :         for (i = 0; i < arr_argc; i++) {
    4211        1028 :                 hash = Z_ARRVAL(args[i]);
    4212        1028 :                 pefree(lists[i], hash->u.flags & HASH_FLAG_PERSISTENT);
    4213             :         }
    4214             : 
    4215         767 :         PHP_ARRAY_CMP_FUNC_RESTORE();
    4216             : 
    4217         767 :         efree(ptrs);
    4218         767 :         efree(lists);
    4219             : }
    4220             : /* }}} */
    4221             : 
    4222             : /* {{{ proto array array_intersect_key(array arr1, array arr2 [, array ...])
    4223             :    Returns the entries of arr1 that have keys which are present in all the other arguments. Kind of equivalent to array_diff(array_keys($arr1), array_keys($arr2)[,array_keys(...)]). Equivalent of array_intersect_assoc() but does not do compare of the data. */
    4224         181 : PHP_FUNCTION(array_intersect_key)
    4225             : {
    4226         181 :         php_array_intersect_key(INTERNAL_FUNCTION_PARAM_PASSTHRU, INTERSECT_COMP_DATA_NONE);
    4227         181 : }
    4228             : /* }}} */
    4229             : 
    4230             : /* {{{ proto array array_intersect_ukey(array arr1, array arr2 [, array ...], callback key_compare_func)
    4231             :    Returns the entries of arr1 that have keys which are present in all the other arguments. Kind of equivalent to array_diff(array_keys($arr1), array_keys($arr2)[,array_keys(...)]). The comparison of the keys is performed by a user supplied function. Equivalent of array_intersect_uassoc() but does not do compare of the data. */
    4232         233 : PHP_FUNCTION(array_intersect_ukey)
    4233             : {
    4234         233 :         php_array_intersect(INTERNAL_FUNCTION_PARAM_PASSTHRU, INTERSECT_KEY, INTERSECT_COMP_DATA_INTERNAL, INTERSECT_COMP_KEY_USER);
    4235         233 : }
    4236             : /* }}} */
    4237             : 
    4238             : /* {{{ proto array array_intersect(array arr1, array arr2 [, array ...])
    4239             :    Returns the entries of arr1 that have values which are present in all the other arguments */
    4240         283 : PHP_FUNCTION(array_intersect)
    4241             : {
    4242         283 :         php_array_intersect(INTERNAL_FUNCTION_PARAM_PASSTHRU, INTERSECT_NORMAL, INTERSECT_COMP_DATA_INTERNAL, INTERSECT_COMP_KEY_INTERNAL);
    4243         283 : }
    4244             : /* }}} */
    4245             : 
    4246             : /* {{{ proto array array_uintersect(array arr1, array arr2 [, array ...], callback data_compare_func)
    4247             :    Returns the entries of arr1 that have values which are present in all the other arguments. Data is compared by using a user-supplied callback. */
    4248         114 : PHP_FUNCTION(array_uintersect)
    4249             : {
    4250         114 :         php_array_intersect(INTERNAL_FUNCTION_PARAM_PASSTHRU, INTERSECT_NORMAL, INTERSECT_COMP_DATA_USER, INTERSECT_COMP_KEY_INTERNAL);
    4251         114 : }
    4252             : /* }}} */
    4253             : 
    4254             : /* {{{ proto array array_intersect_assoc(array arr1, array arr2 [, array ...])
    4255             :    Returns the entries of arr1 that have values which are present in all the other arguments. Keys are used to do more restrictive check */
    4256         279 : PHP_FUNCTION(array_intersect_assoc)
    4257             : {
    4258         279 :         php_array_intersect_key(INTERNAL_FUNCTION_PARAM_PASSTHRU, INTERSECT_COMP_DATA_INTERNAL);
    4259         279 : }
    4260             : /* }}} */
    4261             : 
    4262             : /* {{{ proto array array_intersect_uassoc(array arr1, array arr2 [, array ...], callback key_compare_func) U
    4263             :    Returns the entries of arr1 that have values which are present in all the other arguments. Keys are used to do more restrictive check and they are compared by using a user-supplied callback. */
    4264         194 : PHP_FUNCTION(array_intersect_uassoc)
    4265             : {
    4266         194 :         php_array_intersect(INTERNAL_FUNCTION_PARAM_PASSTHRU, INTERSECT_ASSOC, INTERSECT_COMP_DATA_INTERNAL, INTERSECT_COMP_KEY_USER);
    4267         194 : }
    4268             : /* }}} */
    4269             : 
    4270             : /* {{{ proto array array_uintersect_assoc(array arr1, array arr2 [, array ...], callback data_compare_func) U
    4271             :    Returns the entries of arr1 that have values which are present in all the other arguments. Keys are used to do more restrictive check. Data is compared by using a user-supplied callback. */
    4272         112 : PHP_FUNCTION(array_uintersect_assoc)
    4273             : {
    4274         112 :         php_array_intersect_key(INTERNAL_FUNCTION_PARAM_PASSTHRU, INTERSECT_COMP_DATA_USER);
    4275         112 : }
    4276             : /* }}} */
    4277             : 
    4278             : /* {{{ proto array array_uintersect_uassoc(array arr1, array arr2 [, array ...], callback data_compare_func, callback key_compare_func)
    4279             :    Returns the entries of arr1 that have values which are present in all the other arguments. Keys are used to do more restrictive check. Both data and keys are compared by using user-supplied callbacks. */
    4280         141 : PHP_FUNCTION(array_uintersect_uassoc)
    4281             : {
    4282         141 :         php_array_intersect(INTERNAL_FUNCTION_PARAM_PASSTHRU, INTERSECT_ASSOC, INTERSECT_COMP_DATA_USER, INTERSECT_COMP_KEY_USER);
    4283         141 : }
    4284             : /* }}} */
    4285             : 
    4286         421 : static void php_array_diff_key(INTERNAL_FUNCTION_PARAMETERS, int data_compare_type) /* {{{ */
    4287             : {
    4288             :     uint idx;
    4289             :         Bucket *p;
    4290             :         int argc, i;
    4291             :         zval *args;
    4292         421 :         int (*diff_data_compare_func)(zval *, zval *) = NULL;
    4293             :         zend_bool ok;
    4294             :         zval *val, *data;
    4295             : 
    4296             :         /* Get the argument count */
    4297         421 :         argc = ZEND_NUM_ARGS();
    4298         421 :         if (data_compare_type == DIFF_COMP_DATA_USER) {
    4299         114 :                 if (argc < 3) {
    4300           1 :                         php_error_docref(NULL, E_WARNING, "at least 3 parameters are required, %d given", ZEND_NUM_ARGS());
    4301           1 :                         return;
    4302             :                 }
    4303         113 :                 if (zend_parse_parameters(ZEND_NUM_ARGS(), "+f", &args, &argc, &BG(user_compare_fci), &BG(user_compare_fci_cache)) == FAILURE) {
    4304          30 :                         return;
    4305             :                 }
    4306          83 :                 diff_data_compare_func = zval_user_compare;
    4307             :         } else {
    4308         307 :                 if (argc < 2) {
    4309           4 :                         php_error_docref(NULL, E_WARNING, "at least 2 parameters are required, %d given", ZEND_NUM_ARGS());
    4310           4 :                         return;
    4311             :                 }
    4312         303 :                 if (zend_parse_parameters(ZEND_NUM_ARGS(), "+", &args, &argc) == FAILURE) {
    4313           0 :                         return;
    4314             :                 }
    4315         303 :                 if (data_compare_type == DIFF_COMP_DATA_INTERNAL) {
    4316         141 :                         diff_data_compare_func = zval_compare;
    4317             :                 }
    4318             :         }
    4319             : 
    4320         862 :         for (i = 0; i < argc; i++) {
    4321        1466 :                 if (Z_TYPE(args[i]) != IS_ARRAY) {
    4322         257 :                         php_error_docref(NULL, E_WARNING, "Argument #%d is not an array", i + 1);
    4323         257 :                         RETURN_NULL();
    4324             :                 }
    4325             :         }
    4326             : 
    4327         129 :         array_init(return_value);
    4328             : 
    4329        1001 :         for (idx = 0; idx < Z_ARRVAL(args[0])->nNumUsed; idx++) {
    4330         872 :                 p = Z_ARRVAL(args[0])->arData + idx;
    4331         872 :                 val = &p->val;
    4332         872 :                 if (Z_TYPE_P(val) == IS_UNDEF) continue;
    4333         868 :                 if (UNEXPECTED(Z_TYPE_P(val) == IS_INDIRECT)) {
    4334           2 :                         val = Z_INDIRECT_P(val);
    4335           2 :                         if (Z_TYPE_P(val) == IS_UNDEF) continue;
    4336             :                 }
    4337         891 :                 if (Z_ISREF_P(val) && Z_REFCOUNT_P(val) == 1) {
    4338          12 :                         ZVAL_UNREF(val);
    4339             :                 }
    4340         868 :                 if (p->key == NULL) {
    4341         740 :                         ok = 1;
    4342        1362 :                         for (i = 1; i < argc; i++) {
    4343        1375 :                                 if ((data = zend_hash_index_find(Z_ARRVAL(args[i]), p->h)) != NULL &&
    4344             :                                         (!diff_data_compare_func ||
    4345         601 :                                         diff_data_compare_func(val, data) == 0)
    4346             :                                 ) {
    4347         152 :                                         ok = 0;
    4348         152 :                                         break;
    4349             :                                 }
    4350             :                         }
    4351         740 :                         if (ok) {
    4352         588 :                                 if (Z_REFCOUNTED_P(val)) {
    4353             :                                         Z_ADDREF_P(val);
    4354             :                                 }
    4355         588 :                                 zend_hash_index_update(Z_ARRVAL_P(return_value), p->h, val);
    4356             :                         }
    4357             :                 } else {
    4358         128 :                         ok = 1;
    4359         218 :                         for (i = 1; i < argc; i++) {
    4360         330 :                                 if ((data = zend_hash_find_ind(Z_ARRVAL(args[i]), p->key)) != NULL &&
    4361             :                                         (!diff_data_compare_func ||
    4362          46 :                                         diff_data_compare_func(val, data) == 0)
    4363             :                                 ) {
    4364          52 :                                         ok = 0;
    4365          52 :                                         break;
    4366             :                                 }
    4367             :                         }
    4368         128 :                         if (ok) {
    4369          76 :                                 if (Z_REFCOUNTED_P(val)) {
    4370             :                                         Z_ADDREF_P(val);
    4371             :                                 }
    4372          76 :                                 zend_hash_update(Z_ARRVAL_P(return_value), p->key, val);
    4373             :                         }
    4374             :                 }
    4375             :         }
    4376             : }
    4377             : /* }}} */
    4378             : 
    4379         608 : static void php_array_diff(INTERNAL_FUNCTION_PARAMETERS, int behavior, int data_compare_type, int key_compare_type) /* {{{ */
    4380             : {
    4381         608 :         zval *args = NULL;
    4382             :         HashTable *hash;
    4383             :         int arr_argc, i, c;
    4384             :         uint idx;
    4385             :         Bucket **lists, *list, **ptrs, *p;
    4386             :         uint32_t req_args;
    4387             :         char *param_spec;
    4388             :         zend_fcall_info fci1, fci2;
    4389         608 :         zend_fcall_info_cache fci1_cache = empty_fcall_info_cache, fci2_cache = empty_fcall_info_cache;
    4390         608 :         zend_fcall_info *fci_key = NULL, *fci_data;
    4391         608 :         zend_fcall_info_cache *fci_key_cache = NULL, *fci_data_cache;
    4392             :         PHP_ARRAY_CMP_FUNC_VARS;
    4393             : 
    4394             :         int (*diff_key_compare_func)(const void *, const void *);
    4395             :         int (*diff_data_compare_func)(const void *, const void *);
    4396             : 
    4397         608 :         if (behavior == DIFF_NORMAL) {
    4398         112 :                 diff_key_compare_func = php_array_key_compare_string;
    4399             : 
    4400         112 :                 if (data_compare_type == DIFF_COMP_DATA_INTERNAL) {
    4401             :                         /* array_diff */
    4402           0 :                         req_args = 2;
    4403           0 :                         param_spec = "+";
    4404           0 :                         diff_data_compare_func = php_array_data_compare_string;
    4405         112 :                 } else if (data_compare_type == DIFF_COMP_DATA_USER) {
    4406             :                         /* array_udiff */
    4407         112 :                         req_args = 3;
    4408         112 :                         param_spec = "+f";
    4409         112 :                         diff_data_compare_func = php_array_user_compare;
    4410             :                 } else {
    4411           0 :                         php_error_docref(NULL, E_WARNING, "data_compare_type is %d. This should never happen. Please report as a bug", data_compare_type);
    4412           0 :                         return;
    4413             :                 }
    4414             : 
    4415         112 :                 if (ZEND_NUM_ARGS() < req_args) {
    4416           1 :                         php_error_docref(NULL, E_WARNING, "at least %d parameters are required, %d given", req_args, ZEND_NUM_ARGS());
    4417           1 :                         return;
    4418             :                 }
    4419             : 
    4420         111 :                 if (zend_parse_parameters(ZEND_NUM_ARGS(), param_spec, &args, &arr_argc, &fci1, &fci1_cache) == FAILURE) {
    4421          30 :                         return;
    4422             :                 }
    4423          81 :                 fci_data = &fci1;
    4424          81 :                 fci_data_cache = &fci1_cache;
    4425             : 
    4426         496 :         } else if (behavior & DIFF_ASSOC) { /* triggered also if DIFF_KEY */
    4427             :                 /* DIFF_KEY is subset of DIFF_ASSOC. When having the former
    4428             :                  * no comparison of the data is done (part of DIFF_ASSOC) */
    4429             : 
    4430         496 :                 if (data_compare_type == DIFF_COMP_DATA_INTERNAL && key_compare_type == DIFF_COMP_KEY_INTERNAL) {
    4431             :                         /* array_diff_assoc() or array_diff_key() */
    4432           0 :                         req_args = 2;
    4433           0 :                         param_spec = "+";
    4434           0 :                         diff_key_compare_func = php_array_key_compare_string;
    4435           0 :                         diff_data_compare_func = php_array_data_compare_string;
    4436         496 :                 } else if (data_compare_type == DIFF_COMP_DATA_USER && key_compare_type == DIFF_COMP_KEY_INTERNAL) {
    4437             :                         /* array_udiff_assoc() */
    4438           0 :                         req_args = 3;
    4439           0 :                         param_spec = "+f";
    4440           0 :                         diff_key_compare_func = php_array_key_compare_string;
    4441           0 :                         diff_data_compare_func = php_array_user_compare;
    4442           0 :                         fci_data = &fci1;
    4443           0 :                         fci_data_cache = &fci1_cache;
    4444         851 :                 } else if (data_compare_type == DIFF_COMP_DATA_INTERNAL && key_compare_type == DIFF_COMP_KEY_USER) {
    4445             :                         /* array_diff_uassoc() or array_diff_ukey() */
    4446         355 :                         req_args = 3;
    4447         355 :                         param_spec = "+f";
    4448         355 :                         diff_key_compare_func = php_array_user_key_compare;
    4449         355 :                         diff_data_compare_func = php_array_data_compare_string;
    4450         355 :                         fci_key = &fci1;
    4451         355 :                         fci_key_cache = &fci1_cache;
    4452         282 :                 } else if (data_compare_type == DIFF_COMP_DATA_USER && key_compare_type == DIFF_COMP_KEY_USER) {
    4453             :                         /* array_udiff_uassoc() */
    4454         141 :                         req_args = 4;
    4455         141 :                         param_spec = "+ff";
    4456         141 :                         diff_key_compare_func = php_array_user_key_compare;
    4457         141 :                         diff_data_compare_func = php_array_user_compare;
    4458         141 :                         fci_data = &fci1;
    4459         141 :                         fci_data_cache = &fci1_cache;
    4460         141 :                         fci_key = &fci2;
    4461         141 :                         fci_key_cache = &fci2_cache;
    4462             :                 } else {
    4463           0 :                         php_error_docref(NULL, E_WARNING, "data_compare_type is %d. key_compare_type is %d. This should never happen. Please report as a bug", data_compare_type, key_compare_type);
    4464           0 :                         return;
    4465             :                 }
    4466             : 
    4467         496 :                 if (ZEND_NUM_ARGS() < req_args) {
    4468           5 :                         php_error_docref(NULL, E_WARNING, "at least %d parameters are required, %d given", req_args, ZEND_NUM_ARGS());
    4469           5 :                         return;
    4470             :                 }
    4471             : 
    4472         491 :                 if (zend_parse_parameters(ZEND_NUM_ARGS(), param_spec, &args, &arr_argc, &fci1, &fci1_cache, &fci2, &fci2_cache) == FAILURE) {
    4473         138 :                         return;
    4474             :                 }
    4475             : 
    4476             :         } else {
    4477           0 :                 php_error_docref(NULL, E_WARNING, "behavior is %d. This should never happen. Please report as a bug", behavior);
    4478           0 :                 return;
    4479             :         }
    4480             : 
    4481         434 :         PHP_ARRAY_CMP_FUNC_BACKUP();
    4482             : 
    4483             :         /* for each argument, create and sort list with pointers to the hash buckets */
    4484         434 :         lists = (Bucket **)safe_emalloc(arr_argc, sizeof(Bucket *), 0);
    4485         434 :         ptrs = (Bucket **)safe_emalloc(arr_argc, sizeof(Bucket *), 0);
    4486             : 
    4487         515 :         if (behavior == DIFF_NORMAL && data_compare_type == DIFF_COMP_DATA_USER) {
    4488          81 :                 BG(user_compare_fci) = *fci_data;
    4489          81 :                 BG(user_compare_fci_cache) = *fci_data_cache;
    4490         353 :         } else if (behavior & DIFF_ASSOC && key_compare_type == DIFF_COMP_KEY_USER) {
    4491         353 :                 BG(user_compare_fci) = *fci_key;
    4492         353 :                 BG(user_compare_fci_cache) = *fci_key_cache;
    4493             :         }
    4494             : 
    4495         923 :         for (i = 0; i < arr_argc; i++) {
    4496        1694 :                 if (Z_TYPE(args[i]) != IS_ARRAY) {
    4497         358 :                         php_error_docref(NULL, E_WARNING, "Argument #%d is not an array", i + 1);
    4498         358 :                         arr_argc = i; /* only free up to i - 1 */
    4499         358 :                         goto out;
    4500             :                 }
    4501         489 :                 hash = Z_ARRVAL(args[i]);
    4502         489 :                 list = (Bucket *) pemalloc((hash->nNumOfElements + 1) * sizeof(Bucket), hash->u.flags & HASH_FLAG_PERSISTENT);
    4503         489 :                 if (!list) {
    4504           0 :                         PHP_ARRAY_CMP_FUNC_RESTORE();
    4505             : 
    4506           0 :                         efree(ptrs);
    4507           0 :                         efree(lists);
    4508           0 :                         RETURN_FALSE;
    4509             :                 }
    4510         489 :                 lists[i] = list;
    4511         489 :                 ptrs[i] = list;
    4512        1981 :                 for (idx = 0; idx < hash->nNumUsed; idx++) {
    4513        1492 :                         p = hash->arData + idx;
    4514        2984 :                         if (Z_TYPE(p->val) == IS_UNDEF) continue;
    4515        1492 :                         *list++ = *p;
    4516             :                 }
    4517         489 :                 ZVAL_UNDEF(&list->val);
    4518         489 :                 if (hash->nNumOfElements > 1) {
    4519         465 :                         if (behavior == DIFF_NORMAL) {
    4520          81 :                                 zend_sort((void *) lists[i], hash->nNumOfElements,
    4521             :                                                 sizeof(Bucket), diff_data_compare_func, (swap_func_t)zend_hash_bucket_swap);
    4522         384 :                         } else if (behavior & DIFF_ASSOC) { /* triggered also when DIFF_KEY */
    4523         384 :                                 zend_sort((void *) lists[i], hash->nNumOfElements,
    4524             :                                                 sizeof(Bucket), diff_key_compare_func, (swap_func_t)zend_hash_bucket_swap);
    4525             :                         }
    4526             :                 }
    4527             :         }
    4528             : 
    4529             :         /* copy the argument array */
    4530          76 :         RETVAL_ARR(zend_array_dup(Z_ARRVAL(args[0])));
    4531             : 
    4532             :         /* go through the lists and look for values of ptr[0] that are not in the others */
    4533         532 :         while (Z_TYPE(ptrs[0]->val) != IS_UNDEF) {
    4534         228 :                 if ((behavior & DIFF_ASSOC) /* triggered also when DIFF_KEY */
    4535             :                         &&
    4536             :                         key_compare_type == DIFF_COMP_KEY_USER
    4537             :                 ) {
    4538         212 :                         BG(user_compare_fci) = *fci_key;
    4539         212 :                         BG(user_compare_fci_cache) = *fci_key_cache;
    4540             :                 }
    4541         228 :                 c = 1;
    4542         364 :                 for (i = 1; i < arr_argc; i++) {
    4543         246 :                         Bucket *ptr = ptrs[i];
    4544         246 :                         if (behavior == DIFF_NORMAL) {
    4545          58 :                                 while (Z_TYPE(ptrs[i]->val) != IS_UNDEF && (0 < (c = diff_data_compare_func(ptrs[0], ptrs[i])))) {
    4546           5 :                                         ptrs[i]++;
    4547             :                                 }
    4548         230 :                         } else if (behavior & DIFF_ASSOC) { /* triggered also when DIFF_KEY */
    4549        1936 :                                 while (Z_TYPE(ptr->val) != IS_UNDEF && (0 != (c = diff_key_compare_func(ptrs[0], ptr)))) {
    4550         623 :                                         ptr++;
    4551             :                                 }
    4552             :                         }
    4553         246 :                         if (!c) {
    4554         135 :                                 if (behavior == DIFF_NORMAL) {
    4555          20 :                                         if (Z_TYPE(ptrs[i]->val) != IS_UNDEF) {
    4556          10 :                                                 ptrs[i]++;
    4557             :                                         }
    4558          10 :                                         break;
    4559         125 :                                 } else if (behavior == DIFF_ASSOC) {  /* only when DIFF_ASSOC */
    4560             :                                         /* In this branch is execute only when DIFF_ASSOC. If behavior == DIFF_KEY
    4561             :                                          * data comparison is not needed - skipped. */
    4562         142 :                                         if (Z_TYPE(ptr->val) != IS_UNDEF) {
    4563          71 :                                                 if (data_compare_type == DIFF_COMP_DATA_USER) {
    4564          13 :                                                         BG(user_compare_fci) = *fci_data;
    4565          13 :                                                         BG(user_compare_fci_cache) = *fci_data_cache;
    4566             :                                                 }
    4567          71 :                                                 if (diff_data_compare_func(ptrs[0], ptr) != 0) {
    4568             :                                                         /* the data is not the same */
    4569          25 :                                                         c = -1;
    4570          25 :                                                         if (key_compare_type == DIFF_COMP_KEY_USER) {
    4571          25 :                                                                 BG(user_compare_fci) = *fci_key;
    4572          25 :                                                                 BG(user_compare_fci_cache) = *fci_key_cache;
    4573             :                                                         }
    4574             :                                                 } else {
    4575          46 :                                                         break;
    4576             :                                                         /* we have found the element in other arrays thus we don't want it
    4577             :                                                          * in the return_value -> delete from there */
    4578             :                                                 }
    4579             :                                         }
    4580          54 :                                 } else if (behavior == DIFF_KEY) { /* only when DIFF_KEY */
    4581             :                                         /* the behavior here differs from INTERSECT_KEY in php_intersect
    4582             :                                          * since in the "diff" case we have to remove the entry from
    4583             :                                          * return_value while when doing intersection the entry must not
    4584             :                                          * be deleted. */
    4585          54 :                                         break; /* remove the key */
    4586             :                                 }
    4587             :                         }
    4588             :                 }
    4589         228 :                 if (!c) {
    4590             :                         /* ptrs[0] in one of the other arguments */
    4591             :                         /* delete all entries with value as ptrs[0] */
    4592             :                         for (;;) {
    4593         110 :                                 p = ptrs[0];
    4594         110 :                                 if (p->key == NULL) {
    4595          86 :                                         zend_hash_index_del(Z_ARRVAL_P(return_value), p->h);
    4596             :                                 } else {
    4597          24 :                                         zend_hash_del(Z_ARRVAL_P(return_value), p->key);
    4598             :                                 }
    4599         220 :                                 if (Z_TYPE((++ptrs[0])->val) == IS_UNDEF) {
    4600          31 :                                         goto out;
    4601             :                                 }
    4602          79 :                                 if (behavior == DIFF_NORMAL) {
    4603           7 :                                         if (diff_data_compare_func(ptrs[0] - 1, ptrs[0])) {
    4604           7 :                                                 break;
    4605             :                                         }
    4606          72 :                                 } else if (behavior & DIFF_ASSOC) { /* triggered also when DIFF_KEY */
    4607             :                                         /* in this case no array_key_compare is needed */
    4608          72 :                                         break;
    4609             :                                 }
    4610           0 :                         }
    4611             :                 } else {
    4612             :                         /* ptrs[0] in none of the other arguments */
    4613             :                         /* skip all entries with value as ptrs[0] */
    4614             :                         for (;;) {
    4615         236 :                                 if (Z_TYPE((++ptrs[0])->val) == IS_UNDEF) {
    4616          45 :                                         goto out;
    4617             :                                 }
    4618          73 :                                 if (behavior == DIFF_NORMAL) {
    4619           3 :                                         if (diff_data_compare_func(ptrs[0] - 1, ptrs[0])) {
    4620           3 :                                                 break;
    4621             :                                         }
    4622          70 :                                 } else if (behavior & DIFF_ASSOC) { /* triggered also when DIFF_KEY */
    4623             :                                         /* in this case no array_key_compare is needed */
    4624          70 :                                         break;
    4625             :                                 }
    4626           0 :                         }
    4627             :                 }
    4628             :         }
    4629             : out:
    4630         923 :         for (i = 0; i < arr_argc; i++) {
    4631         489 :                 hash = Z_ARRVAL(args[i]);
    4632         489 :                 pefree(lists[i], hash->u.flags & HASH_FLAG_PERSISTENT);
    4633             :         }
    4634             : 
    4635         434 :         PHP_ARRAY_CMP_FUNC_RESTORE();
    4636             : 
    4637         434 :         efree(ptrs);
    4638         434 :         efree(lists);
    4639             : }
    4640             : /* }}} */
    4641             : 
    4642             : /* {{{ proto array array_diff_key(array arr1, array arr2 [, array ...])
    4643             :    Returns the entries of arr1 that have keys which are not present in any of the others arguments. This function is like array_diff() but works on the keys instead of the values. The associativity is preserved. */
    4644         164 : PHP_FUNCTION(array_diff_key)
    4645             : {
    4646         164 :         php_array_diff_key(INTERNAL_FUNCTION_PARAM_PASSTHRU, DIFF_COMP_DATA_NONE);
    4647         164 : }
    4648             : /* }}} */
    4649             : 
    4650             : /* {{{ proto array array_diff_ukey(array arr1, array arr2 [, array ...], callback key_comp_func)
    4651             :    Returns the entries of arr1 that have keys which are not present in any of the others arguments. User supplied function is used for comparing the keys. This function is like array_udiff() but works on the keys instead of the values. The associativity is preserved. */
    4652         206 : PHP_FUNCTION(array_diff_ukey)
    4653             : {
    4654         206 :         php_array_diff(INTERNAL_FUNCTION_PARAM_PASSTHRU, DIFF_KEY, DIFF_COMP_DATA_INTERNAL, DIFF_COMP_KEY_USER);
    4655         206 : }
    4656             : /* }}} */
    4657             : 
    4658             : /* {{{ proto array array_diff(array arr1, array arr2 [, array ...])
    4659             :    Returns the entries of arr1 that have values which are not present in any of the others arguments. */
    4660         141 : PHP_FUNCTION(array_diff)
    4661             : {
    4662             :         zval *args;
    4663             :         int argc, i;
    4664             :         uint32_t num;
    4665             :         HashTable exclude;
    4666             :         zval *value;
    4667             :         zend_string *str, *key;
    4668             :         zend_long idx;
    4669             :         zval dummy;
    4670             : 
    4671         141 :         if (ZEND_NUM_ARGS() < 2) {
    4672           4 :                 php_error_docref(NULL, E_WARNING, "at least 2 parameters are required, %d given", ZEND_NUM_ARGS());
    4673           4 :                 return;
    4674             :         }
    4675             : 
    4676         137 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "+", &args, &argc) == FAILURE) {
    4677           0 :                 return;
    4678             :         }
    4679             : 
    4680         274 :         if (Z_TYPE(args[0]) != IS_ARRAY) {
    4681          26 :                 php_error_docref(NULL, E_WARNING, "Argument #1 is not an array");
    4682          26 :                 RETURN_NULL();
    4683             :         }
    4684             : 
    4685             :         /* count number of elements */
    4686         111 :         num = 0;
    4687         199 :         for (i = 1; i < argc; i++) {
    4688         230 :                 if (Z_TYPE(args[i]) != IS_ARRAY) {
    4689          27 :                         php_error_docref(NULL, E_WARNING, "Argument #%d is not an array", i + 1);
    4690          27 :                         RETURN_NULL();
    4691             :                 }
    4692          88 :                 num += zend_hash_num_elements(Z_ARRVAL(args[i]));
    4693             :         }
    4694             : 
    4695          84 :         if (num == 0) {
    4696           1 :                 ZVAL_COPY(return_value, &args[0]);
    4697           1 :                 return;
    4698             :         }
    4699             : 
    4700          83 :         ZVAL_NULL(&dummy);
    4701             :         /* create exclude map */
    4702          83 :         zend_hash_init(&exclude, num, NULL, NULL, 0);
    4703         170 :         for (i = 1; i < argc; i++) {
    4704        9021 :                 ZEND_HASH_FOREACH_VAL_IND(Z_ARRVAL(args[i]), value) {
    4705        2977 :                         str = zval_get_string(value);
    4706        2977 :                         zend_hash_add(&exclude, str, &dummy);
    4707             :                         zend_string_release(str);
    4708             :                 } ZEND_HASH_FOREACH_END();
    4709             :         }
    4710             : 
    4711             :         /* copy all elements of first array that are not in exclude set */
    4712          83 :         array_init_size(return_value, zend_hash_num_elements(Z_ARRVAL(args[0])));
    4713        8996 :         ZEND_HASH_FOREACH_KEY_VAL_IND(Z_ARRVAL(args[0]), idx, key, value) {
    4714        2970 :                 str = zval_get_string(value);
    4715        2970 :                 if (!zend_hash_exists(&exclude, str)) {
    4716         157 :                         if (key) {
    4717          49 :                                 value = zend_hash_add_new(Z_ARRVAL_P(return_value), key, value);
    4718             :                         } else {
    4719         108 :                                 value = zend_hash_index_add_new(Z_ARRVAL_P(return_value), idx, value);
    4720             :                         }
    4721         157 :                         zval_add_ref(value);
    4722             :                 }
    4723             :                 zend_string_release(str);
    4724             :         } ZEND_HASH_FOREACH_END();
    4725             : 
    4726          83 :         zend_hash_destroy(&exclude);
    4727             : }
    4728             : /* }}} */
    4729             : 
    4730             : /* {{{ proto array array_udiff(array arr1, array arr2 [, array ...], callback data_comp_func)
    4731             :    Returns the entries of arr1 that have values which are not present in any of the others arguments. Elements are compared by user supplied function. */
    4732         112 : PHP_FUNCTION(array_udiff)
    4733             : {
    4734         112 :         php_array_diff(INTERNAL_FUNCTION_PARAM_PASSTHRU, DIFF_NORMAL, DIFF_COMP_DATA_USER, DIFF_COMP_KEY_INTERNAL);
    4735         112 : }
    4736             : /* }}} */
    4737             : 
    4738             : /* {{{ proto array array_diff_assoc(array arr1, array arr2 [, array ...])
    4739             :    Returns the entries of arr1 that have values which are not present in any of the others arguments but do additional checks whether the keys are equal */
    4740         143 : PHP_FUNCTION(array_diff_assoc)
    4741             : {
    4742         143 :         php_array_diff_key(INTERNAL_FUNCTION_PARAM_PASSTHRU, DIFF_COMP_DATA_INTERNAL);
    4743         143 : }
    4744             : /* }}} */
    4745             : 
    4746             : /* {{{ proto array array_diff_uassoc(array arr1, array arr2 [, array ...], callback data_comp_func)
    4747             :    Returns the entries of arr1 that have values which are not present in any of the others arguments but do additional checks whether the keys are equal. Elements are compared by user supplied function. */
    4748         149 : PHP_FUNCTION(array_diff_uassoc)
    4749             : {
    4750         149 :         php_array_diff(INTERNAL_FUNCTION_PARAM_PASSTHRU, DIFF_ASSOC, DIFF_COMP_DATA_INTERNAL, DIFF_COMP_KEY_USER);
    4751         149 : }
    4752             : /* }}} */
    4753             : 
    4754             : /* {{{ proto array array_udiff_assoc(array arr1, array arr2 [, array ...], callback key_comp_func)
    4755             :    Returns the entries of arr1 that have values which are not present in any of the others arguments but do additional checks whether the keys are equal. Keys are compared by user supplied function. */
    4756         114 : PHP_FUNCTION(array_udiff_assoc)
    4757             : {
    4758         114 :         php_array_diff_key(INTERNAL_FUNCTION_PARAM_PASSTHRU, DIFF_COMP_DATA_USER);
    4759         114 : }
    4760             : /* }}} */
    4761             : 
    4762             : /* {{{ proto array array_udiff_uassoc(array arr1, array arr2 [, array ...], callback data_comp_func, callback key_comp_func)
    4763             :    Returns the entries of arr1 that have values which are not present in any of the others arguments but do additional checks whether the keys are equal. Keys and elements are compared by user supplied functions. */
    4764         141 : PHP_FUNCTION(array_udiff_uassoc)
    4765             : {
    4766         141 :         php_array_diff(INTERNAL_FUNCTION_PARAM_PASSTHRU, DIFF_ASSOC, DIFF_COMP_DATA_USER, DIFF_COMP_KEY_USER);
    4767         141 : }
    4768             : /* }}} */
    4769             : 
    4770             : #define MULTISORT_ORDER 0
    4771             : #define MULTISORT_TYPE  1
    4772             : #define MULTISORT_LAST  2
    4773             : 
    4774         174 : PHPAPI int php_multisort_compare(const void *a, const void *b) /* {{{ */
    4775             : {
    4776         174 :         Bucket *ab = *(Bucket **)a;
    4777         174 :         Bucket *bb = *(Bucket **)b;
    4778             :         int r;
    4779             :         zend_long result;
    4780             : 
    4781         174 :         r = 0;
    4782             :         do {
    4783         180 :                 result = ARRAYG(multisort_func)[r](&ab[r], &bb[r]);
    4784         180 :                 if (result != 0) {
    4785         157 :                         return result > 0 ? 1 : -1;
    4786             :                 }
    4787          23 :                 r++;
    4788          46 :         } while (Z_TYPE(ab[r].val) != IS_UNDEF);
    4789             : 
    4790          17 :         return 0;
    4791             : }
    4792             : /* }}} */
    4793             : 
    4794             : #define MULTISORT_ABORT                         \
    4795             :         efree(ARRAYG(multisort_func));  \
    4796             :         efree(arrays);                                  \
    4797             :         RETURN_FALSE;
    4798             : 
    4799          99 : static void array_bucket_p_sawp(void *p, void *q) /* {{{ */ {
    4800             :         Bucket *t;
    4801          99 :         Bucket **f = (Bucket **)p;
    4802          99 :         Bucket **g = (Bucket **)q;
    4803             : 
    4804          99 :         t = *f;
    4805          99 :         *f = *g;
    4806          99 :         *g = t;
    4807          99 : }
    4808             : /* }}} */
    4809             : 
    4810             : /* {{{ proto bool array_multisort(array &$array1 [, mixed $array1_sort_order [, mixed $array1_sort_flags [, mixed ... ]]]
    4811             :    Sort multiple arrays at once similar to how ORDER BY clause works in SQL */
    4812         115 : PHP_FUNCTION(array_multisort)
    4813             : {
    4814             :         zval*                   args;
    4815             :         zval**                  arrays;
    4816             :         Bucket**                indirect;
    4817             :         uint            idx;
    4818             :         Bucket*                 p;
    4819             :         HashTable*              hash;
    4820             :         int                             argc;
    4821             :         int                             array_size;
    4822         115 :         int                             num_arrays = 0;
    4823             :         int                             parse_state[MULTISORT_LAST];   /* 0 - flag not allowed 1 - flag allowed */
    4824         115 :         int                             sort_order = PHP_SORT_ASC;
    4825         115 :         int                             sort_type  = PHP_SORT_REGULAR;
    4826             :         int                             i, k, n;
    4827             : 
    4828         115 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "+", &args, &argc) == FAILURE) {
    4829           1 :                 return;
    4830             :         }
    4831             : 
    4832             :         /* Allocate space for storing pointers to input arrays and sort flags. */
    4833         114 :         arrays = (zval **)ecalloc(argc, sizeof(zval *));
    4834         342 :         for (i = 0; i < MULTISORT_LAST; i++) {
    4835         228 :                 parse_state[i] = 0;
    4836             :         }
    4837         114 :         ARRAYG(multisort_func) = (compare_func_t*)ecalloc(argc, sizeof(compare_func_t));
    4838             : 
    4839             :         /* Here we go through the input arguments and parse them. Each one can
    4840             :          * be either an array or a sort flag which follows an array. If not
    4841             :          * specified, the sort flags defaults to PHP_SORT_ASC and PHP_SORT_REGULAR
    4842             :          * accordingly. There can't be two sort flags of the same type after an
    4843             :          * array, and the very first argument has to be an array. */
    4844         280 :         for (i = 0; i < argc; i++) {
    4845         241 :                 zval *arg = &args[i];
    4846             : 
    4847         241 :                 ZVAL_DEREF(arg);
    4848         241 :                 if (Z_TYPE_P(arg) == IS_ARRAY) {
    4849         106 :                         SEPARATE_ARRAY(arg);
    4850             :                         /* We see the next array, so we update the sort flags of
    4851             :                          * the previous array and reset the sort flags. */
    4852         106 :                         if (i > 0) {
    4853          17 :                                 ARRAYG(multisort_func)[num_arrays - 1] = php_get_data_compare_func(sort_type, sort_order != PHP_SORT_ASC);
    4854          17 :                                 sort_order = PHP_SORT_ASC;
    4855          17 :                                 sort_type = PHP_SORT_REGULAR;
    4856             :                         }
    4857         106 :                         arrays[num_arrays++] = arg;
    4858             : 
    4859             :                         /* Next one may be an array or a list of sort flags. */
    4860         318 :                         for (k = 0; k < MULTISORT_LAST; k++) {
    4861         212 :                                 parse_state[k] = 1;
    4862             :                         }
    4863         135 :                 } else if (Z_TYPE_P(arg) == IS_LONG) {
    4864          72 :                         switch (Z_LVAL_P(arg) & ~PHP_SORT_FLAG_CASE) {
    4865             :                                 case PHP_SORT_ASC:
    4866             :                                 case PHP_SORT_DESC:
    4867             :                                         /* flag allowed here */
    4868          15 :                                         if (parse_state[MULTISORT_ORDER] == 1) {
    4869             :                                                 /* Save the flag and make sure then next arg is not the current flag. */
    4870          14 :                                                 sort_order = Z_LVAL_P(arg) == PHP_SORT_DESC ? PHP_SORT_DESC : PHP_SORT_ASC;
    4871          14 :                                                 parse_state[MULTISORT_ORDER] = 0;
    4872             :                                         } else {
    4873           1 :                                                 php_error_docref(NULL, E_WARNING, "Argument #%d is expected to be an array or sorting flag that has not already been specified", i + 1);
    4874           1 :                                                 MULTISORT_ABORT;
    4875             :                                         }
    4876          14 :                                         break;
    4877             : 
    4878             :                                 case PHP_SORT_REGULAR:
    4879             :                                 case PHP_SORT_NUMERIC:
    4880             :                                 case PHP_SORT_STRING:
    4881             :                                 case PHP_SORT_NATURAL:
    4882             : #if HAVE_STRCOLL
    4883             :                                 case PHP_SORT_LOCALE_STRING:
    4884             : #endif
    4885             :                                         /* flag allowed here */
    4886          51 :                                         if (parse_state[MULTISORT_TYPE] == 1) {
    4887             :                                                 /* Save the flag and make sure then next arg is not the current flag. */
    4888          46 :                                                 sort_type = (int)Z_LVAL_P(arg);
    4889          46 :                                                 parse_state[MULTISORT_TYPE] = 0;
    4890             :                                         } else {
    4891           5 :                                                 php_error_docref(NULL, E_WARNING, "Argument #%d is expected to be an array or sorting flag that has not already been specified", i + 1);
    4892           5 :                                                 MULTISORT_ABORT;
    4893             :                                         }
    4894          46 :                                         break;
    4895             : 
    4896             :                                 default:
    4897           6 :                                         php_error_docref(NULL, E_WARNING, "Argument #%d is an unknown sort flag", i + 1);
    4898           6 :                                         MULTISORT_ABORT;
    4899             :                                         break;
    4900             : 
    4901             :                         }
    4902             :                 } else {
    4903          63 :                         php_error_docref(NULL, E_WARNING, "Argument #%d is expected to be an array or a sort flag", i + 1);
    4904          63 :                         MULTISORT_ABORT;
    4905             :                 }
    4906             :         }
    4907             :         /* Take care of the last array sort flags. */
    4908          39 :         ARRAYG(multisort_func)[num_arrays - 1] = php_get_data_compare_func(sort_type, sort_order != PHP_SORT_ASC);
    4909             : 
    4910             :         /* Make sure the arrays are of the same size. */
    4911          39 :         array_size = zend_hash_num_elements(Z_ARRVAL_P(arrays[0]));
    4912          92 :         for (i = 0; i < num_arrays; i++) {
    4913          56 :                 if (zend_hash_num_elements(Z_ARRVAL_P(arrays[i])) != (uint32_t)array_size) {
    4914           3 :                         php_error_docref(NULL, E_WARNING, "Array sizes are inconsistent");
    4915           3 :                         MULTISORT_ABORT;
    4916             :                 }
    4917             :         }
    4918             : 
    4919             :         /* If all arrays are empty we don't need to do anything. */
    4920          36 :         if (array_size < 1) {
    4921           2 :                 efree(ARRAYG(multisort_func));
    4922           2 :                 efree(arrays);
    4923           2 :                 RETURN_TRUE;
    4924             :         }
    4925             : 
    4926             :         /* Create the indirection array. This array is of size MxN, where
    4927             :          * M is the number of entries in each input array and N is the number
    4928             :          * of the input arrays + 1. The last column is NULL to indicate the end
    4929             :          * of the row. */
    4930          34 :         indirect = (Bucket **)safe_emalloc(array_size, sizeof(Bucket *), 0);
    4931         173 :         for (i = 0; i < array_size; i++) {
    4932         139 :                 indirect[i] = (Bucket *)safe_emalloc((num_arrays + 1), sizeof(Bucket), 0);
    4933             :         }
    4934          80 :         for (i = 0; i < num_arrays; i++) {
    4935          46 :                 k = 0;
    4936         245 :                 for (idx = 0; idx < Z_ARRVAL_P(arrays[i])->nNumUsed; idx++) {
    4937         199 :                         p = Z_ARRVAL_P(arrays[i])->arData + idx;
    4938         398 :                         if (Z_TYPE(p->val) == IS_UNDEF) continue;
    4939         198 :                         indirect[k][i] = *p;
    4940         198 :                         k++;
    4941             :                 }
    4942             :         }
    4943         173 :         for (k = 0; k < array_size; k++) {
    4944         139 :                 ZVAL_UNDEF(&indirect[k][num_arrays].val);
    4945             :         }
    4946             : 
    4947             :         /* Do the actual sort magic - bada-bim, bada-boom. */
    4948          34 :         zend_sort(indirect, array_size, sizeof(Bucket *), php_multisort_compare, (swap_func_t)array_bucket_p_sawp);
    4949             : 
    4950             :         /* Restructure the arrays based on sorted indirect - this is mostly taken from zend_hash_sort() function. */
    4951          80 :         for (i = 0; i < num_arrays; i++) {
    4952             :                 int repack;
    4953             : 
    4954          46 :                 hash = Z_ARRVAL_P(arrays[i]);
    4955          46 :                 hash->nNumUsed = array_size;
    4956          46 :                 hash->nInternalPointer = 0;
    4957          46 :                 repack = !(hash->u.flags & HASH_FLAG_PACKED);
    4958             : 
    4959         244 :                 for (n = 0, k = 0; k < array_size; k++) {
    4960         198 :                         hash->arData[k] = indirect[k][i];
    4961         198 :                         if (hash->arData[k].key == NULL) {
    4962         148 :                                 hash->arData[k].h = n++;
    4963             :                         } else {
    4964          50 :                                 repack = 0;
    4965             :                         }
    4966             :                 }
    4967          46 :                 hash->nNextFreeElement = array_size;
    4968          46 :                 if (repack) {
    4969           0 :                         zend_hash_to_packed(hash);
    4970             :                 } else {
    4971          46 :                         zend_hash_rehash(hash);
    4972             :                 }
    4973             :         }
    4974             : 
    4975             :         /* Clean up. */
    4976         173 :         for (i = 0; i < array_size; i++) {
    4977         139 :                 efree(indirect[i]);
    4978             :         }
    4979          34 :         efree(indirect);
    4980          34 :         efree(ARRAYG(multisort_func));
    4981          34 :         efree(arrays);
    4982          34 :         RETURN_TRUE;
    4983             : }
    4984             : /* }}} */
    4985             : 
    4986             : /* {{{ proto mixed array_rand(array input [, int num_req])
    4987             :    Return key/keys for random entry/entries in the array */
    4988         363 : PHP_FUNCTION(array_rand)
    4989             : {
    4990             :         zval *input;
    4991         363 :         zend_long num_req = 1;
    4992             :         zend_string *string_key;
    4993             :         zend_ulong num_key;
    4994             :         int i;
    4995             :         int num_avail;
    4996             :         zend_bitset bitset;
    4997         363 :         int negative_bitset = 0;
    4998             :         uint32_t bitset_len;
    4999             :         ALLOCA_FLAG(use_heap)
    5000             : 
    5001         363 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "a|l", &input, &num_req) == FAILURE) {
    5002          32 :                 return;
    5003             :         }
    5004             : 
    5005         331 :         num_avail = zend_hash_num_elements(Z_ARRVAL_P(input));
    5006             : 
    5007         331 :         if (num_avail == 0) {
    5008           2 :                 php_error_docref(NULL, E_WARNING, "Array is empty");
    5009           2 :                 return;
    5010             :         }
    5011             : 
    5012         329 :         if (num_req == 1) {
    5013         284 :                 HashTable *ht = Z_ARRVAL_P(input);
    5014             : 
    5015             :                 /* Compact the hashtable if less than 3/4 of elements are used */
    5016         284 :                 if (num_avail < ht->nNumUsed - (ht->nNumUsed>>2)) {
    5017           0 :                         if (ht->u.flags & HASH_FLAG_PACKED) {
    5018           0 :                                 zend_hash_packed_to_hash(ht);
    5019             :                         } else {
    5020           0 :                                 zend_hash_rehash(ht);
    5021             :                         }
    5022             :                 }
    5023             : 
    5024             :                 /* Sample random buckets until we hit one that is not empty.
    5025             :                  * The worst case probability of hitting an empty element is 1-3/4. The worst case
    5026             :                  * probability of hitting N empty elements in a row is (1-3/4)**N.
    5027             :                  * For N=5 this becomes smaller than 0.1%. */
    5028             :                 do {
    5029         284 :                         zend_long randval = php_mt_rand_range(0, ht->nNumUsed - 1);
    5030         284 :                         Bucket *bucket = &ht->arData[randval];
    5031         568 :                         if (!Z_ISUNDEF(bucket->val)) {
    5032         284 :                                 if (bucket->key) {
    5033           7 :                                         RETURN_STR_COPY(bucket->key);
    5034             :                                 } else {
    5035         277 :                                         RETURN_LONG(bucket->h);
    5036             :                                 }
    5037             :                         }
    5038           0 :                 } while (1);
    5039             :         }
    5040             : 
    5041          45 :         if (num_req <= 0 || num_req > num_avail) {
    5042          20 :                 php_error_docref(NULL, E_WARNING, "Second argument has to be between 1 and the number of elements in the array");
    5043          20 :                 return;
    5044             :         }
    5045             : 
    5046             :         /* Make the return value an array only if we need to pass back more than one result. */
    5047          25 :         array_init_size(return_value, (uint32_t)num_req);
    5048          25 :         if (num_req > (num_avail >> 1)) {
    5049          15 :                 negative_bitset = 1;
    5050          15 :                 num_req = num_avail - num_req;
    5051             :         }
    5052             : 
    5053          25 :         bitset_len = zend_bitset_len(num_avail);
    5054          25 :         bitset = ZEND_BITSET_ALLOCA(bitset_len, use_heap);
    5055          25 :         zend_bitset_clear(bitset, bitset_len);
    5056             : 
    5057          25 :         i = num_req;
    5058          97 :         while (i) {
    5059          47 :                 zend_long randval = php_mt_rand_range(0, num_avail - 1);
    5060          47 :                 if (!zend_bitset_in(bitset, randval)) {
    5061          41 :                         zend_bitset_incl(bitset, randval);
    5062          41 :                         i--;
    5063             :                 }
    5064             :         }
    5065             :         /* i = 0; */
    5066             : 
    5067          25 :         zend_hash_real_init(Z_ARRVAL_P(return_value), 1);
    5068          25 :         ZEND_HASH_FILL_PACKED(Z_ARRVAL_P(return_value)) {
    5069             :                 zval zv;
    5070             :                 /* We can't use zend_hash_index_find()
    5071             :                  * because the array may have string keys or gaps. */
    5072        1087 :                 ZEND_HASH_FOREACH_KEY(Z_ARRVAL_P(input), num_key, string_key) {
    5073         531 :                         if (zend_bitset_in(bitset, i) ^ negative_bitset) {
    5074         476 :                                 if (string_key) {
    5075          19 :                                         ZVAL_STR_COPY(&zv, string_key);
    5076             :                                 } else {
    5077         457 :                                         ZVAL_LONG(&zv, num_key);
    5078             :                                 }
    5079         476 :                                 ZEND_HASH_FILL_ADD(&zv);
    5080             :                         }
    5081         531 :                         i++;
    5082             :                 } ZEND_HASH_FOREACH_END();
    5083          25 :         } ZEND_HASH_FILL_END();
    5084             : 
    5085          25 :         free_alloca(bitset, use_heap);
    5086             : }
    5087             : /* }}} */
    5088             : 
    5089             : /* {{{ proto mixed array_sum(array input)
    5090             :    Returns the sum of the array entries */
    5091          64 : PHP_FUNCTION(array_sum)
    5092             : {
    5093             :         zval *input,
    5094             :                  *entry,
    5095             :                  entry_n;
    5096             : 
    5097          64 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "a", &input) == FAILURE) {
    5098          25 :                 return;
    5099             :         }
    5100             : 
    5101          39 :         ZVAL_LONG(return_value, 0);
    5102             : 
    5103      404355 :         ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(input), entry) {
    5104      404312 :                 if (Z_TYPE_P(entry) == IS_ARRAY || Z_TYPE_P(entry) == IS_OBJECT) {
    5105           8 :                         continue;
    5106             :                 }
    5107      202150 :                 ZVAL_COPY(&entry_n, entry);
    5108      202150 :                 convert_scalar_to_number(&entry_n);
    5109             :                 fast_add_function(return_value, return_value, &entry_n);
    5110             :         } ZEND_HASH_FOREACH_END();
    5111             : }
    5112             : /* }}} */
    5113             : 
    5114             : /* {{{ proto mixed array_product(array input)
    5115             :    Returns the product of the array entries */
    5116          53 : PHP_FUNCTION(array_product)
    5117             : {
    5118             :         zval *input,
    5119             :                  *entry,
    5120             :                  entry_n;
    5121             :         double dval;
    5122             : 
    5123          53 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "a", &input) == FAILURE) {
    5124          29 :                 return;
    5125             :         }
    5126             : 
    5127          24 :         ZVAL_LONG(return_value, 1);
    5128          24 :         if (!zend_hash_num_elements(Z_ARRVAL_P(input))) {
    5129           2 :                 return;
    5130             :         }
    5131             : 
    5132        2086 :         ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(input), entry) {
    5133        2063 :                 if (Z_TYPE_P(entry) == IS_ARRAY || Z_TYPE_P(entry) == IS_OBJECT) {
    5134           2 :                         continue;
    5135             :                 }
    5136        1030 :                 ZVAL_COPY(&entry_n, entry);
    5137        1030 :                 convert_scalar_to_number(&entry_n);
    5138             : 
    5139        2053 :                 if (Z_TYPE(entry_n) == IS_LONG && Z_TYPE_P(return_value) == IS_LONG) {
    5140          28 :                         dval = (double)Z_LVAL_P(return_value) * (double)Z_LVAL(entry_n);
    5141          28 :                         if ( (double)ZEND_LONG_MIN <= dval && dval <= (double)ZEND_LONG_MAX ) {
    5142          27 :                                 Z_LVAL_P(return_value) *= Z_LVAL(entry_n);
    5143          27 :                                 continue;
    5144             :                         }
    5145             :                 }
    5146        1003 :                 convert_to_double(return_value);
    5147        1003 :                 convert_to_double(&entry_n);
    5148        1003 :                 Z_DVAL_P(return_value) *= Z_DVAL(entry_n);
    5149             :         } ZEND_HASH_FOREACH_END();
    5150             : }
    5151             : /* }}} */
    5152             : 
    5153             : /* {{{ proto mixed array_reduce(array input, mixed callback [, mixed initial])
    5154             :    Iteratively reduce the array to a single value via the callback. */
    5155          79 : PHP_FUNCTION(array_reduce)
    5156             : {
    5157             :         zval *input;
    5158             :         zval args[2];
    5159             :         zval *operand;
    5160             :         zval result;
    5161             :         zval retval;
    5162             :         zend_fcall_info fci;
    5163          79 :         zend_fcall_info_cache fci_cache = empty_fcall_info_cache;
    5164          79 :         zval *initial = NULL;
    5165             :         HashTable *htbl;
    5166             : 
    5167          79 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "af|z", &input, &fci, &fci_cache, &initial) == FAILURE) {
    5168           5 :                 return;
    5169             :         }
    5170             : 
    5171             : 
    5172          74 :         if (ZEND_NUM_ARGS() > 2) {
    5173          16 :                 ZVAL_DUP(&result, initial);
    5174             :         } else {
    5175          58 :                 ZVAL_NULL(&result);
    5176             :         }
    5177             : 
    5178             :         /* (zval **)input points to an element of argument stack
    5179             :          * the base pointer of which is subject to change.
    5180             :          * thus we need to keep the pointer to the hashtable for safety */
    5181          74 :         htbl = Z_ARRVAL_P(input);
    5182             : 
    5183          74 :         if (zend_hash_num_elements(htbl) == 0) {
    5184           1 :                 ZVAL_COPY_VALUE(return_value, &result);
    5185           1 :                 return;
    5186             :         }
    5187             : 
    5188          73 :         fci.retval = &retval;
    5189          73 :         fci.param_count = 2;
    5190          73 :         fci.no_separation = 0;
    5191             : 
    5192       49608 :         ZEND_HASH_FOREACH_VAL(htbl, operand) {
    5193       24768 :                 ZVAL_COPY(&args[0], &result);
    5194       24768 :                 ZVAL_COPY(&args[1], operand);
    5195       24768 :                 fci.params = args;
    5196             : 
    5197       74303 :                 if (zend_call_function(&fci, &fci_cache) == SUCCESS && Z_TYPE(retval) != IS_UNDEF) {
    5198       24767 :                         zval_ptr_dtor(&args[1]);
    5199       24767 :                         zval_ptr_dtor(&args[0]);
    5200       24767 :                         zval_ptr_dtor(&result);
    5201       24767 :                         ZVAL_COPY_VALUE(&result, &retval);
    5202             :                 } else {
    5203           1 :                         zval_ptr_dtor(&args[1]);
    5204           1 :                         zval_ptr_dtor(&args[0]);
    5205           1 :                         return;
    5206             :                 }
    5207             :         } ZEND_HASH_FOREACH_END();
    5208             : 
    5209         144 :         RETVAL_ZVAL(&result, 1, 1);
    5210             : }
    5211             : /* }}} */
    5212             : 
    5213             : /* {{{ proto array array_filter(array input [, mixed callback])
    5214             :    Filters elements from the array via the callback. */
    5215         125 : PHP_FUNCTION(array_filter)
    5216             : {
    5217             :         zval *array;
    5218             :         zval *operand;
    5219             :         zval *key;
    5220             :         zval args[2];
    5221             :         zval retval;
    5222         125 :         zend_bool have_callback = 0;
    5223         125 :         zend_long use_type = 0;
    5224             :         zend_string *string_key;
    5225         125 :         zend_fcall_info fci = empty_fcall_info;
    5226         125 :         zend_fcall_info_cache fci_cache = empty_fcall_info_cache;
    5227             :         zend_ulong num_key;
    5228             : 
    5229         125 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "a|fl", &array, &fci, &fci_cache, &use_type) == FAILURE) {
    5230          60 :                 return;
    5231             :         }
    5232             : 
    5233          65 :         array_init(return_value);
    5234          65 :         if (zend_hash_num_elements(Z_ARRVAL_P(array)) == 0) {
    5235           1 :                 return;
    5236             :         }
    5237             : 
    5238          64 :         if (ZEND_NUM_ARGS() > 1) {
    5239          52 :                 have_callback = 1;
    5240          52 :                 fci.no_separation = 0;
    5241          52 :                 fci.retval = &retval;
    5242          52 :                 if (use_type == ARRAY_FILTER_USE_BOTH) {
    5243           4 :                         fci.param_count = 2;
    5244           4 :                         key = &args[1];
    5245             :                 } else {
    5246          48 :                         fci.param_count = 1;
    5247          48 :                         key = &args[0];
    5248             :                 }
    5249             :         }
    5250             : 
    5251        3361 :         ZEND_HASH_FOREACH_KEY_VAL_IND(Z_ARRVAL_P(array), num_key, string_key, operand) {
    5252        1099 :                 if (have_callback) {
    5253        1038 :                         if (use_type) {
    5254             :                                 /* Set up the key */
    5255          26 :                                 if (!string_key) {
    5256          20 :                                         ZVAL_LONG(key, num_key);
    5257             :                                 } else {
    5258           6 :                                         ZVAL_STR_COPY(key, string_key);
    5259             :                                 }
    5260             :                         }
    5261        1038 :                         if (use_type != ARRAY_FILTER_USE_KEY) {
    5262        1034 :                                 ZVAL_COPY(&args[0], operand);
    5263             :                         }
    5264        1038 :                         fci.params = args;
    5265             : 
    5266        1038 :                         if (zend_call_function(&fci, &fci_cache) == SUCCESS) {
    5267        1038 :                                 zval_ptr_dtor(&args[0]);
    5268        1038 :                                 if (use_type == ARRAY_FILTER_USE_BOTH) {
    5269          22 :                                         zval_ptr_dtor(&args[1]);
    5270             :                                 }
    5271        1038 :                                 if (!Z_ISUNDEF(retval)) {
    5272        1037 :                                         int retval_true = zend_is_true(&retval);
    5273             : 
    5274        1037 :                                         zval_ptr_dtor(&retval);
    5275        1037 :                                         if (!retval_true) {
    5276         144 :                                                 continue;
    5277             :                                         }
    5278             :                                 } else {
    5279           1 :                                         continue;
    5280             :                                 }
    5281             :                         } else {
    5282           0 :                                 zval_ptr_dtor(&args[0]);
    5283           0 :                                 if (use_type == ARRAY_FILTER_USE_BOTH) {
    5284           0 :                                         zval_ptr_dtor(&args[1]);
    5285             :                                 }
    5286           0 :                                 return;
    5287             :                         }
    5288          61 :                 } else if (!zend_is_true(operand)) {
    5289          26 :                         continue;
    5290             :                 }
    5291             : 
    5292         928 :                 if (string_key) {
    5293          17 :                         operand = zend_hash_update(Z_ARRVAL_P(return_value), string_key, operand);
    5294             :                 } else {
    5295         911 :                         operand = zend_hash_index_update(Z_ARRVAL_P(return_value), num_key, operand);
    5296             :                 }
    5297         928 :                 zval_add_ref(operand);
    5298             :         } ZEND_HASH_FOREACH_END();
    5299             : }
    5300             : /* }}} */
    5301             : 
    5302             : /* {{{ proto array array_map(mixed callback, array input1 [, array input2 ,...])
    5303             :    Applies the callback to the elements in given arrays. */
    5304         250 : PHP_FUNCTION(array_map)
    5305             : {
    5306         250 :         zval *arrays = NULL;
    5307         250 :         int n_arrays = 0;
    5308             :         zval result;
    5309         250 :         zend_fcall_info fci = empty_fcall_info;
    5310         250 :         zend_fcall_info_cache fci_cache = empty_fcall_info_cache;
    5311             :         int i;
    5312         250 :         uint32_t k, maxlen = 0;
    5313             : 
    5314         250 :         ZEND_PARSE_PARAMETERS_START(2, -1)
    5315         744 :                 Z_PARAM_FUNC_EX(fci, fci_cache, 1, 0)
    5316         198 :                 Z_PARAM_VARIADIC('+', arrays, n_arrays)
    5317         250 :         ZEND_PARSE_PARAMETERS_END();
    5318             : 
    5319         198 :         RETVAL_NULL();
    5320             : 
    5321         198 :         if (n_arrays == 1) {
    5322             :                 zend_ulong num_key;
    5323             :                 zend_string *str_key;
    5324             :                 zval *zv, arg;
    5325             : 
    5326         174 :                 if (Z_TYPE(arrays[0]) != IS_ARRAY) {
    5327          26 :                         php_error_docref(NULL, E_WARNING, "Argument #%d should be an array", 2);
    5328          26 :                         return;
    5329             :                 }
    5330         148 :                 maxlen = zend_hash_num_elements(Z_ARRVAL(arrays[0]));
    5331             : 
    5332             :                 /* Short-circuit: if no callback and only one array, just return it. */
    5333         148 :                 if (!ZEND_FCI_INITIALIZED(fci)) {
    5334           3 :                         ZVAL_COPY(return_value, &arrays[0]);
    5335           3 :                         return;
    5336             :                 }
    5337             : 
    5338         145 :                 array_init_size(return_value, maxlen);
    5339             : 
    5340        1741 :                 ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL(arrays[0]), num_key, str_key, zv) {
    5341         793 :                         fci.retval = &result;
    5342         793 :                         fci.param_count = 1;
    5343         793 :                         fci.params = &arg;
    5344         793 :                         fci.no_separation = 0;
    5345             : 
    5346         793 :                         ZVAL_COPY(&arg, zv);
    5347             : 
    5348        1586 :                         if (zend_call_function(&fci, &fci_cache) != SUCCESS || Z_TYPE(result) == IS_UNDEF) {
    5349             :                                 zval_dtor(return_value);
    5350           4 :                                 zval_ptr_dtor(&arg);
    5351           4 :                                 RETURN_NULL();
    5352             :                         } else {
    5353         789 :                                 zval_ptr_dtor(&arg);
    5354             :                         }
    5355         789 :                         if (str_key) {
    5356          54 :                                 zend_hash_add_new(Z_ARRVAL_P(return_value), str_key, &result);
    5357             :                         } else {
    5358         735 :                                 zend_hash_index_add_new(Z_ARRVAL_P(return_value), num_key, &result);
    5359             :                         }
    5360             :                 } ZEND_HASH_FOREACH_END();
    5361             :         } else {
    5362          24 :                 uint32_t *array_pos = (HashPosition *)ecalloc(n_arrays, sizeof(HashPosition));
    5363             : 
    5364          79 :                 for (i = 0; i < n_arrays; i++) {
    5365         110 :                         if (Z_TYPE(arrays[i]) != IS_ARRAY) {
    5366           0 :                                 php_error_docref(NULL, E_WARNING, "Argument #%d should be an array", i + 2);
    5367           0 :                                 efree(array_pos);
    5368           0 :                                 return;
    5369             :                         }
    5370          55 :                         if (zend_hash_num_elements(Z_ARRVAL(arrays[i])) > maxlen) {
    5371          24 :                                 maxlen = zend_hash_num_elements(Z_ARRVAL(arrays[i]));
    5372             :                         }
    5373             :                 }
    5374             : 
    5375          24 :                 array_init_size(return_value, maxlen);
    5376             : 
    5377          24 :                 if (!ZEND_FCI_INITIALIZED(fci)) {
    5378             :                         zval zv;
    5379             : 
    5380             :                         /* We iterate through all the arrays at once. */
    5381          24 :                         for (k = 0; k < maxlen; k++) {
    5382             : 
    5383             :                                 /* If no callback, the result will be an array, consisting of current
    5384             :                                  * entries from all arrays. */
    5385          17 :                                 array_init_size(&result, n_arrays);
    5386             : 
    5387          63 :                                 for (i = 0; i < n_arrays; i++) {
    5388             :                                         /* If this array still has elements, add the current one to the
    5389             :                                          * parameter list, otherwise use null value. */
    5390          46 :                                         uint32_t pos = array_pos[i];
    5391             :                                         while (1) {
    5392          46 :                                                 if (pos >= Z_ARRVAL(arrays[i])->nNumUsed) {
    5393           0 :                                                         ZVAL_NULL(&zv);
    5394           0 :                                                         break;
    5395          92 :                                                 } else if (Z_TYPE(Z_ARRVAL(arrays[i])->arData[pos].val) != IS_UNDEF) {
    5396          46 :                                                         ZVAL_COPY(&zv, &Z_ARRVAL(arrays[i])->arData[pos].val);
    5397          46 :                                                         array_pos[i] = pos + 1;
    5398          46 :                                                         break;
    5399             :                                                 }
    5400           0 :                                                 pos++;
    5401           0 :                                         }
    5402             : 
    5403          46 :                                         zend_hash_next_index_insert_new(Z_ARRVAL(result), &zv);
    5404             :                                 }
    5405             : 
    5406          17 :                                 zend_hash_next_index_insert_new(Z_ARRVAL_P(return_value), &result);
    5407             :                         }
    5408             :                 } else {
    5409          17 :                         zval *params = (zval *)safe_emalloc(n_arrays, sizeof(zval), 0);
    5410             : 
    5411             :                         /* We iterate through all the arrays at once. */
    5412          65 :                         for (k = 0; k < maxlen; k++) {
    5413         152 :                                 for (i = 0; i < n_arrays; i++) {
    5414             :                                         /* If this array still has elements, add the current one to the
    5415             :                                          * parameter list, otherwise use null value. */
    5416         103 :                                         uint32_t pos = array_pos[i];
    5417             :                                         while (1) {
    5418         103 :                                                 if (pos >= Z_ARRVAL(arrays[i])->nNumUsed) {
    5419          12 :                                                         ZVAL_NULL(&params[i]);
    5420          12 :                                                         break;
    5421         182 :                                                 } else if (Z_TYPE(Z_ARRVAL(arrays[i])->arData[pos].val) != IS_UNDEF) {
    5422          91 :                                                         ZVAL_COPY(&params[i], &Z_ARRVAL(arrays[i])->arData[pos].val);
    5423          91 :                                                         array_pos[i] = pos + 1;
    5424          91 :                                                         break;
    5425             :                                                 }
    5426           0 :                                                 pos++;
    5427           0 :                                         }
    5428             :                                 }
    5429             : 
    5430          49 :                                 fci.retval = &result;
    5431          49 :                                 fci.param_count = n_arrays;
    5432          49 :                                 fci.params = params;
    5433          49 :                                 fci.no_separation = 0;
    5434             : 
    5435          98 :                                 if (zend_call_function(&fci, &fci_cache) != SUCCESS || Z_TYPE(result) == IS_UNDEF) {
    5436           1 :                                         efree(array_pos);
    5437             :                                         zval_dtor(return_value);
    5438           3 :                                         for (i = 0; i < n_arrays; i++) {
    5439           2 :                                                 zval_ptr_dtor(&params[i]);
    5440             :                                         }
    5441           1 :                                         efree(params);
    5442           1 :                                         RETURN_NULL();
    5443             :                                 } else {
    5444         149 :                                         for (i = 0; i < n_arrays; i++) {
    5445         101 :                                                 zval_ptr_dtor(&params[i]);
    5446             :                                         }
    5447             :                                 }
    5448             : 
    5449          48 :                                 zend_hash_next_index_insert_new(Z_ARRVAL_P(return_value), &result);
    5450             :                         }
    5451             : 
    5452          16 :                         efree(params);
    5453             :                 }
    5454          23 :                 efree(array_pos);
    5455             :         }
    5456             : }
    5457             : /* }}} */
    5458             : 
    5459             : /* {{{ proto bool array_key_exists(mixed key, array search)
    5460             :    Checks if the given key or index exists in the array */
    5461      177568 : PHP_FUNCTION(array_key_exists)
    5462             : {
    5463             :         zval *key;                                      /* key to check for */
    5464             :         HashTable *array;                       /* array to check in */
    5465             : 
    5466      177568 :         ZEND_PARSE_PARAMETERS_START(2, 2)
    5467      177562 :                 Z_PARAM_ZVAL(key)
    5468      532686 :                 Z_PARAM_ARRAY_OR_OBJECT_HT(array)
    5469      177568 :         ZEND_PARSE_PARAMETERS_END();
    5470             : 
    5471      355066 :         switch (Z_TYPE_P(key)) {
    5472             :                 case IS_STRING:
    5473      354420 :                         if (zend_symtable_exists_ind(array, Z_STR_P(key))) {
    5474       12150 :                                 RETURN_TRUE;
    5475             :                         }
    5476      165060 :                         RETURN_FALSE;
    5477             :                 case IS_LONG:
    5478         250 :                         if (zend_hash_index_exists(array, Z_LVAL_P(key))) {
    5479         110 :                                 RETURN_TRUE;
    5480             :                         }
    5481         140 :                         RETURN_FALSE;
    5482             :                 case IS_NULL:
    5483         110 :                         if (zend_hash_exists_ind(array, ZSTR_EMPTY_ALLOC())) {
    5484          27 :                                 RETURN_TRUE;
    5485             :                         }
    5486          28 :                         RETURN_FALSE;
    5487             : 
    5488             :                 default:
    5489          18 :                         php_error_docref(NULL, E_WARNING, "The first argument should be either a string or an integer");
    5490          18 :                         RETURN_FALSE;
    5491             :         }
    5492             : }
    5493             : /* }}} */
    5494             : 
    5495             : /* {{{ proto array array_chunk(array input, int size [, bool preserve_keys])
    5496             :    Split array into chunks */
    5497         521 : PHP_FUNCTION(array_chunk)
    5498             : {
    5499         521 :         int argc = ZEND_NUM_ARGS(), num_in;
    5500         521 :         zend_long size, current = 0;
    5501             :         zend_string *str_key;
    5502             :         zend_ulong num_key;
    5503         521 :         zend_bool preserve_keys = 0;
    5504         521 :         zval *input = NULL;
    5505             :         zval chunk;
    5506             :         zval *entry;
    5507             : 
    5508         521 :         if (zend_parse_parameters(argc, "al|b", &input, &size, &preserve_keys) == FAILURE) {
    5509         106 :                 return;
    5510             :         }
    5511             :         /* Do bounds checking for size parameter. */
    5512         415 :         if (size < 1) {
    5513         107 :                 php_error_docref(NULL, E_WARNING, "Size parameter expected to be greater than 0");
    5514         107 :                 return;
    5515             :         }
    5516             : 
    5517         308 :         num_in = zend_hash_num_elements(Z_ARRVAL_P(input));
    5518             : 
    5519         308 :         if (size > num_in) {
    5520          34 :                 size = num_in > 0 ? num_in : 1;
    5521             :         }
    5522             : 
    5523         308 :         array_init_size(return_value, (uint32_t)(((num_in - 1) / size) + 1));
    5524             : 
    5525         308 :         ZVAL_UNDEF(&chunk);
    5526             : 
    5527        3340 :         ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(input), num_key, str_key, entry) {
    5528             :                 /* If new chunk, create and initialize it. */
    5529        1468 :                 if (Z_TYPE(chunk) == IS_UNDEF) {
    5530         683 :                         array_init_size(&chunk, (uint32_t)size);
    5531             :                 }
    5532             : 
    5533             :                 /* Add entry to the chunk, preserving keys if necessary. */
    5534        1468 :                 if (preserve_keys) {
    5535         507 :                         if (str_key) {
    5536          93 :                                 entry = zend_hash_update(Z_ARRVAL(chunk), str_key, entry);
    5537             :                         } else {
    5538         414 :                                 entry = zend_hash_index_update(Z_ARRVAL(chunk), num_key, entry);
    5539             :                         }
    5540             :                 } else {
    5541         961 :                         entry = zend_hash_next_index_insert(Z_ARRVAL(chunk), entry);
    5542             :                 }
    5543        1468 :                 zval_add_ref(entry);
    5544             : 
    5545             :                 /* If reached the chunk size, add it to the result array, and reset the
    5546             :                  * pointer. */
    5547        1468 :                 if (!(++current % size)) {
    5548         576 :                         add_next_index_zval(return_value, &chunk);
    5549         576 :                         ZVAL_UNDEF(&chunk);
    5550             :                 }
    5551             :         } ZEND_HASH_FOREACH_END();
    5552             : 
    5553             :         /* Add the final chunk if there is one. */
    5554         308 :         if (Z_TYPE(chunk) != IS_UNDEF) {
    5555         107 :                 add_next_index_zval(return_value, &chunk);
    5556             :         }
    5557             : }
    5558             : /* }}} */
    5559             : 
    5560             : /* {{{ proto array array_combine(array keys, array values)
    5561             :    Creates an array by using the elements of the first parameter as keys and the elements of the second as the corresponding values */
    5562         118 : PHP_FUNCTION(array_combine)
    5563             : {
    5564             :         HashTable *values, *keys;
    5565         118 :         uint32_t pos_values = 0;
    5566             :         zval *entry_keys, *entry_values;
    5567             :         int num_keys, num_values;
    5568             : 
    5569         118 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "hh", &keys, &values) == FAILURE) {
    5570          51 :                 return;
    5571             :         }
    5572             : 
    5573          67 :         num_keys = zend_hash_num_elements(keys);
    5574          67 :         num_values = zend_hash_num_elements(values);
    5575             : 
    5576          67 :         if (num_keys != num_values) {
    5577           3 :                 php_error_docref(NULL, E_WARNING, "Both parameters should have an equal number of elements");
    5578           3 :                 RETURN_FALSE;
    5579             :         }
    5580             : 
    5581          64 :         array_init_size(return_value, num_keys);
    5582             : 
    5583          64 :         if (!num_keys) {
    5584           4 :                 return;
    5585             :         }
    5586             : 
    5587         440 :         ZEND_HASH_FOREACH_VAL(keys, entry_keys) {
    5588             :                 while (1) {
    5589         194 :                         if (pos_values >= values->nNumUsed) {
    5590           0 :                                 break;
    5591         388 :                         } else if (Z_TYPE(values->arData[pos_values].val) != IS_UNDEF) {
    5592         181 :                                 entry_values = &values->arData[pos_values].val;
    5593         181 :                                 if (Z_TYPE_P(entry_keys) == IS_LONG) {
    5594          43 :                                         entry_values = zend_hash_index_update(Z_ARRVAL_P(return_value),
    5595             :                                                 Z_LVAL_P(entry_keys), entry_values);
    5596             :                                 } else {
    5597         138 :                                         zend_string *key = zval_get_string(entry_keys);
    5598         276 :                                         entry_values = zend_symtable_update(Z_ARRVAL_P(return_value),
    5599             :                                                 key, entry_values);
    5600             :                                         zend_string_release(key);
    5601             :                                 }
    5602         181 :                                 zval_add_ref(entry_values);
    5603         181 :                                 pos_values++;
    5604         181 :                                 break;
    5605             :                         }
    5606          13 :                         pos_values++;
    5607          13 :                 }
    5608             :         } ZEND_HASH_FOREACH_END();
    5609             : }
    5610             : /* }}} */
    5611             : 
    5612             : /*
    5613             :  * Local variables:
    5614             :  * tab-width: 4
    5615             :  * c-basic-offset: 4
    5616             :  * End:
    5617             :  * vim600: noet sw=4 ts=4 fdm=marker
    5618             :  * vim<600: noet sw=4 ts=4
    5619             :  */

Generated by: LCOV version 1.10

Generated at Sun, 18 Sep 2016 08:20:17 +0000 (6 days ago)

Copyright © 2005-2016 The PHP Group
All rights reserved.