@@ -3455,6 +3455,32 @@ PHP_FUNCTION(array_splice)
34553455}
34563456/* }}} */
34573457
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+
34583484/* {{{ proto array array_slice(array input, int offset [, int length [, bool preserve_keys]])
34593485 Returns elements specified by offset and length */
34603486PHP_FUNCTION (array_slice )
@@ -3466,7 +3492,6 @@ PHP_FUNCTION(array_slice)
34663492 zend_bool length_is_null = 1 ; /* Whether an explicit length has been omitted */
34673493 zend_bool preserve_keys = 0 ; /* Whether to preserve keys while copying to the new array */
34683494 uint32_t num_in ; /* Number of elements in the input array */
3469- uint32_t pos ; /* Current position in the array */
34703495 zend_string * string_key ;
34713496 zend_ulong num_key ;
34723497
@@ -3507,50 +3532,61 @@ PHP_FUNCTION(array_slice)
35073532 /* Initialize returned array */
35083533 array_init_size (return_value , (uint32_t )length );
35093534
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 )) {
35203569 continue ;
35213570 }
3522- if (pos > offset + length ) {
3571+ if (n >= length ) {
35233572 break ;
35243573 }
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 ;
35423577
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 );
35483580 } 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+ }
35503586 }
3587+ zval_add_ref (entry );
35513588 }
3552- zval_add_ref (entry );
3553- } ZEND_HASH_FOREACH_END ();
3589+ }
35543590 }
35553591}
35563592/* }}} */
0 commit comments