]> granicus.if.org Git - php/commitdiff
Fix bug #7045: shuffle() now provides consistent distribution of values
authorAndrei Zmievski <andrei@php.net>
Mon, 10 Jun 2002 02:28:32 +0000 (02:28 +0000)
committerAndrei Zmievski <andrei@php.net>
Mon, 10 Jun 2002 02:28:32 +0000 (02:28 +0000)
in the array.

NEWS
ext/standard/array.c

diff --git a/NEWS b/NEWS
index 8065f745a32c047dd9c504bac7cf42d6fe86bf7f..c54bcd373595a52a84046d554d5e10d36a8a8a7e 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -1,6 +1,7 @@
 PHP 4                                                                      NEWS
 |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
 ?? ??? 2002, Version 4.3.0
+- Fixed shuffle() to provide equal distribution of values. (Andrei)
 - Added --with-mysql-sock configure option which can be used to override
   the unix socket location. (e.g. NFS compiles, etc.) (imajes)
 - Fixed is_a() to properly work on extension registered classes. (Andrei)
index 77544a2c1368324b537eb038f28fee1f230ae01f..79dc8778fe817108117a01f7300d0a9b041c2cb2 100644 (file)
@@ -1435,24 +1435,68 @@ PHP_FUNCTION(range)
 /* }}} */
 
 
-static int array_data_shuffle(const void *a, const void *b TSRMLS_DC) 
-{
-       return (php_rand(TSRMLS_C) % 2) ? 1 : -1;
-}
-
-
 /* {{{ proto bool shuffle(array array_arg)
    Randomly shuffle the contents of an array */
 PHP_FUNCTION(shuffle)
 {
        zval *array;
+       Bucket **elems, *temp;
+       HashTable *hash;
+       int j, n_elems, cur_elem = 0, rnd_idx, n_left;
+       TSRMLS_FETCH();
 
        if (zend_parse_parameters(1 TSRMLS_CC, "a", &array) == FAILURE) {
                RETURN_FALSE;
        }
-       if (zend_hash_sort(Z_ARRVAL_PP(&array), (sort_func_t)php_mergesort, array_data_shuffle, 1 TSRMLS_CC) == FAILURE) {
-               RETURN_FALSE;
+
+       n_elems = zend_hash_num_elements(Z_ARRVAL_P(array));
+       if (n_elems <= 1) {
+               RETURN_TRUE;
        }
+
+       elems = (Bucket **)emalloc(n_elems * sizeof(Bucket *));
+       hash = Z_ARRVAL_P(array);
+       n_left = n_elems;
+
+       for (j = 0, temp = hash->pListHead; temp; temp = temp->pListNext)
+               elems[j++] = temp;
+       while (--n_left) {
+               rnd_idx = php_rand(TSRMLS_C);
+               RAND_RANGE(rnd_idx, cur_elem, n_left, PHP_RAND_MAX);
+               if (rnd_idx != cur_elem) {
+                       temp = elems[cur_elem];
+                       elems[cur_elem] = elems[rnd_idx];
+                       elems[rnd_idx] = temp;
+               }
+               cur_elem++;
+       }
+
+       HANDLE_BLOCK_INTERRUPTIONS();
+       hash->pListHead = elems[0];
+       hash->pListTail = NULL;
+       hash->pInternalPointer = hash->pListHead;
+
+       for (j = 0; j < n_elems; j++) {
+               if (hash->pListTail) {
+                       hash->pListTail->pListNext = elems[j];
+               }
+               elems[j]->pListLast = hash->pListTail;
+               elems[j]->pListNext = NULL;
+               hash->pListTail = elems[j];
+       }
+       temp = hash->pListHead;
+       j = 0;
+       while (temp != NULL) {
+               temp->nKeyLength = 0;
+               temp->h = j++;
+               temp = temp->pListNext;
+       }
+       hash->nNextFreeElement = n_elems;
+       zend_hash_rehash(hash);
+       HANDLE_UNBLOCK_INTERRUPTIONS();
+
+       efree(elems);
+       
        RETURN_TRUE;
 }
 /* }}} */