@@ -3455,6 +3455,32 @@ PHP_FUNCTION(array_splice)
3455
3455
}
3456
3456
/* }}} */
3457
3457
3458
+ /* {{{ find_bucket_at_offset(HashTable* ht, zend_long offset)
3459
+ Finds the bucket at the given valid offset */
3460
+ static inline Bucket * find_bucket_at_offset (HashTable * ht , zend_long offset )
3461
+ {
3462
+ zend_long pos ;
3463
+ Bucket * bucket ;
3464
+ ZEND_ASSERT (offset >= 0 && offset <= ht -> nNumOfElements );
3465
+ if (HT_IS_WITHOUT_HOLES (ht )) {
3466
+ /* There's no need to iterate over the array to filter out holes if there are no holes */
3467
+ /* This properly handles both packed and unpacked arrays. */
3468
+ return ht -> arData + offset ;
3469
+ }
3470
+ /* Otherwise, this code has to iterate over the HashTable and skip holes in the array. */
3471
+ pos = 0 ;
3472
+ ZEND_HASH_FOREACH_BUCKET (ht , bucket ) {
3473
+ if (pos >= offset ) {
3474
+ /* This is the bucket of the array element at the requested offset */
3475
+ return bucket ;
3476
+ }
3477
+ ++ pos ;
3478
+ } ZEND_HASH_FOREACH_END ();
3479
+
3480
+ /* Return a pointer to the end of the bucket array. */
3481
+ return ht -> arData + ht -> nNumUsed ;
3482
+ }
3483
+
3458
3484
/* {{{ proto array array_slice(array input, int offset [, int length [, bool preserve_keys]])
3459
3485
Returns elements specified by offset and length */
3460
3486
PHP_FUNCTION (array_slice )
@@ -3466,7 +3492,6 @@ PHP_FUNCTION(array_slice)
3466
3492
zend_bool length_is_null = 1 ; /* Whether an explicit length has been omitted */
3467
3493
zend_bool preserve_keys = 0 ; /* Whether to preserve keys while copying to the new array */
3468
3494
uint32_t num_in ; /* Number of elements in the input array */
3469
- uint32_t pos ; /* Current position in the array */
3470
3495
zend_string * string_key ;
3471
3496
zend_ulong num_key ;
3472
3497
@@ -3507,50 +3532,61 @@ PHP_FUNCTION(array_slice)
3507
3532
/* Initialize returned array */
3508
3533
array_init_size (return_value , (uint32_t )length );
3509
3534
3510
- /* Start at the beginning and go until we hit offset */
3511
- pos = 0 ;
3512
- if (HT_IS_PACKED (Z_ARRVAL_P (input )) &&
3513
- (!preserve_keys ||
3514
- (offset == 0 && HT_IS_WITHOUT_HOLES (Z_ARRVAL_P (input ))))) {
3515
- zend_hash_real_init_packed (Z_ARRVAL_P (return_value ));
3516
- ZEND_HASH_FILL_PACKED (Z_ARRVAL_P (return_value )) {
3517
- ZEND_HASH_FOREACH_VAL (Z_ARRVAL_P (input ), entry ) {
3518
- pos ++ ;
3519
- if (pos <= offset ) {
3535
+ // Contains modified variants of ZEND_HASH_FOREACH_VAL
3536
+ {
3537
+ HashTable * ht = Z_ARRVAL_P (input );
3538
+ Bucket * p = find_bucket_at_offset (ht , offset );
3539
+ Bucket * end = ht -> arData + ht -> nNumUsed ;
3540
+
3541
+ /* Start at the beginning and go until we hit offset */
3542
+ if (HT_IS_PACKED (Z_ARRVAL_P (input )) &&
3543
+ (!preserve_keys ||
3544
+ (offset == 0 && HT_IS_WITHOUT_HOLES (Z_ARRVAL_P (input ))))) {
3545
+
3546
+ zend_hash_real_init_packed (Z_ARRVAL_P (return_value ));
3547
+ ZEND_HASH_FILL_PACKED (Z_ARRVAL_P (return_value )) {
3548
+ for (; p != end ; p ++ ) {
3549
+ if (__fill_idx >= length ) {
3550
+ break ;
3551
+ }
3552
+ entry = & p -> val ;
3553
+ if (UNEXPECTED (Z_TYPE_P (entry ) == IS_UNDEF )) {
3554
+ continue ;
3555
+ }
3556
+ if (UNEXPECTED (Z_ISREF_P (entry )) &&
3557
+ UNEXPECTED (Z_REFCOUNT_P (entry ) == 1 )) {
3558
+ entry = Z_REFVAL_P (entry );
3559
+ }
3560
+ Z_TRY_ADDREF_P (entry );
3561
+ ZEND_HASH_FILL_ADD (entry );
3562
+ }
3563
+ } ZEND_HASH_FILL_END ();
3564
+ } else {
3565
+ zend_long n = 0 ; /* Current number of elements */
3566
+ for (; p != end ; p ++ ) {
3567
+ entry = & p -> val ;
3568
+ if (UNEXPECTED (Z_TYPE_P (entry ) == IS_UNDEF )) {
3520
3569
continue ;
3521
3570
}
3522
- if (pos > offset + length ) {
3571
+ if (n >= length ) {
3523
3572
break ;
3524
3573
}
3525
- if (UNEXPECTED (Z_ISREF_P (entry )) &&
3526
- UNEXPECTED (Z_REFCOUNT_P (entry ) == 1 )) {
3527
- entry = Z_REFVAL_P (entry );
3528
- }
3529
- Z_TRY_ADDREF_P (entry );
3530
- ZEND_HASH_FILL_ADD (entry );
3531
- } ZEND_HASH_FOREACH_END ();
3532
- } ZEND_HASH_FILL_END ();
3533
- } else {
3534
- ZEND_HASH_FOREACH_KEY_VAL (Z_ARRVAL_P (input ), num_key , string_key , entry ) {
3535
- pos ++ ;
3536
- if (pos <= offset ) {
3537
- continue ;
3538
- }
3539
- if (pos > offset + length ) {
3540
- break ;
3541
- }
3574
+ n ++ ;
3575
+ num_key = p -> h ;
3576
+ string_key = p -> key ;
3542
3577
3543
- if (string_key ) {
3544
- entry = zend_hash_add_new (Z_ARRVAL_P (return_value ), string_key , entry );
3545
- } else {
3546
- if (preserve_keys ) {
3547
- entry = zend_hash_index_add_new (Z_ARRVAL_P (return_value ), num_key , entry );
3578
+ if (string_key ) {
3579
+ entry = zend_hash_add_new (Z_ARRVAL_P (return_value ), string_key , entry );
3548
3580
} else {
3549
- entry = zend_hash_next_index_insert_new (Z_ARRVAL_P (return_value ), entry );
3581
+ if (preserve_keys ) {
3582
+ entry = zend_hash_index_add_new (Z_ARRVAL_P (return_value ), num_key , entry );
3583
+ } else {
3584
+ entry = zend_hash_next_index_insert_new (Z_ARRVAL_P (return_value ), entry );
3585
+ }
3550
3586
}
3587
+ zval_add_ref (entry );
3551
3588
}
3552
- zval_add_ref (entry );
3553
- } ZEND_HASH_FOREACH_END ();
3589
+ }
3554
3590
}
3555
3591
}
3556
3592
/* }}} */
0 commit comments