diff --git a/UPGRADING b/UPGRADING index 0a639508ef696..44450084c5bf4 100644 --- a/UPGRADING +++ b/UPGRADING @@ -567,6 +567,8 @@ MBString: . Improved performance of array functions with callbacks (array_find, array_filter, array_map, usort, ...). . Improved performance of urlencode() and rawurlencode(). + . Improved unpack() performance with nameless repetitions by avoiding + creating temporary strings and reparsing them. - XMLReader: . Improved property access performance. diff --git a/ext/standard/pack.c b/ext/standard/pack.c index ec30be436741d..1dc04dab86c1a 100644 --- a/ext/standard/pack.c +++ b/ext/standard/pack.c @@ -885,12 +885,15 @@ PHP_FUNCTION(unpack) if ((inputpos + size) <= inputlen) { zend_string* real_name; + zend_long long_key = 0; zval val; - if (repetitions == 1 && namelen > 0) { + if (namelen == 0) { + real_name = NULL; + long_key = i + 1; + } else if (repetitions == 1) { /* Use a part of the formatarg argument directly as the name. */ real_name = zend_string_init_fast(name, namelen); - } else { /* Need to add the 1-based element number to the name */ char buf[MAX_LENGTH_OF_LONG + 1]; @@ -912,7 +915,6 @@ PHP_FUNCTION(unpack) size = len; ZVAL_STRINGL(&val, &input[inputpos], len); - zend_symtable_update(Z_ARRVAL_P(return_value), real_name, &val); break; } case 'A': { @@ -939,7 +941,6 @@ PHP_FUNCTION(unpack) } ZVAL_STRINGL(&val, &input[inputpos], len + 1); - zend_symtable_update(Z_ARRVAL_P(return_value), real_name, &val); break; } /* New option added for Z to remain in-line with the Perl implementation */ @@ -964,7 +965,6 @@ PHP_FUNCTION(unpack) len = s; ZVAL_STRINGL(&val, &input[inputpos], len); - zend_symtable_update(Z_ARRVAL_P(return_value), real_name, &val); break; } @@ -979,7 +979,9 @@ PHP_FUNCTION(unpack) if (size > INT_MAX / 2) { - zend_string_release(real_name); + if (real_name) { + zend_string_release_ex(real_name, false); + } zend_argument_value_error(1, "repeater must be less than or equal to %d", INT_MAX / 2); RETURN_THROWS(); } @@ -1016,7 +1018,6 @@ PHP_FUNCTION(unpack) ZSTR_VAL(buf)[len] = '\0'; ZVAL_STR(&val, buf); - zend_symtable_update(Z_ARRVAL_P(return_value), real_name, &val); break; } @@ -1026,7 +1027,6 @@ PHP_FUNCTION(unpack) zend_long v = (type == 'c') ? (int8_t) x : x; ZVAL_LONG(&val, v); - zend_symtable_update(Z_ARRVAL_P(return_value), real_name, &val); break; } @@ -1046,7 +1046,6 @@ PHP_FUNCTION(unpack) } ZVAL_LONG(&val, v); - zend_symtable_update(Z_ARRVAL_P(return_value), real_name, &val); break; } @@ -1062,7 +1061,6 @@ PHP_FUNCTION(unpack) } ZVAL_LONG(&val, v); - zend_symtable_update(Z_ARRVAL_P(return_value), real_name, &val); break; } @@ -1082,8 +1080,6 @@ PHP_FUNCTION(unpack) } ZVAL_LONG(&val, v); - zend_symtable_update(Z_ARRVAL_P(return_value), real_name, &val); - break; } @@ -1104,7 +1100,6 @@ PHP_FUNCTION(unpack) } ZVAL_LONG(&val, v); - zend_symtable_update(Z_ARRVAL_P(return_value), real_name, &val); break; } #endif @@ -1124,7 +1119,6 @@ PHP_FUNCTION(unpack) } ZVAL_DOUBLE(&val, v); - zend_symtable_update(Z_ARRVAL_P(return_value), real_name, &val); break; } @@ -1143,13 +1137,12 @@ PHP_FUNCTION(unpack) } ZVAL_DOUBLE(&val, v); - zend_symtable_update(Z_ARRVAL_P(return_value), real_name, &val); break; } case 'x': /* Do nothing with input, just skip it */ - break; + goto no_output; case 'X': if (inputpos < size) { @@ -1160,7 +1153,7 @@ PHP_FUNCTION(unpack) php_error_docref(NULL, E_WARNING, "Type %c: outside of string", type); } } - break; + goto no_output; case '@': if (repetitions <= inputlen) { @@ -1170,10 +1163,19 @@ PHP_FUNCTION(unpack) } i = repetitions - 1; /* Done, break out of for loop */ - break; + goto no_output; } - zend_string_release(real_name); + if (real_name) { + zend_symtable_update(Z_ARRVAL_P(return_value), real_name, &val); + } else { + zend_hash_index_update(Z_ARRVAL_P(return_value), long_key, &val); + } + +no_output: + if (real_name) { + zend_string_release_ex(real_name, false); + } inputpos += size; if (inputpos < 0) {