cvs: /php4 TODO /php4/ext/standard array.c php_array.h

From: Date: Mon, 13 Dec 1999 19:42:57 +0000
Subject: cvs: /php4 TODO /php4/ext/standard array.c php_array.h
Groups: php.version4 
Request: Send a blank email to php-version4+get-7869@lists.php.net to get a copy of this message
andrei Mon Dec 13 14:42:57 1999 EDT Modified files: /php4 TODO /php4/ext/standard array.c php_array.h Log: Finished array_multisort() function. Basically it sorts multiple arrays similar to ORDER BY SQL clause. @ Added array_multisort() function. (Andrei) # Docs are coming soon Index: php4/TODO diff -u php4/TODO:1.16 php4/TODO:1.17 --- php4/TODO:1.16 Sat Dec 11 15:00:40 1999 +++ php4/TODO Mon Dec 13 14:42:25 1999 @@ -24,7 +24,6 @@ ext/standard ------------ * strpad() (Andrei) - * advanced sort (Andrei) * NOT binary safe: strcspn() strtok() Index: php4/ext/standard/array.c diff -u php4/ext/standard/array.c:1.13 php4/ext/standard/array.c:1.14 --- php4/ext/standard/array.c:1.13 Sun Dec 12 05:50:30 1999 +++ php4/ext/standard/array.c Mon Dec 13 14:42:26 1999 @@ -49,7 +49,8 @@ #define EXTR_PREFIX_SAME 2 #define EXTR_PREFIX_ALL 3 -static unsigned char all_args_force_ref[] = { 1, BYREF_FORCE_REST }; +#define SORT_DESC -1 +#define SORT_ASC 1 function_entry array_functions[] = { PHP_FE(ksort, first_arg_force_ref) @@ -76,7 +77,7 @@ PHP_FE(extract, NULL) PHP_FE(compact, NULL) PHP_FE(range, NULL) - PHP_FE(multisort, all_args_force_ref) + PHP_FE(array_multisort, NULL) PHP_FE(array_push, first_arg_force_ref) PHP_FE(array_pop, first_arg_force_ref) PHP_FE(array_shift, first_arg_force_ref) @@ -122,6 +123,9 @@ REGISTER_LONG_CONSTANT("EXTR_PREFIX_SAME", EXTR_PREFIX_SAME, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("EXTR_PREFIX_ALL", EXTR_PREFIX_ALL, CONST_CS | CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("SORT_ASC", SORT_ASC, CONST_CS | CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("SORT_DESC", SORT_DESC, CONST_CS | CONST_PERSISTENT); + return SUCCESS; } @@ -1960,27 +1964,42 @@ int r; int result = 0; zval temp; + ARRAYLS_FETCH(); r = 0; do { compare_function(&temp, *((zval **)ab[r]->pData), *((zval **)bb[r]->pData)); - result = temp.value.lval; + result = ARRAYG(multisort_flags)[r] * temp.value.lval; if (result != 0) return result; r++; } while (ab[r] != NULL); return result; } + +#define MULTISORT_ABORT \ + efree(ARRAYG(multisort_flags)); \ + efree(arrays); \ + efree(args); \ + RETURN_FALSE; -PHP_FUNCTION(multisort) +/* {{{ proto bool array_multisort(array $ar1 [, SORT_ASC|SORT_DESC] [, array $ar2 [ICASE|NUM] [DESC|ASC], ...]) + Sort multiple arrays at once similar to how ORDER BY clause works in SQL */ +PHP_FUNCTION(array_multisort) { zval*** args; + zval*** arrays; Bucket*** indirect; Bucket* p; HashTable* hash; int argc; int array_size; + int num_arrays = 0; + int parse_state = 0; /* 0 - flag not allowed + 1 - flag allowed */ + int sort_order = SORT_ASC; int i, k; + ARRAYLS_FETCH(); /* Get the argument count and check it */ argc = ARG_COUNT(ht); @@ -1995,46 +2014,89 @@ WRONG_PARAM_COUNT; } + /* Allocate space for storing pointers to input arrays and sort flags */ + arrays = (zval ***)ecalloc(argc, sizeof(zval **)); + ARRAYG(multisort_flags) = (int *)ecalloc(argc, sizeof(int)); + + /* Here we go through the input arguments and parse them. Each one can + be either an array or a sort order flag which follows an array. If + not specified, the sort order flag defaults to SORT_ASC. There can't + be two sort order flags in a row, and the very first argument has + to be an array. + */ for (i = 0; i < argc; i++) { - if ((*args[i])->type != IS_ARRAY) { - php_error(E_WARNING, "Argument %i to %s() is not an array", i+1, + if ((*args[i])->type == IS_ARRAY) { + /* We see the next array so update the sort order of + the previous array and reset the sort order */ + if (i > 0) { + ARRAYG(multisort_flags)[num_arrays-1] = sort_order; + sort_order = SORT_ASC; + } + arrays[num_arrays++] = args[i]; + + /* next one may be array or sort flag */ + parse_state = 1; + } else if ((*args[i])->type == IS_LONG) { + /* flag allowed here */ + if (parse_state == 1) { + if ((*args[i])->value.lval == SORT_ASC || (*args[i])->value.lval == SORT_DESC) { + /* Save the flag and make sure then next arg is not a flag */ + sort_order = (*args[i])->value.lval; + parse_state = 0; + } else { + php_error(E_WARNING, "Argument %i to %s() is an unknown sort flag", i+1, + get_active_function_name()); + MULTISORT_ABORT; + } + } else { + php_error(E_WARNING, "Argument %i to %s() is expected to be an array", i+1, + get_active_function_name()); + MULTISORT_ABORT; + } + } else { + php_error(E_WARNING, "Argument %i to %s() is expected to be an array or a sort flag", i+1, get_active_function_name()); - efree(args); - return; + MULTISORT_ABORT; } } + /* Take care of the last array sort flag */ + ARRAYG(multisort_flags)[num_arrays-1] = sort_order; /* Make sure the arrays are of the same size */ - array_size = zend_hash_num_elements((*args[0])->value.ht); - for (i = 0; i < argc; i++) { - if (zend_hash_num_elements((*args[i])->value.ht) != array_size) { + array_size = zend_hash_num_elements((*arrays[0])->value.ht); + for (i = 0; i < num_arrays; i++) { + if (zend_hash_num_elements((*arrays[i])->value.ht) != array_size) { php_error(E_WARNING, "Array sizes are inconsistent"); - efree(args); - return; + MULTISORT_ABORT; } } - /* Create the indirection array */ + /* Create the indirection array. This array is of size MxN, where + M is the number of entries in each input array and N is the number + of the input arrays + 1. The last column is NULL to indicate the end + of the row. + */ indirect = (Bucket ***)emalloc(array_size * sizeof(Bucket **)); for (i = 0; i < array_size; i++) - indirect[i] = (Bucket **)emalloc((argc+1) * sizeof(Bucket *)); + indirect[i] = (Bucket **)emalloc((num_arrays+1) * sizeof(Bucket *)); - for (i = 0; i < argc; i++) { + for (i = 0; i < num_arrays; i++) { k = 0; - for (p = (*args[i])->value.ht->pListHead; p; p = p->pListNext, k++) { + for (p = (*arrays[i])->value.ht->pListHead; p; p = p->pListNext, k++) { indirect[k][i] = p; } } for (k = 0; k < array_size; k++) - indirect[k][argc] = NULL; + indirect[k][num_arrays] = NULL; - /* Do the actual sort */ + /* Do the actual sort magic - bada-bim, bada-boom */ qsort(indirect, array_size, sizeof(Bucket **), multisort_compare); - /* Restructure the arrays based on sorted indirect */ + /* Restructure the arrays based on sorted indirect - this is mostly + take from zend_hash_sort() function. */ HANDLE_BLOCK_INTERRUPTIONS(); - for (i = 0; i < argc; i++) { - hash = (*args[i])->value.ht; + for (i = 0; i < num_arrays; i++) { + hash = (*arrays[i])->value.ht; hash->pListHead = indirect[0][i];; hash->pListTail = NULL; hash->pInternalPointer = hash->pListHead; @@ -2064,5 +2126,8 @@ for (i = 0; i < array_size; i++) efree(indirect[i]); efree(indirect); + efree(ARRAYG(multisort_flags)); + efree(arrays); efree(args); + RETURN_TRUE; } Index: php4/ext/standard/php_array.h diff -u php4/ext/standard/php_array.h:1.4 php4/ext/standard/php_array.h:1.5 --- php4/ext/standard/php_array.h:1.4 Sat Dec 11 17:42:01 1999 +++ php4/ext/standard/php_array.h Mon Dec 13 14:42:26 1999 @@ -27,7 +27,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: php_array.h,v 1.4 1999/12/11 22:42:01 andrei Exp $ */ +/* $Id: php_array.h,v 1.5 1999/12/13 19:42:26 andrei Exp $ */ #ifndef _PHP_ARRAY_H #define _PHP_ARRAY_H @@ -62,7 +62,7 @@ PHP_FUNCTION(compact); PHP_FUNCTION(range); PHP_FUNCTION(shuffle); -PHP_FUNCTION(multisort); +PHP_FUNCTION(array_multisort); PHP_FUNCTION(array_push); PHP_FUNCTION(array_pop); PHP_FUNCTION(array_shift);

« previous php.version4 (#7869) next »