added direct bytes interface

This commit is contained in:
Josh Baker 2016-09-08 08:08:53 -07:00
parent b7e578ec72
commit 124a25db9e
2 changed files with 77 additions and 4 deletions

View File

@ -3,6 +3,7 @@ package gjson
import ( import (
"strconv" "strconv"
"unsafe"
"github.com/tidwall/match" "github.com/tidwall/match"
) )
@ -1080,6 +1081,11 @@ func parseArray(c *parseContext, i int, path string) (int, bool) {
return i, false return i, false
} }
type parseContext struct {
json string
value Result
}
// Get searches json for the specified path. // Get searches json for the specified path.
// A path is in dot syntax, such as "name.last" or "age". // A path is in dot syntax, such as "name.last" or "age".
// This function expects that the json is well-formed, and does not validate. // This function expects that the json is well-formed, and does not validate.
@ -1127,9 +1133,18 @@ func Get(json, path string) Result {
return c.value return c.value
} }
type parseContext struct { // GetBytes searches json for the specified path.
json string // If working with bytes, this method preferred over Get(string(data), path)
value Result func GetBytes(json []byte, path string) Result {
var result 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)))
}
return result
} }
// unescape unescapes a string // unescape unescapes a string

View File

@ -35,7 +35,7 @@ func TestRandomData(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
lstr = string(b[:n]) lstr = string(b[:n])
Get(lstr, "zzzz") GetBytes([]byte(lstr), "zzzz")
} }
} }
@ -125,6 +125,21 @@ var basicJSON = `{"age":100, "name":{"here":"B\\\"R"},
] ]
} }
}` }`
var basicJSONB = []byte(basicJSON)
func TestByteSafety(t *testing.T) {
jsonb := []byte(`{"name":"Janet"}`)
mtok := GetBytes(jsonb, "name")
if mtok.String() != "Janet" {
t.Fatalf("expected %v, got %v", "Jason", mtok.String())
}
jsonb[9] = 'T'
jsonb[12] = 'd'
jsonb[13] = 'y'
if mtok.String() != "Janet" {
t.Fatalf("expected %v, got %v", "Jason", mtok.String())
}
}
func TestBasic(t *testing.T) { func TestBasic(t *testing.T) {
var mtok Result var mtok Result
@ -134,6 +149,11 @@ func TestBasic(t *testing.T) {
t.Fatalf("expected %v, got %v", "1002,3", mtok.String()) t.Fatalf("expected %v, got %v", "1002,3", mtok.String())
} }
mtok = GetBytes(basicJSONB, `loggy.programmers.#[age=101].firstName`)
if mtok.String() != "1002.3" {
t.Fatalf("expected %v, got %v", "1002,3", mtok.String())
}
mtok = Get(basicJSON, `loggy.programmers.#[firstName == "Brett"].email`) mtok = Get(basicJSON, `loggy.programmers.#[firstName == "Brett"].email`)
if mtok.String() != "aaaa" { if mtok.String() != "aaaa" {
t.Fatalf("expected %v, got %v", "aaaa", mtok.String()) t.Fatalf("expected %v, got %v", "aaaa", mtok.String())
@ -740,3 +760,41 @@ func BenchmarkJSONParserGet(t *testing.B) {
} }
t.N *= len(benchPaths) // because we are running against 3 paths t.N *= len(benchPaths) // because we are running against 3 paths
} }
var massiveJSON = func() string {
var buf bytes.Buffer
buf.WriteString("[")
for i := 0; i < 100; i++ {
if i > 0 {
buf.WriteByte(',')
}
buf.WriteString(exampleJSON)
}
buf.WriteString("]")
return buf.String()
}()
func BenchmarkConvertNone(t *testing.B) {
json := massiveJSON
t.ReportAllocs()
t.ResetTimer()
for i := 0; i < t.N; i++ {
Get(json, "50.widget.text.onMouseUp")
}
}
func BenchmarkConvertGet(t *testing.B) {
data := []byte(massiveJSON)
t.ReportAllocs()
t.ResetTimer()
for i := 0; i < t.N; i++ {
Get(string(data), "50.widget.text.onMouseUp")
}
}
func BenchmarkConvertGetBytes(t *testing.B) {
data := []byte(massiveJSON)
t.ReportAllocs()
t.ResetTimer()
for i := 0; i < t.N; i++ {
GetBytes(data, "50.widget.text.onMouseUp")
}
}