commit a05d1d989b35d29d7db8b730cdd64859b2149cde
parent be3d98c46fee4dac764ce13df59c905dbf5ad4b6
Author: francoispqt <francois@parquet.ninja>
Date: Sun, 6 May 2018 23:35:15 +0800
preload pools and, optimise encoder and add functions to have external control over encoder
Diffstat:
11 files changed, 161 insertions(+), 100 deletions(-)
diff --git a/decode_pool.go b/decode_pool.go
@@ -2,7 +2,26 @@ package gojay
import "io"
-var decPool = make(chan *Decoder, 16)
+var decPool = make(chan *Decoder, 32)
+
+func init() {
+initStreamDecPool:
+ for {
+ select {
+ case streamDecPool <- Stream.NewDecoder(nil):
+ default:
+ break initStreamDecPool
+ }
+ }
+initDecPool:
+ for {
+ select {
+ case decPool <- NewDecoder(nil):
+ default:
+ break initDecPool
+ }
+ }
+}
// NewDecoder returns a new decoder.
// It takes an io.Reader implementation as data input.
diff --git a/decode_stream_pool.go b/decode_stream_pool.go
@@ -2,7 +2,7 @@ package gojay
import "io"
-var streamDecPool = make(chan *StreamDecoder, 16)
+var streamDecPool = make(chan *StreamDecoder, 32)
// NewDecoder returns a new StreamDecoder.
// It takes an io.Reader implementation as data input.
diff --git a/encode.go b/encode.go
@@ -183,13 +183,29 @@ type Encoder struct {
err error
}
-func (enc *Encoder) getPreviousRune() (byte, bool) {
- last := len(enc.buf) - 1
- return enc.buf[last], true
+// AppendBytes allows a modular usage by appending bytes manually to the current state of the buffer.
+func (enc *Encoder) AppendBytes(b []byte) {
+ enc.writeBytes(b)
+}
+
+// AppendByte allows a modular usage by appending a single byte manually to the current state of the buffer.
+func (enc *Encoder) AppendByte(b byte) {
+ enc.writeByte(b)
+}
+
+// Buf returns the Encoder's buffer.
+func (enc *Encoder) Buf() []byte {
+ return enc.buf
}
-func (enc *Encoder) write() (int, error) {
+// Write writes to the io.Writer and resets the buffer.
+func (enc *Encoder) Write() (int, error) {
i, err := enc.w.Write(enc.buf)
enc.buf = enc.buf[:0]
return i, err
}
+
+func (enc *Encoder) getPreviousRune() byte {
+ last := len(enc.buf) - 1
+ return enc.buf[last]
+}
diff --git a/encode_array.go b/encode_array.go
@@ -6,7 +6,7 @@ func (enc *Encoder) EncodeArray(v MarshalerArray) error {
panic(InvalidUsagePooledEncoderError("Invalid usage of pooled encoder"))
}
_, _ = enc.encodeArray(v)
- _, err := enc.write()
+ _, err := enc.Write()
if err != nil {
enc.err = err
return err
@@ -26,8 +26,8 @@ func (enc *Encoder) encodeArray(v MarshalerArray) ([]byte, error) {
func (enc *Encoder) AddArray(v MarshalerArray) {
if v.IsNil() {
enc.grow(3)
- r, ok := enc.getPreviousRune()
- if ok && r != '[' {
+ r := enc.getPreviousRune()
+ if r != '[' {
enc.writeByte(',')
}
enc.writeByte('[')
@@ -35,8 +35,8 @@ func (enc *Encoder) AddArray(v MarshalerArray) {
return
}
enc.grow(100)
- r, ok := enc.getPreviousRune()
- if ok && r != '[' {
+ r := enc.getPreviousRune()
+ if r != '[' {
enc.writeByte(',')
}
enc.writeByte('[')
@@ -51,8 +51,8 @@ func (enc *Encoder) AddArrayOmitEmpty(v MarshalerArray) {
return
}
enc.grow(4)
- r, ok := enc.getPreviousRune()
- if ok && r != '[' {
+ r := enc.getPreviousRune()
+ if r != '[' {
enc.writeByte(',')
}
enc.writeByte('[')
@@ -65,8 +65,8 @@ func (enc *Encoder) AddArrayOmitEmpty(v MarshalerArray) {
func (enc *Encoder) AddArrayKey(key string, v MarshalerArray) {
if v.IsNil() {
enc.grow(2 + len(key))
- r, ok := enc.getPreviousRune()
- if ok && r != '[' {
+ r := enc.getPreviousRune()
+ if r != '[' {
enc.writeByte(',')
}
enc.writeByte('"')
@@ -76,8 +76,8 @@ func (enc *Encoder) AddArrayKey(key string, v MarshalerArray) {
return
}
enc.grow(5 + len(key))
- r, ok := enc.getPreviousRune()
- if ok && r != '[' && r != '{' {
+ r := enc.getPreviousRune()
+ if r != '[' && r != '{' {
enc.writeByte(',')
}
enc.writeByte('"')
@@ -94,8 +94,8 @@ func (enc *Encoder) AddArrayKeyOmitEmpty(key string, v MarshalerArray) {
return
}
enc.grow(5 + len(key))
- r, ok := enc.getPreviousRune()
- if ok && r != '[' && r != '{' {
+ r := enc.getPreviousRune()
+ if r != '[' && r != '{' {
enc.writeByte(',')
}
enc.writeByte('"')
diff --git a/encode_bool.go b/encode_bool.go
@@ -8,7 +8,7 @@ func (enc *Encoder) EncodeBool(v bool) error {
panic(InvalidUsagePooledEncoderError("Invalid usage of pooled encoder"))
}
_, _ = enc.encodeBool(v)
- _, err := enc.write()
+ _, err := enc.Write()
if err != nil {
enc.err = err
return err
@@ -30,8 +30,8 @@ func (enc *Encoder) encodeBool(v bool) ([]byte, error) {
// AddBool adds a bool to be encoded, must be used inside a slice or array encoding (does not encode a key)
func (enc *Encoder) AddBool(v bool) {
enc.grow(5)
- r, ok := enc.getPreviousRune()
- if ok && r != '[' {
+ r := enc.getPreviousRune()
+ if r != '[' {
enc.writeByte(',')
}
if v {
@@ -47,8 +47,8 @@ func (enc *Encoder) AddBoolOmitEmpty(v bool) {
return
}
enc.grow(5)
- r, ok := enc.getPreviousRune()
- if ok && r != '[' {
+ r := enc.getPreviousRune()
+ if r != '[' {
enc.writeByte(',')
}
enc.writeString("true")
@@ -57,8 +57,8 @@ func (enc *Encoder) AddBoolOmitEmpty(v bool) {
// AddBoolKey adds a bool to be encoded, must be used inside an object as it will encode a key.
func (enc *Encoder) AddBoolKey(key string, value bool) {
enc.grow(5 + len(key))
- r, ok := enc.getPreviousRune()
- if ok && r != '{' && r != '[' {
+ r := enc.getPreviousRune()
+ if r != '{' && r != '[' {
enc.writeByte(',')
}
enc.writeByte('"')
@@ -74,8 +74,8 @@ func (enc *Encoder) AddBoolKeyOmitEmpty(key string, v bool) {
return
}
enc.grow(5 + len(key))
- r, ok := enc.getPreviousRune()
- if ok && r != '{' && r != '[' {
+ r := enc.getPreviousRune()
+ if r != '{' && r != '[' {
enc.writeByte(',')
}
enc.writeByte('"')
diff --git a/encode_number.go b/encode_number.go
@@ -8,7 +8,7 @@ func (enc *Encoder) EncodeInt(n int) error {
panic(InvalidUsagePooledEncoderError("Invalid usage of pooled encoder"))
}
_, _ = enc.encodeInt(n)
- _, err := enc.write()
+ _, err := enc.Write()
if err != nil {
return err
}
@@ -27,7 +27,7 @@ func (enc *Encoder) EncodeInt64(n int64) error {
panic(InvalidUsagePooledEncoderError("Invalid usage of pooled encoder"))
}
_, _ = enc.encodeInt64(n)
- _, err := enc.write()
+ _, err := enc.Write()
if err != nil {
return err
}
@@ -46,7 +46,7 @@ func (enc *Encoder) EncodeFloat(n float64) error {
panic(InvalidUsagePooledEncoderError("Invalid usage of pooled encoder"))
}
_, _ = enc.encodeFloat(n)
- _, err := enc.write()
+ _, err := enc.Write()
if err != nil {
return err
}
@@ -65,7 +65,7 @@ func (enc *Encoder) EncodeFloat32(n float32) error {
panic(InvalidUsagePooledEncoderError("Invalid usage of pooled encoder"))
}
_, _ = enc.encodeFloat32(n)
- _, err := enc.write()
+ _, err := enc.Write()
if err != nil {
return err
}
@@ -80,8 +80,8 @@ func (enc *Encoder) encodeFloat32(n float32) ([]byte, error) {
// AddInt adds an int to be encoded, must be used inside a slice or array encoding (does not encode a key)
func (enc *Encoder) AddInt(v int) {
enc.grow(10)
- r, ok := enc.getPreviousRune()
- if ok && r != '[' {
+ r := enc.getPreviousRune()
+ if r != '[' {
enc.writeByte(',')
}
enc.buf = strconv.AppendInt(enc.buf, int64(v), 10)
@@ -94,8 +94,8 @@ func (enc *Encoder) AddIntOmitEmpty(v int) {
return
}
enc.grow(10)
- r, ok := enc.getPreviousRune()
- if ok && r != '[' {
+ r := enc.getPreviousRune()
+ if r != '[' {
enc.writeByte(',')
}
enc.buf = strconv.AppendInt(enc.buf, int64(v), 10)
@@ -104,8 +104,8 @@ func (enc *Encoder) AddIntOmitEmpty(v int) {
// AddFloat adds a float64 to be encoded, must be used inside a slice or array encoding (does not encode a key)
func (enc *Encoder) AddFloat(v float64) {
enc.grow(10)
- r, ok := enc.getPreviousRune()
- if ok && r != '[' {
+ r := enc.getPreviousRune()
+ if r != '[' {
enc.writeByte(',')
}
enc.buf = strconv.AppendFloat(enc.buf, v, 'f', -1, 64)
@@ -118,8 +118,8 @@ func (enc *Encoder) AddFloatOmitEmpty(v float64) {
return
}
enc.grow(10)
- r, ok := enc.getPreviousRune()
- if ok && r != '[' {
+ r := enc.getPreviousRune()
+ if r != '[' {
enc.writeByte(',')
}
enc.buf = strconv.AppendFloat(enc.buf, v, 'f', -1, 64)
@@ -127,8 +127,8 @@ func (enc *Encoder) AddFloatOmitEmpty(v float64) {
// AddFloat32 adds a float32 to be encoded, must be used inside a slice or array encoding (does not encode a key)
func (enc *Encoder) AddFloat32(v float32) {
- r, ok := enc.getPreviousRune()
- if ok && r != '[' {
+ r := enc.getPreviousRune()
+ if r != '[' {
enc.writeByte(',')
}
enc.buf = strconv.AppendFloat(enc.buf, float64(v), 'f', -1, 32)
@@ -141,8 +141,8 @@ func (enc *Encoder) AddFloat32OmitEmpty(v float32) {
return
}
enc.grow(10)
- r, ok := enc.getPreviousRune()
- if ok && r != '[' {
+ r := enc.getPreviousRune()
+ if r != '[' {
enc.writeByte(',')
}
enc.buf = strconv.AppendFloat(enc.buf, float64(v), 'f', -1, 32)
@@ -151,8 +151,8 @@ func (enc *Encoder) AddFloat32OmitEmpty(v float32) {
// AddIntKey adds an int to be encoded, must be used inside an object as it will encode a key
func (enc *Encoder) AddIntKey(key string, v int) {
enc.grow(10 + len(key))
- r, ok := enc.getPreviousRune()
- if ok && r != '{' && r != '[' {
+ r := enc.getPreviousRune()
+ if r != '{' && r != '[' {
enc.writeByte(',')
}
enc.writeByte('"')
@@ -168,8 +168,8 @@ func (enc *Encoder) AddIntKeyOmitEmpty(key string, v int) {
return
}
enc.grow(10 + len(key))
- r, ok := enc.getPreviousRune()
- if ok && r != '{' && r != '[' {
+ r := enc.getPreviousRune()
+ if r != '{' && r != '[' {
enc.writeByte(',')
}
enc.writeByte('"')
@@ -180,8 +180,8 @@ func (enc *Encoder) AddIntKeyOmitEmpty(key string, v int) {
// AddFloatKey adds a float64 to be encoded, must be used inside an object as it will encode a key
func (enc *Encoder) AddFloatKey(key string, value float64) {
- r, ok := enc.getPreviousRune()
- if ok && r != '{' && r != '[' {
+ r := enc.getPreviousRune()
+ if r != '{' && r != '[' {
enc.writeByte(',')
}
enc.grow(10)
@@ -198,8 +198,8 @@ func (enc *Encoder) AddFloatKeyOmitEmpty(key string, v float64) {
return
}
enc.grow(10 + len(key))
- r, ok := enc.getPreviousRune()
- if ok && r != '{' && r != '[' {
+ r := enc.getPreviousRune()
+ if r != '{' && r != '[' {
enc.writeByte(',')
}
enc.writeByte('"')
@@ -211,8 +211,8 @@ func (enc *Encoder) AddFloatKeyOmitEmpty(key string, v float64) {
// AddFloat32Key adds a float32 to be encoded, must be used inside an object as it will encode a key
func (enc *Encoder) AddFloat32Key(key string, v float32) {
enc.grow(10 + len(key))
- r, ok := enc.getPreviousRune()
- if ok && r != '{' && r != '[' {
+ r := enc.getPreviousRune()
+ if r != '{' && r != '[' {
enc.writeByte(',')
}
enc.writeByte('"')
@@ -229,8 +229,8 @@ func (enc *Encoder) AddFloat32KeyOmitEmpty(key string, v float32) {
return
}
enc.grow(10 + len(key))
- r, ok := enc.getPreviousRune()
- if ok && r != '{' && r != '[' {
+ r := enc.getPreviousRune()
+ if r != '{' && r != '[' {
enc.writeByte(',')
}
enc.writeByte('"')
diff --git a/encode_object.go b/encode_object.go
@@ -15,7 +15,7 @@ func (enc *Encoder) EncodeObject(v MarshalerObject) error {
enc.err = err
return err
}
- _, err = enc.write()
+ _, err = enc.Write()
if err != nil {
enc.err = err
return err
@@ -38,8 +38,8 @@ func (enc *Encoder) encodeObject(v MarshalerObject) ([]byte, error) {
func (enc *Encoder) AddObject(v MarshalerObject) {
if v.IsNil() {
enc.grow(2)
- r, ok := enc.getPreviousRune()
- if ok && r != '{' && r != '[' {
+ r := enc.getPreviousRune()
+ if r != '{' && r != '[' {
enc.writeByte(',')
}
enc.writeByte('{')
@@ -47,8 +47,8 @@ func (enc *Encoder) AddObject(v MarshalerObject) {
return
}
enc.grow(4)
- r, ok := enc.getPreviousRune()
- if ok && r != '[' {
+ r := enc.getPreviousRune()
+ if r != '[' {
enc.writeByte(',')
}
enc.writeByte('{')
@@ -64,8 +64,8 @@ func (enc *Encoder) AddObjectOmitEmpty(v MarshalerObject) {
return
}
enc.grow(2)
- r, ok := enc.getPreviousRune()
- if ok && r != '[' {
+ r := enc.getPreviousRune()
+ if r != '[' {
enc.writeByte(',')
}
enc.writeByte('{')
@@ -78,8 +78,8 @@ func (enc *Encoder) AddObjectOmitEmpty(v MarshalerObject) {
func (enc *Encoder) AddObjectKey(key string, value MarshalerObject) {
if value.IsNil() {
enc.grow(2 + len(key))
- r, ok := enc.getPreviousRune()
- if ok && r != '{' {
+ r := enc.getPreviousRune()
+ if r != '{' {
enc.writeByte(',')
}
enc.writeByte('"')
@@ -89,8 +89,8 @@ func (enc *Encoder) AddObjectKey(key string, value MarshalerObject) {
return
}
enc.grow(5 + len(key))
- r, ok := enc.getPreviousRune()
- if ok && r != '{' {
+ r := enc.getPreviousRune()
+ if r != '{' {
enc.writeByte(',')
}
enc.writeByte('"')
@@ -108,8 +108,8 @@ func (enc *Encoder) AddObjectKeyOmitEmpty(key string, value MarshalerObject) {
return
}
enc.grow(5 + len(key))
- r, ok := enc.getPreviousRune()
- if ok && r != '{' {
+ r := enc.getPreviousRune()
+ if r != '{' {
enc.writeByte(',')
}
enc.writeByte('"')
diff --git a/encode_pool.go b/encode_pool.go
@@ -2,9 +2,8 @@ package gojay
import "io"
-var encPool = make(chan *Encoder, 16)
-var streamEncPool = make(chan *StreamEncoder, 16)
-var bufPool = make(chan []byte, 16)
+var encPool = make(chan *Encoder, 32)
+var streamEncPool = make(chan *StreamEncoder, 32)
func init() {
initStreamEncPool:
@@ -23,13 +22,6 @@ initEncPool:
break initEncPool
}
}
- for {
- select {
- case bufPool <- make([]byte, 0, 512):
- default:
- return
- }
- }
}
// NewEncoder returns a new encoder or borrows one from the pool
@@ -49,7 +41,7 @@ func BorrowEncoder(w io.Writer) *Encoder {
enc.err = nil
return enc
default:
- return &Encoder{w: w, buf: borrowBuf()}
+ return &Encoder{w: w, buf: make([]byte, 0, 512)}
}
}
@@ -62,12 +54,3 @@ func (enc *Encoder) Release() {
default:
}
}
-
-func borrowBuf() []byte {
- select {
- case b := <-bufPool:
- return b
- default:
- return make([]byte, 0, 512)
- }
-}
diff --git a/encode_stream.go b/encode_stream.go
@@ -180,7 +180,7 @@ func consume(init *StreamEncoder, s *StreamEncoder, m MarshalerStream) {
init.Cancel(s.Encoder.err)
return
}
- i, err := s.Encoder.write()
+ i, err := s.Encoder.Write()
if err != nil || i == 0 {
init.Cancel(err)
return
diff --git a/encode_string.go b/encode_string.go
@@ -6,7 +6,7 @@ func (enc *Encoder) EncodeString(s string) error {
panic(InvalidUsagePooledEncoderError("Invalid usage of pooled encoder"))
}
_, _ = enc.encodeString(s)
- _, err := enc.write()
+ _, err := enc.Write()
if err != nil {
enc.err = err
return err
@@ -22,11 +22,18 @@ func (enc *Encoder) encodeString(v string) ([]byte, error) {
return enc.buf, nil
}
+func (enc *Encoder) AppendString(v string) {
+ enc.grow(len(v) + 2)
+ enc.writeByte('"')
+ enc.writeStringEscape(v)
+ enc.writeByte('"')
+}
+
// AddString adds a string to be encoded, must be used inside a slice or array encoding (does not encode a key)
func (enc *Encoder) AddString(v string) {
enc.grow(len(v) + 4)
- r, ok := enc.getPreviousRune()
- if ok && r != '[' {
+ r := enc.getPreviousRune()
+ if r != '[' {
enc.writeByte(',')
}
enc.writeByte('"')
@@ -40,8 +47,8 @@ func (enc *Encoder) AddStringOmitEmpty(v string) {
if v == "" {
return
}
- r, ok := enc.getPreviousRune()
- if ok && r != '[' {
+ r := enc.getPreviousRune()
+ if r != '[' {
enc.writeByte(',')
}
enc.writeByte('"')
@@ -52,8 +59,8 @@ func (enc *Encoder) AddStringOmitEmpty(v string) {
// AddStringKey adds a string to be encoded, must be used inside an object as it will encode a key
func (enc *Encoder) AddStringKey(key, v string) {
enc.grow(len(key) + len(v) + 5)
- r, ok := enc.getPreviousRune()
- if ok && r != '{' {
+ r := enc.getPreviousRune()
+ if r != '{' {
enc.writeByte(',')
}
enc.writeByte('"')
@@ -70,8 +77,8 @@ func (enc *Encoder) AddStringKeyOmitEmpty(key, v string) {
return
}
enc.grow(len(key) + len(v) + 5)
- r, ok := enc.getPreviousRune()
- if ok && r != '{' {
+ r := enc.getPreviousRune()
+ if r != '{' {
enc.writeByte(',')
}
enc.writeByte('"')
diff --git a/encode_test.go b/encode_test.go
@@ -1,9 +1,45 @@
package gojay
-import "errors"
+import (
+ "errors"
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+)
type TestWriterError string
func (t TestWriterError) Write(b []byte) (int, error) {
return 0, errors.New("Test Error")
}
+
+func TestAppendBytes(t *testing.T) {
+ b := []byte(``)
+ enc := NewEncoder(nil)
+ enc.buf = b
+ enc.AppendBytes([]byte(`true`))
+ assert.Equal(t, string(enc.buf), `true`, "string(enc.buf) should equal to true")
+}
+
+func TestAppendByte(t *testing.T) {
+ b := []byte(``)
+ enc := NewEncoder(nil)
+ enc.buf = b
+ enc.AppendByte(1)
+ assert.Equal(t, enc.buf[0], uint8(0x1), "b[0] should equal to 1")
+}
+
+func TestAppendString(t *testing.T) {
+ b := []byte(``)
+ enc := NewEncoder(nil)
+ enc.buf = b
+ enc.AppendString("true")
+ assert.Equal(t, string(enc.buf), `"true"`, "string(enc.buf) should equal to true")
+}
+
+func TestBuf(t *testing.T) {
+ b := []byte(`test`)
+ enc := NewEncoder(nil)
+ enc.buf = b
+ assert.Equal(t, b, enc.Buf(), "enc.Buf() should equal to b")
+}