diff options
Diffstat (limited to 'ext/standard/string.c')
-rw-r--r-- | ext/standard/string.c | 104 |
1 files changed, 57 insertions, 47 deletions
diff --git a/ext/standard/string.c b/ext/standard/string.c index 3162533186..8d95290ca2 100644 --- a/ext/standard/string.c +++ b/ext/standard/string.c @@ -1200,69 +1200,79 @@ PHP_FUNCTION(explode) */ PHPAPI void php_implode(const zend_string *delim, zval *arr, zval *return_value) { - zval *tmp; - smart_str implstr = {0}; - int numelems, i = 0; - zend_string *str; + zval *tmp; + int numelems; + zend_string *str; + char *cptr; + size_t len = 0; + zend_string **strings, **strptr; numelems = zend_hash_num_elements(Z_ARRVAL_P(arr)); if (numelems == 0) { RETURN_EMPTY_STRING(); + } else if (numelems == 1) { + /* loop to search the first not undefined element... */ + ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(arr), tmp) { + RETURN_STR(zval_get_string(tmp)); + } ZEND_HASH_FOREACH_END(); } - ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(arr), tmp) { -again: - switch (Z_TYPE_P(tmp)) { - case IS_STRING: - smart_str_append(&implstr, Z_STR_P(tmp)); - break; - - case IS_LONG: - smart_str_append_long(&implstr, Z_LVAL_P(tmp)); - break; - - case IS_TRUE: - smart_str_appendl(&implstr, "1", sizeof("1")-1); - break; - - case IS_NULL: - case IS_FALSE: - break; + strings = emalloc((sizeof(zend_long) + sizeof(zend_string *)) * numelems); + strptr = strings - 1; - case IS_DOUBLE: { - char *stmp; - size_t str_len = spprintf(&stmp, 0, "%.*G", (int) EG(precision), Z_DVAL_P(tmp)); - smart_str_appendl(&implstr, stmp, str_len); - efree(stmp); - break; + ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(arr), tmp) { + if (Z_TYPE_P(tmp) == IS_LONG) { + double val = Z_LVAL_P(tmp); + *++strptr = NULL; + ((zend_long *) (strings + numelems))[strptr - strings] = Z_LVAL_P(tmp); + if (val < 0) { + val = -10 * val; } - - case IS_REFERENCE: - tmp = Z_REFVAL_P(tmp); - goto again; - - default: - str = zval_get_string(tmp); - smart_str_append(&implstr, str); - zend_string_release(str); - break; - + if (val < 10) { + len++; + } else { + len += (int) log10(10 * (double) val); + } + } else { + *++strptr = zval_get_string(tmp); + len += (*strptr)->len; } + } ZEND_HASH_FOREACH_END(); + + str = zend_string_alloc(len + (numelems - 1) * delim->len, 0); + cptr = str->val + str->len; + *cptr = 0; - if (++i != numelems) { - smart_str_append(&implstr, delim); + do { + if (*strptr) { + cptr -= (*strptr)->len; + memcpy(cptr, (*strptr)->val, (*strptr)->len); + zend_string_release(*strptr); + } else { + char *oldPtr = cptr; + char oldVal = *cptr; + zend_long val = ((zend_long *) (strings + numelems))[strptr - strings]; + cptr = zend_print_long_to_buf(cptr, val); + *oldPtr = oldVal; } - } ZEND_HASH_FOREACH_END(); - smart_str_0(&implstr); + cptr -= delim->len; + memcpy(cptr, delim->val, delim->len); + } while (--strptr > strings); - if (implstr.s) { - RETURN_NEW_STR(implstr.s); + if (*strptr) { + memcpy(str->val, (*strptr)->val, (*strptr)->len); + zend_string_release(*strptr); } else { - smart_str_free(&implstr); - RETURN_EMPTY_STRING(); + char *oldPtr = cptr; + char oldVal = *cptr; + zend_print_long_to_buf(cptr, ((zend_long *) (strings + numelems))[strptr - strings]); + *oldPtr = oldVal; } + + efree(strings); + RETURN_NEW_STR(str); } /* }}} */ |