From 65353b6d52a31e808c07f9d4651b9473525dcd88 Mon Sep 17 00:00:00 2001 From: tidwall Date: Sat, 30 Jan 2021 12:50:49 -0700 Subject: [PATCH] Removed reflect package This commit removes the reflect package to avoid using the reflect.SliceHeader and reflect.StringHeader structures. Instead new sliceHeader and stringHeader stuctures have been added with the same layout expect that they intentionally expose the data field as an unsafe.Pointer instead of a uintptr. --- gjson.go | 51 ++++++++++++++++++++++++++++++++------------------- 1 file changed, 32 insertions(+), 19 deletions(-) diff --git a/gjson.go b/gjson.go index 66965ba..4f988d0 100644 --- a/gjson.go +++ b/gjson.go @@ -3,7 +3,6 @@ package gjson import ( "encoding/json" - "reflect" "strconv" "strings" "time" @@ -2836,6 +2835,19 @@ func modValid(json, arg string) string { return json } +// stringHeader instead of reflect.StringHeader +type stringHeader struct { + data unsafe.Pointer + len int +} + +// sliceHeader instead of reflect.SliceHeader +type sliceHeader struct { + data unsafe.Pointer + len int + cap int +} + // getBytes casts the input json bytes to a string and safely returns the // results as uniquely allocated data. This operation is intended to minimize // copies and allocations for the large json string->[]byte. @@ -2845,14 +2857,14 @@ func getBytes(json []byte, path string) Result { // unsafe cast to string result = Get(*(*string)(unsafe.Pointer(&json)), path) // safely get the string headers - rawhi := *(*reflect.StringHeader)(unsafe.Pointer(&result.Raw)) - strhi := *(*reflect.StringHeader)(unsafe.Pointer(&result.Str)) + rawhi := *(*stringHeader)(unsafe.Pointer(&result.Raw)) + strhi := *(*stringHeader)(unsafe.Pointer(&result.Str)) // create byte slice headers - rawh := reflect.SliceHeader{Data: rawhi.Data, Len: rawhi.Len} - strh := reflect.SliceHeader{Data: strhi.Data, Len: strhi.Len} - if strh.Data == 0 { + rawh := sliceHeader{data: rawhi.data, len: rawhi.len, cap: rawhi.len} + strh := sliceHeader{data: strhi.data, len: strhi.len, cap: rawhi.len} + if strh.data == nil { // str is nil - if rawh.Data == 0 { + if rawh.data == nil { // raw is nil result.Raw = "" } else { @@ -2860,19 +2872,20 @@ func getBytes(json []byte, path string) Result { result.Raw = string(*(*[]byte)(unsafe.Pointer(&rawh))) } result.Str = "" - } else if rawh.Data == 0 { + } else if rawh.data == nil { // raw is nil result.Raw = "" // str has data, safely copy the slice header to a string result.Str = string(*(*[]byte)(unsafe.Pointer(&strh))) - } else if strh.Data >= rawh.Data && - int(strh.Data)+strh.Len <= int(rawh.Data)+rawh.Len { + } else if uintptr(strh.data) >= uintptr(rawh.data) && + uintptr(strh.data)+uintptr(strh.len) <= + uintptr(rawh.data)+uintptr(rawh.len) { // Str is a substring of Raw. - start := int(strh.Data - rawh.Data) + start := uintptr(strh.data) - uintptr(rawh.data) // safely copy the raw slice header result.Raw = string(*(*[]byte)(unsafe.Pointer(&rawh))) // substring the raw - result.Str = result.Raw[start : start+strh.Len] + result.Str = result.Raw[start : start+uintptr(strh.len)] } else { // safely copy both the raw and str slice headers to strings result.Raw = string(*(*[]byte)(unsafe.Pointer(&rawh))) @@ -2887,9 +2900,9 @@ func getBytes(json []byte, path string) Result { // used instead. func fillIndex(json string, c *parseContext) { if len(c.value.Raw) > 0 && !c.calcd { - jhdr := *(*reflect.StringHeader)(unsafe.Pointer(&json)) - rhdr := *(*reflect.StringHeader)(unsafe.Pointer(&(c.value.Raw))) - c.value.Index = int(rhdr.Data - jhdr.Data) + jhdr := *(*stringHeader)(unsafe.Pointer(&json)) + rhdr := *(*stringHeader)(unsafe.Pointer(&(c.value.Raw))) + c.value.Index = int(uintptr(rhdr.data) - uintptr(jhdr.data)) if c.value.Index < 0 || c.value.Index >= len(json) { c.value.Index = 0 } @@ -2897,10 +2910,10 @@ func fillIndex(json string, c *parseContext) { } func stringBytes(s string) []byte { - return *(*[]byte)(unsafe.Pointer(&reflect.SliceHeader{ - Data: (*reflect.StringHeader)(unsafe.Pointer(&s)).Data, - Len: len(s), - Cap: len(s), + return *(*[]byte)(unsafe.Pointer(&sliceHeader{ + data: (*stringHeader)(unsafe.Pointer(&s)).data, + len: len(s), + cap: len(s), })) }