diff options
author | itchyny <itchyny@cybozu.co.jp> | 2024-03-02 00:33:17 +0900 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-03-01 16:33:17 +0100 |
commit | ce0e788ce28c675808a6bc9a34f8db1199cd7cef (patch) | |
tree | af497f3fe3d560a92d5dd6e25874bfd07e0fc8b3 /src | |
parent | 913b26469f47351a9f75a1bc4145f45421115e37 (diff) |
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.
Diffstat (limited to 'src')
-rw-r--r-- | src/builtin.c | 21 |
1 files changed, 17 insertions, 4 deletions
diff --git a/src/builtin.c b/src/builtin.c index 9aebd1f2..393fac0d 100644 --- a/src/builtin.c +++ b/src/builtin.c @@ -43,6 +43,8 @@ void *alloca (size_t); #include "locfile.h" #include "jv_unicode.h" #include "jv_alloc.h" +#include "jv_dtoa.h" +#include "jv_dtoa_tsd.h" #include "jv_private.h" #include "util.h" @@ -464,11 +466,22 @@ static jv f_tonumber(jq_state *jq, jv input) { return input; } if (jv_get_kind(input) == JV_KIND_STRING) { - jv parsed = jv_parse(jv_string_value(input)); - if (!jv_is_valid(parsed) || jv_get_kind(parsed) == JV_KIND_NUMBER) { - jv_free(input); - return parsed; + const char* s = jv_string_value(input); +#ifdef USE_DECNUM + jv number = jv_number_with_literal(s); + 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"); } |