From 1e092ec62cf591e57f0b0bfb80b4484dd90c9c8c Mon Sep 17 00:00:00 2001 From: Charlie Stanton Date: Mon, 24 Apr 2023 19:02:23 +0100 Subject: Improves performance of reading JSON strings --- walk/walk.go | 81 +++++++++++++++++++++++++++++------------------------------- 1 file changed, 39 insertions(+), 42 deletions(-) (limited to 'walk/walk.go') diff --git a/walk/walk.go b/walk/walk.go index 008713b..0719d1c 100644 --- a/walk/walk.go +++ b/walk/walk.go @@ -228,7 +228,7 @@ type JSONIn struct { func NewJSONIn(reader *bufio.Reader) JSONIn { return JSONIn { - path: nil, + path: make([]Atom, 0, 256), reader: reader, structure: []JSONInStructure{JSONInRoot}, } @@ -297,6 +297,41 @@ func (in *JSONIn) require(criterion rune) { } } +func (in *JSONIn) readString(out []Atom) []Atom { + // TODO: improve + out = append(out, NewAtomStringTerminal()) + for { + r, _, err := in.reader.ReadRune() + if err != nil { + panic("Missing closing terminal in string input: " + err.Error()) + } + if r == '"' { + break + } + if r == '\\' { + r, _, err = in.reader.ReadRune() + if err != nil { + panic("Missing rune after \\") + } + if len(out) == cap(out) { + newOut := make([]Atom, len(out), cap(out) * 2) + copy(newOut, out) + out = newOut + } + out = append(out, NewAtomStringRune(r)) + continue + } + if len(out) == cap(out) { + newOut := make([]Atom, len(out), cap(out) * 2) + copy(newOut, out) + out = newOut + } + out = append(out, NewAtomStringRune(r)) + } + out = append(out, NewAtomStringTerminal()) + return out +} + func (in *JSONIn) Read() (WalkItem, error) { item, err := in.read() if err != nil { @@ -331,26 +366,7 @@ func (in *JSONIn) read() (WalkItem, error) { if r != '"' { panic("Expected key, found something else") } - in.path = append(in.path, NewAtomStringTerminal()) - for { - r, _, err = in.reader.ReadRune() - if err != nil { - return WalkItem {}, err - } - if r == '"' { - break - } - if r == '\\' { - r, _, err = in.reader.ReadRune() - if err != nil { - panic("Missing rune after \\") - } - in.path = append(in.path, NewAtomStringRune(r)) - continue - } - in.path = append(in.path, NewAtomStringRune(r)) - } - in.path = append(in.path, NewAtomStringTerminal()) + in.path = in.readString(in.path) r, err = in.nextNonWsRune() if err != nil { panic("Expected : got: " + err.Error()) @@ -432,27 +448,8 @@ func (in *JSONIn) read() (WalkItem, error) { Path: in.path, }, nil case '"': - value := make([]Atom, 0, 2) - value = append(value, NewAtomStringTerminal()) - for { - r, _, err = in.reader.ReadRune() - if err != nil { - panic("Missing closing terminal in string input: " + err.Error()) - } - if r == '"' { - break - } - if r == '\\' { - r, _, err = in.reader.ReadRune() - if err != nil { - panic("Missing rune after \\") - } - value = append(value, NewAtomStringRune(r)) - continue - } - value = append(value, NewAtomStringRune(r)) - } - value = append(value, NewAtomStringTerminal()) + value := make([]Atom, 0, 64) + value = in.readString(value) in.structure = append(in.structure, JSONInValueEnd) return WalkItem { Value: value, -- cgit v1.2.3