diff options
author | Nikita Popov <nikita.ppv@gmail.com> | 2019-02-21 17:38:25 +0100 |
---|---|---|
committer | Nikita Popov <nikita.ppv@gmail.com> | 2020-07-22 12:23:49 +0200 |
commit | acbf7802af7b88d16497971494f5dc42c4e08ce6 (patch) | |
tree | 571f3a6bb871e0c6d4948e4e5cb1406e1305a04f /Zend/zend_operators.c | |
parent | 2940839d280d307fd1e8a06aefbd1fb31f1d3242 (diff) | |
download | php-git-acbf7802af7b88d16497971494f5dc42c4e08ce6.tar.gz |
Improved number to string comparison semantics
RFC: https://wiki.php.net/rfc/string_to_number_comparison
Closes GH-3886.
Diffstat (limited to 'Zend/zend_operators.c')
-rw-r--r-- | Zend/zend_operators.c | 69 |
1 files changed, 69 insertions, 0 deletions
diff --git a/Zend/zend_operators.c b/Zend/zend_operators.c index 9fdc006e64..a468962491 100644 --- a/Zend/zend_operators.c +++ b/Zend/zend_operators.c @@ -1991,6 +1991,55 @@ ZEND_API int ZEND_FASTCALL compare_function(zval *result, zval *op1, zval *op2) } /* }}} */ +static int compare_long_to_string(zend_long lval, zend_string *str) /* {{{ */ +{ + zend_long str_lval; + double str_dval; + zend_uchar type = is_numeric_string(ZSTR_VAL(str), ZSTR_LEN(str), &str_lval, &str_dval, 0); + + if (type == IS_LONG) { + return lval > str_lval ? 1 : lval < str_lval ? -1 : 0; + } + + if (type == IS_DOUBLE) { + double diff = (double) lval - str_dval; + return ZEND_NORMALIZE_BOOL(diff); + } + + zend_string *lval_as_str = zend_long_to_str(lval); + int cmp_result = zend_binary_strcmp( + ZSTR_VAL(lval_as_str), ZSTR_LEN(lval_as_str), ZSTR_VAL(str), ZSTR_LEN(str)); + zend_string_release(lval_as_str); + return ZEND_NORMALIZE_BOOL(cmp_result); +} +/* }}} */ + +static int compare_double_to_string(double dval, zend_string *str) /* {{{ */ +{ + zend_long str_lval; + double str_dval; + zend_uchar type = is_numeric_string(ZSTR_VAL(str), ZSTR_LEN(str), &str_lval, &str_dval, 0); + + if (type == IS_LONG) { + double diff = dval - (double) str_lval; + return ZEND_NORMALIZE_BOOL(diff); + } + + if (type == IS_DOUBLE) { + if (dval == str_dval) { + return 0; + } + return ZEND_NORMALIZE_BOOL(dval - str_dval); + } + + zend_string *dval_as_str = zend_strpprintf(0, "%.*G", (int) EG(precision), dval); + int cmp_result = zend_binary_strcmp( + ZSTR_VAL(dval_as_str), ZSTR_LEN(dval_as_str), ZSTR_VAL(str), ZSTR_LEN(str)); + zend_string_release(dval_as_str); + return ZEND_NORMALIZE_BOOL(cmp_result); +} +/* }}} */ + ZEND_API int ZEND_FASTCALL zend_compare(zval *op1, zval *op2) /* {{{ */ { int converted = 0; @@ -2042,6 +2091,26 @@ ZEND_API int ZEND_FASTCALL zend_compare(zval *op1, zval *op2) /* {{{ */ case TYPE_PAIR(IS_STRING, IS_NULL): return Z_STRLEN_P(op1) == 0 ? 0 : 1; + case TYPE_PAIR(IS_LONG, IS_STRING): + return compare_long_to_string(Z_LVAL_P(op1), Z_STR_P(op2)); + + case TYPE_PAIR(IS_STRING, IS_LONG): + return -compare_long_to_string(Z_LVAL_P(op2), Z_STR_P(op1)); + + case TYPE_PAIR(IS_DOUBLE, IS_STRING): + if (zend_isnan(Z_DVAL_P(op1))) { + return 1; + } + + return compare_double_to_string(Z_DVAL_P(op1), Z_STR_P(op2)); + + case TYPE_PAIR(IS_STRING, IS_DOUBLE): + if (zend_isnan(Z_DVAL_P(op2))) { + return 1; + } + + return -compare_double_to_string(Z_DVAL_P(op2), Z_STR_P(op1)); + case TYPE_PAIR(IS_OBJECT, IS_NULL): return 1; |