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, []);

Reply via email to