<- Back to shtanton's homepage
aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCharlie Stanton <charlie@shtanton.xyz>2023-04-25 17:42:05 +0100
committerCharlie Stanton <charlie@shtanton.xyz>2023-04-25 17:42:05 +0100
commit72964bfa1f10b183de2a1d6577aad09d81609ae3 (patch)
tree538648da0d2530d582c5b614fed905a5fb257771
parent11bfa042040803061fa8cf04ab00d0e815ebafad (diff)
downloadstred-go-72964bfa1f10b183de2a1d6577aad09d81609ae3.tar
Replace readString in walk/read.go with a faster implementation that makes better use of the buffer system
-rw-r--r--walk/read.go190
1 files changed, 100 insertions, 90 deletions
diff --git a/walk/read.go b/walk/read.go
index 58dfcae..c98b941 100644
--- a/walk/read.go
+++ b/walk/read.go
@@ -8,31 +8,14 @@ import (
"fmt"
)
-type ReadAction interface {
- String() string
-}
-
-type ActionReadValue struct {}
-func (_ ActionReadValue) String() string {
- return "read"
-}
-
-type ActionAppendPath struct {
- atoms []Atom
-}
-func (action ActionAppendPath) String() string {
- return fmt.Sprintf("append(%v)", action.atoms)
-}
-
-type ActionPopPath struct {}
-func (_ ActionPopPath) String() string {
- return "pop"
-}
-
-type ActionIncrementPath struct {}
-func (_ ActionIncrementPath) String() string {
- return "increment"
-}
+type ReadAction int
+const (
+ ActionReadValue ReadAction = iota
+ ActionAppendPath
+ ActionPopPath
+ ActionIncrementPath
+ ActionAppendPathNull
+)
type JSONInStructure int
const (
@@ -41,6 +24,8 @@ const (
JSONInArray
JSONInString
JSONInValueEnd
+ JSONInKey
+ JSONInKeyEnd
)
type JSONIn struct {
@@ -130,41 +115,6 @@ 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
-}
-
// Returns the first full value of a list of atoms and also a boolean to indicate if there isn't a value at the beginning
func firstValue(atoms []Atom) ([]Atom, bool) {
if len(atoms) == 0 {
@@ -199,7 +149,7 @@ func (in *JSONIn) Read() (WalkItem, error) {
}
}
action := in.actionBuffer[in.actionIndex]
- switch a := action.(type) {
+ switch action {
case ActionReadValue:
value, incomplete := firstValue(in.readBuffer[in.readIndex:])
if incomplete {
@@ -229,7 +179,31 @@ func (in *JSONIn) Read() (WalkItem, error) {
Path: in.path,
}, nil
case ActionAppendPath:
- in.path = append(in.path, a.atoms...)
+ value, incomplete := firstValue(in.readBuffer[in.readIndex:])
+ if incomplete {
+ if in.readIndex == 0 {
+ newReadBuffer := make([]Atom, len(in.readBuffer), in.readBufferCapacity * 2)
+ in.readBufferCapacity *= 2
+ copy(newReadBuffer, in.readBuffer)
+ in.readBuffer = newReadBuffer
+ structure, _ := in.fillReadBuffer(in.structure)
+ in.structure = structure
+ continue actionLoop
+ }
+ copy(in.readBuffer, in.readBuffer[in.readIndex:])
+ in.readBuffer = in.readBuffer[:len(in.readBuffer) - in.readIndex]
+ in.readIndex = 0
+ copy(in.actionBuffer, in.actionBuffer[in.actionIndex:])
+ in.actionBuffer = in.actionBuffer[:len(in.actionBuffer) - in.actionIndex]
+ in.actionIndex = 0
+ structure, _ := in.fillReadBuffer(in.structure)
+ in.structure = structure
+ continue actionLoop
+ }
+ in.readIndex += len(value)
+ in.path = append(in.path, value...)
+ case ActionAppendPathNull:
+ in.path = append(in.path, NewAtomNull())
case ActionPopPath:
in.popPath()
case ActionIncrementPath:
@@ -275,6 +249,12 @@ func (in *JSONIn) fillReadBuffer(structure []JSONInStructure) ([]JSONInStructure
case JSONInValueEnd:
structure = structure[:len(structure) - 1]
goto valueEnd
+ case JSONInKey:
+ structure = structure[:len(structure) - 1]
+ goto key
+ case JSONInKeyEnd:
+ structure = structure[:len(structure) - 1]
+ goto keyEnd
case JSONInMap:
goto mapValue
case JSONInArray:
@@ -291,43 +271,43 @@ func (in *JSONIn) fillReadBuffer(structure []JSONInStructure) ([]JSONInStructure
switch r {
case 'n':
in.requireString("ull")
- in.pushActionBuffer(ActionReadValue{})
+ in.pushActionBuffer(ActionReadValue)
if in.pushReadBuffer(NewAtomNull()) {
return append(structure, JSONInValueEnd), nil
}
goto valueEnd
case 'f':
in.requireString("alse")
- in.pushActionBuffer(ActionReadValue{})
+ in.pushActionBuffer(ActionReadValue)
if in.pushReadBuffer(NewAtomBool(false)) {
return append(structure, JSONInValueEnd), nil
}
goto valueEnd
case 't':
in.requireString("rue")
- in.pushActionBuffer(ActionReadValue{})
+ in.pushActionBuffer(ActionReadValue)
if in.pushReadBuffer(NewAtomBool(true)) {
return append(structure, JSONInValueEnd), nil
}
goto valueEnd
case '"':
- in.pushActionBuffer(ActionReadValue{})
+ in.pushActionBuffer(ActionReadValue)
if in.pushReadBuffer(NewAtomStringTerminal()) {
return append(structure, JSONInString), nil
}
goto string
case '{':
structure = append(structure, JSONInMap)
- in.pushActionBuffer(ActionReadValue{})
- in.pushActionBuffer(ActionAppendPath {[]Atom{NewAtomNull()}})
+ in.pushActionBuffer(ActionReadValue)
+ in.pushActionBuffer(ActionAppendPathNull)
if in.pushReadBuffer(NewAtomTerminal(MapBegin)) {
return structure, nil
}
goto mapValue
case '[':
structure = append(structure, JSONInArray)
- in.pushActionBuffer(ActionReadValue{})
- in.pushActionBuffer(ActionAppendPath {[]Atom{NewAtomNull()}})
+ in.pushActionBuffer(ActionReadValue)
+ in.pushActionBuffer(ActionAppendPathNull)
if in.pushReadBuffer(NewAtomTerminal(ArrayBegin)) {
return structure, nil
}
@@ -351,7 +331,7 @@ func (in *JSONIn) fillReadBuffer(structure []JSONInStructure) ([]JSONInStructure
if parseError != nil {
panic("Invalid number")
}
- in.pushActionBuffer(ActionReadValue{})
+ in.pushActionBuffer(ActionReadValue)
if in.pushReadBuffer(NewAtomNumber(number)) {
return append(structure, JSONInValueEnd), nil
}
@@ -385,6 +365,42 @@ func (in *JSONIn) fillReadBuffer(structure []JSONInStructure) ([]JSONInStructure
}
goto string
}
+ key: {
+ r, _, err := in.reader.ReadRune()
+ if err != nil {
+ panic("Missing closing terminal in string input: " + err.Error())
+ }
+ if r == '"' {
+ if in.pushReadBuffer(NewAtomStringTerminal()) {
+ return append(structure, JSONInKeyEnd), nil
+ }
+ goto keyEnd
+ }
+ if r == '\\' {
+ r, _, err = in.reader.ReadRune()
+ if err != nil {
+ panic("Missing rune after \\")
+ }
+ if in.pushReadBuffer(NewAtomStringRune(r)) {
+ return append(structure, JSONInKey), nil
+ }
+ goto key
+ }
+ if in.pushReadBuffer(NewAtomStringRune(r)) {
+ return append(structure, JSONInKey), nil
+ }
+ goto key
+ }
+ keyEnd: {
+ r, err := in.nextNonWsRune()
+ if err != nil {
+ panic("Expected : got: " + err.Error())
+ }
+ if r != ':' {
+ panic("Expected : after key")
+ }
+ goto value
+ }
valueEnd: {
r, err := in.nextNonWsRune()
if err != nil {
@@ -395,16 +411,16 @@ func (in *JSONIn) fillReadBuffer(structure []JSONInStructure) ([]JSONInStructure
panic("More input after root JSON object ends")
} else if underState == JSONInMap && r == '}' {
structure = structure[:len(structure) - 1]
- in.pushActionBuffer(ActionPopPath{})
- in.pushActionBuffer(ActionReadValue{})
+ in.pushActionBuffer(ActionPopPath)
+ in.pushActionBuffer(ActionReadValue)
if in.pushReadBuffer(NewAtomTerminal(MapEnd)) {
return append(structure, JSONInValueEnd), nil
}
goto valueEnd
} else if underState == JSONInArray && r == ']' {
structure = structure[:len(structure) - 1]
- in.pushActionBuffer(ActionPopPath{})
- in.pushActionBuffer(ActionReadValue{})
+ in.pushActionBuffer(ActionPopPath)
+ in.pushActionBuffer(ActionReadValue)
if in.pushReadBuffer(NewAtomTerminal(ArrayEnd)) {
return append(structure, JSONInValueEnd), nil
}
@@ -416,14 +432,14 @@ func (in *JSONIn) fillReadBuffer(structure []JSONInStructure) ([]JSONInStructure
goto valueStart
}
mapValue: {
- in.pushActionBuffer(ActionPopPath{})
+ in.pushActionBuffer(ActionPopPath)
r, err := in.nextNonWsRune()
if err != nil {
panic("Missing value inside object")
}
if r == '}' {
structure = structure[:len(structure) - 1]
- in.pushActionBuffer(ActionReadValue{})
+ in.pushActionBuffer(ActionReadValue)
if in.pushReadBuffer(NewAtomTerminal(MapEnd)) {
return append(structure, JSONInValueEnd), nil
}
@@ -432,17 +448,11 @@ func (in *JSONIn) fillReadBuffer(structure []JSONInStructure) ([]JSONInStructure
if r != '"' {
panic("Expected key found something else")
}
- var keyAtoms []Atom
- keyAtoms = in.readString(keyAtoms)
- in.pushActionBuffer(ActionAppendPath {keyAtoms})
- r, err = in.nextNonWsRune()
- if err != nil {
- panic("Expected : got: " + err.Error())
+ in.pushActionBuffer(ActionAppendPath)
+ if in.pushReadBuffer(NewAtomStringTerminal()) {
+ return append(structure, JSONInKey), nil
}
- if r != ':' {
- panic("Expected : after key")
- }
- goto value
+ goto key
}
arrayValue: {
r, err := in.nextNonWsRune()
@@ -451,15 +461,15 @@ func (in *JSONIn) fillReadBuffer(structure []JSONInStructure) ([]JSONInStructure
}
if r == ']' {
structure = structure[:len(structure) - 1]
- in.pushActionBuffer(ActionPopPath{})
- in.pushActionBuffer(ActionReadValue{})
+ in.pushActionBuffer(ActionPopPath)
+ in.pushActionBuffer(ActionReadValue)
if in.pushReadBuffer(NewAtomTerminal(ArrayEnd)) {
return append(structure, JSONInValueEnd), nil
}
goto valueEnd
}
in.reader.UnreadRune()
- in.pushActionBuffer(ActionIncrementPath{})
+ in.pushActionBuffer(ActionIncrementPath)
goto value
}
}