summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuke Shumaker <lukeshu@lukeshu.com>2023-01-28 10:43:23 -0700
committerLuke Shumaker <lukeshu@lukeshu.com>2023-01-30 22:00:25 -0700
commit284be3f68b1eaf2ba693e0a8ae03baa80ebc973f (patch)
tree4960651aadbc360123fd73265bced507a829e836
parentbf28b48d23d19990190d5e5aeaee14ea6652a293 (diff)
reencode: Reuse speculation buffers
-rw-r--r--encode.go4
-rw-r--r--reencode.go34
2 files changed, 23 insertions, 15 deletions
diff --git a/encode.go b/encode.go
index 57f3852..949fd55 100644
--- a/encode.go
+++ b/encode.go
@@ -116,7 +116,7 @@ func encode(w internal.AllWriter, val reflect.Value, escaper BackslashEscaper, q
return discardInt(w.WriteString("null"))
}
// Use a sub-ReEncoder to check that it's a full element.
- validator := NewReEncoder(w, ReEncoderConfig{BackslashEscape: escaper})
+ validator := &ReEncoder{out: w, ReEncoderConfig: ReEncoderConfig{BackslashEscape: escaper}}
if err := obj.EncodeJSON(validator); err != nil {
return &EncodeMethodError{
Type: val.Type(),
@@ -152,7 +152,7 @@ func encode(w internal.AllWriter, val reflect.Value, escaper BackslashEscaper, q
}
}
// Use a sub-ReEncoder to check that it's a full element.
- validator := NewReEncoder(w, ReEncoderConfig{BackslashEscape: escaper})
+ validator := &ReEncoder{out: w, ReEncoderConfig: ReEncoderConfig{BackslashEscape: escaper}}
if _, err := validator.Write(dat); err != nil {
return &EncodeMethodError{
Type: val.Type(),
diff --git a/reencode.go b/reencode.go
index d588b1b..49d8ddb 100644
--- a/reencode.go
+++ b/reencode.go
@@ -72,6 +72,7 @@ func NewReEncoder(out io.Writer, cfg ReEncoderConfig) *ReEncoder {
return &ReEncoder{
ReEncoderConfig: cfg,
out: internal.NewAllWriter(out),
+ specu: new(speculation),
}
}
@@ -108,12 +109,21 @@ type ReEncoder struct {
}
type speculation struct {
+ speculating bool
endWhenStackSize int
fmt ReEncoder
compact bytes.Buffer
buf []inputTuple
}
+func (specu *speculation) Reset() {
+ specu.speculating = false
+ specu.endWhenStackSize = 0
+ specu.fmt = ReEncoder{}
+ specu.compact.Reset()
+ specu.buf = specu.buf[:0]
+}
+
type inputTuple struct {
c rune
t internal.RuneType
@@ -278,27 +288,25 @@ func (enc *ReEncoder) handleRune(c rune, t internal.RuneType, stackSize int) err
}
// main
- if enc.specu == nil { // not speculating
+ if !enc.specu.speculating { // not speculating
switch t {
case internal.RuneTypeObjectBeg, internal.RuneTypeArrayBeg: // start speculating
if err, _ := enc.handleRunePre(c, t); err != nil {
return err
}
- specu := &speculation{
- endWhenStackSize: stackSize - 1,
- fmt: ReEncoder{
- ReEncoderConfig: enc.ReEncoderConfig,
- },
+ enc.specu.speculating = true
+ enc.specu.endWhenStackSize = stackSize - 1
+ enc.specu.fmt = ReEncoder{
+ ReEncoderConfig: enc.ReEncoderConfig,
+ out: &enc.specu.compact,
}
- specu.fmt.Compact = true
- specu.fmt.out = &specu.compact
- enc.specu = specu
+ enc.specu.fmt.Compact = true
enc.specu.buf = append(enc.specu.buf, inputTuple{
c: c,
t: t,
stackSize: stackSize,
})
- if err := specu.fmt.handleRuneMain(c, t); err != nil {
+ if err := enc.specu.fmt.handleRuneMain(c, t); err != nil {
return err
}
default:
@@ -317,8 +325,8 @@ func (enc *ReEncoder) handleRune(c rune, t internal.RuneType, stackSize int) err
}
switch {
case enc.specu.compact.Len() >= enc.CompactIfUnder: // stop speculating; use indent
- buf := enc.specu.buf
- enc.specu = nil
+ buf := append([]inputTuple(nil), enc.specu.buf...)
+ enc.specu.Reset()
if err := enc.handleRuneMain(buf[0].c, buf[0].t); err != nil {
return err
}
@@ -331,9 +339,9 @@ func (enc *ReEncoder) handleRune(c rune, t internal.RuneType, stackSize int) err
if _, err := enc.specu.compact.WriteTo(enc.out); err != nil {
return err
}
+ enc.specu.Reset()
enc.lastNonSpace = t
enc.curIndent--
- enc.specu = nil
}
}