diff --git a/bench_test.go b/bench_test.go index 15898cd..38ea795 100644 --- a/bench_test.go +++ b/bench_test.go @@ -106,6 +106,19 @@ func BenchmarkDecoderDecodeInterfaceAny(b *testing.B) { check(b, err) } }) + b.Run("pkgjson/reuse/"+tc.path, func(b *testing.B) { + b.ReportAllocs() + b.SetBytes(r.Size()) + b.ResetTimer() + dec := NewDecoderBuffer(r, buf[:]) + for i := 0; i < b.N; i++ { + r.Seek(0, 0) + dec.Reset(r) + var i interface{} + err := dec.Decode(&i) + check(b, err) + } + }) b.Run("encodingjson/"+tc.path, func(b *testing.B) { b.ReportAllocs() b.SetBytes(r.Size()) diff --git a/decoder.go b/decoder.go index 5c033b1..e2da5f0 100644 --- a/decoder.go +++ b/decoder.go @@ -111,6 +111,13 @@ func (d *Decoder) NextToken() ([]byte, error) { return d.state(d) } +// Reset resets the decoder to read from a new io.Reader to avoid reallocation. +func (d *Decoder) Reset(r io.Reader) { + d.scanner.Reset(r) + d.state = (*Decoder).stateValue + d.stack = d.stack[:0] +} + func (d *Decoder) stateObjectString() ([]byte, error) { tok := d.scanner.Next() if len(tok) < 1 { diff --git a/reader.go b/reader.go index a954da4..9b0c723 100644 --- a/reader.go +++ b/reader.go @@ -68,3 +68,11 @@ func (b *byteReader) compact() { copy(b.data, b.data[b.offset:]) b.offset = 0 } + +// reset resets the byteReader to read from a new r without reallocating. +func (b *byteReader) reset(r io.Reader) { + b.data = b.data[:0] + b.offset = 0 + b.r = r + b.err = nil +} diff --git a/scanner.go b/scanner.go index d2db9fa..6ece4bd 100644 --- a/scanner.go +++ b/scanner.go @@ -107,6 +107,12 @@ func (s *Scanner) Next() []byte { } } +// Reset resets the scanner to read from a new io.Reader to avoid reallocation. +func (s *Scanner) Reset(r io.Reader) { + s.br.reset(r) + s.offset = 0 +} + func (s *Scanner) validateToken(expected string) int { for { w := s.br.window()