andrey Tue Sep 23 13:37:29 2003 EDT Modified files: /php-src/ext/standard array.c basic_functions.c php_array.h Log: 4 new functions : array_udiff() array_udiff_assoc() array_diff_uassoc() array_udiff_uassoc() They work like array_diff() or array_diff_assoc() but callback function(s) can be used to perform the comparisons. For example array_udiff_uassoc() expects 2 callbacks are last 2 parameters one is used to compare the values of the entries in the arrays the second to compare the keys. Class methods are also valid callbacks. Even when the data that should be used in the comparison is private or protected then a static method of a class should be used (this behaviour can be seen in the regression test - 007.phpt).
Index: php-src/ext/standard/array.c diff -u php-src/ext/standard/array.c:1.246 php-src/ext/standard/array.c:1.247 --- php-src/ext/standard/array.c:1.246 Mon Sep 22 19:19:17 2003 +++ php-src/ext/standard/array.c Tue Sep 23 13:37:28 2003 @@ -21,7 +21,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: array.c,v 1.246 2003/09/22 23:19:17 andrey Exp $ */ +/* $Id: array.c,v 1.247 2003/09/23 17:37:28 andrey Exp $ */ #include "php.h" #include "php_ini.h" @@ -77,6 +77,10 @@ #define DIFF_NORMAL 0 #define DIFF_ASSOC 1 +#define DIFF_COMP_DATA_INTERNAL 0 +#define DIFF_COMP_DATA_USER 1 +#define DIFF_COMP_KEY_INTERNAL 0 +#define DIFF_COMP_KEY_USER 1 #define INTERSECT_NORMAL 0 #define INTERSECT_ASSOC 1 @@ -2866,29 +2870,147 @@ /* }}} */ -static void php_array_diff(INTERNAL_FUNCTION_PARAMETERS, int behavior) +static void php_array_diff(INTERNAL_FUNCTION_PARAMETERS, int behavior, int data_compare_type, int key_compare_type) { zval ***args = NULL; HashTable *hash; - int argc, i, c; + int argc, arr_argc, i, c; Bucket ***lists, **list, ***ptrs, *p; + char *callback_name; + + zval **old_compare_func; + int (*diff_key_compare_func)(const void *, const void * TSRMLS_DC); + int (*diff_data_compare_func)(const void *, const void * TSRMLS_DC); + /* Get the argument count and check it */ argc = ZEND_NUM_ARGS(); - if (argc < 2) { - WRONG_PARAM_COUNT; - } - /* Allocate arguments array and get the arguments, checking for errors. */ args = (zval ***)safe_emalloc(argc, sizeof(zval **), 0); if (zend_get_parameters_array_ex(argc, args) == FAILURE) { efree(args); WRONG_PARAM_COUNT; } + + old_compare_func = BG(user_compare_func_name); + + if (behavior == DIFF_NORMAL) { + diff_key_compare_func = array_key_compare; + if (data_compare_type == DIFF_COMP_DATA_INTERNAL) { + /* array_diff */ + + if (argc < 2) { + efree(args); + WRONG_PARAM_COUNT; + } + arr_argc = argc; + diff_data_compare_func = array_data_compare; + } else if (data_compare_type = DIFF_COMP_DATA_USER) { + /* array_udiff */ + if (argc < 3) { + WRONG_PARAM_COUNT; + } + arr_argc = argc - 1; + diff_data_compare_func = array_user_compare; + if (!zend_is_callable(*args[arr_argc], 0, &callback_name)) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Not a valid callback %s", callback_name); + efree(callback_name); + efree(args); + return; + } + efree(callback_name); + + BG(user_compare_func_name) = args[arr_argc]; + } + } else if (behavior == DIFF_ASSOC) { + diff_key_compare_func = array_key_compare; + if (data_compare_type == DIFF_COMP_DATA_INTERNAL + && + key_compare_type == DIFF_COMP_KEY_INTERNAL) { + /* array_diff_assoc() */ + + if (argc < 2) { + efree(args); + WRONG_PARAM_COUNT; + } + arr_argc = argc; + diff_key_compare_func = array_key_compare; + diff_data_compare_func = array_data_compare; + } else if (data_compare_type == DIFF_COMP_DATA_USER + && + key_compare_type == DIFF_COMP_KEY_INTERNAL) { + /* array_udiff_assoc() */ + + if (argc < 3) { + efree(args); + WRONG_PARAM_COUNT; + } + arr_argc = argc - 1; + if (!zend_is_callable(*args[arr_argc], 0, &callback_name)) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Not a valid callback %s", callback_name); + efree(callback_name); + efree(args); + return; + } + efree(callback_name); + diff_key_compare_func = array_key_compare; + diff_data_compare_func = array_user_compare; + } else if (data_compare_type == DIFF_COMP_DATA_INTERNAL + && + key_compare_type == DIFF_COMP_KEY_USER) { + /* array_diff_uassoc() */ + + if (argc < 3) { + efree(args); + WRONG_PARAM_COUNT; + } + arr_argc = argc - 1; + if (!zend_is_callable(*args[arr_argc], 0, &callback_name)) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Not a valid callback %s", callback_name); + efree(callback_name); + efree(args); + return; + } + efree(callback_name); + diff_key_compare_func = array_user_key_compare; + diff_data_compare_func = array_data_compare; + BG(user_compare_func_name) = args[arr_argc]; + } else if (data_compare_type == DIFF_COMP_DATA_USER + && + key_compare_type == DIFF_COMP_KEY_USER) { + /* array_udiff_uassoc() */ + + if (argc < 4) { + efree(args); + WRONG_PARAM_COUNT; + } + arr_argc = argc - 2; + if (!zend_is_callable(*args[arr_argc], 0, &callback_name)) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Not a valid callback %s", callback_name); + efree(callback_name); + efree(args); + return; + } + efree(callback_name); + if (!zend_is_callable(*args[arr_argc + 1], 0, &callback_name)) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Not a valid callback %s", callback_name); + efree(callback_name); + efree(args); + return; + } + efree(callback_name); + diff_key_compare_func = array_user_key_compare; + diff_data_compare_func = array_user_compare; + BG(user_compare_func_name) = args[arr_argc + 1];/* data - key*/ + } + } + /* Allocate arguments array and get the arguments, checking for errors. */ + + /* for each argument, create and sort list with pointers to the hash buckets */ - lists = (Bucket ***)safe_emalloc(argc, sizeof(Bucket **), 0); - ptrs = (Bucket ***)safe_emalloc(argc, sizeof(Bucket **), 0); + lists = (Bucket ***)safe_emalloc(arr_argc, sizeof(Bucket **), 0); + ptrs = (Bucket ***)safe_emalloc(arr_argc, sizeof(Bucket **), 0); set_compare_func(SORT_STRING TSRMLS_CC); - for (i = 0; i < argc; i++) { + for (i = 0; i < arr_argc; i++) { if (Z_TYPE_PP(args[i]) != IS_ARRAY) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "Argument #%d is not an array", i + 1); argc = i; /* only free up to i-1 */ @@ -2906,9 +3028,9 @@ } *list = NULL; if (behavior == DIFF_NORMAL) { - zend_qsort((void *) lists[i], hash->nNumOfElements, sizeof(Bucket *), array_data_compare TSRMLS_CC); + zend_qsort((void *) lists[i], hash->nNumOfElements, sizeof(Bucket *), diff_data_compare_func TSRMLS_CC); } else if (behavior == DIFF_ASSOC) { - zend_qsort((void *) lists[i], hash->nNumOfElements, sizeof(Bucket *), array_key_compare TSRMLS_CC); + zend_qsort((void *) lists[i], hash->nNumOfElements, sizeof(Bucket *), diff_key_compare_func TSRMLS_CC); } } @@ -2916,16 +3038,27 @@ *return_value = **args[0]; zval_copy_ctor(return_value); + if (behavior == DIFF_NORMAL && data_compare_type == DIFF_COMP_DATA_USER) { + /* array_udiff() */ + BG(user_compare_func_name) = args[arr_argc]; + } + /* go through the lists and look for values of ptr[0] that are not in the others */ while (*ptrs[0]) { + if (behavior == DIFF_ASSOC + && + key_compare_type == DIFF_COMP_KEY_USER) { + + BG(user_compare_func_name) = args[argc - 1]; + } c = 1; - for (i = 1; i < argc; i++) { + for (i = 1; i < arr_argc; i++) { if (behavior == DIFF_NORMAL) { - while (*ptrs[i] && (0 < (c = array_data_compare(ptrs[0], ptrs[i] TSRMLS_CC)))) { + while (*ptrs[i] && (0 < (c = diff_data_compare_func(ptrs[0], ptrs[i] TSRMLS_CC)))) { ptrs[i]++; } } else if (behavior == DIFF_ASSOC) { - while (*ptrs[i] && (0 < (c = array_key_compare(ptrs[0], ptrs[i] TSRMLS_CC)))) { + while (*ptrs[i] && (0 < (c = diff_key_compare_func(ptrs[0], ptrs[i] TSRMLS_CC)))) { ptrs[i]++; } } @@ -2937,8 +3070,14 @@ break; } else if (behavior == DIFF_ASSOC) { if (*ptrs[i]) { - if (array_data_compare(ptrs[0], ptrs[i] TSRMLS_CC) != 0) { + if (data_compare_type == DIFF_COMP_DATA_USER) { + BG(user_compare_func_name) = args[arr_argc]; + } + if (diff_data_compare_func(ptrs[0], ptrs[i] TSRMLS_CC) != 0) { c = -1; + if (key_compare_type == DIFF_COMP_KEY_USER) { + BG(user_compare_func_name) = args[argc - 1]; + } } else { break; } @@ -2960,7 +3099,7 @@ goto out; } if (behavior == DIFF_NORMAL) { - if (array_data_compare(ptrs[0] - 1, ptrs[0] TSRMLS_CC)) { + if (diff_data_compare_func(ptrs[0] - 1, ptrs[0] TSRMLS_CC)) { break; } } else if (behavior == DIFF_ASSOC) { @@ -2976,7 +3115,7 @@ goto out; } if (behavior == DIFF_NORMAL) { - if (array_data_compare(ptrs[0]-1, ptrs[0] TSRMLS_CC)) { + if (diff_data_compare_func(ptrs[0]-1, ptrs[0] TSRMLS_CC)) { break; } } else if (behavior == DIFF_ASSOC) { @@ -2987,31 +3126,74 @@ } } out: - for (i = 0; i < argc; i++) { + for (i = 0; i < arr_argc; i++) { hash = HASH_OF(*args[i]); pefree(lists[i], hash->persistent); } + + BG(user_compare_func_name) = old_compare_func; + efree(ptrs); efree(lists); efree(args); } + /* {{{ proto array array_diff(array arr1, array arr2 [, array ...]) - Returns the entries of arr1 that have values which are not present in any of the others arguments */ + Returns the entries of arr1 that have values which are not present in any of the others arguments. */ PHP_FUNCTION(array_diff) { - php_array_diff(INTERNAL_FUNCTION_PARAM_PASSTHRU, DIFF_NORMAL); + php_array_diff(INTERNAL_FUNCTION_PARAM_PASSTHRU, DIFF_NORMAL, + DIFF_COMP_DATA_INTERNAL, DIFF_COMP_KEY_INTERNAL); +} +/* }}} */ + +/* {{{ proto array array_udiff(array arr1, array arr2 [, array ...], callback data_comp_func) + 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. */ +PHP_FUNCTION(array_udiff) +{ + php_array_diff(INTERNAL_FUNCTION_PARAM_PASSTHRU, DIFF_NORMAL, + DIFF_COMP_DATA_USER, DIFF_COMP_KEY_INTERNAL); } /* }}} */ + /* {{{ proto array array_diff_assoc(array arr1, array arr2 [, array ...]) 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 */ PHP_FUNCTION(array_diff_assoc) { - php_array_diff(INTERNAL_FUNCTION_PARAM_PASSTHRU, DIFF_ASSOC); + php_array_diff(INTERNAL_FUNCTION_PARAM_PASSTHRU, DIFF_ASSOC, + DIFF_COMP_DATA_INTERNAL, DIFF_COMP_KEY_INTERNAL); } /* }}} */ +/* {{{ proto array array_diff_uassoc(array arr1, array arr2 [, array ...], callback data_comp_func) + 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. */ +PHP_FUNCTION(array_diff_uassoc) +{ + php_array_diff(INTERNAL_FUNCTION_PARAM_PASSTHRU, DIFF_ASSOC, + DIFF_COMP_DATA_INTERNAL, DIFF_COMP_KEY_USER); +} +/* }}} */ + + +/* {{{ proto array array_udiff_assoc(array arr1, array arr2 [, array ...], callback key_comp_func) + 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. */ +PHP_FUNCTION(array_udiff_assoc) +{ + php_array_diff(INTERNAL_FUNCTION_PARAM_PASSTHRU, DIFF_ASSOC, + DIFF_COMP_DATA_USER, DIFF_COMP_KEY_INTERNAL); +} +/* }}} */ + +/* {{{ proto array array_udiff_uassoc(array arr1, array arr2 [, array ...], callback data_comp_func, callback key_comp_func) + 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. */ +PHP_FUNCTION(array_udiff_uassoc) +{ + php_array_diff(INTERNAL_FUNCTION_PARAM_PASSTHRU, DIFF_ASSOC, + DIFF_COMP_DATA_USER, DIFF_COMP_KEY_USER); +} +/* }}} */ #define MULTISORT_ORDER 0 Index: php-src/ext/standard/basic_functions.c diff -u php-src/ext/standard/basic_functions.c:1.627 php-src/ext/standard/basic_functions.c:1.628 --- php-src/ext/standard/basic_functions.c:1.627 Sat Sep 6 10:52:10 2003 +++ php-src/ext/standard/basic_functions.c Tue Sep 23 13:37:29 2003 @@ -17,7 +17,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: basic_functions.c,v 1.627 2003/09/06 14:52:10 pollita Exp $ */ +/* $Id: basic_functions.c,v 1.628 2003/09/23 17:37:29 andrey Exp $ */ #include "php.h" #include "php_streams.h" @@ -897,9 +897,13 @@ PHP_FE(array_rand, NULL) PHP_FE(array_unique, NULL) PHP_FE(array_intersect, NULL) - PHP_FE(array_intersect_assoc, NULL) + PHP_FE(array_intersect_assoc, NULL) PHP_FE(array_diff, NULL) - PHP_FE(array_diff_assoc, NULL) + PHP_FE(array_udiff, NULL) + PHP_FE(array_diff_assoc, NULL) + PHP_FE(array_udiff_assoc, NULL) + PHP_FE(array_diff_uassoc, NULL) + PHP_FE(array_udiff_uassoc, NULL) PHP_FE(array_sum, NULL) PHP_FE(array_filter, NULL) PHP_FE(array_map, NULL) Index: php-src/ext/standard/php_array.h diff -u php-src/ext/standard/php_array.h:1.43 php-src/ext/standard/php_array.h:1.44 --- php-src/ext/standard/php_array.h:1.43 Tue Jun 10 16:03:38 2003 +++ php-src/ext/standard/php_array.h Tue Sep 23 13:37:29 2003 @@ -19,7 +19,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: php_array.h,v 1.43 2003/06/10 20:03:38 imajes Exp $ */ +/* $Id: php_array.h,v 1.44 2003/09/23 17:37:29 andrey Exp $ */ #ifndef PHP_ARRAY_H #define PHP_ARRAY_H @@ -78,7 +78,11 @@ PHP_FUNCTION(array_intersect); PHP_FUNCTION(array_intersect_assoc); PHP_FUNCTION(array_diff); +PHP_FUNCTION(array_udiff); PHP_FUNCTION(array_diff_assoc); +PHP_FUNCTION(array_udiff_assoc); +PHP_FUNCTION(array_diff_uassoc); +PHP_FUNCTION(array_udiff_uassoc); PHP_FUNCTION(array_sum); PHP_FUNCTION(array_filter); PHP_FUNCTION(array_map);
-- PHP CVS Mailing List (http://www.php.net/) To unsubscribe, visit: http://www.php.net/unsub.php