Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:10436 Return-Path: Mailing-List: contact internals-help@lists.php.net; run by ezmlm Delivered-To: mailing list internals@lists.php.net Received: (qmail 28348 invoked by uid 1010); 14 Jun 2004 11:36:42 -0000 Delivered-To: ezmlm-scan-internals@lists.php.net Delivered-To: ezmlm-internals@lists.php.net Received: (qmail 28324 invoked by uid 1007); 14 Jun 2004 11:36:42 -0000 To: internals@lists.php.net Date: Mon, 14 Jun 2004 14:35:53 +0300 References: Organization: none Content-Type: text/plain; format=flowed; delsp=yes; charset=koi8-r MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Message-ID: User-Agent: Opera M2/7.50 (Win32, build 3778) X-Posted-By: 217.23.116.150 Subject: Re: implode() speedup From: valyala@tut.by ("Alexander Valyalkin") I've read CODING_STANDARDS (thanks to Christian Schneider) and corrected my code according to your standards. Also I've improved speed of algorithm. Now it is not duplicate the string value of array item, if it is has string type already: if (Z_TYPE_PP(tmp) != IS_STRING) { /* create new instance of a var, then convert it to a string */ SEPARATE_ZVAL(tmp); convert_to_string(*tmp); } unified diff: =========cut=========== --- string.c Thu May 13 20:44:32 2004 +++ string_implode.c Mon Jun 14 14:28:29 2004 @@ -827,31 +827,84 @@ { zval **tmp; HashPosition pos; - smart_str implstr = {0}; - int numelems, i = 0; + int numelems, i; + size_t result_len, delim_len, tmp_len; + char *result_str, *delim_str, *ptr; + char **str_arr; + size_t *len_arr; numelems = zend_hash_num_elements(Z_ARRVAL_P(arr)); - - if(numelems == 0) { - RETURN_EMPTY_STRING(); + if (numelems < 1) RETURN_EMPTY_STRING(); + str_arr = (char **) emalloc(numelems * sizeof(char *)); + len_arr = (size_t *) emalloc(numelems * sizeof(size_t)); + if (str_arr == NULL || len_arr == NULL) { + TSRMLS_FETCH(); + php_error_docref(NULL TSRMLS_CC, E_ERROR, "Out of memory"); + RETURN_FALSE; } + delim_str = Z_STRVAL_P(delim); + delim_len = Z_STRLEN_P(delim); + /* the first pass: calculate size of memory to allocate */ + i = 0; + result_len = 0; zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(arr), &pos); while (zend_hash_get_current_data_ex(Z_ARRVAL_P(arr), (void **) &tmp, &pos) == SUCCESS) { + if (Z_TYPE_PP(tmp) != IS_STRING) { + /* create new instance of a var, then convert it to a string */ SEPARATE_ZVAL(tmp); convert_to_string(*tmp); - - smart_str_appendl(&implstr, Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp)); - if (++i != numelems) { - smart_str_appendl(&implstr, Z_STRVAL_P(delim), Z_STRLEN_P(delim)); } + str_arr[i] = Z_STRVAL_PP(tmp); /* save pointer to string for the second pass (see below) */ + len_arr[i] = Z_STRLEN_PP(tmp); /* length of the string */ + result_len += len_arr[i]; + i++; + if (delim_len && i < numelems) result_len += delim_len; zend_hash_move_forward_ex(Z_ARRVAL_P(arr), &pos); } - smart_str_0(&implstr); + if (result_len == 0) { + /* result_len could be 0 in two cases: + 1) both delimiter & array values have nul length + 2) array contains one element with nul length + */ + efree(len_arr); + efree(str_arr); + RETURN_EMPTY_STRING(); + } + + /* allocate memory */ + ptr = result_str = emalloc(result_len + 1); + if (ptr == NULL) { + efree(len_arr); + efree(str_arr); + TSRMLS_FETCH(); + php_error_docref(NULL TSRMLS_CC, E_ERROR, "Out of memory"); + RETURN_FALSE; + } - RETURN_STRINGL(implstr.c, implstr.len, 0); + /* the second pass: implode array into allocated memory */ + for (i = 0; i < numelems - 1; i++) { + if (tmp_len = len_arr[i]) { + memcpy(ptr, str_arr[i], tmp_len); + ptr += tmp_len; + } + if (delim_len) { + memcpy(ptr, delim_str, delim_len); + ptr += delim_len; + } + } + /* copy the last element of the array */ + if (tmp_len = len_arr[i]) { + memcpy(ptr, str_arr[i], tmp_len); + ptr += tmp_len; + } + *ptr = '\0'; + + efree(len_arr); + efree(str_arr); + RETURN_STRINGL(result_str, result_len, 0); } /* }}} */ =========cut=========== -- Using Opera's revolutionary e-mail client: http://www.opera.com/m2/