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

Reply via email to