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

Generated by: LCOV version 1.10

Generated at Wed, 24 Aug 2016 12:20:31 +0000 (46 hours ago)

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