dmitry          Thu Sep 20 09:23:00 2007 UTC

  Modified files:              (Branch: PHP_5_2)
    /php-src    NEWS 
    /php-src/ext/standard       array.c 
  Log:
  Improved speed of array_intersect_key(), array_intersect_assoc() and 
array_uintersect_assoc(). (100 times faster on arrays with 100000 elements)
  
  
http://cvs.php.net/viewvc.cgi/php-src/NEWS?r1=1.2027.2.547.2.957&r2=1.2027.2.547.2.958&diff_format=u
Index: php-src/NEWS
diff -u php-src/NEWS:1.2027.2.547.2.957 php-src/NEWS:1.2027.2.547.2.958
--- php-src/NEWS:1.2027.2.547.2.957     Wed Sep 19 22:37:58 2007
+++ php-src/NEWS        Thu Sep 20 09:22:59 2007
@@ -5,6 +5,9 @@
 - Added optional parameter $provide_object to debug_backtrace(). (Sebastian)
 - Added alpha support for imagefilter() IMG_FILTER_COLORIZE. (Pierre)
 
+- Improved speed of array_intersect_key(), array_intersect_assoc() and
+  array_uintersect_assoc(). (Dmitry)
+
 - Fixed regression in glob() when enforcing safe_mode/open_basedir checks on
   paths containing '*'. (Ilia)
 - Fixed "mail.force_extra_parameters" php.ini directive not to be modifiable
http://cvs.php.net/viewvc.cgi/php-src/ext/standard/array.c?r1=1.308.2.21.2.32&r2=1.308.2.21.2.33&diff_format=u
Index: php-src/ext/standard/array.c
diff -u php-src/ext/standard/array.c:1.308.2.21.2.32 
php-src/ext/standard/array.c:1.308.2.21.2.33
--- php-src/ext/standard/array.c:1.308.2.21.2.32        Fri Aug 10 12:17:26 2007
+++ php-src/ext/standard/array.c        Thu Sep 20 09:22:59 2007
@@ -21,7 +21,7 @@
    +----------------------------------------------------------------------+
 */
 
-/* $Id: array.c,v 1.308.2.21.2.32 2007/08/10 12:17:26 jani Exp $ */
+/* $Id: array.c,v 1.308.2.21.2.33 2007/09/20 09:22:59 dmitry Exp $ */
 
 #include "php.h"
 #include "php_ini.h"
@@ -86,6 +86,7 @@
 #define INTERSECT_NORMAL               1
 #define INTERSECT_KEY                  2
 #define INTERSECT_ASSOC                        6
+#define INTERSECT_COMP_DATA_NONE    -1
 #define INTERSECT_COMP_DATA_INTERNAL 0
 #define INTERSECT_COMP_DATA_USER     1
 #define INTERSECT_COMP_KEY_INTERNAL  0
@@ -2869,6 +2870,149 @@
 }
 /* }}} */
 
