From ba3c30799b1f2b0a0845bd82ea94ace9f904be09 Mon Sep 17 00:00:00 2001 From: Tao Wen Date: Sat, 7 Jan 2017 23:06:48 +0800 Subject: [PATCH] write float 32 --- feature_stream_float.go | 39 +++++++++++++++++++++++++++++++++++++++ jsoniter_float_test.go | 27 +++++++++++++++++++++++++++ stream.go | 18 +++++++++++++++++- 3 files changed, 83 insertions(+), 1 deletion(-) create mode 100644 feature_stream_float.go diff --git a/feature_stream_float.go b/feature_stream_float.go new file mode 100644 index 0000000..5a82f5c --- /dev/null +++ b/feature_stream_float.go @@ -0,0 +1,39 @@ +package jsoniter + +import "strconv" + +var POW10 []uint64 + +func init() { + POW10 = []uint64{1, 10, 100, 1000, 10000, 100000, 1000000} +} + +func (stream *Stream) WriteFloat32(val float32) { + if val < 0 { + stream.writeByte('-') + val = -val + } + if val > 0x4ffffff { + stream.WriteRaw(strconv.FormatFloat(float64(val), 'f', -1, 32)); + return + } + precision := 6 + exp := uint64(1000000) // 6 + lval := uint64(float64(val) * float64(exp) + 0.5) + stream.WriteUint64(lval / exp) + fval := lval % exp + if fval == 0 { + return + } + stream.writeByte('.') + if stream.Available() < 10 { + stream.Flush() + } + for p := precision - 1; p > 0 && fval < POW10[p]; p-- { + stream.writeByte('0') + } + stream.WriteUint64(fval); + for stream.buf[stream.n - 1] == '0' { + stream.n--; + } +} \ No newline at end of file diff --git a/jsoniter_float_test.go b/jsoniter_float_test.go index 3941d0e..0bf4319 100644 --- a/jsoniter_float_test.go +++ b/jsoniter_float_test.go @@ -4,6 +4,9 @@ import ( "encoding/json" "fmt" "testing" + "github.com/json-iterator/go/require" + "bytes" + "strconv" ) func Test_float64_0(t *testing.T) { @@ -31,6 +34,30 @@ func Test_float32_1_dot_1_comma(t *testing.T) { } } +func Test_write_float32(t *testing.T) { + vals := []float32{0, 1, -1, 99, 0xff, 0xfff, 0xffff, 0xfffff, 0xffffff, 0x4ffffff, 0xfffffff, + -0x4ffffff, -0xfffffff, 1.2345, 1.23456, 1.234567, 1.001} + for _, val := range vals { + t.Run(fmt.Sprintf("%v", val), func(t *testing.T) { + should := require.New(t) + buf := &bytes.Buffer{} + stream := NewStream(buf, 4096) + stream.WriteFloat32(val) + stream.Flush() + should.Nil(stream.Error) + should.Equal(strconv.FormatFloat(float64(val), 'f', -1, 32), buf.String()) + }) + } + should := require.New(t) + buf := &bytes.Buffer{} + stream := NewStream(buf, 10) + stream.WriteRaw("abcdefg") + stream.WriteFloat32(1.123456) + stream.Flush() + should.Nil(stream.Error) + should.Equal("abcdefg1.123456", buf.String()) +} + func Benchmark_jsoniter_float(b *testing.B) { b.ReportAllocs() for n := 0; n < b.N; n++ { diff --git a/stream.go b/stream.go index cb95255..78ed186 100644 --- a/stream.go +++ b/stream.go @@ -104,7 +104,7 @@ func (b *Stream) Flush() error { return nil } -func (b *Stream) WriteString(s string) { +func (b *Stream) WriteRaw(s string) { for len(s) > b.Available() && b.Error == nil { n := copy(b.buf[b.n:], s) b.n += n @@ -118,6 +118,22 @@ func (b *Stream) WriteString(s string) { b.n += n } +func (b *Stream) WriteString(s string) { + b.writeByte('"') + for len(s) > b.Available() && b.Error == nil { + n := copy(b.buf[b.n:], s) + b.n += n + s = s[n:] + b.Flush() + } + if b.Error != nil { + return + } + n := copy(b.buf[b.n:], s) + b.n += n + b.writeByte('"') +} + func (stream *Stream) WriteNull() { stream.Write(bytesNull) }