diff options
| author | Charlie Stanton <charlie@shtanton.xyz> | 2023-04-25 17:42:05 +0100 | 
|---|---|---|
| committer | Charlie Stanton <charlie@shtanton.xyz> | 2023-04-25 17:42:05 +0100 | 
| commit | 72964bfa1f10b183de2a1d6577aad09d81609ae3 (patch) | |
| tree | 538648da0d2530d582c5b614fed905a5fb257771 /walk | |
| parent | 11bfa042040803061fa8cf04ab00d0e815ebafad (diff) | |
| download | stred-go-72964bfa1f10b183de2a1d6577aad09d81609ae3.tar | |
Replace readString in walk/read.go with a faster implementation that makes better use of the buffer system
Diffstat (limited to 'walk')
| -rw-r--r-- | walk/read.go | 190 | 
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  	}  } | 
