1
0
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:
Tao Wen 2016-12-04 13:13:38 +08:00
parent dd431da523
commit 33e3df45dd
2 changed files with 89 additions and 20 deletions

View File

@ -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(&copy))
}
}
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(&copy))
}
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]
}

View File

@ -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++ {