Skip to content

Commit

Permalink
Better safe integer range for numbers
Browse files Browse the repository at this point in the history
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
  • Loading branch information
tidwall committed Nov 4, 2020
1 parent 2f043b7 commit 5100d69
Showing 1 changed file with 24 additions and 36 deletions.
60 changes: 24 additions & 36 deletions gjson.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
}

Expand All @@ -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)
}
}

Expand Down Expand Up @@ -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
}
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
func safeInt(f float64) (n int64, ok bool) {
if f < -9007199254740991 || f > 9007199254740991 {
return 0, false
}
return 0, false
return int64(f), true
}

// execModifier parses the path to find a matching modifier function.
Expand Down

0 comments on commit 5100d69

Please sign in to comment.