summaryrefslogtreecommitdiff
path: root/ext/standard/array.c
diff options
context:
space:
mode:
Diffstat (limited to 'ext/standard/array.c')
-rw-r--r--ext/standard/array.c1256
1 files changed, 849 insertions, 407 deletions
diff --git a/ext/standard/array.c b/ext/standard/array.c
index 696ad05ff6..cba3b5d46e 100644
--- a/ext/standard/array.c
+++ b/ext/standard/array.c
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| PHP Version 7 |
+----------------------------------------------------------------------+
- | Copyright (c) 1997-2015 The PHP Group |
+ | Copyright (c) 1997-2016 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
@@ -46,9 +46,7 @@
#include "php_string.h"
#include "php_rand.h"
#include "zend_smart_str.h"
-#ifdef HAVE_SPL
#include "ext/spl/spl_array.h"
-#endif
/* {{{ defines */
#define EXTR_OVERWRITE 0
@@ -81,8 +79,6 @@
#define INTERSECT_COMP_DATA_USER 1
#define INTERSECT_COMP_KEY_INTERNAL 0
#define INTERSECT_COMP_KEY_USER 1
-
-#define DOUBLE_DRIFT_FIX 0.000000000000001
/* }}} */
ZEND_DECLARE_MODULE_GLOBALS(array)
@@ -141,75 +137,561 @@ PHP_MSHUTDOWN_FUNCTION(array) /* {{{ */
}
/* }}} */
-static void php_set_compare_func(zend_long sort_type) /* {{{ */
+static int php_array_key_compare(const void *a, const void *b) /* {{{ */
{
- switch (sort_type & ~PHP_SORT_FLAG_CASE) {
- case PHP_SORT_NUMERIC:
- ARRAYG(compare_func) = numeric_compare_function;
- break;
+ Bucket *f = (Bucket *) a;
+ Bucket *s = (Bucket *) b;
+ zend_uchar t;
+ zend_long l1, l2;
+ double d;
- case PHP_SORT_STRING:
- ARRAYG(compare_func) = sort_type & PHP_SORT_FLAG_CASE ? string_case_compare_function : string_compare_function;
- break;
+ if (f->key == NULL) {
+ if (s->key == NULL) {
+ return (zend_long)f->h > (zend_long)s->h ? 1 : -1;
+ } else {
+ l1 = (zend_long)f->h;
+ t = is_numeric_string(s->key->val, s->key->len, &l2, &d, 1);
+ if (t == IS_LONG) {
+ /* pass */
+ } else if (t == IS_DOUBLE) {
+ return ZEND_NORMALIZE_BOOL((double)l1 - d);
+ } else {
+ l2 = 0;
+ }
+ }
+ } else {
+ if (s->key) {
+ return zendi_smart_strcmp(f->key, s->key);
+ } else {
+ l2 = (zend_long)s->h;
+ t = is_numeric_string(f->key->val, f->key->len, &l1, &d, 1);
+ if (t == IS_LONG) {
+ /* pass */
+ } else if (t == IS_DOUBLE) {
+ return ZEND_NORMALIZE_BOOL(d - (double)l2);
+ } else {
+ l1 = 0;
+ }
+ }
+ }
+ return l1 > l2 ? 1 : (l1 < l2 ? -1 : 0);
+}
+/* }}} */
- case PHP_SORT_NATURAL:
- ARRAYG(compare_func) = sort_type & PHP_SORT_FLAG_CASE ? string_natural_case_compare_function : string_natural_compare_function;
- break;
+static int php_array_reverse_key_compare(const void *a, const void *b) /* {{{ */
+{
+ return php_array_key_compare(b, a);
+}
+/* }}} */
+
+static int php_array_key_compare_numeric(const void *a, const void *b) /* {{{ */
+{
+ Bucket *f = (Bucket *) a;
+ Bucket *s = (Bucket *) b;
+
+ if (f->key == NULL && s->key == NULL) {
+ return (zend_long)f->h > (zend_long)s->h ? 1 : -1;
+ } else {
+ double d1, d2;
+ if (f->key) {
+ d1 = zend_strtod(f->key->val, NULL);
+ } else {
+ d1 = (double)(zend_long)f->h;
+ }
+ if (s->key) {
+ d2 = zend_strtod(s->key->val, NULL);
+ } else {
+ d2 = (double)(zend_long)s->h;
+ }
+ return ZEND_NORMALIZE_BOOL(d1 - d2);
+ }
+}
+/* }}} */
+
+static int php_array_reverse_key_compare_numeric(const void *a, const void *b) /* {{{ */
+{
+ return php_array_key_compare_numeric(b, a);
+}
+/* }}} */
+
+static int php_array_key_compare_string_case(const void *a, const void *b) /* {{{ */
+{
+ Bucket *f = (Bucket *) a;
+ Bucket *s = (Bucket *) b;
+ char *s1, *s2;
+ size_t l1, l2;
+ char buf1[MAX_LENGTH_OF_LONG + 1];
+ char buf2[MAX_LENGTH_OF_LONG + 1];
+
+ if (f->key) {
+ s1 = f->key->val;
+ l1 = f->key->len;
+ } else {
+ s1 = zend_print_long_to_buf(buf1 + sizeof(buf1) - 1, f->h);
+ l1 = buf1 + sizeof(buf1) - 1 - s1;
+ }
+ if (s->key) {
+ s2 = s->key->val;
+ l2 = s->key->len;
+ } else {
+ s2 = zend_print_long_to_buf(buf2 + sizeof(buf2) - 1, s->h);
+ l2 = buf2 + sizeof(buf2) - 1 - s1;
+ }
+ return zend_binary_strcasecmp_l(s1, l1, s2, l2);
+}
+/* }}} */
+
+static int php_array_reverse_key_compare_string_case(const void *a, const void *b) /* {{{ */
+{
+ return php_array_key_compare_string_case(b, a);
+}
+/* }}} */
+
+static int php_array_key_compare_string(const void *a, const void *b) /* {{{ */
+{
+ Bucket *f = (Bucket *) a;
+ Bucket *s = (Bucket *) b;
+ char *s1, *s2;
+ size_t l1, l2;
+ char buf1[MAX_LENGTH_OF_LONG + 1];
+ char buf2[MAX_LENGTH_OF_LONG + 1];
+
+ if (f->key) {
+ s1 = f->key->val;
+ l1 = f->key->len;
+ } else {
+ s1 = zend_print_long_to_buf(buf1 + sizeof(buf1) - 1, f->h);
+ l1 = buf1 + sizeof(buf1) - 1 - s1;
+ }
+ if (s->key) {
+ s2 = s->key->val;
+ l2 = s->key->len;
+ } else {
+ s2 = zend_print_long_to_buf(buf2 + sizeof(buf2) - 1, s->h);
+ l2 = buf2 + sizeof(buf2) - 1 - s2;
+ }
+ return zend_binary_strcmp(s1, l1, s2, l2);
+}
+/* }}} */
+
+static int php_array_reverse_key_compare_string(const void *a, const void *b) /* {{{ */
+{
+ return php_array_key_compare_string(b, a);
+}
+/* }}} */
+
+static int php_array_key_compare_string_natural_general(const void *a, const void *b, int fold_case) /* {{{ */
+{
+ Bucket *f = (Bucket *) a;
+ Bucket *s = (Bucket *) b;
+ char *s1, *s2;
+ size_t l1, l2;
+ char buf1[MAX_LENGTH_OF_LONG + 1];
+ char buf2[MAX_LENGTH_OF_LONG + 1];
+
+ if (f->key) {
+ s1 = f->key->val;
+ l1 = f->key->len;
+ } else {
+ s1 = zend_print_long_to_buf(buf1 + sizeof(buf1) - 1, f->h);
+ l1 = buf1 + sizeof(buf1) - 1 - s1;
+ }
+ if (s->key) {
+ s2 = s->key->val;
+ l2 = s->key->len;
+ } else {
+ s2 = zend_print_long_to_buf(buf2 + sizeof(buf2) - 1, s->h);
+ l2 = buf2 + sizeof(buf2) - 1 - s1;
+ }
+ return strnatcmp_ex(s1, l1, s2, l2, fold_case);
+}
+/* }}} */
+
+static int php_array_key_compare_string_natural_case(const void *a, const void *b) /* {{{ */
+{
+ return php_array_key_compare_string_natural_general(a, b, 1);
+}
+/* }}} */
+
+static int php_array_reverse_key_compare_string_natural_case(const void *a, const void *b) /* {{{ */
+{
+ return php_array_key_compare_string_natural_general(b, a, 1);
+}
+/* }}} */
+
+static int php_array_key_compare_string_natural(const void *a, const void *b) /* {{{ */
+{
+ return php_array_key_compare_string_natural_general(a, b, 0);
+}
+/* }}} */
+
+static int php_array_reverse_key_compare_string_natural(const void *a, const void *b) /* {{{ */
+{
+ return php_array_key_compare_string_natural_general(b, a, 0);
+}
+/* }}} */
#if HAVE_STRCOLL
- case PHP_SORT_LOCALE_STRING:
- ARRAYG(compare_func) = string_locale_compare_function;
- break;
-#endif
+static int php_array_key_compare_string_locale(const void *a, const void *b) /* {{{ */
+{
+ Bucket *f = (Bucket *) a;
+ Bucket *s = (Bucket *) b;
+ char *s1, *s2;
+ char buf1[MAX_LENGTH_OF_LONG + 1];
+ char buf2[MAX_LENGTH_OF_LONG + 1];
- case PHP_SORT_REGULAR:
- default:
- ARRAYG(compare_func) = zval_compare_function;
- break;
+ if (f->key) {
+ s1 = f->key->val;
+ } else {
+ s1 = zend_print_long_to_buf(buf1 + sizeof(buf1) - 1, f->h);
}
+ if (s->key) {
+ s2 = s->key->val;
+ } else {
+ s2 = zend_print_long_to_buf(buf2 + sizeof(buf2) - 1, s->h);
+ }
+ return strcoll(s1, s2);
}
/* }}} */
-static int php_array_key_compare(const void *a, const void *b) /* {{{ */
+static int php_array_reverse_key_compare_string_locale(const void *a, const void *b) /* {{{ */
+{
+ return php_array_key_compare_string_locale(b, a);
+}
+/* }}} */
+#endif
+
+/* Numbers are always smaller than strings int this function as it
+ * anyway doesn't make much sense to compare two different data types.
+ * This keeps it consistent and simple.
+ *
+ * This is not correct any more, depends on what compare_func is set to.
+ */
+static int php_array_data_compare(const void *a, const void *b) /* {{{ */
{
Bucket *f;
Bucket *s;
zval result;
- zval first;
- zval second;
+ zval *first;
+ zval *second;
f = (Bucket *) a;
s = (Bucket *) b;
- if (f->key == NULL) {
- ZVAL_LONG(&first, f->h);
- } else {
- ZVAL_STR(&first, f->key);
+ first = &f->val;
+ second = &s->val;
+
+ if (UNEXPECTED(Z_TYPE_P(first) == IS_INDIRECT)) {
+ first = Z_INDIRECT_P(first);
+ }
+ if (UNEXPECTED(Z_TYPE_P(second) == IS_INDIRECT)) {
+ second = Z_INDIRECT_P(second);
+ }
+ if (compare_function(&result, first, second) == FAILURE) {
+ return 0;
}
- if (s->key == NULL) {
- ZVAL_LONG(&second, s->h);
- } else {
- ZVAL_STR(&second, s->key);
+ ZEND_ASSERT(Z_TYPE(result) == IS_LONG);
+ return Z_LVAL(result);
+}
+/* }}} */
+
+static int php_array_reverse_data_compare(const void *a, const void *b) /* {{{ */
+{
+ return php_array_data_compare(a, b) * -1;
+}
+/* }}} */
+
+static int php_array_data_compare_numeric(const void *a, const void *b) /* {{{ */
+{
+ Bucket *f;
+ Bucket *s;
+ zval *first;
+ zval *second;
+
+ f = (Bucket *) a;
+ s = (Bucket *) b;
+
+ first = &f->val;
+ second = &s->val;
+
+ if (UNEXPECTED(Z_TYPE_P(first) == IS_INDIRECT)) {
+ first = Z_INDIRECT_P(first);
+ }
+ if (UNEXPECTED(Z_TYPE_P(second) == IS_INDIRECT)) {
+ second = Z_INDIRECT_P(second);
}
- if (ARRAYG(compare_func)(&result, &first, &second) == FAILURE) {
- return 0;
+ return numeric_compare_function(first, second);
+}
+/* }}} */
+
+static int php_array_reverse_data_compare_numeric(const void *a, const void *b) /* {{{ */
+{
+ return php_array_data_compare_numeric(b, a);
+}
+/* }}} */
+
+static int php_array_data_compare_string_case(const void *a, const void *b) /* {{{ */
+{
+ Bucket *f;
+ Bucket *s;
+ zval *first;
+ zval *second;
+
+ f = (Bucket *) a;
+ s = (Bucket *) b;
+
+ first = &f->val;
+ second = &s->val;
+
+ if (UNEXPECTED(Z_TYPE_P(first) == IS_INDIRECT)) {
+ first = Z_INDIRECT_P(first);
}
+ if (UNEXPECTED(Z_TYPE_P(second) == IS_INDIRECT)) {
+ second = Z_INDIRECT_P(second);
+ }
+
+ return string_case_compare_function(first, second);
+}
+/* }}} */
+
+static int php_array_reverse_data_compare_string_case(const void *a, const void *b) /* {{{ */
+{
+ return php_array_data_compare_string_case(b, a);
+}
+/* }}} */
+
+static int php_array_data_compare_string(const void *a, const void *b) /* {{{ */
+{
+ Bucket *f;
+ Bucket *s;
+ zval *first;
+ zval *second;
+
+ f = (Bucket *) a;
+ s = (Bucket *) b;
+
+ first = &f->val;
+ second = &s->val;
- if (EXPECTED(Z_TYPE(result) == IS_LONG)) {
- return ZEND_NORMALIZE_BOOL(Z_LVAL(result));
- } else if (Z_TYPE(result) == IS_DOUBLE) {
- return ZEND_NORMALIZE_BOOL(Z_DVAL(result));
+ if (UNEXPECTED(Z_TYPE_P(first) == IS_INDIRECT)) {
+ first = Z_INDIRECT_P(first);
+ }
+ if (UNEXPECTED(Z_TYPE_P(second) == IS_INDIRECT)) {
+ second = Z_INDIRECT_P(second);
}
- return ZEND_NORMALIZE_BOOL(zval_get_long(&result));
+ return string_compare_function(first, second);
}
/* }}} */
-static int php_array_reverse_key_compare(const void *a, const void *b) /* {{{ */
+static int php_array_reverse_data_compare_string(const void *a, const void *b) /* {{{ */
+{
+ return php_array_data_compare_string(b, a);
+}
+/* }}} */
+
+static int php_array_natural_general_compare(const void *a, const void *b, int fold_case) /* {{{ */
+{
+ Bucket *f = (Bucket *) a;
+ Bucket *s = (Bucket *) b;
+ zend_string *str1 = zval_get_string(&f->val);
+ zend_string *str2 = zval_get_string(&s->val);
+
+ int result = strnatcmp_ex(ZSTR_VAL(str1), ZSTR_LEN(str1), ZSTR_VAL(str2), ZSTR_LEN(str2), fold_case);
+
+ zend_string_release(str1);
+ zend_string_release(str2);
+ return result;
+}
+/* }}} */
+
+static int php_array_natural_compare(const void *a, const void *b) /* {{{ */
+{
+ return php_array_natural_general_compare(a, b, 0);
+}
+/* }}} */
+
+static int php_array_reverse_natural_compare(const void *a, const void *b) /* {{{ */
+{
+ return php_array_natural_general_compare(b, a, 0);
+}
+/* }}} */
+
+static int php_array_natural_case_compare(const void *a, const void *b) /* {{{ */
+{
+ return php_array_natural_general_compare(a, b, 1);
+}
+/* }}} */
+
+static int php_array_reverse_natural_case_compare(const void *a, const void *b) /* {{{ */
+{
+ return php_array_natural_general_compare(b, a, 1);
+}
+/* }}} */
+
+#if HAVE_STRCOLL
+static int php_array_data_compare_string_locale(const void *a, const void *b) /* {{{ */
+{
+ Bucket *f;
+ Bucket *s;
+ zval *first;
+ zval *second;
+
+ f = (Bucket *) a;
+ s = (Bucket *) b;
+
+ first = &f->val;
+ second = &s->val;
+
+ if (UNEXPECTED(Z_TYPE_P(first) == IS_INDIRECT)) {
+ first = Z_INDIRECT_P(first);
+ }
+ if (UNEXPECTED(Z_TYPE_P(second) == IS_INDIRECT)) {
+ second = Z_INDIRECT_P(second);
+ }
+
+ return string_locale_compare_function(first, second);
+}
+/* }}} */
+
+static int php_array_reverse_data_compare_string_locale(const void *a, const void *b) /* {{{ */
+{
+ return php_array_data_compare_string_locale(b, a);
+}
+/* }}} */
+#endif
+
+static compare_func_t php_get_key_compare_func(zend_long sort_type, int reverse) /* {{{ */
+{
+ switch (sort_type & ~PHP_SORT_FLAG_CASE) {
+ case PHP_SORT_NUMERIC:
+ if (reverse) {
+ return php_array_reverse_key_compare_numeric;
+ } else {
+ return php_array_key_compare_numeric;
+ }
+ break;
+
+ case PHP_SORT_STRING:
+ if (sort_type & PHP_SORT_FLAG_CASE) {
+ if (reverse) {
+ return php_array_reverse_key_compare_string_case;
+ } else {
+ return php_array_key_compare_string_case;
+ }
+ } else {
+ if (reverse) {
+ return php_array_reverse_key_compare_string;
+ } else {
+ return php_array_key_compare_string;
+ }
+ }
+ break;
+
+ case PHP_SORT_NATURAL:
+ if (sort_type & PHP_SORT_FLAG_CASE) {
+ if (reverse) {
+ return php_array_reverse_key_compare_string_natural_case;
+ } else {
+ return php_array_key_compare_string_natural_case;
+ }
+ } else {
+ if (reverse) {
+ return php_array_reverse_key_compare_string_natural;
+ } else {
+ return php_array_key_compare_string_natural;
+ }
+ }
+ break;
+
+#if HAVE_STRCOLL
+ case PHP_SORT_LOCALE_STRING:
+ if (reverse) {
+ return php_array_reverse_key_compare_string_locale;
+ } else {
+ return php_array_key_compare_string_locale;
+ }
+ break;
+#endif
+
+ case PHP_SORT_REGULAR:
+ default:
+ if (reverse) {
+ return php_array_reverse_key_compare;
+ } else {
+ return php_array_key_compare;
+ }
+ break;
+ }
+ return NULL;
+}
+/* }}} */
+
+static compare_func_t php_get_data_compare_func(zend_long sort_type, int reverse) /* {{{ */
{
- return php_array_key_compare(a, b) * -1;
+ switch (sort_type & ~PHP_SORT_FLAG_CASE) {
+ case PHP_SORT_NUMERIC:
+ if (reverse) {
+ return php_array_reverse_data_compare_numeric;
+ } else {
+ return php_array_data_compare_numeric;
+ }
+ break;
+
+ case PHP_SORT_STRING:
+ if (sort_type & PHP_SORT_FLAG_CASE) {
+ if (reverse) {
+ return php_array_reverse_data_compare_string_case;
+ } else {
+ return php_array_data_compare_string_case;
+ }
+ } else {
+ if (reverse) {
+ return php_array_reverse_data_compare_string;
+ } else {
+ return php_array_data_compare_string;
+ }
+ }
+ break;
+
+ case PHP_SORT_NATURAL:
+ if (sort_type & PHP_SORT_FLAG_CASE) {
+ if (reverse) {
+ return php_array_reverse_natural_case_compare;
+ } else {
+ return php_array_natural_case_compare;
+ }
+ } else {
+ if (reverse) {
+ return php_array_reverse_natural_compare;
+ } else {
+ return php_array_natural_compare;
+ }
+ }
+ break;
+
+#if HAVE_STRCOLL
+ case PHP_SORT_LOCALE_STRING:
+ if (reverse) {
+ return php_array_reverse_data_compare_string_locale;
+ } else {
+ return php_array_data_compare_string_locale;
+ }
+ break;
+#endif
+
+ case PHP_SORT_REGULAR:
+ default:
+ if (reverse) {
+ return php_array_reverse_data_compare;
+ } else {
+ return php_array_data_compare;
+ }
+ break;
+ }
+ return NULL;
}
/* }}} */
@@ -219,6 +701,7 @@ PHP_FUNCTION(krsort)
{
zval *array;
zend_long sort_type = PHP_SORT_REGULAR;
+ compare_func_t cmp;
#ifndef FAST_ZPP
if (zend_parse_parameters(ZEND_NUM_ARGS(), "a/|l", &array, &sort_type) == FAILURE) {
@@ -232,9 +715,9 @@ PHP_FUNCTION(krsort)
ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE);
#endif
- php_set_compare_func(sort_type);
+ cmp = php_get_key_compare_func(sort_type, 1);
- if (zend_hash_sort(Z_ARRVAL_P(array), php_array_reverse_key_compare, 0) == FAILURE) {
+ if (zend_hash_sort(Z_ARRVAL_P(array), cmp, 0) == FAILURE) {
RETURN_FALSE;
}
RETURN_TRUE;
@@ -247,6 +730,7 @@ PHP_FUNCTION(ksort)
{
zval *array;
zend_long sort_type = PHP_SORT_REGULAR;
+ compare_func_t cmp;
#ifndef FAST_ZPP
if (zend_parse_parameters(ZEND_NUM_ARGS(), "a/|l", &array, &sort_type) == FAILURE) {
@@ -260,9 +744,9 @@ PHP_FUNCTION(ksort)
ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE);
#endif
- php_set_compare_func(sort_type);
+ cmp = php_get_key_compare_func(sort_type, 0);
- if (zend_hash_sort(Z_ARRVAL_P(array), php_array_key_compare, 0) == FAILURE) {
+ if (zend_hash_sort(Z_ARRVAL_P(array), cmp, 0) == FAILURE) {
RETURN_FALSE;
}
RETURN_TRUE;
@@ -280,7 +764,7 @@ PHPAPI zend_long php_count_recursive(zval *array, zend_long mode) /* {{{ */
return 0;
}
- cnt = zend_hash_num_elements(Z_ARRVAL_P(array));
+ cnt = zend_array_count(Z_ARRVAL_P(array));
if (mode == COUNT_RECURSIVE) {
if (ZEND_HASH_APPLY_PROTECTION(Z_ARRVAL_P(array))) {
Z_ARRVAL_P(array)->u.v.nApplyCount++;
@@ -325,7 +809,7 @@ PHP_FUNCTION(count)
RETURN_LONG(0);
break;
case IS_ARRAY:
- cnt = zend_hash_num_elements(Z_ARRVAL_P(array));
+ cnt = zend_array_count(Z_ARRVAL_P(array));
if (mode == COUNT_RECURSIVE) {
ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(array), element) {
ZVAL_DEREF(element);
@@ -335,9 +819,7 @@ PHP_FUNCTION(count)
RETURN_LONG(cnt);
break;
case IS_OBJECT: {
-#ifdef HAVE_SPL
zval retval;
-#endif
/* first, we check if the handler is defined */
if (Z_OBJ_HT_P(array)->count_elements) {
RETVAL_LONG(1);
@@ -345,7 +827,6 @@ PHP_FUNCTION(count)
return;
}
}
-#ifdef HAVE_SPL
/* if not and the object implements Countable we call its count() method */
if (instanceof_function(Z_OBJCE_P(array), spl_ce_Countable)) {
zend_call_method_with_0_params(array, NULL, NULL, "count", &retval);
@@ -355,7 +836,6 @@ PHP_FUNCTION(count)
}
return;
}
-#endif
}
default:
RETURN_LONG(1);
@@ -364,79 +844,6 @@ PHP_FUNCTION(count)
}
/* }}} */
-/* Numbers are always smaller than strings int this function as it
- * anyway doesn't make much sense to compare two different data types.
- * This keeps it consistent and simple.
- *
- * This is not correct any more, depends on what compare_func is set to.
- */
-static int php_array_data_compare(const void *a, const void *b) /* {{{ */
-{
- Bucket *f;
- Bucket *s;
- zval result;
- zval *first;
- zval *second;
-
- f = (Bucket *) a;
- s = (Bucket *) b;
-
- first = &f->val;
- second = &s->val;
-
- if (Z_TYPE_P(first) == IS_INDIRECT) {
- first = Z_INDIRECT_P(first);
- }
- if (Z_TYPE_P(second) == IS_INDIRECT) {
- second = Z_INDIRECT_P(second);
- }
- if (ARRAYG(compare_func)(&result, first, second) == FAILURE) {
- return 0;
- }
-
- if (EXPECTED(Z_TYPE(result) == IS_LONG)) {
- return ZEND_NORMALIZE_BOOL(Z_LVAL(result));
- } else if (Z_TYPE(result) == IS_DOUBLE) {
- return ZEND_NORMALIZE_BOOL(Z_DVAL(result));
- }
-
- return ZEND_NORMALIZE_BOOL(zval_get_long(&result));
-}
-/* }}} */
-
-static int php_array_reverse_data_compare(const void *a, const void *b) /* {{{ */
-{
- return php_array_data_compare(a, b) * -1;
-}
-/* }}} */
-
-static int php_array_natural_general_compare(const void *a, const void *b, int fold_case) /* {{{ */
-{
- Bucket *f = (Bucket *) a;
- Bucket *s = (Bucket *) b;
- zend_string *str1 = zval_get_string(&f->val);
- zend_string *str2 = zval_get_string(&s->val);
-
- int result = strnatcmp_ex(ZSTR_VAL(str1), ZSTR_LEN(str1), ZSTR_VAL(str2), ZSTR_LEN(str2), fold_case);
-
- zend_string_release(str1);
- zend_string_release(str2);
- return result;
-}
-/* }}} */
-
-static int php_array_natural_compare(const void *a, const void *b) /* {{{ */
-{
- return php_array_natural_general_compare(a, b, 0);
-}
-/* }}} */
-
-static int php_array_natural_case_compare(const void *a, const void *b) /* {{{ */
-{
- return php_array_natural_general_compare(a, b, 1);
-}
-/* }}} */
-
static void php_natsort(INTERNAL_FUNCTION_PARAMETERS, int fold_case) /* {{{ */
{
zval *array;
@@ -481,14 +888,15 @@ PHP_FUNCTION(asort)
{
zval *array;
zend_long sort_type = PHP_SORT_REGULAR;
+ compare_func_t cmp;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "a/|l", &array, &sort_type) == FAILURE) {
RETURN_FALSE;
}
- php_set_compare_func(sort_type);
+ cmp = php_get_data_compare_func(sort_type, 0);
- if (zend_hash_sort(Z_ARRVAL_P(array), php_array_data_compare, 0) == FAILURE) {
+ if (zend_hash_sort(Z_ARRVAL_P(array), cmp, 0) == FAILURE) {
RETURN_FALSE;
}
RETURN_TRUE;
@@ -501,14 +909,15 @@ PHP_FUNCTION(arsort)
{
zval *array;
zend_long sort_type = PHP_SORT_REGULAR;
+ compare_func_t cmp;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "a/|l", &array, &sort_type) == FAILURE) {
RETURN_FALSE;
}
- php_set_compare_func(sort_type);
+ cmp = php_get_data_compare_func(sort_type, 1);
- if (zend_hash_sort(Z_ARRVAL_P(array), php_array_reverse_data_compare, 0) == FAILURE) {
+ if (zend_hash_sort(Z_ARRVAL_P(array), cmp, 0) == FAILURE) {
RETURN_FALSE;
}
RETURN_TRUE;
@@ -521,14 +930,15 @@ PHP_FUNCTION(sort)
{
zval *array;
zend_long sort_type = PHP_SORT_REGULAR;
+ compare_func_t cmp;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "a/|l", &array, &sort_type) == FAILURE) {
RETURN_FALSE;
}
- php_set_compare_func(sort_type);
+ cmp = php_get_data_compare_func(sort_type, 0);
- if (zend_hash_sort(Z_ARRVAL_P(array), php_array_data_compare, 1) == FAILURE) {
+ if (zend_hash_sort(Z_ARRVAL_P(array), cmp, 1) == FAILURE) {
RETURN_FALSE;
}
RETURN_TRUE;
@@ -541,14 +951,15 @@ PHP_FUNCTION(rsort)
{
zval *array;
zend_long sort_type = PHP_SORT_REGULAR;
+ compare_func_t cmp;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "a/|l", &array, &sort_type) == FAILURE) {
RETURN_FALSE;
}
- php_set_compare_func(sort_type);
+ cmp = php_get_data_compare_func(sort_type, 1);
- if (zend_hash_sort(Z_ARRVAL_P(array), php_array_reverse_data_compare, 1) == FAILURE) {
+ if (zend_hash_sort(Z_ARRVAL_P(array), cmp, 1) == FAILURE) {
RETURN_FALSE;
}
RETURN_TRUE;
@@ -615,48 +1026,44 @@ static int php_array_user_compare(const void *a, const void *b) /* {{{ */
BG(user_compare_fci) = old_user_compare_fci; \
BG(user_compare_fci_cache) = old_user_compare_fci_cache; \
-/* {{{ proto bool usort(array array_arg, string cmp_function)
- Sort an array by values using a user-defined comparison function */
-PHP_FUNCTION(usort)
+static void php_usort(INTERNAL_FUNCTION_PARAMETERS, compare_func_t compare_func, zend_bool renumber) /* {{{ */
{
zval *array;
- zend_refcounted *arr;
- unsigned int refcount;
+ zend_array *arr;
+ zend_bool retval;
PHP_ARRAY_CMP_FUNC_VARS;
PHP_ARRAY_CMP_FUNC_BACKUP();
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "a/f", &array, &BG(user_compare_fci), &BG(user_compare_fci_cache)) == FAILURE) {
+ if (zend_parse_parameters(ZEND_NUM_ARGS(), "af", &array, &BG(user_compare_fci), &BG(user_compare_fci_cache)) == FAILURE) {
PHP_ARRAY_CMP_FUNC_RESTORE();
return;
}
- /* Increase reference counter, so the attempts to modify the array in user
- * comparison function will create a copy of array and won't affect the
- * original array. The fact of modification is detected using refcount
- * comparison. The result of sorting in such case is undefined and the
- * function returns FALSE.
- */
- Z_ADDREF_P(array);
- refcount = Z_REFCOUNT_P(array);
- arr = Z_COUNTED_P(array);
-
- if (zend_hash_sort(Z_ARRVAL_P(array), php_array_user_compare, 1) == FAILURE) {
- RETVAL_FALSE;
- } else {
- if (refcount > Z_REFCOUNT_P(array)) {
- php_error_docref(NULL, E_WARNING, "Array was modified by the user comparison function");
- if (--GC_REFCOUNT(arr) <= 0) {
- _zval_dtor_func(arr ZEND_FILE_LINE_CC);
- }
- RETVAL_FALSE;
- } else {
- Z_DELREF_P(array);
- RETVAL_TRUE;
- }
+ arr = Z_ARR_P(array);
+ if (zend_hash_num_elements(arr) == 0) {
+ PHP_ARRAY_CMP_FUNC_RESTORE();
+ RETURN_TRUE;
}
+ /* Copy array, so the in-place modifications will not be visible to the callback function */
+ arr = zend_array_dup(arr);
+
+ retval = zend_hash_sort(arr, compare_func, renumber) != FAILURE;
+
+ zval_ptr_dtor(array);
+ ZVAL_ARR(array, arr);
+
PHP_ARRAY_CMP_FUNC_RESTORE();
+ RETURN_BOOL(retval);
+}
+/* }}} */
+
+/* {{{ proto bool usort(array array_arg, string cmp_function)
+ Sort an array by values using a user-defined comparison function */
+PHP_FUNCTION(usort)
+{
+ php_usort(INTERNAL_FUNCTION_PARAM_PASSTHRU, php_array_user_compare, 1);
}
/* }}} */
@@ -664,44 +1071,7 @@ PHP_FUNCTION(usort)
Sort an array with a user-defined comparison function and maintain index association */
PHP_FUNCTION(uasort)
{
- zval *array;
- zend_refcounted *arr;
- unsigned int refcount;
- PHP_ARRAY_CMP_FUNC_VARS;
-
- PHP_ARRAY_CMP_FUNC_BACKUP();
-
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "a/f", &array, &BG(user_compare_fci), &BG(user_compare_fci_cache)) == FAILURE) {
- PHP_ARRAY_CMP_FUNC_RESTORE();
- return;
- }
-
- /* Increase reference counter, so the attempts to modify the array in user
- * comparison function will create a copy of array and won't affect the
- * original array. The fact of modification is detected using refcount
- * comparison. The result of sorting in such case is undefined and the
- * function returns FALSE.
- */
- Z_ADDREF_P(array);
- refcount = Z_REFCOUNT_P(array);
- arr = Z_COUNTED_P(array);
-
- if (zend_hash_sort(Z_ARRVAL_P(array), php_array_user_compare, 0) == FAILURE) {
- RETVAL_FALSE;
- } else {
- if (refcount > Z_REFCOUNT_P(array)) {
- php_error_docref(NULL, E_WARNING, "Array was modified by the user comparison function");
- if (--GC_REFCOUNT(arr) <= 0) {
- _zval_dtor_func(arr ZEND_FILE_LINE_CC);
- }
- RETVAL_FALSE;
- } else {
- Z_DELREF_P(array);
- RETVAL_TRUE;
- }
- }
-
- PHP_ARRAY_CMP_FUNC_RESTORE();
+ php_usort(INTERNAL_FUNCTION_PARAM_PASSTHRU, php_array_user_compare, 0);
}
/* }}} */
@@ -752,44 +1122,7 @@ static int php_array_user_key_compare(const void *a, const void *b) /* {{{ */
Sort an array by keys using a user-defined comparison function */
PHP_FUNCTION(uksort)
{
- zval *array;
- zend_refcounted *arr;
- unsigned int refcount;
- PHP_ARRAY_CMP_FUNC_VARS;
-
- PHP_ARRAY_CMP_FUNC_BACKUP();
-
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "a/f", &array, &BG(user_compare_fci), &BG(user_compare_fci_cache)) == FAILURE) {
- PHP_ARRAY_CMP_FUNC_RESTORE();
- return;
- }
-
- /* Increase reference counter, so the attempts to modify the array in user
- * comparison function will create a copy of array and won't affect the
- * original array. The fact of modification is detected using refcount
- * comparison. The result of sorting in such case is undefined and the
- * function returns FALSE.
- */
- Z_ADDREF_P(array);
- refcount = Z_REFCOUNT_P(array);
- arr = Z_COUNTED_P(array);
-
- if (zend_hash_sort(Z_ARRVAL_P(array), php_array_user_key_compare, 0) == FAILURE) {
- RETVAL_FALSE;
- } else {
- if (refcount > Z_REFCOUNT_P(array)) {
- php_error_docref(NULL, E_WARNING, "Array was modified by the user comparison function");
- if (--GC_REFCOUNT(arr) <= 0) {
- _zval_dtor_func(arr ZEND_FILE_LINE_CC);
- }
- RETVAL_FALSE;
- } else {
- Z_DELREF_P(array);
- RETVAL_TRUE;
- }
- }
-
- PHP_ARRAY_CMP_FUNC_RESTORE();
+ php_usort(INTERNAL_FUNCTION_PARAM_PASSTHRU, php_array_user_key_compare, 0);
}
/* }}} */
@@ -990,8 +1323,6 @@ PHP_FUNCTION(min)
return;
}
- php_set_compare_func(PHP_SORT_REGULAR);
-
/* mixed min ( array $values ) */
if (argc == 1) {
zval *result;
@@ -1039,8 +1370,6 @@ PHP_FUNCTION(max)
return;
}
- php_set_compare_func(PHP_SORT_REGULAR);
-
/* mixed max ( array $values ) */
if (argc == 1) {
zval *result;
@@ -1084,7 +1413,6 @@ static int php_array_walk(HashTable *target_hash, zval *userdata, int recursive)
*zv;
/* Set up known arguments */
- ZVAL_UNDEF(&retval);
ZVAL_UNDEF(&args[1]);
if (userdata) {
ZVAL_COPY(&args[2], userdata);
@@ -1112,12 +1440,9 @@ static int php_array_walk(HashTable *target_hash, zval *userdata, int recursive)
zend_fcall_info orig_array_walk_fci;
zend_fcall_info_cache orig_array_walk_fci_cache;
- if (Z_ISREF_P(zv)) {
- thash = Z_ARRVAL_P(Z_REFVAL_P(zv));
- } else {
- SEPARATE_ZVAL(zv);
- thash = Z_ARRVAL_P(zv);
- }
+ ZVAL_DEREF(zv);
+ SEPARATE_ARRAY(zv);
+ thash = Z_ARRVAL_P(zv);
if (thash->u.v.nApplyCount > 1) {
php_error_docref(NULL, E_WARNING, "recursion detected");
if (userdata) {
@@ -1433,7 +1758,7 @@ PHPAPI int php_prefix_varname(zval *result, zval *prefix, char *var_name, size_t
Imports variables into symbol table from an array */
PHP_FUNCTION(extract)
{
- zval *var_array, *prefix = NULL;
+ zval *var_array_param, *prefix = NULL;
zend_long extract_type = EXTR_OVERWRITE;
zval *entry;
zend_string *var_name;
@@ -1441,14 +1766,15 @@ PHP_FUNCTION(extract)
int var_exists, count = 0;
int extract_refs = 0;
zend_array *symbol_table;
+ zval var_array;
#ifndef FAST_ZPP
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "a|lz/", &var_array, &extract_type, &prefix) == FAILURE) {
+ if (zend_parse_parameters(ZEND_NUM_ARGS(), "a|lz/", &var_array_param, &extract_type, &prefix) == FAILURE) {
return;
}
#else
ZEND_PARSE_PARAMETERS_START(1, 3)
- Z_PARAM_ARRAY(var_array)
+ Z_PARAM_ARRAY(var_array_param)
Z_PARAM_OPTIONAL
Z_PARAM_LONG(extract_type)
Z_PARAM_ZVAL_EX(prefix, 0, 1)
@@ -1457,7 +1783,7 @@ PHP_FUNCTION(extract)
extract_refs = (extract_type & EXTR_REFS);
if (extract_refs) {
- SEPARATE_ZVAL(var_array);
+ SEPARATE_ZVAL(var_array_param);
}
extract_type &= 0xff;
@@ -1479,6 +1805,10 @@ PHP_FUNCTION(extract)
}
}
+ if (zend_forbid_dynamic_call("extract()") == FAILURE) {
+ return;
+ }
+
symbol_table = zend_rebuild_symbol_table();
#if 0
if (!symbol_table) {
@@ -1487,7 +1817,11 @@ PHP_FUNCTION(extract)
}
#endif
- ZEND_HASH_FOREACH_KEY_VAL_IND(Z_ARRVAL_P(var_array), num_key, var_name, entry) {
+ /* The array might be stored in a local variable that will be overwritten. To avoid losing the
+ * reference in that case we work on a copy. */
+ ZVAL_COPY(&var_array, var_array_param);
+
+ ZEND_HASH_FOREACH_KEY_VAL_IND(Z_ARRVAL(var_array), num_key, var_name, entry) {
zval final_name;
ZVAL_NULL(&final_name);
@@ -1513,8 +1847,11 @@ PHP_FUNCTION(extract)
if (var_exists && ZSTR_LEN(var_name) == sizeof("GLOBALS")-1 && !strcmp(ZSTR_VAL(var_name), "GLOBALS")) {
break;
}
- if (var_exists && ZSTR_LEN(var_name) == sizeof("this")-1 && !strcmp(ZSTR_VAL(var_name), "this") && EG(scope) && ZSTR_LEN(EG(scope)->name) != 0) {
- break;
+ if (var_exists && ZSTR_LEN(var_name) == sizeof("this")-1 && !strcmp(ZSTR_VAL(var_name), "this")) {
+ zend_class_entry *scope = zend_get_executed_scope();
+ if (scope && ZSTR_LEN(scope->name) != 0) {
+ break;
+ }
}
ZVAL_STR_COPY(&final_name, var_name);
break;
@@ -1555,8 +1892,8 @@ PHP_FUNCTION(extract)
}
if (Z_TYPE(final_name) == IS_STRING && php_valid_var_name(Z_STRVAL(final_name), Z_STRLEN(final_name))) {
+ zval *orig_var;
if (extract_refs) {
- zval *orig_var;
ZVAL_MAKE_REF(entry);
Z_ADDREF_P(entry);
@@ -1571,13 +1908,24 @@ PHP_FUNCTION(extract)
zend_hash_update(symbol_table, Z_STR(final_name), entry);
}
} else {
+ ZVAL_DEREF(entry);
if (Z_REFCOUNTED_P(entry)) Z_ADDREF_P(entry);
- zend_hash_update_ind(symbol_table, Z_STR(final_name), entry);
+ if ((orig_var = zend_hash_find(symbol_table, Z_STR(final_name))) != NULL) {
+ if (Z_TYPE_P(orig_var) == IS_INDIRECT) {
+ orig_var = Z_INDIRECT_P(orig_var);
+ }
+ ZVAL_DEREF(orig_var);
+ zval_ptr_dtor(orig_var);
+ ZVAL_COPY_VALUE(orig_var, entry);
+ } else {
+ zend_hash_update(symbol_table, Z_STR(final_name), entry);
+ }
}
count++;
}
zval_dtor(&final_name);
} ZEND_HASH_FOREACH_END();
+ zval_ptr_dtor(&var_array);
RETURN_LONG(count);
}
@@ -1590,7 +1938,8 @@ static void php_compact_var(HashTable *eg_active_symbol_table, zval *return_valu
ZVAL_DEREF(entry);
if (Z_TYPE_P(entry) == IS_STRING) {
if ((value_ptr = zend_hash_find_ind(eg_active_symbol_table, Z_STR_P(entry))) != NULL) {
- ZVAL_DUP(&data, value_ptr);
+ ZVAL_DEREF(value_ptr);
+ ZVAL_COPY(&data, value_ptr);
zend_hash_update(Z_ARRVAL_P(return_value), Z_STR_P(entry), &data);
}
} else if (Z_TYPE_P(entry) == IS_ARRAY) {
@@ -1624,7 +1973,14 @@ PHP_FUNCTION(compact)
return;
}
+ if (zend_forbid_dynamic_call("compact()") == FAILURE) {
+ return;
+ }
+
symbol_table = zend_rebuild_symbol_table();
+ if (UNEXPECTED(symbol_table == NULL)) {
+ return;
+ }
/* compact() is probably most used with a single array of var_names
or multiple string names, rather than a combination of both.
@@ -1648,34 +2004,73 @@ PHP_FUNCTION(array_fill)
zval *val;
zend_long start_key, num;
+#ifndef FAST_ZPP
if (zend_parse_parameters(ZEND_NUM_ARGS(), "llz", &start_key, &num, &val) == FAILURE) {
return;
}
+#else
+ ZEND_PARSE_PARAMETERS_START(3, 3)
+ Z_PARAM_LONG(start_key)
+ Z_PARAM_LONG(num)
+ Z_PARAM_ZVAL(val)
+ ZEND_PARSE_PARAMETERS_END();
+#endif
- if (num < 0) {
- php_error_docref(NULL, E_WARNING, "Number of elements can't be negative");
- RETURN_FALSE;
- }
+ if (EXPECTED(num > 0)) {
+ if (sizeof(num) > 4 && UNEXPECTED(EXPECTED(num > 0x7fffffff))) {
+ php_error_docref(NULL, E_WARNING, "Too many elements");
+ RETURN_FALSE;
+ } else if (UNEXPECTED(start_key > ZEND_LONG_MAX - num + 1)) {
+ php_error_docref(NULL, E_WARNING, "Cannot add element to the array as the next element is already occupied");
+ RETURN_FALSE;
+ } else if (EXPECTED(start_key >= 0) && EXPECTED(start_key < num)) {
+ /* create packed array */
+ Bucket *p;
+ zend_long n;
- /* allocate an array for return */
- array_init_size(return_value, (uint32_t)num);
+ array_init_size(return_value, (uint32_t)(start_key + num));
+ zend_hash_real_init(Z_ARRVAL_P(return_value), 1);
+ Z_ARRVAL_P(return_value)->nNumUsed = start_key + num;
+ Z_ARRVAL_P(return_value)->nNumOfElements = num;
+ Z_ARRVAL_P(return_value)->nInternalPointer = start_key;
+ Z_ARRVAL_P(return_value)->nNextFreeElement = start_key + num;
- if (num == 0) {
- return;
- }
+ if (Z_REFCOUNTED_P(val)) {
+ GC_REFCOUNT(Z_COUNTED_P(val)) += num;
+ }
- num--;
- zend_hash_index_update(Z_ARRVAL_P(return_value), start_key, val);
- Z_TRY_ADDREF_P(val);
+ p = Z_ARRVAL_P(return_value)->arData;
+ n = start_key;
- while (num--) {
- if (zend_hash_next_index_insert(Z_ARRVAL_P(return_value), val) != NULL) {
- Z_TRY_ADDREF_P(val);
+ while (start_key--) {
+ ZVAL_UNDEF(&p->val);
+ p++;
+ }
+ while (num--) {
+ ZVAL_COPY_VALUE(&p->val, val);
+ p->h = n++;
+ p->key = NULL;
+ p++;
+ }
} else {
- zval_dtor(return_value);
- php_error_docref(NULL, E_WARNING, "Cannot add element to the array as the next element is already occupied");
- RETURN_FALSE;
+ /* create hash */
+ array_init_size(return_value, (uint32_t)num);
+ zend_hash_real_init(Z_ARRVAL_P(return_value), 0);
+ if (Z_REFCOUNTED_P(val)) {
+ GC_REFCOUNT(Z_COUNTED_P(val)) += num;
+ }
+ zend_hash_index_add_new(Z_ARRVAL_P(return_value), start_key, val);
+ while (--num) {
+ zend_hash_next_index_insert_new(Z_ARRVAL_P(return_value), val);
+ start_key++;
+ }
}
+ } else if (EXPECTED(num == 0)) {
+ array_init(return_value);
+ return;
+ } else {
+ php_error_docref(NULL, E_WARNING, "Number of elements can't be negative");
+ RETURN_FALSE;
}
}
/* }}} */
@@ -1707,6 +2102,28 @@ PHP_FUNCTION(array_fill_keys)
}
/* }}} */
+#define RANGE_CHECK_DOUBLE_INIT_ARRAY(start, end) do { \
+ double __calc_size = ((start - end) / step) + 1; \
+ if (__calc_size >= (double)HT_MAX_SIZE) { \
+ php_error_docref(NULL, E_WARNING, "The supplied range exceeds the maximum array size: start=%0.0f end=%0.0f", end, start); \
+ RETURN_FALSE; \
+ } \
+ size = (uint32_t)round(__calc_size); \
+ array_init_size(return_value, size); \
+ zend_hash_real_init(Z_ARRVAL_P(return_value), 1); \
+ } while (0)
+
+#define RANGE_CHECK_LONG_INIT_ARRAY(start, end) do { \
+ zend_ulong __calc_size = (start - end) / lstep; \
+ if (__calc_size >= HT_MAX_SIZE - 1) { \
+ php_error_docref(NULL, E_WARNING, "The supplied range exceeds the maximum array size: start=%pd end=%pd", end, start); \
+ RETURN_FALSE; \
+ } \
+ size = (uint32_t)(__calc_size + 1); \
+ array_init_size(return_value, size); \
+ zend_hash_real_init(Z_ARRVAL_P(return_value), 1); \
+ } while (0)
+
/* {{{ proto array range(mixed low, mixed high[, int step])
Create an array containing the range of integers or characters from low to high (inclusive) */
PHP_FUNCTION(range)
@@ -1803,12 +2220,16 @@ PHP_FUNCTION(range)
zend_hash_next_index_insert_new(Z_ARRVAL_P(return_value), &tmp);
}
} else if (Z_TYPE_P(zlow) == IS_DOUBLE || Z_TYPE_P(zhigh) == IS_DOUBLE || is_step_double) {
- double low, high, value;
- zend_long i;
+ double low, high, element;
+ uint32_t i, size;
double_str:
low = zval_get_double(zlow);
high = zval_get_double(zhigh);
- i = 0;
+
+ if (zend_isinf(high) || zend_isinf(low)) {
+ php_error_docref(NULL, E_WARNING, "Invalid range supplied: start=%0.0f end=%0.0f", low, high);
+ RETURN_FALSE;
+ }
Z_TYPE_INFO(tmp) = IS_DOUBLE;
if (low > high) { /* Negative steps */
@@ -1817,13 +2238,13 @@ double_str:
goto err;
}
- array_init_size(return_value, (uint32_t)(((low - high) / step) + 1));
- zend_hash_real_init(Z_ARRVAL_P(return_value), 1);
+ RANGE_CHECK_DOUBLE_INIT_ARRAY(low, high);
+
ZEND_HASH_FILL_PACKED(Z_ARRVAL_P(return_value)) {
- for (value = low; value >= (high - DOUBLE_DRIFT_FIX); value = low - (++i * step)) {
- Z_DVAL(tmp) = value;
- ZEND_HASH_FILL_ADD(&tmp);
- }
+ for (i = 0, element = low; i < size && element >= high; ++i, element = low - (i * step)) {
+ Z_DVAL(tmp) = element;
+ ZEND_HASH_FILL_ADD(&tmp);
+ }
} ZEND_HASH_FILL_END();
} else if (high > low) { /* Positive steps */
if (high - low < step || step <= 0) {
@@ -1831,11 +2252,11 @@ double_str:
goto err;
}
- array_init_size(return_value, (uint32_t)(((high - low) / step) + 1));
- zend_hash_real_init(Z_ARRVAL_P(return_value), 1);
+ RANGE_CHECK_DOUBLE_INIT_ARRAY(high, low);
+
ZEND_HASH_FILL_PACKED(Z_ARRVAL_P(return_value)) {
- for (value = low; value <= (high + DOUBLE_DRIFT_FIX); value = low + (++i * step)) {
- Z_DVAL(tmp) = value;
+ for (i = 0, element = low; i < size && element <= high; ++i, element = low + (i * step)) {
+ Z_DVAL(tmp) = element;
ZEND_HASH_FILL_ADD(&tmp);
}
} ZEND_HASH_FILL_END();
@@ -1845,43 +2266,53 @@ double_str:
zend_hash_next_index_insert_new(Z_ARRVAL_P(return_value), &tmp);
}
} else {
- double low, high;
- zend_long lstep;
+ zend_long low, high;
+ /* lstep is a ulong so that comparisons to it don't overflow, i.e. low - high < lstep */
+ zend_ulong lstep;
+ uint32_t i, size;
long_str:
- low = zval_get_double(zlow);
- high = zval_get_double(zhigh);
- lstep = (zend_long) step;
+ low = zval_get_long(zlow);
+ high = zval_get_long(zhigh);
+
+ if (step <= 0) {
+ err = 1;
+ goto err;
+ }
+
+ lstep = step;
Z_TYPE_INFO(tmp) = IS_LONG;
if (low > high) { /* Negative steps */
- if (low - high < lstep || lstep <= 0) {
+ if (low - high < lstep) {
err = 1;
goto err;
}
- array_init_size(return_value, (uint32_t)(((low - high) / lstep) + 1));
- zend_hash_real_init(Z_ARRVAL_P(return_value), 1);
+
+ RANGE_CHECK_LONG_INIT_ARRAY(low, high);
+
ZEND_HASH_FILL_PACKED(Z_ARRVAL_P(return_value)) {
- for (; low >= high; low -= lstep) {
- Z_LVAL(tmp) = (zend_long)low;
+ for (i = 0; i < size; ++i) {
+ Z_LVAL(tmp) = low - (i * lstep);
ZEND_HASH_FILL_ADD(&tmp);
}
} ZEND_HASH_FILL_END();
} else if (high > low) { /* Positive steps */
- if (high - low < lstep || lstep <= 0) {
+ if (high - low < lstep) {
err = 1;
goto err;
}
- array_init_size(return_value, (uint32_t)(((high - low) / lstep) + 1));
- zend_hash_real_init(Z_ARRVAL_P(return_value), 1);
+
+ RANGE_CHECK_LONG_INIT_ARRAY(high, low);
+
ZEND_HASH_FILL_PACKED(Z_ARRVAL_P(return_value)) {
- for (; low <= high; low += lstep) {
- Z_LVAL(tmp) = (zend_long)low;
+ for (i = 0; i < size; ++i) {
+ Z_LVAL(tmp) = low + (i * lstep);
ZEND_HASH_FILL_ADD(&tmp);
}
} ZEND_HASH_FILL_END();
} else {
array_init(return_value);
- Z_LVAL(tmp) = (zend_long)low;
+ Z_LVAL(tmp) = low;
zend_hash_next_index_insert_new(Z_ARRVAL_P(return_value), &tmp);
}
}
@@ -1893,6 +2324,9 @@ err:
}
/* }}} */
+#undef RANGE_CHECK_DOUBLE_INIT_ARRAY
+#undef RANGE_CHECK_LONG_INIT_ARRAY
+
static void php_array_data_shuffle(zval *array) /* {{{ */
{
uint32_t idx, j, n_elems;
@@ -2611,6 +3045,10 @@ PHPAPI int php_array_merge_recursive(HashTable *dest, HashTable *src) /* {{{ */
if (Z_TYPE_P(dest_zval) == IS_NULL) {
convert_to_array_ex(dest_zval);
add_next_index_null(dest_zval);
+ } else if (Z_TYPE_P(dest_zval) == IS_ARRAY) {
+ if (UNEXPECTED(Z_ARRVAL_P(dest_zval)->nNextFreeElement > Z_ARRVAL_P(dest_zval)->nNumUsed)) {
+ Z_ARRVAL_P(dest_zval)->nNextFreeElement = Z_ARRVAL_P(dest_zval)->nNumUsed;
+ }
} else {
convert_to_array_ex(dest_zval);
}
@@ -2661,15 +3099,20 @@ PHPAPI int php_array_merge(HashTable *dest, HashTable *src) /* {{{ */
zend_string *string_key;
ZEND_HASH_FOREACH_STR_KEY_VAL(src, string_key, src_entry) {
- if (string_key) {
- if (Z_REFCOUNTED_P(src_entry)) {
+ if (Z_REFCOUNTED_P(src_entry)) {
+ if (UNEXPECTED(Z_ISREF_P(src_entry))
+ && UNEXPECTED(Z_REFCOUNT_P(src_entry) == 1)) {
+ ZVAL_UNREF(src_entry);
+ if (Z_REFCOUNTED_P(src_entry)) {
+ Z_ADDREF_P(src_entry);
+ }
+ } else {
Z_ADDREF_P(src_entry);
}
+ }
+ if (string_key) {
zend_hash_update(dest, string_key, src_entry);
} else {
- if (Z_REFCOUNTED_P(src_entry)) {
- Z_ADDREF_P(src_entry);
- }
zend_hash_next_index_insert_new(dest, src_entry);
}
} ZEND_HASH_FOREACH_END();
@@ -2796,15 +3239,19 @@ static inline void php_array_merge_or_replace_wrapper(INTERNAL_FUNCTION_PARAMETE
src = Z_ARRVAL_P(arg);
dest = Z_ARRVAL_P(return_value);
ZEND_HASH_FOREACH_KEY_VAL(src, idx, string_key, src_entry) {
- if (string_key) {
- if (Z_REFCOUNTED_P(src_entry)) {
+ if (Z_REFCOUNTED_P(src_entry)) {
+ if (UNEXPECTED(Z_ISREF_P(src_entry) && Z_REFCOUNT_P(src_entry) == 1)) {
+ src_entry = Z_REFVAL_P(src_entry);
+ if (Z_REFCOUNTED_P(src_entry)) {
+ Z_ADDREF_P(src_entry);
+ }
+ } else {
Z_ADDREF_P(src_entry);
}
+ }
+ if (string_key) {
zend_hash_add_new(dest, string_key, src_entry);
} else {
- if (Z_REFCOUNTED_P(src_entry)) {
- Z_ADDREF_P(src_entry);
- }
zend_hash_index_add_new(dest, idx, src_entry);
}
} ZEND_HASH_FOREACH_END();
@@ -2833,15 +3280,19 @@ static inline void php_array_merge_or_replace_wrapper(INTERNAL_FUNCTION_PARAMETE
src = Z_ARRVAL_P(arg);
dest = Z_ARRVAL_P(return_value);
ZEND_HASH_FOREACH_STR_KEY_VAL(src, string_key, src_entry) {
- if (string_key) {
- if (Z_REFCOUNTED_P(src_entry)) {
+ if (Z_REFCOUNTED_P(src_entry)) {
+ if (UNEXPECTED(Z_ISREF_P(src_entry) && Z_REFCOUNT_P(src_entry) == 1)) {
+ src_entry = Z_REFVAL_P(src_entry);
+ if (Z_REFCOUNTED_P(src_entry)) {
+ Z_ADDREF_P(src_entry);
+ }
+ } else {
Z_ADDREF_P(src_entry);
}
+ }
+ if (string_key) {
zend_hash_add_new(dest, string_key, src_entry);
} else {
- if (Z_REFCOUNTED_P(src_entry)) {
- Z_ADDREF_P(src_entry);
- }
zend_hash_next_index_insert_new(dest, src_entry);
}
} ZEND_HASH_FOREACH_END();
@@ -2926,6 +3377,7 @@ PHP_FUNCTION(array_keys)
if (strict) {
ZEND_HASH_FOREACH_KEY_VAL_IND(Z_ARRVAL_P(input), num_idx, str_idx, entry) {
+ ZVAL_DEREF(entry);
if (fast_is_identical_function(search_value, entry)) {
if (str_idx) {
ZVAL_STR_COPY(&new_val, str_idx);
@@ -2949,6 +3401,9 @@ PHP_FUNCTION(array_keys)
}
} else {
array_init_size(return_value, zend_hash_num_elements(Z_ARRVAL_P(input)));
+ if (!zend_hash_num_elements(Z_ARRVAL_P(input))) {
+ return;
+ }
zend_hash_real_init(Z_ARRVAL_P(return_value), 1);
ZEND_HASH_FILL_PACKED(Z_ARRVAL_P(return_value)) {
/* Go through input array and add keys to the return array */
@@ -2984,6 +3439,11 @@ PHP_FUNCTION(array_values)
/* Initialize return array */
array_init_size(return_value, zend_hash_num_elements(Z_ARRVAL_P(input)));
+
+ if (!zend_hash_num_elements(Z_ARRVAL_P(input))) {
+ return;
+ }
+
zend_hash_real_init(Z_ARRVAL_P(return_value), 1);
/* Go through input array and add values to the return array */
@@ -3073,20 +3533,29 @@ static inline zval *array_column_fetch_prop(zval *data, zval *name, zval *rv)
zval *prop = NULL;
if (Z_TYPE_P(data) == IS_OBJECT) {
- zend_string *key = zval_get_string(name);
+ if (!Z_OBJ_HANDLER_P(data, has_property) || !Z_OBJ_HANDLER_P(data, read_property)) {
+ return NULL;
+ }
- if (!Z_OBJ_HANDLER_P(data, has_property) || Z_OBJ_HANDLER_P(data, has_property)(data, name, 1, NULL)) {
- prop = zend_read_property(Z_OBJCE_P(data), data, ZSTR_VAL(key), ZSTR_LEN(key), 1, rv);
+ /* The has_property check is first performed in "exists" mode (which returns true for
+ * properties that are null but exist) and then in "has" mode to handle objects that
+ * implement __isset (which is not called in "exists" mode). */
+ if (Z_OBJ_HANDLER_P(data, has_property)(data, name, 2, NULL)
+ || Z_OBJ_HANDLER_P(data, has_property)(data, name, 0, NULL)) {
+ prop = Z_OBJ_HANDLER_P(data, read_property)(data, name, BP_VAR_R, NULL, rv);
}
- zend_string_release(key);
} else if (Z_TYPE_P(data) == IS_ARRAY) {
if (Z_TYPE_P(name) == IS_STRING) {
- prop = zend_hash_find(Z_ARRVAL_P(data), Z_STR_P(name));
+ prop = zend_symtable_find(Z_ARRVAL_P(data), Z_STR_P(name));
} else if (Z_TYPE_P(name) == IS_LONG) {
prop = zend_hash_index_find(Z_ARRVAL_P(data), Z_LVAL_P(name));
}
}
+ if (prop) {
+ ZVAL_DEREF(prop);
+ }
+
return prop;
}
@@ -3340,19 +3809,22 @@ PHP_FUNCTION(array_unique)
struct bucketindex *arTmp, *cmpdata, *lastkept;
unsigned int i;
zend_long sort_type = PHP_SORT_STRING;
+ compare_func_t cmp;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "a|l", &array, &sort_type) == FAILURE) {
return;
}
- php_set_compare_func(sort_type);
+ cmp = php_get_data_compare_func(sort_type, 0);
- RETVAL_ARR(zend_array_dup(Z_ARRVAL_P(array)));
if (Z_ARRVAL_P(array)->nNumOfElements <= 1) { /* nothing to do */
+ ZVAL_COPY(return_value, array);
return;
}
+ RETVAL_ARR(zend_array_dup(Z_ARRVAL_P(array)));
+
/* create and sort array with pointers to the target_hash buckets */
arTmp = (struct bucketindex *) pemalloc((Z_ARRVAL_P(array)->nNumOfElements + 1) * sizeof(struct bucketindex), Z_ARRVAL_P(array)->u.flags & HASH_FLAG_PERSISTENT);
if (!arTmp) {
@@ -3369,11 +3841,11 @@ PHP_FUNCTION(array_unique)
}
ZVAL_UNDEF(&arTmp[i].b.val);
zend_sort((void *) arTmp, i, sizeof(struct bucketindex),
- php_array_data_compare, (swap_func_t)array_bucketindex_swap);
+ cmp, (swap_func_t)array_bucketindex_swap);
/* go through the sorted array and delete duplicates from the copy */
lastkept = arTmp;
for (cmpdata = arTmp + 1; Z_TYPE(cmpdata->b.val) != IS_UNDEF; cmpdata++) {
- if (php_array_data_compare(lastkept, cmpdata)) {
+ if (cmp(lastkept, cmpdata)) {
lastkept = cmpdata;
} else {
if (lastkept->i > cmpdata->i) {
@@ -3399,24 +3871,7 @@ PHP_FUNCTION(array_unique)
static int zval_compare(zval *first, zval *second) /* {{{ */
{
- zval result;
-
- if (Z_TYPE_P(first) == IS_INDIRECT) {
- first = Z_INDIRECT_P(first);
- }
- if (Z_TYPE_P(second) == IS_INDIRECT) {
- second = Z_INDIRECT_P(second);
- }
- if (string_compare_function(&result, first, second) == FAILURE) {
- return 0;
- }
-
- if (Z_TYPE(result) == IS_DOUBLE) {
- return ZEND_NORMALIZE_BOOL(Z_DVAL(result));
- }
-
- convert_to_long(&result);
- return ZEND_NORMALIZE_BOOL(Z_LVAL(result));
+ return string_compare_function(first, second);
}
/* }}} */
@@ -3425,13 +3880,6 @@ static int zval_user_compare(zval *a, zval *b) /* {{{ */
zval args[2];
zval retval;
- if (Z_TYPE_P(a) == IS_INDIRECT) {
- a = Z_INDIRECT_P(a);
- }
- if (Z_TYPE_P(b) == IS_INDIRECT) {
- b = Z_INDIRECT_P(b);
- }
-
ZVAL_COPY_VALUE(&args[0], a);
ZVAL_COPY_VALUE(&args[1], b);
@@ -3502,6 +3950,10 @@ static void php_array_intersect_key(INTERNAL_FUNCTION_PARAMETERS, int data_compa
p = Z_ARRVAL(args[0])->arData + idx;
val = &p->val;
if (Z_TYPE_P(val) == IS_UNDEF) continue;
+ if (UNEXPECTED(Z_TYPE_P(val) == IS_INDIRECT)) {
+ val = Z_INDIRECT_P(val);
+ if (Z_TYPE_P(val) == IS_UNDEF) continue;
+ }
if (Z_ISREF_P(val) && Z_REFCOUNT_P(val) == 1) {
ZVAL_UNREF(val);
}
@@ -3525,7 +3977,7 @@ static void php_array_intersect_key(INTERNAL_FUNCTION_PARAMETERS, int data_compa
} else {
ok = 1;
for (i = 1; i < argc; i++) {
- if ((data = zend_hash_find(Z_ARRVAL(args[i]), p->key)) == NULL ||
+ if ((data = zend_hash_find_ind(Z_ARRVAL(args[i]), p->key)) == NULL ||
(intersect_data_compare_func &&
intersect_data_compare_func(val, data) != 0)
) {
@@ -3563,13 +4015,13 @@ static void php_array_intersect(INTERNAL_FUNCTION_PARAMETERS, int behavior, int
int (*intersect_data_compare_func)(const void *, const void *);
if (behavior == INTERSECT_NORMAL) {
- intersect_key_compare_func = php_array_key_compare;
+ intersect_key_compare_func = php_array_key_compare_string;
if (data_compare_type == INTERSECT_COMP_DATA_INTERNAL) {
/* array_intersect() */
req_args = 2;
param_spec = "+";
- intersect_data_compare_func = php_array_data_compare;
+ intersect_data_compare_func = php_array_data_compare_string;
} else if (data_compare_type == INTERSECT_COMP_DATA_USER) {
/* array_uintersect() */
req_args = 3;
@@ -3594,19 +4046,19 @@ static void php_array_intersect(INTERNAL_FUNCTION_PARAMETERS, int behavior, int
} else if (behavior & INTERSECT_ASSOC) { /* triggered also when INTERSECT_KEY */
/* INTERSECT_KEY is subset of INTERSECT_ASSOC. When having the former
* no comparison of the data is done (part of INTERSECT_ASSOC) */
- intersect_key_compare_func = php_array_key_compare;
+ intersect_key_compare_func = php_array_key_compare_string;
if (data_compare_type == INTERSECT_COMP_DATA_INTERNAL && key_compare_type == INTERSECT_COMP_KEY_INTERNAL) {
/* array_intersect_assoc() or array_intersect_key() */
req_args = 2;
param_spec = "+";
- intersect_key_compare_func = php_array_key_compare;
- intersect_data_compare_func = php_array_data_compare;
+ intersect_key_compare_func = php_array_key_compare_string;
+ intersect_data_compare_func = php_array_data_compare_string;
} else if (data_compare_type == INTERSECT_COMP_DATA_USER && key_compare_type == INTERSECT_COMP_KEY_INTERNAL) {
/* array_uintersect_assoc() */
req_args = 3;
param_spec = "+f";
- intersect_key_compare_func = php_array_key_compare;
+ intersect_key_compare_func = php_array_key_compare_string;
intersect_data_compare_func = php_array_user_compare;
fci_data = &fci1;
fci_data_cache = &fci1_cache;
@@ -3615,7 +4067,7 @@ static void php_array_intersect(INTERNAL_FUNCTION_PARAMETERS, int behavior, int
req_args = 3;
param_spec = "+f";
intersect_key_compare_func = php_array_user_key_compare;
- intersect_data_compare_func = php_array_data_compare;
+ intersect_data_compare_func = php_array_data_compare_string;
fci_key = &fci1;
fci_key_cache = &fci1_cache;
} else if (data_compare_type == INTERSECT_COMP_DATA_USER && key_compare_type == INTERSECT_COMP_KEY_USER) {
@@ -3652,7 +4104,6 @@ static void php_array_intersect(INTERNAL_FUNCTION_PARAMETERS, int behavior, int
/* for each argument, create and sort list with pointers to the hash buckets */
lists = (Bucket **)safe_emalloc(arr_argc, sizeof(Bucket *), 0);
ptrs = (Bucket **)safe_emalloc(arr_argc, sizeof(Bucket *), 0);
- php_set_compare_func(PHP_SORT_STRING);
if (behavior == INTERSECT_NORMAL && data_compare_type == INTERSECT_COMP_DATA_USER) {
BG(user_compare_fci) = *fci_data;
@@ -3922,6 +4373,10 @@ static void php_array_diff_key(INTERNAL_FUNCTION_PARAMETERS, int data_compare_ty
p = Z_ARRVAL(args[0])->arData + idx;
val = &p->val;
if (Z_TYPE_P(val) == IS_UNDEF) continue;
+ if (UNEXPECTED(Z_TYPE_P(val) == IS_INDIRECT)) {
+ val = Z_INDIRECT_P(val);
+ if (Z_TYPE_P(val) == IS_UNDEF) continue;
+ }
if (Z_ISREF_P(val) && Z_REFCOUNT_P(val) == 1) {
ZVAL_UNREF(val);
}
@@ -3945,7 +4400,7 @@ static void php_array_diff_key(INTERNAL_FUNCTION_PARAMETERS, int data_compare_ty
} else {
ok = 1;
for (i = 1; i < argc; i++) {
- if ((data = zend_hash_find(Z_ARRVAL(args[i]), p->key)) != NULL &&
+ if ((data = zend_hash_find_ind(Z_ARRVAL(args[i]), p->key)) != NULL &&
(!diff_data_compare_func ||
diff_data_compare_func(val, data) == 0)
) {
@@ -3983,13 +4438,13 @@ static void php_array_diff(INTERNAL_FUNCTION_PARAMETERS, int behavior, int data_
int (*diff_data_compare_func)(const void *, const void *);
if (behavior == DIFF_NORMAL) {
- diff_key_compare_func = php_array_key_compare;
+ diff_key_compare_func = php_array_key_compare_string;
if (data_compare_type == DIFF_COMP_DATA_INTERNAL) {
/* array_diff */
req_args = 2;
param_spec = "+";
- diff_data_compare_func = php_array_data_compare;
+ diff_data_compare_func = php_array_data_compare_string;
} else if (data_compare_type == DIFF_COMP_DATA_USER) {
/* array_udiff */
req_args = 3;
@@ -4019,13 +4474,13 @@ static void php_array_diff(INTERNAL_FUNCTION_PARAMETERS, int behavior, int data_
/* array_diff_assoc() or array_diff_key() */
req_args = 2;
param_spec = "+";
- diff_key_compare_func = php_array_key_compare;
- diff_data_compare_func = php_array_data_compare;
+ diff_key_compare_func = php_array_key_compare_string;
+ diff_data_compare_func = php_array_data_compare_string;
} else if (data_compare_type == DIFF_COMP_DATA_USER && key_compare_type == DIFF_COMP_KEY_INTERNAL) {
/* array_udiff_assoc() */
req_args = 3;
param_spec = "+f";
- diff_key_compare_func = php_array_key_compare;
+ diff_key_compare_func = php_array_key_compare_string;
diff_data_compare_func = php_array_user_compare;
fci_data = &fci1;
fci_data_cache = &fci1_cache;
@@ -4034,7 +4489,7 @@ static void php_array_diff(INTERNAL_FUNCTION_PARAMETERS, int behavior, int data_
req_args = 3;
param_spec = "+f";
diff_key_compare_func = php_array_user_key_compare;
- diff_data_compare_func = php_array_data_compare;
+ diff_data_compare_func = php_array_data_compare_string;
fci_key = &fci1;
fci_key_cache = &fci1_cache;
} else if (data_compare_type == DIFF_COMP_DATA_USER && key_compare_type == DIFF_COMP_KEY_USER) {
@@ -4071,7 +4526,6 @@ static void php_array_diff(INTERNAL_FUNCTION_PARAMETERS, int behavior, int data_
/* for each argument, create and sort list with pointers to the hash buckets */
lists = (Bucket **)safe_emalloc(arr_argc, sizeof(Bucket *), 0);
ptrs = (Bucket **)safe_emalloc(arr_argc, sizeof(Bucket *), 0);
- php_set_compare_func(PHP_SORT_STRING);
if (behavior == DIFF_NORMAL && data_compare_type == DIFF_COMP_DATA_USER) {
BG(user_compare_fci) = *fci_data;
@@ -4366,15 +4820,10 @@ PHPAPI int php_multisort_compare(const void *a, const void *b) /* {{{ */
Bucket *bb = *(Bucket **)b;
int r;
zend_long result;
- zval temp;
r = 0;
do {
-
- php_set_compare_func(ARRAYG(multisort_flags)[MULTISORT_TYPE][r]);
-
- ARRAYG(compare_func)(&temp, &ab[r].val, &bb[r].val);
- result = ARRAYG(multisort_flags)[MULTISORT_ORDER][r] * Z_LVAL(temp);
+ result = ARRAYG(multisort_func)[r](&ab[r], &bb[r]);
if (result != 0) {
return result > 0 ? 1 : -1;
}
@@ -4385,10 +4834,9 @@ PHPAPI int php_multisort_compare(const void *a, const void *b) /* {{{ */
}
/* }}} */
-#define MULTISORT_ABORT \
- for (k = 0; k < MULTISORT_LAST; k++) \
- efree(ARRAYG(multisort_flags)[k]); \
- efree(arrays); \
+#define MULTISORT_ABORT \
+ efree(ARRAYG(multisort_func)); \
+ efree(arrays); \
RETURN_FALSE;
static void array_bucket_p_sawp(void *p, void *q) /* {{{ */ {
@@ -4428,8 +4876,8 @@ PHP_FUNCTION(array_multisort)
arrays = (zval **)ecalloc(argc, sizeof(zval *));
for (i = 0; i < MULTISORT_LAST; i++) {
parse_state[i] = 0;
- ARRAYG(multisort_flags)[i] = (int *)ecalloc(argc, sizeof(int));
}
+ ARRAYG(multisort_func) = (compare_func_t*)ecalloc(argc, sizeof(compare_func_t));
/* Here we go through the input arguments and parse them. Each one can
* be either an array or a sort flag which follows an array. If not
@@ -4445,8 +4893,7 @@ PHP_FUNCTION(array_multisort)
/* We see the next array, so we update the sort flags of
* the previous array and reset the sort flags. */
if (i > 0) {
- ARRAYG(multisort_flags)[MULTISORT_ORDER][num_arrays - 1] = sort_order;
- ARRAYG(multisort_flags)[MULTISORT_TYPE][num_arrays - 1] = sort_type;
+ ARRAYG(multisort_func)[num_arrays - 1] = php_get_data_compare_func(sort_type, sort_order != PHP_SORT_ASC);
sort_order = PHP_SORT_ASC;
sort_type = PHP_SORT_REGULAR;
}
@@ -4463,7 +4910,7 @@ PHP_FUNCTION(array_multisort)
/* flag allowed here */
if (parse_state[MULTISORT_ORDER] == 1) {
/* Save the flag and make sure then next arg is not the current flag. */
- sort_order = Z_LVAL_P(arg) == PHP_SORT_DESC ? -1 : 1;
+ sort_order = Z_LVAL_P(arg) == PHP_SORT_DESC ? PHP_SORT_DESC : PHP_SORT_ASC;
parse_state[MULTISORT_ORDER] = 0;
} else {
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);
@@ -4501,8 +4948,7 @@ PHP_FUNCTION(array_multisort)
}
}
/* Take care of the last array sort flags. */
- ARRAYG(multisort_flags)[MULTISORT_ORDER][num_arrays - 1] = sort_order;
- ARRAYG(multisort_flags)[MULTISORT_TYPE][num_arrays - 1] = sort_type;
+ ARRAYG(multisort_func)[num_arrays - 1] = php_get_data_compare_func(sort_type, sort_order != PHP_SORT_ASC);
/* Make sure the arrays are of the same size. */
array_size = zend_hash_num_elements(Z_ARRVAL_P(arrays[0]));
@@ -4515,9 +4961,7 @@ PHP_FUNCTION(array_multisort)
/* If all arrays are empty we don't need to do anything. */
if (array_size < 1) {
- for (k = 0; k < MULTISORT_LAST; k++) {
- efree(ARRAYG(multisort_flags)[k]);
- }
+ efree(ARRAYG(multisort_func));
efree(arrays);
RETURN_TRUE;
}
@@ -4578,9 +5022,7 @@ PHP_FUNCTION(array_multisort)
efree(indirect[i]);
}
efree(indirect);
- for (k = 0; k < MULTISORT_LAST; k++) {
- efree(ARRAYG(multisort_flags)[k]);
- }
+ efree(ARRAYG(multisort_func));
efree(arrays);
RETURN_TRUE;
}
@@ -4807,7 +5249,7 @@ PHP_FUNCTION(array_filter)
}
}
- ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(array), num_key, string_key, operand) {
+ ZEND_HASH_FOREACH_KEY_VAL_IND(Z_ARRVAL_P(array), num_key, string_key, operand) {
if (have_callback) {
if (use_type) {
/* Set up the key */
@@ -5041,7 +5483,7 @@ PHP_FUNCTION(array_key_exists)
switch (Z_TYPE_P(key)) {
case IS_STRING:
- if (zend_symtable_exists(array, Z_STR_P(key))) {
+ if (zend_symtable_exists_ind(array, Z_STR_P(key))) {
RETURN_TRUE;
}
RETURN_FALSE;
@@ -5051,7 +5493,7 @@ PHP_FUNCTION(array_key_exists)
}
RETURN_FALSE;
case IS_NULL:
- if (zend_hash_exists(array, ZSTR_EMPTY_ALLOC())) {
+ if (zend_hash_exists_ind(array, ZSTR_EMPTY_ALLOC())) {
RETURN_TRUE;
}
RETURN_FALSE;
@@ -5132,17 +5574,17 @@ PHP_FUNCTION(array_chunk)
Creates an array by using the elements of the first parameter as keys and the elements of the second as the corresponding values */
PHP_FUNCTION(array_combine)
{
- zval *values, *keys;
+ HashTable *values, *keys;
uint32_t pos_values = 0;
zval *entry_keys, *entry_values;
int num_keys, num_values;
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "aa", &keys, &values) == FAILURE) {
+ if (zend_parse_parameters(ZEND_NUM_ARGS(), "hh", &keys, &values) == FAILURE) {
return;
}
- num_keys = zend_hash_num_elements(Z_ARRVAL_P(keys));
- num_values = zend_hash_num_elements(Z_ARRVAL_P(values));
+ num_keys = zend_hash_num_elements(keys);
+ num_values = zend_hash_num_elements(values);
if (num_keys != num_values) {
php_error_docref(NULL, E_WARNING, "Both parameters should have an equal number of elements");
@@ -5155,12 +5597,12 @@ PHP_FUNCTION(array_combine)
return;
}
- ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(keys), entry_keys) {
+ ZEND_HASH_FOREACH_VAL(keys, entry_keys) {
while (1) {
- if (pos_values >= Z_ARRVAL_P(values)->nNumUsed) {
+ if (pos_values >= values->nNumUsed) {
break;
- } else if (Z_TYPE(Z_ARRVAL_P(values)->arData[pos_values].val) != IS_UNDEF) {
- entry_values = &Z_ARRVAL_P(values)->arData[pos_values].val;
+ } else if (Z_TYPE(values->arData[pos_values].val) != IS_UNDEF) {
+ entry_values = &values->arData[pos_values].val;
if (Z_TYPE_P(entry_keys) == IS_LONG) {
entry_values = zend_hash_index_update(Z_ARRVAL_P(return_value),
Z_LVAL_P(entry_keys), entry_values);