summaryrefslogtreecommitdiff
path: root/Zend/zend_operators.h
diff options
context:
space:
mode:
Diffstat (limited to 'Zend/zend_operators.h')
-rw-r--r--Zend/zend_operators.h231
1 files changed, 58 insertions, 173 deletions
diff --git a/Zend/zend_operators.h b/Zend/zend_operators.h
index 41342de020..8075edf939 100644
--- a/Zend/zend_operators.h
+++ b/Zend/zend_operators.h
@@ -69,14 +69,41 @@ ZEND_API int is_smaller_or_equal_function(zval *result, zval *op1, zval *op2 TSR
ZEND_API zend_bool instanceof_function_ex(const zend_class_entry *instance_ce, const zend_class_entry *ce, zend_bool interfaces_only TSRMLS_DC);
ZEND_API zend_bool instanceof_function(const zend_class_entry *instance_ce, const zend_class_entry *ce TSRMLS_DC);
+
+/**
+ * Checks whether the string "str" with length "length" is numeric. The value
+ * of allow_errors determines whether it's required to be entirely numeric, or
+ * just its prefix. Leading whitespace is allowed.
+ *
+ * The function returns 0 if the string did not contain a valid number; IS_LONG
+ * if it contained a number that fits within the range of a long; or IS_DOUBLE
+ * if the number was out of long range or contained a decimal point/exponent.
+ * The number's value is returned into the respective pointer, *lval or *dval,
+ * if that pointer is not NULL.
+ *
+ * This variant also gives information if a string that represents an integer
+ * 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.
+ */
+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);
+
END_EXTERN_C()
#if ZEND_DVAL_TO_LVAL_CAST_OK
-# define zend_dval_to_lval(d) ((zend_long) (d))
+static zend_always_inline zend_long zend_dval_to_lval(double d)
+{
+ if (EXPECTED(zend_finite(d)) && EXPECTED(!zend_isnan(d))) {
+ return (zend_long)d;
+ } else {
+ return 0;
+ }
+}
#elif SIZEOF_ZEND_LONG == 4
static zend_always_inline zend_long zend_dval_to_lval(double d)
{
- if (d > ZEND_LONG_MAX || d < ZEND_LONG_MIN) {
+ if (UNEXPECTED(!zend_finite(d)) || UNEXPECTED(zend_isnan(d))) {
+ return 0;
+ } else if (d > ZEND_LONG_MAX || d < ZEND_LONG_MIN) {
double two_pow_32 = pow(2., 32.),
dmod;
@@ -93,8 +120,10 @@ static zend_always_inline zend_long zend_dval_to_lval(double d)
#else
static zend_always_inline zend_long zend_dval_to_lval(double d)
{
+ if (UNEXPECTED(!zend_finite(d)) || UNEXPECTED(zend_isnan(d))) {
+ return 0;
/* >= as (double)ZEND_LONG_MAX is outside signed range */
- if (d >= ZEND_LONG_MAX || d < ZEND_LONG_MIN) {
+ } else if (d >= ZEND_LONG_MAX || d < ZEND_LONG_MIN) {
double two_pow_64 = pow(2., 64.),
dmod;
@@ -114,165 +143,21 @@ static zend_always_inline zend_long zend_dval_to_lval(double d)
#define ZEND_IS_DIGIT(c) ((c) >= '0' && (c) <= '9')
#define ZEND_IS_XDIGIT(c) (((c) >= 'A' && (c) <= 'F') || ((c) >= 'a' && (c) <= 'f'))
-/**
- * Checks whether the string "str" with length "length" is numeric. The value
- * of allow_errors determines whether it's required to be entirely numeric, or
- * just its prefix. Leading whitespace is allowed.
- *
- * The function returns 0 if the string did not contain a valid number; IS_LONG
- * if it contained a number that fits within the range of a long; or IS_DOUBLE
- * if the number was out of long range or contained a decimal point/exponent.
- * The number's value is returned into the respective pointer, *lval or *dval,
- * if that pointer is not NULL.
- *
- * This variant also gives information if a string that represents an integer
- * 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)
+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)
{
- const char *ptr;
- int base = 10, digits = 0, dp_or_e = 0;
- double local_dval = 0.0;
- zend_uchar type;
-
- if (!length) {
+ if (*str > '9') {
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;
- }
+ 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 +194,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;
@@ -401,7 +286,6 @@ ZEND_API int zend_atoi(const char *str, int str_len);
ZEND_API zend_long zend_atol(const char *str, int str_len);
ZEND_API void zend_locale_sprintf_double(zval *op ZEND_FILE_LINE_DC);
-END_EXTERN_C()
#define convert_to_ex_master(pzv, lower_type, upper_type) \
if (Z_TYPE_P(pzv)!=upper_type) { \
@@ -1021,30 +905,31 @@ 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 */
+static zend_always_inline char *zend_print_ulong_to_buf(char *buf, zend_ulong num) {
+ *buf = '\0';
+ do {
+ *--buf = (char) (num % 10) + '0';
+ num /= 10;
+ } while (num > 0);
+ return buf;
+}
/* buf points to the END of the buffer */
-#define _zend_print_signed_to_buf(buf, num, vartype, result) do { \
- if (num < 0) { \
- _zend_print_unsigned_to_buf((buf), -(vartype)(num), vartype, (result)); \
- *--(result) = '-'; \
- } else { \
- _zend_print_unsigned_to_buf((buf), (num), vartype, (result)); \
- } \
-} while (0)
+static zend_always_inline char *zend_print_long_to_buf(char *buf, zend_long num) {
+ if (num < 0) {
+ char *result = zend_print_ulong_to_buf(buf, ~((zend_ulong) num) + 1);
+ *--result = '-';
+ return result;
+ } else {
+ return zend_print_ulong_to_buf(buf, num);
+ }
+}
ZEND_API zend_string *zend_long_to_str(zend_long num);
+END_EXTERN_C()
+
#endif
/*