You've already forked json-iterator
							
							
				mirror of
				https://github.com/json-iterator/go.git
				synced 2025-10-31 00:07:40 +02:00 
			
		
		
		
	support optional string
This commit is contained in:
		| @@ -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++ { | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user