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() | ||||
| } | ||||
|  | ||||
| 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++ { | ||||
|   | ||||
		Reference in New Issue
	
	Block a user