minor optz

This commit is contained in:
Josh Baker 2016-08-25 09:40:50 -07:00
parent 19f9404e51
commit 81391efb66
1 changed files with 120 additions and 87 deletions

207
gjson.go
View File

@ -430,18 +430,14 @@ func (t Result) Value() interface{} {
} }
func parseString(json string, i int, raw bool) (int, string, bool, bool) { func parseString(json string, i int) (int, string, bool, bool) {
var s = i var s = i
for ; i < len(json); i++ { for ; i < len(json); i++ {
if json[i] > '\\' { if json[i] > '\\' {
continue continue
} }
if json[i] == '"' { if json[i] == '"' {
if raw { return i + 1, json[s-1 : i+1], false, true
return i + 1, json[s-1 : i+1], false, true
} else {
return i + 1, json[s:i], false, true
}
} }
if json[i] == '\\' { if json[i] == '\\' {
i++ i++
@ -463,21 +459,13 @@ func parseString(json string, i int, raw bool) (int, string, bool, bool) {
continue continue
} }
} }
if raw { return i + 1, json[s-1 : i+1], true, true
return i + 1, json[s-1 : i+1], true, true
} else {
return i + 1, json[s:i], true, true
}
} }
} }
break break
} }
} }
if raw { return i, json[s-1:], false, false
return i, json[s-1:], false, false
} else {
return i, json[s:], false, false
}
} }
func parseNumber(json string, i int) (int, string) { func parseNumber(json string, i int) (int, string) {
@ -575,7 +563,7 @@ func parseObjectPath(path string) (
return path, "", wild, uc, false return path, "", wild, uc, false
} }
func squashObjectOrArray(json string, i int) (int, string) { func parseSquash(json string, i int) (int, string) {
// expects that the lead character is a '[' or '{' // expects that the lead character is a '[' or '{'
// squash the value, ignoring all nested arrays and objects. // squash the value, ignoring all nested arrays and objects.
// the first '[' or '{' has already been read // the first '[' or '{' has already been read
@ -623,17 +611,58 @@ func squashObjectOrArray(json string, i int) (int, string) {
return i, json[s:] return i, json[s:]
} }
func parseObject(json string, i int, path string, value *Result) (int, bool) { func parseObject(c *parseContext, i int, path string) (int, bool) {
var match, kesc, vesc, ok, hit bool var match, kesc, vesc, ok, hit bool
var key, val string var key, val string
part, npath, wild, uc, more := parseObjectPath(path) part, npath, wild, uc, more := parseObjectPath(path)
for i < len(json) { for i < len(c.json) {
for ; i < len(json); i++ { for ; i < len(c.json); i++ {
if json[i] == '"' { if c.json[i] == '"' {
i, key, kesc, ok = parseString(json, i+1, false) // parse_key_string
// this is slightly different from getting s string value
// because we don't need the outer quotes.
i++
var s = i
for ; i < len(c.json); i++ {
if c.json[i] > '\\' {
continue
}
if c.json[i] == '"' {
i, key, kesc, ok = i+1, c.json[s:i], false, true
goto parse_key_string_done
}
if c.json[i] == '\\' {
i++
for ; i < len(c.json); i++ {
if c.json[i] > '\\' {
continue
}
if c.json[i] == '"' {
// look for an escaped slash
if c.json[i-1] == '\\' {
n := 0
for j := i - 2; j > 0; j-- {
if c.json[j] != '\\' {
break
}
n++
}
if n%2 == 0 {
continue
}
}
i, key, kesc, ok = i+1, c.json[s:i], true, true
goto parse_key_string_done
}
}
break
}
}
i, key, kesc, ok = i, c.json[s:], false, false
parse_key_string_done:
break break
} }
if json[i] == '}' { if c.json[i] == '}' {
return i + 1, false return i + 1, false
} }
} }
@ -654,72 +683,72 @@ func parseObject(json string, i int, path string, value *Result) (int, bool) {
} }
} }
hit = match && !more hit = match && !more
for ; i < len(json); i++ { for ; i < len(c.json); i++ {
switch json[i] { switch c.json[i] {
default: default:
continue continue
case '"': case '"':
i++ i++
i, val, vesc, ok = parseString(json, i, true) i, val, vesc, ok = parseString(c.json, i)
if !ok { if !ok {
return i, false return i, false
} }
if hit { if hit {
if vesc { if vesc {
value.Str = unescape(val[1 : len(val)-1]) c.value.Str = unescape(val[1 : len(val)-1])
} else { } else {
value.Str = val[1 : len(val)-1] c.value.Str = val[1 : len(val)-1]
} }
value.Raw = val c.value.Raw = val
value.Type = String c.value.Type = String
return i, true return i, true
} }
case '{': case '{':
if match && !hit { if match && !hit {
i, hit = parseObject(json, i+1, npath, value) i, hit = parseObject(c, i+1, npath)
if hit { if hit {
return i, true return i, true
} }
} else { } else {
i, val = squashObjectOrArray(json, i) i, val = parseSquash(c.json, i)
if hit { if hit {
value.Raw = val c.value.Raw = val
value.Type = JSON c.value.Type = JSON
return i, true return i, true
} }
} }
case '[': case '[':
if match && !hit { if match && !hit {
i, hit = parseArray(json, i+1, npath, value) i, hit = parseArray(c, i+1, npath)
if hit { if hit {
return i, true return i, true
} }
} else { } else {
i, val = squashObjectOrArray(json, i) i, val = parseSquash(c.json, i)
if hit { if hit {
value.Raw = val c.value.Raw = val
value.Type = JSON c.value.Type = JSON
return i, true return i, true
} }
} }
case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
i, val = parseNumber(json, i) i, val = parseNumber(c.json, i)
if hit { if hit {
value.Raw = val c.value.Raw = val
value.Type = Number c.value.Type = Number
value.Num, _ = strconv.ParseFloat(val, 64) c.value.Num, _ = strconv.ParseFloat(val, 64)
return i, true return i, true
} }
case 't', 'f', 'n': case 't', 'f', 'n':
vc := json[i] vc := c.json[i]
i, val = parseLiteral(json, i) i, val = parseLiteral(c.json, i)
if hit { if hit {
value.Raw = val c.value.Raw = val
switch vc { switch vc {
case 't': case 't':
value.Type = True c.value.Type = True
case 'f': case 'f':
value.Type = False c.value.Type = False
} }
return i, true return i, true
} }
@ -730,7 +759,7 @@ func parseObject(json string, i int, path string, value *Result) (int, bool) {
return i, false return i, false
} }
func parseArray(json string, i int, path string, value *Result) (int, bool) { func parseArray(c *parseContext, i int, path string) (int, bool) {
var match, vesc, ok, hit bool var match, vesc, ok, hit bool
var val string var val string
var h int var h int
@ -745,7 +774,7 @@ func parseArray(json string, i int, path string, value *Result) (int, bool) {
partidx = int(n) partidx = int(n)
} }
} }
for i < len(json) { for i < len(c.json) {
if !arrch { if !arrch {
match = partidx == h match = partidx == h
hit = match && !more hit = match && !more
@ -754,13 +783,13 @@ func parseArray(json string, i int, path string, value *Result) (int, bool) {
if alogok { if alogok {
alog = append(alog, i) alog = append(alog, i)
} }
for ; i < len(json); i++ { for ; i < len(c.json); i++ {
switch json[i] { switch c.json[i] {
default: default:
continue continue
case '"': case '"':
i++ i++
i, val, vesc, ok = parseString(json, i, true) i, val, vesc, ok = parseString(c.json, i)
if !ok { if !ok {
return i, false return i, false
} }
@ -769,17 +798,17 @@ func parseArray(json string, i int, path string, value *Result) (int, bool) {
break break
} }
if vesc { if vesc {
value.Str = unescape(val[1 : len(val)-1]) c.value.Str = unescape(val[1 : len(val)-1])
} else { } else {
value.Str = val[1 : len(val)-1] c.value.Str = val[1 : len(val)-1]
} }
value.Raw = val c.value.Raw = val
value.Type = String c.value.Type = String
return i, true return i, true
} }
case '{': case '{':
if match && !hit { if match && !hit {
i, hit = parseObject(json, i+1, npath, value) i, hit = parseObject(c, i+1, npath)
if hit { if hit {
if alogok { if alogok {
break break
@ -787,19 +816,19 @@ func parseArray(json string, i int, path string, value *Result) (int, bool) {
return i, true return i, true
} }
} else { } else {
i, val = squashObjectOrArray(json, i) i, val = parseSquash(c.json, i)
if hit { if hit {
if alogok { if alogok {
break break
} }
value.Raw = val c.value.Raw = val
value.Type = JSON c.value.Type = JSON
return i, true return i, true
} }
} }
case '[': case '[':
if match && !hit { if match && !hit {
i, hit = parseArray(json, i+1, npath, value) i, hit = parseArray(c, i+1, npath)
if hit { if hit {
if alogok { if alogok {
break break
@ -807,51 +836,50 @@ func parseArray(json string, i int, path string, value *Result) (int, bool) {
return i, true return i, true
} }
} else { } else {
i, val = squashObjectOrArray(json, i) i, val = parseSquash(c.json, i)
if hit { if hit {
if alogok { if alogok {
break break
} }
value.Raw = val c.value.Raw = val
value.Type = JSON c.value.Type = JSON
return i, true return i, true
} }
} }
case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
i, val = parseNumber(json, i) i, val = parseNumber(c.json, i)
if hit { if hit {
if alogok { if alogok {
break break
} }
value.Raw = val c.value.Raw = val
value.Type = Number c.value.Type = Number
value.Num, _ = strconv.ParseFloat(val, 64) c.value.Num, _ = strconv.ParseFloat(val, 64)
return i, true return i, true
} }
case 't', 'f', 'n': case 't', 'f', 'n':
vc := json[i] vc := c.json[i]
i, val = parseLiteral(json, i) i, val = parseLiteral(c.json, i)
if hit { if hit {
if alogok { if alogok {
break break
} }
value.Raw = val c.value.Raw = val
switch vc { switch vc {
case 't': case 't':
value.Type = True c.value.Type = True
case 'f': case 'f':
value.Type = False c.value.Type = False
} }
return i, true return i, true
} }
case ']': case ']':
// TODO... '#' counter?
if arrch && part == "#" { if arrch && part == "#" {
if alogok { if alogok {
var jsons = make([]byte, 0, 64) var jsons = make([]byte, 0, 64)
jsons = append(jsons, '[') jsons = append(jsons, '[')
for j := 0; j < len(alog); j++ { for j := 0; j < len(alog); j++ {
res := Get(json[alog[j]:], alogkey) res := Get(c.json[alog[j]:], alogkey)
if res.Exists() { if res.Exists() {
if j > 0 { if j > 0 {
jsons = append(jsons, ',') jsons = append(jsons, ',')
@ -860,16 +888,16 @@ func parseArray(json string, i int, path string, value *Result) (int, bool) {
} }
} }
jsons = append(jsons, ']') jsons = append(jsons, ']')
value.Type = JSON c.value.Type = JSON
value.Raw = string(jsons) c.value.Raw = string(jsons)
return i + 1, true return i + 1, true
} else { } else {
if alogok { if alogok {
break break
} }
value.Raw = val c.value.Raw = val
value.Type = Number c.value.Type = Number
value.Num = float64(h - 1) c.value.Num = float64(h - 1)
return i + 1, true return i + 1, true
} }
} }
@ -912,20 +940,25 @@ func parseArray(json string, i int, path string, value *Result) (int, bool) {
// //
func Get(json, path string) Result { func Get(json, path string) Result {
var i int var i int
var value Result var c = &parseContext{json: json}
for ; i < len(json); i++ { for ; i < len(c.json); i++ {
if json[i] == '{' { if c.json[i] == '{' {
i++ i++
parseObject(json, i, path, &value) parseObject(c, i, path)
break break
} }
if json[i] == '[' { if c.json[i] == '[' {
i++ i++
parseArray(json, i, path, &value) parseArray(c, i, path)
break break
} }
} }
return value return c.value
}
type parseContext struct {
json string
value Result
} }
// unescape unescapes a string // unescape unescapes a string