From b86ff49f46a4a37e5a8e75a140cb5fd6e1331384 Mon Sep 17 00:00:00 2001 From: itchyny Date: Sun, 16 Feb 2025 22:08:36 +0900 Subject: [PATCH] fix: `jv_number_value` should cache the double value of literal numbers (#3245) The code of `jv_number_value` is intended to cache the double value of literal numbers, but it does not work because it accepts the `jv` struct by value. This patch fixes the behavior by checking if the double value is `NaN`, which indicates the unconverted value. This patch improves the performance of major use cases; e.g. `range(1000000)` runs 25% faster. --- src/jv.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/jv.c b/src/jv.c index e7ae5619..4e50c582 100644 --- a/src/jv.c +++ b/src/jv.c @@ -206,9 +206,6 @@ enum { JVP_NUMBER_DECIMAL = 1 }; -#define JV_NUMBER_SIZE_INIT (0) -#define JV_NUMBER_SIZE_CONVERTED (1) - #define JVP_FLAGS_NUMBER_NATIVE JVP_MAKE_FLAGS(JV_KIND_NUMBER, JVP_MAKE_PFLAGS(JVP_NUMBER_NATIVE, 0)) #define JVP_FLAGS_NUMBER_LITERAL JVP_MAKE_FLAGS(JV_KIND_NUMBER, JVP_MAKE_PFLAGS(JVP_NUMBER_DECIMAL, 1)) @@ -587,8 +584,12 @@ static jv jvp_literal_number_new(const char * literal) { jv_mem_free(n); return JV_INVALID; } + if (decNumberIsNaN(&n->num_decimal)) { + jv_mem_free(n); + return jv_number(NAN); + } - jv r = {JVP_FLAGS_NUMBER_LITERAL, 0, 0, JV_NUMBER_SIZE_INIT, {&n->refcnt}}; + jv r = {JVP_FLAGS_NUMBER_LITERAL, 0, 0, 0, {&n->refcnt}}; return r; } @@ -696,9 +697,8 @@ double jv_number_value(jv j) { if (JVP_HAS_FLAGS(j, JVP_FLAGS_NUMBER_LITERAL)) { jvp_literal_number* n = jvp_literal_number_ptr(j); - if (j.size != JV_NUMBER_SIZE_CONVERTED) { + if (isnan(n->num_double)) { n->num_double = jvp_literal_number_to_double(j); - j.size = JV_NUMBER_SIZE_CONVERTED; } return n->num_double; @@ -729,7 +729,7 @@ int jvp_number_is_nan(jv n) { return decNumberIsNaN(pdec); } #endif - return n.u.number != n.u.number; + return isnan(n.u.number); } jv jv_number_negate(jv n) {