From f96cc49fd4c888936d3ac9f78b009bab0e1084ab Mon Sep 17 00:00:00 2001 From: Tao Wen Date: Thu, 1 Dec 2016 23:25:29 +0800 Subject: [PATCH] support float --- README.md | 61 +++++++++++++++++++++++++++++++++++++++++- jsoniter.go | 40 ++++++++++++++++++++++++++- jsoniter_float_test.go | 36 +++++++++++++++++++++++++ 3 files changed, 135 insertions(+), 2 deletions(-) create mode 100644 jsoniter_float_test.go diff --git a/README.md b/README.md index ed1fdbf..357df45 100644 --- a/README.md +++ b/README.md @@ -47,4 +47,63 @@ func Benchmark_json_int(b *testing.B) { } ``` -3000000 505 ns/op (8x slower) \ No newline at end of file +3000000 505 ns/op (8x slower) + +# array + +``` +func Benchmark_jsoniter_array(b *testing.B) { + for n := 0; n < b.N; n++ { + iter := ParseString(`[1,2,3]`) + for iter.ReadArray() { + iter.ReadUint64() + } + } +} +``` + +10000000 189 ns/op + +``` +func Benchmark_json_array(b *testing.B) { + for n := 0; n < b.N; n++ { + result := []interface{}{} + json.Unmarshal([]byte(`[1,2,3]`), &result) + } +} +``` +1000000 1327 ns/op + +# object + +``` +func Benchmark_jsoniter_object(b *testing.B) { + for n := 0; n < b.N; n++ { + iter := ParseString(`{"field1": "1", "field2": 2}`) + obj := TestObj{} + for field := iter.ReadObject(); field != ""; field = iter.ReadObject() { + switch field { + case "field1": + obj.Field1 = iter.ReadString() + case "field2": + obj.Field2 = iter.ReadUint64() + default: + iter.ReportError("bind object", "unexpected field") + } + } + } +} +``` + +5000000 401 ns/op + +``` +func Benchmark_json_object(b *testing.B) { + for n := 0; n < b.N; n++ { + result := TestObj{} + json.Unmarshal([]byte(`{"field1": "1", "field2": 2}`), &result) + } +} +``` + +1000000 1318 ns/op \ No newline at end of file diff --git a/jsoniter.go b/jsoniter.go index 9fe63c3..27ebc5a 100644 --- a/jsoniter.go +++ b/jsoniter.go @@ -4,6 +4,7 @@ import ( "io" "fmt" "unicode/utf16" + "strconv" ) type Iterator struct { @@ -391,4 +392,41 @@ func (iter *Iterator) readObjectField() (ret string) { } iter.skipWhitespaces() return field -} \ No newline at end of file +} + +func (iter *Iterator) ReadFloat64() (ret float64) { + str := make([]byte, 0, 10) + for c := iter.readByte(); iter.Error == nil; c = iter.readByte() { + switch { + case c == '+': + fallthrough + case c == '-': + fallthrough + case c == '.': + fallthrough + case c == 'e': + fallthrough + case c == 'E': + fallthrough + case c > '0' && c < '9': + str = append(str, c) + default: + iter.unreadByte() + val, err := strconv.ParseFloat(string(str), 64) + if err != nil { + iter.Error = err + return + } + return val + } + } + if iter.Error == io.EOF { + val, err := strconv.ParseFloat(string(str), 64) + if err != nil { + iter.Error = err + return + } + return val + } + return +} diff --git a/jsoniter_float_test.go b/jsoniter_float_test.go new file mode 100644 index 0000000..f2b2b14 --- /dev/null +++ b/jsoniter_float_test.go @@ -0,0 +1,36 @@ +package jsoniter + +import ( + "testing" + "encoding/json" +) + +func Test_float64_0(t *testing.T) { + iter := ParseString(`0`) + val := iter.ReadFloat64() + if val != 0 { + t.Fatal(val) + } +} + +func Test_float64_1_dot_1(t *testing.T) { + iter := ParseString(`1.1`) + val := iter.ReadFloat64() + if val != 1.1 { + t.Fatal(val) + } +} + +func Benchmark_jsoniter_float(b *testing.B) { + for n := 0; n < b.N; n++ { + iter := ParseString(`1.1`) + iter.ReadFloat64() + } +} + +func Benchmark_json_float(b *testing.B) { + for n := 0; n < b.N; n++ { + result := float64(0) + json.Unmarshal([]byte(`1.1`), &result) + } +} \ No newline at end of file