This is an automated email from the ASF dual-hosted git repository. nickva pushed a commit to tag 2.0.0 in repository https://gitbox.apache.org/repos/asf/couchdb-jiffy.git
commit 9dc7d0ac7ca9ad19bc03024cc53c95c4b3f8672b Author: Nick Vatamaniuc <[email protected]> AuthorDate: Mon Apr 20 18:56:44 2026 -0400 Simplify numerical overflow handling for doubles Previously, we handled the exponent and the fractional part with different flags and different atoms on the NIF side. There is not reason to do that since we split them on e/E in Erlang anyway, so we can figure out what's what and differentiate between the two cases. --- c_src/decoder.c | 18 ++++++------------ c_src/jiffy.c | 1 - c_src/jiffy.h | 1 - src/jiffy.erl | 40 ++++++++++++++++++++++++---------------- 4 files changed, 30 insertions(+), 30 deletions(-) diff --git a/c_src/decoder.c b/c_src/decoder.c index 7ebaeb9..3617b41 100644 --- a/c_src/decoder.c +++ b/c_src/decoder.c @@ -373,8 +373,7 @@ dec_number(Decoder* d, ERL_NIF_TERM* value) { ERL_NIF_TERM num_type = d->atoms->atom_error; char state = nst_init; - int has_frac = 0; - int has_exp = 0; + int is_real = 0; double dval; int64_t lval; @@ -489,7 +488,7 @@ dec_number(Decoder* d, ERL_NIF_TERM* value) break; case nst_frac1: - has_frac = 1; + is_real = 1; switch(p[idx]) { case '0': case '1': @@ -536,7 +535,7 @@ dec_number(Decoder* d, ERL_NIF_TERM* value) break; case nst_esign: - has_exp = 1; + is_real = 1; switch(p[idx]) { case '-': case '+': @@ -632,7 +631,7 @@ parse: const char* nend = (const char*)&p[d->i]; const size_t num_len = d->i - start; - if(has_frac || has_exp) { + if(is_real) { ffc_parse_options opts = {FFC_PRESET_JSON, '.'}; ffc_result res = ffc_from_chars_double_options(nstart, nend, &dval, opts); if(res.outcome == FFC_OUTCOME_OK) { @@ -647,13 +646,8 @@ parse: } } - if(!has_frac && !has_exp) { - num_type = d->atoms->atom_bignum; - } else if(!has_frac && has_exp) { - num_type = d->atoms->atom_bignum_e; - } else { - num_type = d->atoms->atom_bigdbl; - } + // Let Erlang handle out-of-range cases + num_type = is_real ? d->atoms->atom_bigdbl : d->atoms->atom_bignum; d->is_partial = 1; *value = enif_make_sub_binary(d->env, d->arg, start, num_len); diff --git a/c_src/jiffy.c b/c_src/jiffy.c index c44952a..46cbce7 100644 --- a/c_src/jiffy.c +++ b/c_src/jiffy.c @@ -29,7 +29,6 @@ load(ErlNifEnv* env, void** priv, ERL_NIF_TERM info) st->atom_true = make_atom(env, "true"); st->atom_false = make_atom(env, "false"); st->atom_bignum = make_atom(env, "bignum"); - st->atom_bignum_e = make_atom(env, "bignum_e"); st->atom_bigdbl = make_atom(env, "bigdbl"); st->atom_partial = make_atom(env, "partial"); st->atom_uescape = make_atom(env, "uescape"); diff --git a/c_src/jiffy.h b/c_src/jiffy.h index 68dcb90..7012dad 100644 --- a/c_src/jiffy.h +++ b/c_src/jiffy.h @@ -39,7 +39,6 @@ typedef struct { ERL_NIF_TERM atom_true; ERL_NIF_TERM atom_false; ERL_NIF_TERM atom_bignum; - ERL_NIF_TERM atom_bignum_e; ERL_NIF_TERM atom_bigdbl; ERL_NIF_TERM atom_partial; ERL_NIF_TERM atom_uescape; diff --git a/src/jiffy.erl b/src/jiffy.erl index fd9c230..8f9f4ac 100644 --- a/src/jiffy.erl +++ b/src/jiffy.erl @@ -100,23 +100,31 @@ encode(Data, Options) -> finish_decode({bignum, Value}) -> binary_to_integer(Value); -finish_decode({bignum_e, Value}) -> - {IVal, EVal} = case binary:split(Value, [<<$e>>, <<$E>>]) of - [IStr, EStr] -> - {binary_to_integer(IStr), binary_to_integer(EStr)} - end, - try - IVal * math:pow(10, EVal) - catch - error:badarith -> - error({range, EVal}) - end; finish_decode({bigdbl, Value}) -> - try - binary_to_float(Value) - catch - error:badarg -> - error({range, Value}) + % Got something like a 1e400, 1.5e500, or 999...999.5. Split on e/E and if + % we do have an explicit exponent use math:pow/2 to create the float since + % Erlang/OTP's binary_to_float can't handle something like 1e10, it needs + % the first number (the mantissa) to have '.' in it (it has to be 1.0e10). + case binary:split(Value, [<<$e>>, <<$E>>]) of + [IStr, EStr] -> + EVal = binary_to_integer(EStr), + IVal = case binary:match(IStr, <<$.>>) of + nomatch -> binary_to_integer(IStr); + _ -> binary_to_float(IStr) + end, + try + IVal * math:pow(10, EVal) + catch + error:badarith -> + error({range, Value}) + end; + [_] -> + try + binary_to_float(Value) + catch + error:badarg -> + error({range, Value}) + end end; finish_decode({Pairs}) when is_list(Pairs) -> finish_decode_obj(Pairs, []);
