mirror of
https://github.com/json-iterator/go.git
synced 2025-03-23 21:09:11 +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()
|
||||
}
|
||||
|
||||
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 {
|
||||
fields map[string]Decoder
|
||||
}
|
||||
@ -45,10 +57,32 @@ func (decoder *structFieldDecoder) decode(ptr unsafe.Pointer, iter *Iterator) {
|
||||
}
|
||||
|
||||
var DECODER_STRING *stringDecoder
|
||||
var DECODER_OPTIONAL_STRING *stringOptionalDecoder
|
||||
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() {
|
||||
DECODER_STRING = &stringDecoder{}
|
||||
DECODER_OPTIONAL_STRING = &stringOptionalDecoder{}
|
||||
atomic.StorePointer(&DECODERS_STRUCT, unsafe.Pointer(&map[string]*structDecoder{}))
|
||||
}
|
||||
|
||||
@ -93,11 +127,25 @@ func decoderOfPtr(type_ reflect.Type) (Decoder, error) {
|
||||
return DECODER_STRING, nil
|
||||
case reflect.Struct:
|
||||
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:
|
||||
return nil, errors.New("expect string")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func decoderOfStruct(type_ reflect.Type) (Decoder, error) {
|
||||
cacheKey := type_.String()
|
||||
cachedDecoder := getStructDecoderFromCache(cacheKey)
|
||||
@ -117,23 +165,7 @@ func decoderOfStruct(type_ reflect.Type) (Decoder, error) {
|
||||
return cachedDecoder, nil
|
||||
}
|
||||
|
||||
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 decoderOfSlice(type_ reflect.Type) (Decoder, error) {
|
||||
fmt.Println(type_.Elem())
|
||||
return nil, errors.New("n/a")
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
func Test_reflect_struct(t *testing.T) {
|
||||
func Test_reflect_struct_string(t *testing.T) {
|
||||
iter := ParseString(`{"field1": "hello", "field2": "world"}`)
|
||||
struct_ := StructOfString{}
|
||||
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) {
|
||||
b.ReportAllocs()
|
||||
for n := 0; n < b.N; n++ {
|
||||
|
Loading…
x
Reference in New Issue
Block a user