From 5100d6926a4bea3753fc72352fca70654f04cedc Mon Sep 17 00:00:00 2001 From: tidwall Date: Wed, 4 Nov 2020 16:26:43 -0700 Subject: [PATCH] Better safe integer range for numbers This commit optimizes the safe float to int conversion function by using the full -9007199254740991 to 9007199254740991 range as suggested at: https://tc39.es/ecma262/#sec-number.min_safe_integer closes #174 --- gjson.go | 60 +++++++++++++++++++++++--------------------------------- 1 file changed, 24 insertions(+), 36 deletions(-) diff --git a/gjson.go b/gjson.go index b7d8142..32935de 100644 --- a/gjson.go +++ b/gjson.go @@ -125,16 +125,17 @@ func (t Result) Int() int64 { return n case Number: // try to directly convert the float64 to int64 - n, ok := floatToInt(t.Num) - if !ok { - // now try to parse the raw string - n, ok = parseInt(t.Raw) - if !ok { - // fallback to a standard conversion - return int64(t.Num) - } + i, ok := safeInt(t.Num) + if ok { + return i } - return n + // now try to parse the raw string + i, ok = parseInt(t.Raw) + if ok { + return i + } + // fallback to a standard conversion + return int64(t.Num) } } @@ -150,16 +151,17 @@ func (t Result) Uint() uint64 { return n case Number: // try to directly convert the float64 to uint64 - n, ok := floatToUint(t.Num) - if !ok { - // now try to parse the raw string - n, ok = parseUint(t.Raw) - if !ok { - // fallback to a standard conversion - return uint64(t.Num) - } + i, ok := safeInt(t.Num) + if ok && i >= 0 { + return uint64(i) } - return n + // now try to parse the raw string + u, ok := parseUint(t.Raw) + if ok { + return u + } + // fallback to a standard conversion + return uint64(t.Num) } } @@ -2525,25 +2527,11 @@ func parseInt(s string) (n int64, ok bool) { return n, true } -const minUint53 = 0 -const maxUint53 = 4503599627370495 -const minInt53 = -2251799813685248 -const maxInt53 = 2251799813685247 - -func floatToUint(f float64) (n uint64, ok bool) { - n = uint64(f) - if float64(n) == f && n >= minUint53 && n <= maxUint53 { - return n, true +func safeInt(f float64) (n int64, ok bool) { + if f < -9007199254740991 || f > 9007199254740991 { + return 0, false } - return 0, false -} - -func floatToInt(f float64) (n int64, ok bool) { - n = int64(f) - if float64(n) == f && n >= minInt53 && n <= maxInt53 { - return n, true - } - return 0, false + return int64(f), true } // execModifier parses the path to find a matching modifier function.