From: Dmitry Stogov Date: Thu, 18 Sep 2014 18:19:51 +0000 (+0400) Subject: Split is_numeric_string_ex() into inline and non-inline parts X-Git-Tag: POST_NATIVE_TLS_MERGE^2~225 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=db6306dd0ea6b08586a245a559e428fd1e18e8c1;p=php Split is_numeric_string_ex() into inline and non-inline parts --- diff --git a/Zend/zend_operators.c b/Zend/zend_operators.c index d3a2da8618..db3e8df8c3 100644 --- a/Zend/zend_operators.c +++ b/Zend/zend_operators.c @@ -2530,6 +2530,143 @@ ZEND_API zend_uchar is_numeric_str_function(const zend_string *str, zend_long *l return is_numeric_string_ex(str->val, str->len, lval, dval, -1, NULL); } +ZEND_API zend_uchar _is_numeric_string_ex(const char *str, size_t length, zend_long *lval, double *dval, int allow_errors, int *oflow_info) +{ + const char *ptr; + int base = 10, digits = 0, dp_or_e = 0; + double local_dval = 0.0; + zend_uchar type; + + if (!length) { + return 0; + } + + if (oflow_info != NULL) { + *oflow_info = 0; + } + + /* Skip any whitespace + * This is much faster than the isspace() function */ + while (*str == ' ' || *str == '\t' || *str == '\n' || *str == '\r' || *str == '\v' || *str == '\f') { + str++; + length--; + } + ptr = str; + + if (*ptr == '-' || *ptr == '+') { + ptr++; + } + + if (ZEND_IS_DIGIT(*ptr)) { + /* Handle hex numbers + * str is used instead of ptr to disallow signs and keep old behavior */ + if (length > 2 && *str == '0' && (str[1] == 'x' || str[1] == 'X')) { + base = 16; + ptr += 2; + } + + /* Skip any leading 0s */ + while (*ptr == '0') { + ptr++; + } + + /* Count the number of digits. If a decimal point/exponent is found, + * it's a double. Otherwise, if there's a dval or no need to check for + * a full match, stop when there are too many digits for a long */ + for (type = IS_LONG; !(digits >= MAX_LENGTH_OF_LONG && (dval || allow_errors == 1)); digits++, ptr++) { +check_digits: + if (ZEND_IS_DIGIT(*ptr) || (base == 16 && ZEND_IS_XDIGIT(*ptr))) { + continue; + } else if (base == 10) { + if (*ptr == '.' && dp_or_e < 1) { + goto process_double; + } else if ((*ptr == 'e' || *ptr == 'E') && dp_or_e < 2) { + const char *e = ptr + 1; + + if (*e == '-' || *e == '+') { + ptr = e++; + } + if (ZEND_IS_DIGIT(*e)) { + goto process_double; + } + } + } + + break; + } + + if (base == 10) { + if (digits >= MAX_LENGTH_OF_LONG) { + if (oflow_info != NULL) { + *oflow_info = *str == '-' ? -1 : 1; + } + dp_or_e = -1; + goto process_double; + } + } else if (!(digits < SIZEOF_ZEND_LONG * 2 || (digits == SIZEOF_ZEND_LONG * 2 && ptr[-digits] <= '7'))) { + if (dval) { + local_dval = zend_hex_strtod(str, &ptr); + } + if (oflow_info != NULL) { + *oflow_info = 1; + } + type = IS_DOUBLE; + } + } else if (*ptr == '.' && ZEND_IS_DIGIT(ptr[1])) { +process_double: + type = IS_DOUBLE; + + /* If there's a dval, do the conversion; else continue checking + * the digits if we need to check for a full match */ + if (dval) { + local_dval = zend_strtod(str, &ptr); + } else if (allow_errors != 1 && dp_or_e != -1) { + dp_or_e = (*ptr++ == '.') ? 1 : 2; + goto check_digits; + } + } else { + return 0; + } + + if (ptr != str + length) { + if (!allow_errors) { + return 0; + } + if (allow_errors == -1) { + zend_error(E_NOTICE, "A non well formed numeric value encountered"); + } + } + + if (type == IS_LONG) { + if (digits == MAX_LENGTH_OF_LONG - 1) { + int cmp = strcmp(&ptr[-digits], long_min_digits); + + if (!(cmp < 0 || (cmp == 0 && *str == '-'))) { + if (dval) { + *dval = zend_strtod(str, NULL); + } + if (oflow_info != NULL) { + *oflow_info = *str == '-' ? -1 : 1; + } + + return IS_DOUBLE; + } + } + + if (lval) { + *lval = ZEND_STRTOL(str, NULL, base); + } + + return IS_LONG; + } else { + if (dval) { + *dval = local_dval; + } + + return IS_DOUBLE; + } +} + /* * Local variables: * tab-width: 4 diff --git a/Zend/zend_operators.h b/Zend/zend_operators.h index a50e65d7c2..ece77936eb 100644 --- a/Zend/zend_operators.h +++ b/Zend/zend_operators.h @@ -129,150 +129,23 @@ static zend_always_inline zend_long zend_dval_to_lval(double d) * could not be represented as such due to overflow. It writes 1 to oflow_info * if the integer is larger than ZEND_LONG_MAX and -1 if it's smaller than ZEND_LONG_MIN. */ -static inline zend_uchar is_numeric_string_ex(const char *str, size_t length, zend_long *lval, double *dval, int allow_errors, int *oflow_info) -{ - const char *ptr; - int base = 10, digits = 0, dp_or_e = 0; - double local_dval = 0.0; - zend_uchar type; - - if (!length) { - return 0; - } - - if (oflow_info != NULL) { - *oflow_info = 0; - } - - /* Skip any whitespace - * This is much faster than the isspace() function */ - while (*str == ' ' || *str == '\t' || *str == '\n' || *str == '\r' || *str == '\v' || *str == '\f') { - str++; - length--; - } - ptr = str; - - if (*ptr == '-' || *ptr == '+') { - ptr++; - } - - if (ZEND_IS_DIGIT(*ptr)) { - /* Handle hex numbers - * str is used instead of ptr to disallow signs and keep old behavior */ - if (length > 2 && *str == '0' && (str[1] == 'x' || str[1] == 'X')) { - base = 16; - ptr += 2; - } - - /* Skip any leading 0s */ - while (*ptr == '0') { - ptr++; - } - - /* Count the number of digits. If a decimal point/exponent is found, - * it's a double. Otherwise, if there's a dval or no need to check for - * a full match, stop when there are too many digits for a long */ - for (type = IS_LONG; !(digits >= MAX_LENGTH_OF_LONG && (dval || allow_errors == 1)); digits++, ptr++) { -check_digits: - if (ZEND_IS_DIGIT(*ptr) || (base == 16 && ZEND_IS_XDIGIT(*ptr))) { - continue; - } else if (base == 10) { - if (*ptr == '.' && dp_or_e < 1) { - goto process_double; - } else if ((*ptr == 'e' || *ptr == 'E') && dp_or_e < 2) { - const char *e = ptr + 1; - - if (*e == '-' || *e == '+') { - ptr = e++; - } - if (ZEND_IS_DIGIT(*e)) { - goto process_double; - } - } - } +ZEND_API zend_uchar _is_numeric_string_ex(const char *str, size_t length, zend_long *lval, double *dval, int allow_errors, int *oflow_info); - break; - } - - if (base == 10) { - if (digits >= MAX_LENGTH_OF_LONG) { - if (oflow_info != NULL) { - *oflow_info = *str == '-' ? -1 : 1; - } - dp_or_e = -1; - goto process_double; - } - } else if (!(digits < SIZEOF_ZEND_LONG * 2 || (digits == SIZEOF_ZEND_LONG * 2 && ptr[-digits] <= '7'))) { - if (dval) { - local_dval = zend_hex_strtod(str, &ptr); - } - if (oflow_info != NULL) { - *oflow_info = 1; - } - type = IS_DOUBLE; - } - } else if (*ptr == '.' && ZEND_IS_DIGIT(ptr[1])) { -process_double: - type = IS_DOUBLE; - - /* If there's a dval, do the conversion; else continue checking - * the digits if we need to check for a full match */ - if (dval) { - local_dval = zend_strtod(str, &ptr); - } else if (allow_errors != 1 && dp_or_e != -1) { - dp_or_e = (*ptr++ == '.') ? 1 : 2; - goto check_digits; - } - } else { +static zend_always_inline zend_uchar is_numeric_string_ex(const char *str, size_t length, zend_long *lval, double *dval, int allow_errors, int *oflow_info) +{ + if (*str > '9') { return 0; } - - if (ptr != str + length) { - if (!allow_errors) { - return 0; - } - if (allow_errors == -1) { - zend_error(E_NOTICE, "A non well formed numeric value encountered"); - } - } - - if (type == IS_LONG) { - if (digits == MAX_LENGTH_OF_LONG - 1) { - int cmp = strcmp(&ptr[-digits], long_min_digits); - - if (!(cmp < 0 || (cmp == 0 && *str == '-'))) { - if (dval) { - *dval = zend_strtod(str, NULL); - } - if (oflow_info != NULL) { - *oflow_info = *str == '-' ? -1 : 1; - } - - return IS_DOUBLE; - } - } - - if (lval) { - *lval = ZEND_STRTOL(str, NULL, base); - } - - return IS_LONG; - } else { - if (dval) { - *dval = local_dval; - } - - return IS_DOUBLE; - } + return _is_numeric_string_ex(str, length, lval, dval, allow_errors, oflow_info); } -static inline zend_uchar is_numeric_string(const char *str, size_t length, zend_long *lval, double *dval, int allow_errors) { +static zend_always_inline zend_uchar is_numeric_string(const char *str, size_t length, zend_long *lval, double *dval, int allow_errors) { return is_numeric_string_ex(str, length, lval, dval, allow_errors, NULL); } ZEND_API zend_uchar is_numeric_str_function(const zend_string *str, zend_long *lval, double *dval); -static inline const char * +static zend_always_inline const char * zend_memnstr(const char *haystack, const char *needle, size_t needle_len, char *end) { const char *p = haystack; @@ -309,7 +182,7 @@ zend_memnstr(const char *haystack, const char *needle, size_t needle_len, char * return NULL; } -static inline const void *zend_memrchr(const void *s, int c, size_t n) +static zend_always_inline const void *zend_memrchr(const void *s, int c, size_t n) { register const unsigned char *e;