|
|
@ -5699,19 +5699,26 @@ PHP_FUNCTION(array_rand) |
|
|
if (num_req == 1) { |
|
|
if (num_req == 1) { |
|
|
HashTable *ht = Z_ARRVAL_P(input); |
|
|
HashTable *ht = Z_ARRVAL_P(input); |
|
|
|
|
|
|
|
|
/* Compact the hashtable if less than 3/4 of elements are used */ |
|
|
|
|
|
if (num_avail < ht->nNumUsed - (ht->nNumUsed>>2)) { |
|
|
|
|
|
if (ht->u.flags & HASH_FLAG_PACKED) { |
|
|
|
|
|
zend_hash_packed_to_hash(ht); |
|
|
|
|
|
} else { |
|
|
|
|
|
zend_hash_rehash(ht); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
if (num_avail < ht->nNumUsed - (ht->nNumUsed>>1)) { |
|
|
|
|
|
/* If less than 1/2 of elements are used, don't sample. Instead search for a |
|
|
|
|
|
* specific offset using linear scan. */ |
|
|
|
|
|
zend_long i = 0, randval = php_mt_rand_range(0, num_avail - 1); |
|
|
|
|
|
ZEND_HASH_FOREACH_KEY(Z_ARRVAL_P(input), num_key, string_key) { |
|
|
|
|
|
if (i == randval) { |
|
|
|
|
|
if (string_key) { |
|
|
|
|
|
RETURN_STR_COPY(string_key); |
|
|
|
|
|
} else { |
|
|
|
|
|
RETURN_LONG(num_key); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
i++; |
|
|
|
|
|
} ZEND_HASH_FOREACH_END(); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
/* Sample random buckets until we hit one that is not empty. |
|
|
/* Sample random buckets until we hit one that is not empty. |
|
|
* The worst case probability of hitting an empty element is 1-3/4. The worst case |
|
|
|
|
|
* probability of hitting N empty elements in a row is (1-3/4)**N. |
|
|
|
|
|
* For N=5 this becomes smaller than 0.1%. */ |
|
|
|
|
|
|
|
|
* The worst case probability of hitting an empty element is 1-1/2. The worst case |
|
|
|
|
|
* probability of hitting N empty elements in a row is (1-1/2)**N. |
|
|
|
|
|
* For N=10 this becomes smaller than 0.1%. */ |
|
|
do { |
|
|
do { |
|
|
zend_long randval = php_mt_rand_range(0, ht->nNumUsed - 1); |
|
|
zend_long randval = php_mt_rand_range(0, ht->nNumUsed - 1); |
|
|
Bucket *bucket = &ht->arData[randval]; |
|
|
Bucket *bucket = &ht->arData[randval]; |
|
|
|