From 1d8c499b5152a9e52729ce8e6b2a0feee0192a43 Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Fri, 23 May 2014 13:10:50 +0200 Subject: [PATCH] Optimize int to string conversion Probably platform depedentant, but for me snprintf is terribly slow. The code for the long printing is taken from the smart string API. --- Zend/zend_operators.c | 20 +++++++++------- Zend/zend_operators.h | 27 +++++++++++++++++++++ ext/standard/php_smart_str.h | 35 ++++----------------------- ext/standard/php_smart_string.h | 42 ++++----------------------------- 4 files changed, 49 insertions(+), 75 deletions(-) diff --git a/Zend/zend_operators.c b/Zend/zend_operators.c index 5fb88b1ca8..b8ab22fc06 100644 --- a/Zend/zend_operators.c +++ b/Zend/zend_operators.c @@ -604,9 +604,7 @@ ZEND_API void _convert_to_string(zval *op ZEND_FILE_LINE_DC) /* {{{ */ break; } case IS_LONG: { - char buf[MAX_LENGTH_OF_LONG + 1]; - int len = snprintf(buf, sizeof(buf), "%ld", Z_LVAL_P(op)); - ZVAL_NEW_STR(op, STR_INIT(buf, len, 0)); + ZVAL_NEW_STR(op, zend_long_to_str(Z_LVAL_P(op))); break; } case IS_DOUBLE: { @@ -883,11 +881,7 @@ try_again: return STR_INIT(buf, len, 0); } case IS_LONG: { - char buf[MAX_LENGTH_OF_LONG + 1]; - int len; - - len = snprintf(buf, sizeof(buf), "%ld", Z_LVAL_P(op)); - return STR_INIT(buf, len, 0); + return zend_long_to_str(Z_LVAL_P(op)); } case IS_DOUBLE: { return zend_strpprintf(0, "%.*G", (int) EG(precision), Z_DVAL_P(op)); @@ -2510,6 +2504,16 @@ ZEND_API void zend_locale_sprintf_double(zval *op ZEND_FILE_LINE_DC) /* {{{ */ } /* }}} */ +ZEND_API zend_string *zend_long_to_str(long num) /* {{{ */ +{ + char buf[MAX_LENGTH_OF_LONG + 1]; + char *res; + _zend_print_signed_to_buf(buf + sizeof(buf)-1, num, unsigned long, res); + return STR_INIT(res, buf + sizeof(buf)-1 - res, 0); +} +/* }}} */ + + /* * Local variables: * tab-width: 4 diff --git a/Zend/zend_operators.h b/Zend/zend_operators.h index b7c8c7e7b2..f03e05b3ad 100644 --- a/Zend/zend_operators.h +++ b/Zend/zend_operators.h @@ -964,6 +964,33 @@ static zend_always_inline void fast_is_not_identical_function(zval *result, zval return SUCCESS; \ } +/* input: buf points to the END of the buffer */ +#define _zend_print_unsigned_to_buf(buf, num, vartype, result) do { \ + char *__p = (buf); \ + vartype __num = (num); \ + *__p = '\0'; \ + do { \ + *--__p = (char) (__num % 10) + '0'; \ + __num /= 10; \ + } while (__num > 0); \ + result = __p; \ +} while (0) + +/* buf points to the END of the buffer */ +#define _zend_print_signed_to_buf(buf, num, vartype, result) do { \ + if (num < 0) { \ + /* this might cause problems when dealing with LONG_MIN + and machines which don't support long long. Works + flawlessly on 32bit x86 */ \ + _zend_print_unsigned_to_buf((buf), -(num), vartype, (result)); \ + *--(result) = '-'; \ + } else { \ + _zend_print_unsigned_to_buf((buf), (num), vartype, (result)); \ + } \ +} while (0) + +ZEND_API zend_string *zend_long_to_str(long num); + #endif /* diff --git a/ext/standard/php_smart_str.h b/ext/standard/php_smart_str.h index 81b92d7a80..e10a711435 100644 --- a/ext/standard/php_smart_str.h +++ b/ext/standard/php_smart_str.h @@ -123,31 +123,6 @@ __dest->s->len = __nl; \ } while (0) -/* input: buf points to the END of the buffer */ -#define smart_str_print_unsigned4(buf, num, vartype, result) do { \ - char *__p = (buf); \ - vartype __num = (num); \ - *__p = '\0'; \ - do { \ - *--__p = (char) (__num % 10) + '0'; \ - __num /= 10; \ - } while (__num > 0); \ - result = __p; \ -} while (0) - -/* buf points to the END of the buffer */ -#define smart_str_print_long4(buf, num, vartype, result) do { \ - if (num < 0) { \ - /* this might cause problems when dealing with LONG_MIN \ - and machines which don't support long long. Works \ - flawlessly on 32bit x86 */ \ - smart_str_print_unsigned4((buf), -(num), vartype, (result));\ - *--(result) = '-'; \ - } else { \ - smart_str_print_unsigned4((buf), (num), vartype, (result)); \ - } \ -} while (0) - /* * these could be replaced using a braced-group inside an expression * for GCC compatible compilers, e.g. @@ -157,20 +132,20 @@ static inline char *smart_str_print_long(char *buf, long num) { char *r; - smart_str_print_long4(buf, num, unsigned long, r); + _zend_print_signed_to_buf(buf, num, unsigned long, r); return r; } static inline char *smart_str_print_unsigned(char *buf, long num) { char *r; - smart_str_print_unsigned4(buf, num, unsigned long, r); + _zend_print_unsigned_to_buf(buf, num, unsigned long, r); return r; } #define smart_str_append_generic_ex(dest, num, type, vartype, func) do { \ char __b[32]; \ char *__t; \ - smart_str_print##func##4 (__b + sizeof(__b) - 1, (num), vartype, __t); \ + _zend_print##func##_to_buf (__b + sizeof(__b) - 1, (num), vartype, __t); \ smart_str_appendl_ex((dest), __t, __b + sizeof(__b) - 1 - __t, (type)); \ } while (0) @@ -178,10 +153,10 @@ static inline char *smart_str_print_unsigned(char *buf, long num) { smart_str_append_generic_ex((dest), (num), (type), unsigned long, _unsigned) #define smart_str_append_long_ex(dest, num, type) \ - smart_str_append_generic_ex((dest), (num), (type), unsigned long, _long) + smart_str_append_generic_ex((dest), (num), (type), unsigned long, _signed) #define smart_str_append_off_t_ex(dest, num, type) \ - smart_str_append_generic_ex((dest), (num), (type), off_t, _long) + smart_str_append_generic_ex((dest), (num), (type), off_t, _signed) #define smart_str_append_ex(dest, src, what) \ smart_str_appendl_ex((dest), ((smart_str *)(src))->s->val, \ diff --git a/ext/standard/php_smart_string.h b/ext/standard/php_smart_string.h index 1613e4898b..02ba9fe84e 100644 --- a/ext/standard/php_smart_string.h +++ b/ext/standard/php_smart_string.h @@ -119,54 +119,22 @@ __dest->len = __nl; \ } while (0) -/* input: buf points to the END of the buffer */ -#define smart_string_print_unsigned4(buf, num, vartype, result) do { \ - char *__p = (buf); \ - vartype __num = (num); \ - *__p = '\0'; \ - do { \ - *--__p = (char) (__num % 10) + '0'; \ - __num /= 10; \ - } while (__num > 0); \ - result = __p; \ -} while (0) - -/* buf points to the END of the buffer */ -#define smart_string_print_long4(buf, num, vartype, result) do { \ - if (num < 0) { \ - /* this might cause problems when dealing with LONG_MIN \ - and machines which don't support long long. Works \ - flawlessly on 32bit x86 */ \ - smart_string_print_unsigned4((buf), -(num), vartype, (result)); \ - *--(result) = '-'; \ - } else { \ - smart_string_print_unsigned4((buf), (num), vartype, (result)); \ - } \ -} while (0) - -/* - * these could be replaced using a braced-group inside an expression - * for GCC compatible compilers, e.g. - * - * #define f(..) ({char *r;..;__r;}) - */ - static inline char *smart_string_print_long(char *buf, long num) { char *r; - smart_string_print_long4(buf, num, unsigned long, r); + _zend_print_signed_to_buf(buf, num, unsigned long, r); return r; } static inline char *smart_string_print_unsigned(char *buf, long num) { char *r; - smart_string_print_unsigned4(buf, num, unsigned long, r); + _zend_print_unsigned_to_buf(buf, num, unsigned long, r); return r; } #define smart_string_append_generic_ex(dest, num, type, vartype, func) do { \ char __b[32]; \ char *__t; \ - smart_string_print##func##4 (__b + sizeof(__b) - 1, (num), vartype, __t); \ + _zend_print##func##_to_buf(__b + sizeof(__b) - 1, (num), vartype, __t); \ smart_string_appendl_ex((dest), __t, __b + sizeof(__b) - 1 - __t, (type)); \ } while (0) @@ -174,10 +142,10 @@ static inline char *smart_string_print_unsigned(char *buf, long num) { smart_string_append_generic_ex((dest), (num), (type), unsigned long, _unsigned) #define smart_string_append_long_ex(dest, num, type) \ - smart_string_append_generic_ex((dest), (num), (type), unsigned long, _long) + smart_string_append_generic_ex((dest), (num), (type), unsigned long, _signed) #define smart_string_append_off_t_ex(dest, num, type) \ - smart_string_append_generic_ex((dest), (num), (type), off_t, _long) + smart_string_append_generic_ex((dest), (num), (type), off_t, _signed) #define smart_string_append_ex(dest, src, what) \ smart_string_appendl_ex((dest), ((smart_string *)(src))->c, \ -- 2.50.1