+static int zval_compare(zval **a, zval **b TSRMLS_DC) /* {{{ */
+{
+       zval result;
+       zval *first;
+       zval *second;
+ 
+       first = *((zval **) a);
+       second = *((zval **) b);
+
+       if (string_compare_function(&result, first, second TSRMLS_CC) == 
FAILURE) {
+               return 0;
+       } 
+
+       if (Z_TYPE(result) == IS_DOUBLE) {
+               if (Z_DVAL(result) < 0) {
+                       return -1;
+               } else if (Z_DVAL(result) > 0) {
+                       return 1;
+               } else {
+                       return 0;
+               }
+       }
+
+       convert_to_long(&result);
+
+       if (Z_LVAL(result) < 0) {
+               return -1;
+       } else if (Z_LVAL(result) > 0) {
+               return 1;
+       } 
+
+       return 0;
+}
+/* }}} */
+
+static int zval_user_compare(zval **a, zval **b TSRMLS_DC) /* {{{ */
+{
+       zval **args[2];
+       zval *retval_ptr;
+       zend_fcall_info fci;
+
+       args[0] = (zval **) a;
+       args[1] = (zval **) b;
+
+       fci.size = sizeof(fci);
+       fci.function_table = EG(function_table);
+       fci.function_name = *BG(user_compare_func_name);
+       fci.symbol_table = NULL;
+       fci.object_pp = NULL;
+       fci.retval_ptr_ptr = &retval_ptr;
+       fci.param_count = 2;
+       fci.params = args;
+       fci.no_separation = 0;
+
+       if (zend_call_function(&fci, &BG(user_compare_fci_cache) TSRMLS_CC)== 
SUCCESS
+               && retval_ptr) {
+               long retval;
+
+               convert_to_long_ex(&retval_ptr);
+               retval = Z_LVAL_P(retval_ptr);
+               zval_ptr_dtor(&retval_ptr);
+               return retval < 0 ? -1 : retval > 0 ? 1 : 0;;
+       } else {
+               return 0;
+       }
+}
+/* }}} */
+
+static void php_array_intersect_key(INTERNAL_FUNCTION_PARAMETERS, int 
data_compare_type) /* {{{ */
+{
+       Bucket *p;
+       int argc, i;
+       zval ***args;
+       int (*intersect_data_compare_func)(zval **, zval ** TSRMLS_DC) = NULL;
+       zend_bool ok;
+       zval **data;
+
+       /* Get the argument count */
+       argc = ZEND_NUM_ARGS();
+       /* Allocate arguments array and get the arguments, checking for errors. 
*/
+       args = (zval ***)safe_emalloc(argc, sizeof(zval **), 0);
+       if (argc < 2 || zend_get_parameters_array_ex(argc, args) == FAILURE) {
+               efree(args);
+               WRONG_PARAM_COUNT;
+       }
+       if (data_compare_type == INTERSECT_COMP_DATA_USER) {
+               char *callback_name;
+
+               if (argc < 3) {
+                       efree(args);
+                       WRONG_PARAM_COUNT;
+               }
+               argc--;
+               if (!zend_is_callable(*args[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);
+               intersect_data_compare_func = zval_user_compare;
+               BG(user_compare_func_name) = args[argc];
+       } else if (data_compare_type == INTERSECT_COMP_DATA_INTERNAL) {
+               intersect_data_compare_func = zval_compare;
+       }
+
+       array_init(return_value);
+
+       for (p = Z_ARRVAL_PP(args[0])->pListHead; p != NULL; p = p->pListNext) {
+               if (p->nKeyLength == 0) {
+                       ok = 1;
+                       for (i = 1; i < argc; i++) {
+                               if (zend_hash_index_find(Z_ARRVAL_PP(args[i]), 
p->h, (void**)&data) == FAILURE ||
+                                   (intersect_data_compare_func &&
+                                    
intersect_data_compare_func((zval**)p->pData, data TSRMLS_CC) != 0)) {
+                                       ok = 0;
+                                       break;
+                               }
+                       }
+                       if (ok) {
+                               (*((zval**)p->pData))->refcount++;
+                               
zend_hash_index_update(Z_ARRVAL_P(return_value), p->h, p->pData, sizeof(zval*), 
NULL);
+                       }
+               } else {
+                       ok = 1;
+                       for (i = 1; i < argc; i++) {
+                               if (zend_hash_quick_find(Z_ARRVAL_PP(args[i]), 
p->arKey, p->nKeyLength, p->h, (void**)&data) == FAILURE ||
+                                   (intersect_data_compare_func &&
+                                    
intersect_data_compare_func((zval**)p->pData, data TSRMLS_CC) != 0)) {
+                                       ok = 0;
+                                       break;
+                               }
+                       }
+                       if (ok) {
+                               (*((zval**)p->pData))->refcount++;
+                               
zend_hash_quick_update(Z_ARRVAL_P(return_value), p->arKey, p->nKeyLength, p->h, 
p->pData, sizeof(zval*), NULL);
+                       }
+               }
+       }
+       efree(args);
+}
+/* }}} */
+
 static void php_array_intersect(INTERNAL_FUNCTION_PARAMETERS, int behavior, 
int data_compare_type, int key_compare_type) /* {{{ */
 {
        zval ***args = NULL;
@@ -3185,8 +3329,7 @@
    Returns the entries of arr1 that have keys which are present in all the 
other arguments. Kind of equivalent to array_diff(array_keys($arr1), 
array_keys($arr2)[,array_keys(...)]). Equivalent of array_intersect_assoc() but 
does not do compare of the data. */
 PHP_FUNCTION(array_intersect_key)
 {
-       php_array_intersect(INTERNAL_FUNCTION_PARAM_PASSTHRU, INTERSECT_KEY,
-                               INTERSECT_COMP_DATA_INTERNAL, 
INTERSECT_COMP_KEY_INTERNAL);
+       php_array_intersect_key(INTERNAL_FUNCTION_PARAM_PASSTHRU, 
INTERSECT_COMP_DATA_NONE);
 }
 /* }}} */
 
@@ -3221,8 +3364,7 @@
    Returns the entries of arr1 that have values which are present in all the 
other arguments. Keys are used to do more restrictive check */
 PHP_FUNCTION(array_intersect_assoc)
 {
-       php_array_intersect(INTERNAL_FUNCTION_PARAM_PASSTHRU, INTERSECT_ASSOC,
-                               INTERSECT_COMP_DATA_INTERNAL, 
INTERSECT_COMP_KEY_INTERNAL);
+       php_array_intersect_key(INTERNAL_FUNCTION_PARAM_PASSTHRU, 
INTERSECT_COMP_DATA_INTERNAL);
 }
 /* }}} */
 
@@ -3230,8 +3372,7 @@
    Returns the entries of arr1 that have values which are present in all the 
other arguments. Keys are used to do more restrictive check. Data is compared 
by using an user-supplied callback. */
 PHP_FUNCTION(array_uintersect_assoc)
 {
-       php_array_intersect(INTERNAL_FUNCTION_PARAM_PASSTHRU, INTERSECT_ASSOC,
-                               INTERSECT_COMP_DATA_USER, 
INTERSECT_COMP_KEY_INTERNAL);
+       php_array_intersect_key(INTERNAL_FUNCTION_PARAM_PASSTHRU, 
INTERSECT_COMP_DATA_USER);
 }
 /* }}} */
 

-- 
PHP CVS Mailing List (http://www.php.net/)
To unsubscribe, visit: http://www.php.net/unsub.php

Reply via email to