if (num_req == 1) {
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.
- * 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 {
zend_long randval = php_mt_rand_range(0, ht->nNumUsed - 1);
Bucket *bucket = &ht->arData[randval];