Finished array_multisort() function. Basically it sorts multiple arrays

similar to ORDER BY SQL clause.
@ Added array_multisort() function. (Andrei)
# Docs are coming soon
This commit is contained in:
Andrei Zmievski 1999-12-13 19:42:26 +00:00
parent e911ee38bd
commit 457a13dac5
3 changed files with 88 additions and 24 deletions

1
TODO
View File

@ -24,7 +24,6 @@ ext/oci8
ext/standard
------------
* strpad() (Andrei)
* advanced sort (Andrei)
* NOT binary safe:
strcspn()
strtok()

View File

@ -49,7 +49,8 @@ php_array_globals array_globals;
#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 @@ function_entry array_functions[] = {
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 @@ PHP_MINIT_FUNCTION(array)
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,11 +1964,12 @@ int multisort_compare(const void *a, const void *b)
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++;
@ -1972,15 +1977,29 @@ int multisort_compare(const void *a, const void *b)
return result;
}
PHP_FUNCTION(multisort)
#define MULTISORT_ABORT \
efree(ARRAYG(multisort_flags)); \
efree(arrays); \
efree(args); \
RETURN_FALSE;
/* {{{ 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 @@ PHP_FUNCTION(multisort)
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 @@ PHP_FUNCTION(multisort)
for (i = 0; i < array_size; i++)
efree(indirect[i]);
efree(indirect);
efree(ARRAYG(multisort_flags));
efree(arrays);
efree(args);
RETURN_TRUE;
}

View File

@ -62,7 +62,7 @@ PHP_FUNCTION(extract);
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);