array_unique and some questions on Zend hash internals

From: Date: Sun, 04 Jun 2000 12:13:26 +0000
Subject: array_unique and some questions on Zend hash internals
Groups: php.dev 
Request: Send a blank email to php-dev+get-20175@lists.php.net to get a copy of this message
Hi I'm implementing a function I've called array_unique that takes an array (by reference) and removes all duplicate values (the first remains). It seems to work, but I have a few problems/questions. Below is the code quoted with | and some comments in between. |PHP_FUNCTION(array_unique) |{ | pval **array; | HashTable *target_hash; | Bucket **arTmp, **cmpdata, **lastkept; | Bucket *p; | int i; | | if (ARG_COUNT(ht) != 1 || zend_get_parameters_ex(1, &array) == FAILURE) { | WRONG_PARAM_COUNT; | } | target_hash = HASH_OF(*array); | if (!target_hash) { | php_error(E_WARNING, "Wrong datatype in array_unique() call"); | return; | } | | if (target_hash->nNumOfElements <= 1) { /* No duplicates */ | RETURN_TRUE; | } | | /* create and sort array with pointers to the target_hash buckets */ | arTmp = (Bucket **) pemalloc((target_hash->nNumOfElements + 1) * sizeof(Bucket *), target_hash->persistent); | if (!arTmp) { | return; | } | HANDLE_BLOCK_INTERRUPTIONS(); /* Necessary, and where? */ Do I need to call BLOCK and UNBLOCK? In what situations are they necessary? Where do I need it? | for (i = 0, p = target_hash->pListHead; p; i++, p = p->pListNext) { | arTmp[i] = p; | } | arTmp[i] = NULL; | qsort((void *) arTmp, i, sizeof(Bucket *), array_data_compare); | | /* go through the sorted array and remove duplicates as we go */ | lastkept = arTmp; | for (cmpdata = arTmp + 1; *cmpdata; cmpdata++) { | if (array_data_compare(lastkept, cmpdata)) { array_data_compare returns 0 if compare_function fails (one of the operators being an object or array), this means that array_unique will remove arrays and objects from the array in most cases. Ideally this shouldn't happen, is there a better way than using compare_function directly and duplicate most of the code from array_data_compare? Perhaps I shouldn't bother, at least I can live with this "feature". | lastkept = cmpdata; | } else { | /* should use zend_hash_apply_deleter() from API */ | my_hash_apply_deleter(target_hash, *cmpdata); I want to use zend_hash_apply_deleter here, it will be quicker than finding the bucket from the key, but the deleter function isn't part of the Zend API. If I am to use it I have to either expose it (you probably don't want any functions with Bucket arguments in the API), or add a function zend_hash_unique to the API. Do you see any better way? | } | } | | HANDLE_UNBLOCK_INTERRUPTIONS(); /* Necessary, and where? */ Is this the right place to unblock? | RETURN_TRUE; |} One last thing, if I have an array indexed by numbers, say array("a", "a", "b"), array_unique would change it into array("a", 2 => "b"). Do you think it should be array("a", "b")? What is the best way of doing this? Hope someone can answer at least some of this. Stig -- Stig Venaas UNINETT

« previous php.dev (#20175) next »