[PATCH] array_fill: Allow an array to specify keys
| From: | Matt W | Date: | Sun, 25 Jun 2006 11:10:54 +0000 |
| Subject: | [PATCH] array_fill: Allow an array to specify keys | ||
| Groups: | php.internals | ||
| Request: | Send a blank email to internals+get-24210@lists.php.net to get a copy of this message | ||
Hi all,
I'm on Windows and haven't tried submitting a patch before, so I JUST now
installed WinCvs since I don't think you want just a diff of my local file.
I used PHP_5_1 since: 5.1's the "regular" download I started working on; if
you use it, I assume this can go in 5.1; and I don't know what to do. :-)
I've been casually browsing through the PHP source for a while, but never
modified it or used C. Just found out about VC++ Express, etc. and set it
up to try messing with PHP. Had some missing file errors while building
(don't know if that's my problem, or a bug...), but got it done after
changing a few files that were causing them. Just some background... ;-)
Awhile ago I wished array_fill could also be used like array_fill(array
keys, mixed value), which would work like:
foreach ($keys as $k) { $array[$k] = $val; }
OR
$array = array_combine($keys, array_fill(0, count($keys), $val));
So that's what I did for my first, admittedly simple, modification.
I couldn't figure out a reason for the *newval variable, since it seemed to
be the same as **val (pointer stuff can confuse me, being a C newbie ;-)).
Was I wrong to remove it? I also wasn't sure why sizeof(val) was used in
one place and sizeof(zval *) in another; but it seems to be random after
looking in array.c whether var_name or zval * is used, so I stuck with the
latter. I realize now that they're same (right?), but it delayed me,
assuming there's a *reason* for everything.
Other things I changed while experimenting were initializing the return
array AFTER checking the parameters so it doesn't have to be destroyed/freed
later; and I made the IS_LONG case first in the switch () for the first
parameter's type -- isn't that logical since it's supposed to a PHP int and
probably is? :-)
I hope it's coded correctly (feedback welcome, as basic as it is, LOL).
Everything works like it should as far as I can tell. And it's a lot faster
of course than the other 2 methods I mentioned for initializing arbitrary
keys. Let me know if I need to diff against a version other than 5.1 or
whatever.
Thanks,
Matt
Index: ext/standard/array.c =================================================================== RCS file: /repository/php-src/ext/standard/array.c,v retrieving revision 1.308.2.22 diff -u -r1.308.2.22 array.c --- ext/standard/array.c 3 Jun 2006 18:59:55 -0000 1.308.2.22 +++ ext/standard/array.c 24 Jun 2006 03:14:01 -0000 @@ -1536,45 +1536,81 @@ Create an array containing num elements starting with index start_key each initialized to val */ PHP_FUNCTION(array_fill) { - zval **start_key, **num, **val, *newval; + zval **key_data, **num, **val, **entry; long i; + HashPosition pos; - if (ZEND_NUM_ARGS() != 3 || zend_get_parameters_ex(3, &start_key, &num, &val) == FAILURE) { + if ((ZEND_NUM_ARGS() != 3 || zend_get_parameters_ex(3, &key_data, &num, &val) == FAILURE) && + (ZEND_NUM_ARGS() != 2 || zend_get_parameters_ex(2, &key_data, &val) == FAILURE)) { WRONG_PARAM_COUNT; } - switch (Z_TYPE_PP(start_key)) { - case IS_STRING: - case IS_LONG: - case IS_DOUBLE: - /* allocate an array for return */ - array_init(return_value); - - if (PZVAL_IS_REF(*val)) { - SEPARATE_ZVAL(val); - } - convert_to_long_ex(start_key); - zval_add_ref(val); - zend_hash_index_update(Z_ARRVAL_P(return_value), Z_LVAL_PP(start_key), val, sizeof(val), NULL); - break; - default: - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Wrong data type for start key"); + if (ZEND_NUM_ARGS() == 2) { + if (Z_TYPE_PP(key_data) != IS_ARRAY) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "First parameter must be an array when passing 2 parameters"); RETURN_FALSE; - break; - } + } + } else { + switch (Z_TYPE_PP(key_data)) { + case IS_LONG: + case IS_STRING: + case IS_DOUBLE: + convert_to_long_ex(num); + + i = Z_LVAL_PP(num) - 1; + if (i < 0) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Number of elements must be positive"); + RETURN_FALSE; + } - convert_to_long_ex(num); - i = Z_LVAL_PP(num) - 1; - if (i < 0) { - zend_hash_destroy(Z_ARRVAL_P(return_value)); - efree(Z_ARRVAL_P(return_value)); - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Number of elements must be positive"); - RETURN_FALSE; + convert_to_long_ex(key_data); + break; + default: + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Wrong data type for start key"); + RETURN_FALSE; + break; + } } - newval = *val; - while (i--) { - zval_add_ref(&newval); - zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &newval, sizeof(zval *), NULL); + + /* Initialize return array */ + array_init(return_value); + + if (PZVAL_IS_REF(*val)) { + SEPARATE_ZVAL(val); + } + + + if (Z_TYPE_PP(key_data) == IS_LONG) { + zval_add_ref(val); + zend_hash_index_update(Z_ARRVAL_P(return_value), Z_LVAL_PP(key_data), val, sizeof(zval *), NULL); + + while (i--) { + zval_add_ref(val); + zend_hash_next_index_insert(Z_ARRVAL_P(return_value), val, sizeof(zval *), NULL); + } + } else { + zend_hash_internal_pointer_reset_ex(Z_ARRVAL_PP(key_data), &pos); + + while (zend_hash_get_current_data_ex(Z_ARRVAL_PP(key_data), (void **)&entry, &pos) == SUCCESS) { + zval_add_ref(val); + + if (Z_TYPE_PP(entry) == IS_STRING) { + zend_symtable_update(Z_ARRVAL_P(return_value), Z_STRVAL_PP(entry), Z_STRLEN_PP(entry) + 1, val, sizeof(zval *), NULL); + } else if (Z_TYPE_PP(entry) == IS_LONG) { + zend_hash_index_update(Z_ARRVAL_P(return_value), Z_LVAL_PP(entry), val, sizeof(zval *), NULL); + } else { + zval tmpkey; + + tmpkey = **entry; + zval_copy_ctor(&tmpkey); + convert_to_string(&tmpkey); + + zend_symtable_update(Z_ARRVAL_P(return_value), Z_STRVAL(tmpkey), Z_STRLEN(tmpkey) + 1, val, sizeof(zval *), NULL); + + zval_dtor(&tmpkey); + } + zend_hash_move_forward_ex(Z_ARRVAL_PP(key_data), &pos); + } } } /* }}} */
Index: ext/standard/array.c =================================================================== RCS file: /repository/php-src/ext/standard/array.c,v retrieving revision 1.308.2.22 diff -u -r1.308.2.22 array.c --- ext/standard/array.c 3 Jun 2006 18:59:55 -0000 1.308.2.22 +++ ext/standard/array.c 24 Jun 2006 03:14:01 -0000 @@ -1536,45 +1536,81 @@ Create an array containing num elements starting with index start_key each initialized to val */ PHP_FUNCTION(array_fill) { - zval **start_key, **num, **val, *newval; + zval **key_data, **num, **val, **entry; long i; + HashPosition pos; - if (ZEND_NUM_ARGS() != 3 || zend_get_parameters_ex(3, &start_key, &num, &val) == FAILURE) { + if ((ZEND_NUM_ARGS() != 3 || zend_get_parameters_ex(3, &key_data, &num, &val) == FAILURE) && + (ZEND_NUM_ARGS() != 2 || zend_get_parameters_ex(2, &key_data, &val) == FAILURE)) { WRONG_PARAM_COUNT; } - switch (Z_TYPE_PP(start_key)) { - case IS_STRING: - case IS_LONG: - case IS_DOUBLE: - /* allocate an array for return */ - array_init(return_value); - - if (PZVAL_IS_REF(*val)) { - SEPARATE_ZVAL(val); - } - convert_to_long_ex(start_key); - zval_add_ref(val); - zend_hash_index_update(Z_ARRVAL_P(return_value), Z_LVAL_PP(start_key), val, sizeof(val), NULL); - break; - default: - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Wrong data type for start key"); + if (ZEND_NUM_ARGS() == 2) { + if (Z_TYPE_PP(key_data) != IS_ARRAY) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "First parameter must be an array when passing 2 parameters"); RETURN_FALSE; - break; - } + } + } else { + switch (Z_TYPE_PP(key_data)) { + case IS_LONG: + case IS_STRING: + case IS_DOUBLE: + convert_to_long_ex(num); + + i = Z_LVAL_PP(num) - 1; + if (i < 0) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Number of elements must be positive"); + RETURN_FALSE; + } - convert_to_long_ex(num); - i = Z_LVAL_PP(num) - 1; - if (i < 0) { - zend_hash_destroy(Z_ARRVAL_P(return_value)); - efree(Z_ARRVAL_P(return_value)); - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Number of elements must be positive"); - RETURN_FALSE; + convert_to_long_ex(key_data); + break; + default: + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Wrong data type for start key"); + RETURN_FALSE; + break; + } } - newval = *val; - while (i--) { - zval_add_ref(&newval); - zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &newval, sizeof(zval *), NULL); + + /* Initialize return array */ + array_init(return_value); + + if (PZVAL_IS_REF(*val)) { + SEPARATE_ZVAL(val); + } + + + if (Z_TYPE_PP(key_data) == IS_LONG) { + zval_add_ref(val); + zend_hash_index_update(Z_ARRVAL_P(return_value), Z_LVAL_PP(key_data), val, sizeof(zval *), NULL); + + while (i--) { + zval_add_ref(val); + zend_hash_next_index_insert(Z_ARRVAL_P(return_value), val, sizeof(zval *), NULL); + } + } else { + zend_hash_internal_pointer_reset_ex(Z_ARRVAL_PP(key_data), &pos); + + while (zend_hash_get_current_data_ex(Z_ARRVAL_PP(key_data), (void **)&entry, &pos) == SUCCESS) { + zval_add_ref(val); + + if (Z_TYPE_PP(entry) == IS_STRING) { + zend_symtable_update(Z_ARRVAL_P(return_value), Z_STRVAL_PP(entry), Z_STRLEN_PP(entry) + 1, val, sizeof(zval *), NULL); + } else if (Z_TYPE_PP(entry) == IS_LONG) { + zend_hash_index_update(Z_ARRVAL_P(return_value), Z_LVAL_PP(entry), val, sizeof(zval *), NULL); + } else { + zval tmpkey; + + tmpkey = **entry; + zval_copy_ctor(&tmpkey); + convert_to_string(&tmpkey); + + zend_symtable_update(Z_ARRVAL_P(return_value), Z_STRVAL(tmpkey), Z_STRLEN(tmpkey) + 1, val, sizeof(zval *), NULL); + + zval_dtor(&tmpkey); + } + zend_hash_move_forward_ex(Z_ARRVAL_PP(key_data), &pos); + } } } /* }}} */