@ -1815,93 +1815,15 @@ PHP_FUNCTION(shuffle)
}
/* }}} */
PHPAPI HashTable * php_splice ( HashTable * in_hash , int offset , int length , zval * * * list , int list_count , HashTable * * removed ) /* { { { */
PHPAPI void php_splice ( HashTable * ht , zend_uint offset , zend_u int length , zval * * * list , zend_u int list_count , HashTable * removed TSRMLS_DC ) /* { { { */
{
HashTable * out_hash = NULL ; /* Output hashtable */
int num_in , /* Number of entries in the input hashtable */
pos , /* Current position in the hashtable */
i ; /* Loop counter */
Bucket * p ; /* Pointer to hash bucket */
zval * entry ; /* Hash entry */
zend_hash_splice ( ht , sizeof ( zval * ) , ( copy_ctor_func_t ) zval_add_ref , offset , length , ( void * * ) list , list_count , removed ) ;
/* If input hash doesn't exist, we have nothing to do */
if ( ! in_hash ) {
return NULL ;
}
/* Get number of entries in the input hash */
num_in = zend_hash_num_elements ( in_hash ) ;
/* Clamp the offset.. */
if ( offset > num_in ) {
offset = num_in ;
} else if ( offset < 0 & & ( offset = ( num_in + offset ) ) < 0 ) {
offset = 0 ;
}
/* ..and the length */
if ( length < 0 ) {
length = num_in - offset + length ;
} else if ( ( ( unsigned ) offset + ( unsigned ) length ) > ( unsigned ) num_in ) {
length = num_in - offset ;
}
/* Create and initialize output hash */
ALLOC_HASHTABLE ( out_hash ) ;
zend_hash_init ( out_hash , ( length > 0 ? num_in - length : 0 ) + list_count , NULL , ZVAL_PTR_DTOR , 0 ) ;
/* Start at the beginning of the input hash and copy entries to output hash until offset is reached */
for ( pos = 0 , p = in_hash - > pListHead ; pos < offset & & p ; pos + + , p = p - > pListNext ) {
/* Get entry and increase reference count */
entry = * ( ( zval * * ) p - > pData ) ;
Z_ADDREF_P ( entry ) ;
/* Update output hash depending on key type */
if ( p - > nKeyLength = = 0 ) {
zend_hash_next_index_insert ( out_hash , & entry , sizeof ( zval * ) , NULL ) ;
} else {
zend_hash_quick_update ( out_hash , p - > arKey , p - > nKeyLength , p - > h , & entry , sizeof ( zval * ) , NULL ) ;
}
}
/* If hash for removed entries exists, go until offset+length and copy the entries to it */
if ( removed ! = NULL ) {
for ( ; pos < offset + length & & p ; pos + + , p = p - > pListNext ) {
entry = * ( ( zval * * ) p - > pData ) ;
Z_ADDREF_P ( entry ) ;
if ( p - > nKeyLength = = 0 ) {
zend_hash_next_index_insert ( * removed , & entry , sizeof ( zval * ) , NULL ) ;
} else {
zend_hash_quick_update ( * removed , p - > arKey , p - > nKeyLength , p - > h , & entry , sizeof ( zval * ) , NULL ) ;
}
}
} else { /* otherwise just skip those entries */
for ( ; pos < offset + length & & p ; pos + + , p = p - > pListNext ) ;
}
zend_hash_internal_pointer_reset ( ht ) ;
/* If there are entries to insert.. */
if ( list ! = NULL ) {
/* ..for each one, create a new zval, copy entry into it and copy it into the output hash */
for ( i = 0 ; i < list_count ; i + + ) {
entry = * list [ i ] ;
Z_ADDREF_P ( entry ) ;
zend_hash_next_index_insert ( out_hash , & entry , sizeof ( zval * ) , NULL ) ;
}
}
/* Copy the remaining input hash entries to the output hash */
for ( ; p ; p = p - > pListNext ) {
entry = * ( ( zval * * ) p - > pData ) ;
Z_ADDREF_P ( entry ) ;
if ( p - > nKeyLength = = 0 ) {
zend_hash_next_index_insert ( out_hash , & entry , sizeof ( zval * ) , NULL ) ;
} else {
zend_hash_quick_update ( out_hash , p - > arKey , p - > nKeyLength , p - > h , & entry , sizeof ( zval * ) , NULL ) ;
}
if ( ht = = & EG ( symbol_table ) ) {
zend_reset_all_cv ( & EG ( symbol_table ) TSRMLS_CC ) ;
}
zend_hash_internal_pointer_reset ( out_hash ) ;
return out_hash ;
}
/* }}} */
@ -2006,24 +1928,14 @@ PHP_FUNCTION(array_unshift)
{
zval * * * args , /* Function arguments array */
* stack ; /* Input stack */
HashTable * new_hash ; /* New hashtable for the stack */
HashTable old_hash ;
int argc ; /* Number of function arguments */
if ( zend_parse_parameters ( ZEND_NUM_ARGS ( ) TSRMLS_CC , " a+ " , & stack , & args , & argc ) = = FAILURE ) {
return ;
}
/* Use splice to insert the elements at the beginning. Destroy old
* hashtable and replace it with new one */
new_hash = php_splice ( Z_ARRVAL_P ( stack ) , 0 , 0 , & args [ 0 ] , argc , NULL ) ;
old_hash = * Z_ARRVAL_P ( stack ) ;
if ( Z_ARRVAL_P ( stack ) = = & EG ( symbol_table ) ) {
zend_reset_all_cv ( & EG ( symbol_table ) TSRMLS_CC ) ;
}
* Z_ARRVAL_P ( stack ) = * new_hash ;
FREE_HASHTABLE ( new_hash ) ;
zend_hash_destroy ( & old_hash ) ;
/* Use splice to insert the elements at the beginning. */
php_splice ( Z_ARRVAL_P ( stack ) , 0 , 0 , args , argc , NULL TSRMLS_CC ) ;
/* Clean up and return the number of elements in the stack */
efree ( args ) ;
@ -2038,9 +1950,7 @@ PHP_FUNCTION(array_splice)
zval * array , /* Input array */
* repl_array = NULL , /* Replacement array */
* * * repl = NULL ; /* Replacement elements */
HashTable * new_hash = NULL , /* Output array's hash */
* * rem_hash = NULL ; /* Removed elements' hash */
HashTable old_hash ;
HashTable * rem_hash = NULL ; /* Removed elements' hash */
Bucket * p ; /* Bucket used for traversing hash */
long i ,
offset ,
@ -2058,7 +1968,7 @@ PHP_FUNCTION(array_splice)
length = num_in ;
}
if ( ZEND_NUM_ARGS ( ) = = 4 ) {
if ( repl_array ) {
/* Make sure the last argument, if passed, is an array */
convert_to_array ( repl_array ) ;
@ -2070,44 +1980,32 @@ PHP_FUNCTION(array_splice)
}
}
/* Clamp the offset */
if ( offset < 0 & & ( offset = num_in + offset ) < 0 ) {
offset = 0 ;
} else if ( offset > num_in ) {
offset = num_in ;
}
/* Clamp the length */
if ( length < 0 & & ( length = num_in - offset + length ) < 0 ) {
length = 0 ;
} else if ( ( unsigned long ) offset + ( unsigned long ) length > ( unsigned ) num_in ) {
length = num_in - offset ;
}
/* Don't create the array of removed elements if it's not going
* to be used ; e . g . only removing and / or replacing elements */
if ( return_value_used ) {
int size = length ;
/* Clamp the offset.. */
if ( offset > num_in ) {
offset = num_in ;
} else if ( offset < 0 & & ( offset = ( num_in + offset ) ) < 0 ) {
offset = 0 ;
}
/* ..and the length */
if ( length < 0 ) {
size = num_in - offset + length ;
} else if ( ( ( unsigned long ) offset + ( unsigned long ) length ) > ( unsigned ) num_in ) {
size = num_in - offset ;
}
/* Initialize return value */
array_init_size ( return_value , size > 0 ? size : 0 ) ;
rem_hash = & Z_ARRVAL_P ( return_value ) ;
array_init_size ( return_value , length ) ;
rem_hash = Z_ARRVAL_P ( return_value ) ;
}
/* Perform splice */
new_hash = php_splice ( Z_ARRVAL_P ( array ) , offset , length , repl , repl_num , rem_hash ) ;
/* Replace input array's hashtable with the new one */
old_hash = * Z_ARRVAL_P ( array ) ;
if ( Z_ARRVAL_P ( array ) = = & EG ( symbol_table ) ) {
zend_reset_all_cv ( & EG ( symbol_table ) TSRMLS_CC ) ;
}
* Z_ARRVAL_P ( array ) = * new_hash ;
FREE_HASHTABLE ( new_hash ) ;
zend_hash_destroy ( & old_hash ) ;
php_splice ( Z_ARRVAL_P ( array ) , offset , length , repl , repl_num , rem_hash TSRMLS_CC ) ;
/* Clean up */
if ( ZEND_NUM_ARGS ( ) = = 4 ) {
if ( repl ) {
efree ( repl ) ;
}
}
@ -2669,8 +2567,6 @@ PHP_FUNCTION(array_pad)
zval * input ; /* Input array */
zval * pad_value ; /* Padding value obviously */
zval * * * pads ; /* Array to pass to splice */
HashTable * new_hash ; /* Return value from splice */
HashTable old_hash ;
long pad_size ; /* Size to pad to */
long pad_size_abs ; /* Absolute value of pad_size */
int input_size ; /* Size of the input array */
@ -2714,19 +2610,10 @@ PHP_FUNCTION(array_pad)
/* Pad on the right or on the left */
if ( pad_size > 0 ) {
new_hash = php_splice ( Z_ARRVAL_P ( return_value ) , input_size , 0 , pads , num_pads , NULL ) ;
php_splice ( Z_ARRVAL_P ( return_value ) , input_size , 0 , pads , num_pads , NULL TSRMLS_CC ) ;
} else {
new_hash = php_splice ( Z_ARRVAL_P ( return_value ) , 0 , 0 , pads , num_pads , NULL ) ;
}
/* Copy the result hash into return value */
old_hash = * Z_ARRVAL_P ( return_value ) ;
if ( Z_ARRVAL_P ( return_value ) = = & EG ( symbol_table ) ) {
zend_reset_all_cv ( & EG ( symbol_table ) TSRMLS_CC ) ;
php_splice ( Z_ARRVAL_P ( return_value ) , 0 , 0 , pads , num_pads , NULL TSRMLS_CC ) ;
}
* Z_ARRVAL_P ( return_value ) = * new_hash ;
FREE_HASHTABLE ( new_hash ) ;
zend_hash_destroy ( & old_hash ) ;
/* Clean up */
efree ( pads ) ;