improve tonumber/0 performance by parsing input as number literal

Previously, the tonumber/0 filter parses the input as JSON values, but
this is less-performant on large non-number strings. Parsing the input
string as number literal fixes the performance issue. Also, this fix
changes the filter to reject numbers with white spaces.
This commit is contained in:
itchyny authored and GitHub committed 2024-03-01 16:33:17 +01:00
1 parent 913b26469f
commit ce0e788ce2
2 files changed
+19 -6

No files matched your search

+17 -4
View File
@@ -43,6 +43,8 @@ void *alloca (size_t);
#include "locfile.h" #include "locfile.h"
#include "jv_unicode.h" #include "jv_unicode.h"
#include "jv_alloc.h" #include "jv_alloc.h"
#include "jv_dtoa.h"
#include "jv_dtoa_tsd.h"
#include "jv_private.h" #include "jv_private.h"
#include "util.h" #include "util.h"
@@ -464,11 +466,22 @@ static jv f_tonumber(jq_state *jq, jv input) {
return input; return input;
} }
if (jv_get_kind(input) == JV_KIND_STRING) { if (jv_get_kind(input) == JV_KIND_STRING) {
jv parsed = jv_parse(jv_string_value(input)); const char* s = jv_string_value(input);
if (!jv_is_valid(parsed) || jv_get_kind(parsed) == JV_KIND_NUMBER) { #ifdef USE_DECNUM
jv_free(input); jv number = jv_number_with_literal(s);
return parsed; if (jv_get_kind(number) == JV_KIND_INVALID) {
return type_error(input, "cannot be parsed as a number");
} }
#else
char *end = 0;
double d = jvp_strtod(tsd_dtoa_context_get(), s, &end);
if (end == 0 || *end != 0) {
return type_error(input, "cannot be parsed as a number");
}
jv number = jv_number(d);
#endif
jv_free(input);
return number;
} }
return type_error(input, "cannot be parsed as a number"); return type_error(input, "cannot be parsed as a number");
} }
+2 -2
View File
@@ -2000,8 +2000,8 @@ null
2 2
.[] |= try tonumber .[] |= try tonumber
["1", "2a", "3", 4] ["1", "2a", "3", " 4 ", "5.67", ".89", "-876", "+5.43", 21]
[1, 3, 4] [1, 3, 5.67, 0.89, -876, 5.43, 21]
# Also 1859, but from 2073 # Also 1859, but from 2073
any(keys[]|tostring?;true) any(keys[]|tostring?;true)