bytes substring optimization

This commit is contained in:
Josh Baker 2016-09-08 08:34:01 -07:00
parent 124a25db9e
commit b39aa6075f
2 changed files with 28 additions and 4 deletions

View File

@ -2,6 +2,7 @@
package gjson package gjson
import ( import (
"reflect"
"strconv" "strconv"
"unsafe" "unsafe"
@ -1140,9 +1141,28 @@ func GetBytes(json []byte, path string) Result {
if json != nil { if json != nil {
// unsafe cast to string // unsafe cast to string
result = Get(*(*string)(unsafe.Pointer(&json)), path) result = Get(*(*string)(unsafe.Pointer(&json)), path)
// copy of string data for safety // copy of string data for safety.
result.Raw = string(*(*[]byte)(unsafe.Pointer(&result.Raw))) rawh := *(*reflect.SliceHeader)(unsafe.Pointer(&result.Raw))
result.Str = string(*(*[]byte)(unsafe.Pointer(&result.Str))) strh := *(*reflect.SliceHeader)(unsafe.Pointer(&result.Str))
if strh.Data == 0 {
if rawh.Data == 0 {
result.Raw = ""
} else {
result.Raw = string(*(*[]byte)(unsafe.Pointer(&result.Raw)))
}
result.Str = ""
} else if rawh.Data == 0 {
result.Raw = ""
result.Str = string(*(*[]byte)(unsafe.Pointer(&result.Str)))
} else if strh.Data >= rawh.Data && strh.Len <= rawh.Len {
// Str is a substring of Raw.
result.Raw = string(*(*[]byte)(unsafe.Pointer(&result.Raw)))
start := int(strh.Data - rawh.Data)
result.Str = result.Raw[start : start+strh.Len]
} else {
result.Raw = string(*(*[]byte)(unsafe.Pointer(&result.Raw)))
result.Str = string(*(*[]byte)(unsafe.Pointer(&result.Str)))
}
} }
return result return result
} }

View File

@ -128,11 +128,15 @@ var basicJSON = `{"age":100, "name":{"here":"B\\\"R"},
var basicJSONB = []byte(basicJSON) var basicJSONB = []byte(basicJSON)
func TestByteSafety(t *testing.T) { func TestByteSafety(t *testing.T) {
jsonb := []byte(`{"name":"Janet"}`) jsonb := []byte(`{"name":"Janet","age":38}`)
mtok := GetBytes(jsonb, "name") mtok := GetBytes(jsonb, "name")
if mtok.String() != "Janet" { if mtok.String() != "Janet" {
t.Fatalf("expected %v, got %v", "Jason", mtok.String()) t.Fatalf("expected %v, got %v", "Jason", mtok.String())
} }
mtok2 := GetBytes(jsonb, "age")
if mtok2.Raw != "38" {
t.Fatalf("expected %v, got %v", "Jason", mtok2.Raw)
}
jsonb[9] = 'T' jsonb[9] = 'T'
jsonb[12] = 'd' jsonb[12] = 'd'
jsonb[13] = 'y' jsonb[13] = 'y'