Skip to content

Commit

Permalink
feat(enc): add Field helper
Browse files Browse the repository at this point in the history
  • Loading branch information
ernado committed Nov 7, 2021
1 parent 741e280 commit 30437cb
Show file tree
Hide file tree
Showing 8 changed files with 98 additions and 44 deletions.
9 changes: 0 additions & 9 deletions alloc_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,15 +59,6 @@ func TestZeroAlloc(t *testing.T) {
return err
})
})
t.Run("Str", func(t *testing.T) {
zeroAllocDecStr(t, `"hello"`, func(d *Decoder) error {
v, err := d.Str()
if v != "hello" {
t.Fatal(err)
}
return err
})
})
t.Run("ArrBigFile", func(t *testing.T) {
zeroAllocDec(t, benchData, func(d *Decoder) error {
return d.Arr(nil)
Expand Down
2 changes: 1 addition & 1 deletion any_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ func (v *Any) Read(d *Decoder) error {
// Write json representation of Any to Encoder.
func (v Any) Write(w *Encoder) {
if v.KeyValid {
w.Field(v.Key)
w.FieldStart(v.Key)
}
switch v.Type {
case AnyStr:
Expand Down
30 changes: 26 additions & 4 deletions enc.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ type Encoder struct {
//
// We write commas only before non-first element of Array or Object.
//
// See comma, begin, end and Field for implementation details.
// See comma, begin, end and FieldStart for implementation details.
//
// Note: probably, this can be optimized as bit set to ease memory
// consumption.
Expand Down Expand Up @@ -117,18 +117,22 @@ func (e *Encoder) Bool(v bool) {
}
}

// ObjStart writes object start, performing indentation if needed
// ObjStart writes object start, performing indentation if needed.
//
// Use Obj as convenience helper for writing objects.
func (e *Encoder) ObjStart() {
e.comma()
e.byte('{')
e.begin()
e.writeIndent()
}

// Field encodes field name and writes colon.
// FieldStart encodes field name and writes colon.
//
// For non-zero indentation also writes single space after colon.
func (e *Encoder) Field(field string) {
//
// Use Field as convenience helper for encoding fields.
func (e *Encoder) FieldStart(field string) {
e.Str(field)
if e.indent > 0 {
e.twoBytes(':', ' ')
Expand All @@ -140,7 +144,17 @@ func (e *Encoder) Field(field string) {
}
}

// Field encodes field start and then invokes callback.
//
// Has ~5ns overhead over FieldStart.
func (e *Encoder) Field(name string, f func(e *Encoder)) {
e.FieldStart(name)
f(e)
}

// ObjEnd writes end of object token, performing indentation if needed.
//
// Use Obj as convenience helper for writing objects.
func (e *Encoder) ObjEnd() {
e.end()
e.writeIndent()
Expand All @@ -154,6 +168,8 @@ func (e *Encoder) ObjEmpty() {
}

// Obj writes start of object, invokes callback and writes end of object.
//
// If callback is nil, writes empty object.
func (e *Encoder) Obj(f func(e *Encoder)) {
if f == nil {
e.ObjEmpty()
Expand All @@ -165,6 +181,8 @@ func (e *Encoder) Obj(f func(e *Encoder)) {
}

// ArrStart writes start of array, performing indentation if needed.
//
// Use Arr as convenience helper for writing arrays.
func (e *Encoder) ArrStart() {
e.comma()
e.byte('[')
Expand All @@ -179,13 +197,17 @@ func (e *Encoder) ArrEmpty() {
}

// ArrEnd writes end of array, performing indentation if needed.
//
// Use Arr as convenience helper for writing arrays.
func (e *Encoder) ArrEnd() {
e.end()
e.writeIndent()
e.byte(']')
}

// Arr writes start of array, invokes callback and writes end of array.
//
// If callback is nil, writes empty array.
func (e *Encoder) Arr(f func(e *Encoder)) {
if f == nil {
e.ArrEmpty()
Expand Down
20 changes: 10 additions & 10 deletions enc_bench_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,45 +22,45 @@ func BenchmarkEncoderBigObject(b *testing.B) {
func encodeObject(w *Encoder) {
w.ObjStart()

w.Field("objectId")
w.FieldStart("objectId")
w.Uint64(8838243212)

w.Field("name")
w.FieldStart("name")
w.Str("Jane Doe")

w.Field("address")
w.FieldStart("address")
w.ObjStart()
for _, field := range addressFields {
w.Field(field.key)
w.FieldStart(field.key)
w.Str(field.val)
}

w.Field("geo")
w.FieldStart("geo")
{
w.ObjStart()
w.Field("latitude")
w.FieldStart("latitude")
w.Float64(-154.550817)
w.Field("longitude")
w.FieldStart("longitude")
w.Float64(-84.176159)
w.ObjEnd()
}
w.ObjEnd()

w.Field("specialties")
w.FieldStart("specialties")
w.ArrStart()
for _, s := range specialties {
w.Str(s)
}
w.ArrEnd()

for i, text := range longText {
w.Field("longText" + strconv.Itoa(i))
w.FieldStart("longText" + strconv.Itoa(i))
w.Str(text)
}

for i := 0; i < 25; i++ {
num := i * 18328
w.Field("integerField" + strconv.Itoa(i))
w.FieldStart("integerField" + strconv.Itoa(i))
w.Int64(int64(num))
}

Expand Down
6 changes: 3 additions & 3 deletions enc_comma_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,11 @@ func TestEncoder_comma(t *testing.T) {
t.Run("Object", func(t *testing.T) {
var e Encoder
e.ObjStart()
e.Field("a")
e.FieldStart("a")
e.Int(1)
e.Field("b")
e.FieldStart("b")
e.Int(2)
e.Field("c")
e.FieldStart("c")
e.ArrStart()
e.Int(1)
e.Int(2)
Expand Down
55 changes: 48 additions & 7 deletions enc_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package jx

import (
"fmt"
"testing"

"github.com/stretchr/testify/require"
Expand Down Expand Up @@ -69,11 +70,12 @@ func TestEncoder_ObjEmpty(t *testing.T) {
}

func TestEncoder_Obj(t *testing.T) {
t.Run("Field", func(t *testing.T) {
t.Run("FieldStart", func(t *testing.T) {
var e Encoder
e.Obj(func(e *Encoder) {
e.Field("hello")
e.Str("world")
e.Field("hello", func(e *Encoder) {
e.Str("world")
})
})
require.Equal(t, `{"hello":"world"}`, e.String())
})
Expand Down Expand Up @@ -105,8 +107,7 @@ func BenchmarkEncoder_Arr(b *testing.B) {
var e Encoder
for i := 0; i < b.N; i++ {
e.ArrStart()
e.Int(1)
e.Int(2)
e.Null()
e.ArrEnd()

e.Reset()
Expand All @@ -117,11 +118,51 @@ func BenchmarkEncoder_Arr(b *testing.B) {
var e Encoder
for i := 0; i < b.N; i++ {
e.Arr(func(e *Encoder) {
e.Int(1)
e.Int(2)
e.Null()
})

e.Reset()
}
})
}

func BenchmarkEncoder_Field(b *testing.B) {
for _, fields := range []int{
1,
5,
10,
100,
} {
b.Run(fmt.Sprintf("%d", fields), func(b *testing.B) {
b.Run("Manual", func(b *testing.B) {
b.ReportAllocs()
var e Encoder
for i := 0; i < b.N; i++ {
e.ObjStart()
for j := 0; j < fields; j++ {
e.FieldStart("field")
e.Null()
}
e.ObjEnd()

e.Reset()
}
})
b.Run("Callback", func(b *testing.B) {
b.ReportAllocs()
var e Encoder
for i := 0; i < b.N; i++ {
e.Obj(func(e *Encoder) {
for j := 0; j < fields; j++ {
e.Field("field", func(e *Encoder) {
e.Null()
})
}
})

e.Reset()
}
})
})
}
}
10 changes: 5 additions & 5 deletions examples_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,9 @@ func ExampleDecodeStr() {

func ExampleEncoder_String() {
var e jx.Encoder
e.ObjStart() // {
e.Field("values") // "values":
e.ArrStart() // [
e.ObjStart() // {
e.FieldStart("values") // "values":
e.ArrStart() // [
for _, v := range []int{4, 8, 15, 16, 23, 42} {
e.Int(v)
}
Expand Down Expand Up @@ -157,7 +157,7 @@ func ExampleDecoder_Base64() {
func Example() {
var e jx.Encoder
e.Obj(func(e *jx.Encoder) {
e.Field("data")
e.FieldStart("data")
e.Base64([]byte("hello"))
})
fmt.Println(e)
Expand All @@ -178,7 +178,7 @@ func ExampleEncoder_SetIdent() {
e.SetIdent(2)
e.ObjStart()

e.Field("data")
e.FieldStart("data")
e.ArrStart()
e.Int(1)
e.Int(2)
Expand Down
10 changes: 5 additions & 5 deletions obj_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,16 +31,16 @@ func TestEncoder_SetIdent(t *testing.T) {
e := GetEncoder()
e.SetIdent(2)
e.ObjStart()
e.Field("hello")
e.FieldStart("hello")
e.Int(1)
e.Field("world")
e.FieldStart("world")
e.Int(2)
e.Field("obj")
e.FieldStart("obj")
e.ObjStart()
e.Field("a")
e.FieldStart("a")
e.Str("b")
e.ObjEnd()
e.Field("data")
e.FieldStart("data")
e.ArrStart()
e.Int(1)
e.Int(2)
Expand Down

0 comments on commit 30437cb

Please sign in to comment.