From 1f0abce0bf4061261572f6ed2f815f71647cc7e5 Mon Sep 17 00:00:00 2001 From: Luke Shumaker Date: Fri, 10 Feb 2023 15:48:28 -0700 Subject: encode: Begone with encodeTODO --- borrowed_misc.go | 43 +++++++++++++++++++++++++++++++++++++++++++ encode.go | 29 ++++++++++++++++------------- 2 files changed, 59 insertions(+), 13 deletions(-) diff --git a/borrowed_misc.go b/borrowed_misc.go index 59c49aa..52f4a12 100644 --- a/borrowed_misc.go +++ b/borrowed_misc.go @@ -7,7 +7,10 @@ package lowmemjson import ( + "io" + "math" "reflect" + "strconv" ) // isEmptyValue is borrowed from encode.go. @@ -28,3 +31,43 @@ func isEmptyValue(v reflect.Value) bool { } return false } + +// encodeFloat is lightly modified from +// encode.go:floatEncoder.encode(). +func encodeFloat(w io.Writer, bits int, v reflect.Value) error { + var scratch [64]byte + + f := v.Float() + if math.IsInf(f, 0) || math.IsNaN(f) { + return &EncodeValueError{Value: v, Str: strconv.FormatFloat(f, 'g', -1, bits)} + } + + // Convert as if by ES6 number to string conversion. + // This matches most other JSON generators. + // See golang.org/issue/6384 and golang.org/issue/14135. + // Like fmt %g, but the exponent cutoffs are different + // and exponents themselves are not padded to two digits. + b := scratch[:0] + abs := math.Abs(f) + fmt := byte('f') + // Note: Must use float32 comparisons for underlying float32 value to get precise cutoffs right. + if abs != 0 { + if bits == 64 && (abs < 1e-6 || abs >= 1e21) || bits == 32 && (float32(abs) < 1e-6 || float32(abs) >= 1e21) { + fmt = 'e' + } + } + b = strconv.AppendFloat(b, f, fmt, -1, bits) + if fmt == 'e' { + // clean up e-09 to e-9 + n := len(b) + if n >= 4 && b[n-4] == 'e' && b[n-3] == '-' && b[n-2] == '0' { + b[n-2] = b[n-1] + b = b[:n-1] + } + } + + if _, err := w.Write(b); err != nil { + return err + } + return nil +} diff --git a/encode.go b/encode.go index 2830ace..492b40f 100644 --- a/encode.go +++ b/encode.go @@ -246,13 +246,27 @@ func encode(w *ReEncoder, val reflect.Value, escaper BackslashEscaper, quote boo return err } } - case reflect.Float32, reflect.Float64: + case reflect.Float32: if quote { if err := w.WriteByte('"'); err != nil { return err } } - if err := encodeTODO(w, val); err != nil { + if err := encodeFloat(w, 32, val); err != nil { + return err + } + if quote { + if err := w.WriteByte('"'); err != nil { + return err + } + } + case reflect.Float64: + if quote { + if err := w.WriteByte('"'); err != nil { + return err + } + } + if err := encodeFloat(w, 64, val); err != nil { return err } if quote { @@ -522,14 +536,3 @@ func encodeArray(w *ReEncoder, val reflect.Value, escaper BackslashEscaper, cycl } return nil } - -func encodeTODO(w io.Writer, val reflect.Value) error { - bs, err := json.Marshal(val.Interface()) - if err != nil { - return err - } - if _, err := w.Write(bs); err != nil { - return err - } - return nil -} -- cgit v1.2.3-2-g168b