mirror of
https://github.com/json-iterator/go.git
synced 2025-05-13 21:36:29 +02:00
support optional string
This commit is contained in:
parent
dd431da523
commit
33e3df45dd
@ -19,6 +19,18 @@ func (decoder *stringDecoder) decode(ptr unsafe.Pointer, iter *Iterator) {
|
|||||||
*((*string)(ptr)) = iter.ReadString()
|
*((*string)(ptr)) = iter.ReadString()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type stringOptionalDecoder struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
func (decoder *stringOptionalDecoder) decode(ptr unsafe.Pointer, iter *Iterator) {
|
||||||
|
if iter.ReadNull() {
|
||||||
|
*((**string)(ptr)) = nil
|
||||||
|
} else {
|
||||||
|
result := iter.ReadString()
|
||||||
|
*((**string)(ptr)) = &result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
type structDecoder struct {
|
type structDecoder struct {
|
||||||
fields map[string]Decoder
|
fields map[string]Decoder
|
||||||
}
|
}
|
||||||
@ -45,10 +57,32 @@ func (decoder *structFieldDecoder) decode(ptr unsafe.Pointer, iter *Iterator) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var DECODER_STRING *stringDecoder
|
var DECODER_STRING *stringDecoder
|
||||||
|
var DECODER_OPTIONAL_STRING *stringOptionalDecoder
|
||||||
var DECODERS_STRUCT unsafe.Pointer
|
var DECODERS_STRUCT unsafe.Pointer
|
||||||
|
|
||||||
|
func addStructDecoderToCache(cacheKey string, decoder *structDecoder) {
|
||||||
|
retry := true
|
||||||
|
for retry {
|
||||||
|
ptr := atomic.LoadPointer(&DECODERS_STRUCT)
|
||||||
|
cache := *(*map[string]*structDecoder)(ptr)
|
||||||
|
copy := map[string]*structDecoder{}
|
||||||
|
for k, v := range cache {
|
||||||
|
copy[k] = v
|
||||||
|
}
|
||||||
|
copy[cacheKey] = decoder
|
||||||
|
retry = !atomic.CompareAndSwapPointer(&DECODERS_STRUCT, ptr, unsafe.Pointer(©))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func getStructDecoderFromCache(cacheKey string) *structDecoder {
|
||||||
|
ptr := atomic.LoadPointer(&DECODERS_STRUCT)
|
||||||
|
cache := *(*map[string]*structDecoder)(ptr)
|
||||||
|
return cache[cacheKey]
|
||||||
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
DECODER_STRING = &stringDecoder{}
|
DECODER_STRING = &stringDecoder{}
|
||||||
|
DECODER_OPTIONAL_STRING = &stringOptionalDecoder{}
|
||||||
atomic.StorePointer(&DECODERS_STRUCT, unsafe.Pointer(&map[string]*structDecoder{}))
|
atomic.StorePointer(&DECODERS_STRUCT, unsafe.Pointer(&map[string]*structDecoder{}))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -93,11 +127,25 @@ func decoderOfPtr(type_ reflect.Type) (Decoder, error) {
|
|||||||
return DECODER_STRING, nil
|
return DECODER_STRING, nil
|
||||||
case reflect.Struct:
|
case reflect.Struct:
|
||||||
return decoderOfStruct(type_)
|
return decoderOfStruct(type_)
|
||||||
|
case reflect.Slice:
|
||||||
|
return decoderOfSlice(type_)
|
||||||
|
case reflect.Ptr:
|
||||||
|
return prefix("optional").addTo(decoderOfOptional(type_.Elem()))
|
||||||
|
default:
|
||||||
|
return nil, errors.New("expect string, struct, slice")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func decoderOfOptional(type_ reflect.Type) (Decoder, error) {
|
||||||
|
switch type_.Kind() {
|
||||||
|
case reflect.String:
|
||||||
|
return DECODER_OPTIONAL_STRING, nil
|
||||||
default:
|
default:
|
||||||
return nil, errors.New("expect string")
|
return nil, errors.New("expect string")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func decoderOfStruct(type_ reflect.Type) (Decoder, error) {
|
func decoderOfStruct(type_ reflect.Type) (Decoder, error) {
|
||||||
cacheKey := type_.String()
|
cacheKey := type_.String()
|
||||||
cachedDecoder := getStructDecoderFromCache(cacheKey)
|
cachedDecoder := getStructDecoderFromCache(cacheKey)
|
||||||
@ -117,23 +165,7 @@ func decoderOfStruct(type_ reflect.Type) (Decoder, error) {
|
|||||||
return cachedDecoder, nil
|
return cachedDecoder, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func addStructDecoderToCache(cacheKey string, decoder *structDecoder) {
|
func decoderOfSlice(type_ reflect.Type) (Decoder, error) {
|
||||||
retry := true
|
fmt.Println(type_.Elem())
|
||||||
for retry {
|
return nil, errors.New("n/a")
|
||||||
ptr := atomic.LoadPointer(&DECODERS_STRUCT)
|
|
||||||
cache := *(*map[string]*structDecoder)(ptr)
|
|
||||||
copy := map[string]*structDecoder{}
|
|
||||||
for k, v := range cache {
|
|
||||||
copy[k] = v
|
|
||||||
}
|
|
||||||
copy[cacheKey] = decoder
|
|
||||||
retry = !atomic.CompareAndSwapPointer(&DECODERS_STRUCT, ptr, unsafe.Pointer(©))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func getStructDecoderFromCache(cacheKey string) *structDecoder {
|
|
||||||
ptr := atomic.LoadPointer(&DECODERS_STRUCT)
|
|
||||||
cache := *(*map[string]*structDecoder)(ptr)
|
|
||||||
return cache[cacheKey]
|
|
||||||
}
|
|
||||||
|
|
||||||
|
@ -20,7 +20,7 @@ type StructOfString struct {
|
|||||||
field2 string
|
field2 string
|
||||||
}
|
}
|
||||||
|
|
||||||
func Test_reflect_struct(t *testing.T) {
|
func Test_reflect_struct_string(t *testing.T) {
|
||||||
iter := ParseString(`{"field1": "hello", "field2": "world"}`)
|
iter := ParseString(`{"field1": "hello", "field2": "world"}`)
|
||||||
struct_ := StructOfString{}
|
struct_ := StructOfString{}
|
||||||
iter.Read(&struct_)
|
iter.Read(&struct_)
|
||||||
@ -34,6 +34,43 @@ func Test_reflect_struct(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type StructOfStringPtr struct {
|
||||||
|
field1 *string
|
||||||
|
field2 *string
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_reflect_struct_string_ptr(t *testing.T) {
|
||||||
|
iter := ParseString(`{"field1": null, "field2": "world"}`)
|
||||||
|
struct_ := StructOfStringPtr{}
|
||||||
|
iter.Read(&struct_)
|
||||||
|
if struct_.field1 != nil {
|
||||||
|
fmt.Println(iter.Error)
|
||||||
|
t.Fatal(struct_.field1)
|
||||||
|
}
|
||||||
|
if *struct_.field2 != "world" {
|
||||||
|
fmt.Println(iter.Error)
|
||||||
|
t.Fatal(struct_.field1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_reflect_array(t *testing.T) {
|
||||||
|
iter := ParseString(`{"hello", "world"}`)
|
||||||
|
array := []string{}
|
||||||
|
iter.Read(&array)
|
||||||
|
if len(array) != 2 {
|
||||||
|
fmt.Println(iter.Error)
|
||||||
|
t.Fatal(len(array))
|
||||||
|
}
|
||||||
|
if array[0] != "hello" {
|
||||||
|
fmt.Println(iter.Error)
|
||||||
|
t.Fatal(array[0])
|
||||||
|
}
|
||||||
|
if array[1] != "world" {
|
||||||
|
fmt.Println(iter.Error)
|
||||||
|
t.Fatal(array[1])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func Benchmark_jsoniter_reflect(b *testing.B) {
|
func Benchmark_jsoniter_reflect(b *testing.B) {
|
||||||
b.ReportAllocs()
|
b.ReportAllocs()
|
||||||
for n := 0; n < b.N; n++ {
|
for n := 0; n < b.N; n++ {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user