From b39aa6075f41cb152f56375421e38899d5701dff Mon Sep 17 00:00:00 2001 From: Josh Baker Date: Thu, 8 Sep 2016 08:34:01 -0700 Subject: [PATCH] bytes substring optimization --- gjson.go | 26 +++++++++++++++++++++++--- gjson_test.go | 6 +++++- 2 files changed, 28 insertions(+), 4 deletions(-) diff --git a/gjson.go b/gjson.go index 6c5a718..0a0a898 100644 --- a/gjson.go +++ b/gjson.go @@ -2,6 +2,7 @@ package gjson import ( + "reflect" "strconv" "unsafe" @@ -1140,9 +1141,28 @@ func GetBytes(json []byte, path string) Result { if json != nil { // unsafe cast to string result = Get(*(*string)(unsafe.Pointer(&json)), path) - // copy of string data for safety - result.Raw = string(*(*[]byte)(unsafe.Pointer(&result.Raw))) - result.Str = string(*(*[]byte)(unsafe.Pointer(&result.Str))) + // copy of string data for safety. + rawh := *(*reflect.SliceHeader)(unsafe.Pointer(&result.Raw)) + 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 } diff --git a/gjson_test.go b/gjson_test.go index a8f642e..0c8c518 100644 --- a/gjson_test.go +++ b/gjson_test.go @@ -128,11 +128,15 @@ var basicJSON = `{"age":100, "name":{"here":"B\\\"R"}, var basicJSONB = []byte(basicJSON) func TestByteSafety(t *testing.T) { - jsonb := []byte(`{"name":"Janet"}`) + jsonb := []byte(`{"name":"Janet","age":38}`) mtok := GetBytes(jsonb, "name") if mtok.String() != "Janet" { 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[12] = 'd' jsonb[13] = 'y'