Permalink
Browse files

support int/string encode

  • Loading branch information...
1 parent bdbf8dc commit 5b0609f9013983824baaf659463c3c2daf43ae28 @taowen taowen committed Jan 9, 2017
View
@@ -9,7 +9,7 @@ import (
// Unmarshal adapts to json/encoding APIs
func Unmarshal(data []byte, v interface{}) error {
iter := ParseBytes(data)
- iter.Read(v)
+ iter.ReadVal(v)
if iter.Error == io.EOF {
return nil
}
@@ -20,7 +20,7 @@ func UnmarshalFromString(str string, v interface{}) error {
// safe to do the unsafe cast here, as str is always referenced in this scope
data := *(*[]byte)(unsafe.Pointer(&str))
iter := ParseBytes(data)
- iter.Read(v)
+ iter.ReadVal(v)
if iter.Error == io.EOF {
return nil
}
View
@@ -1,7 +1,6 @@
package jsoniter
import (
- "errors"
"fmt"
"io"
"reflect"
@@ -19,10 +18,12 @@ Reflection on value is avoided as we can, as the reflect.Value itself will alloc
For a simple struct binding, it will be reflect.Value free and allocation free
*/
-// Decoder works like a father class for sub-type decoders
type Decoder interface {
decode(ptr unsafe.Pointer, iter *Iterator)
}
+type Encoder interface {
+ encode(ptr unsafe.Pointer, stream *Stream)
+}
type DecoderFunc func(ptr unsafe.Pointer, iter *Iterator)
type ExtensionFunc func(typ reflect.Type, field *reflect.StructField) ([]string, DecoderFunc)
@@ -36,6 +37,7 @@ func (decoder *funcDecoder) decode(ptr unsafe.Pointer, iter *Iterator) {
}
var DECODERS unsafe.Pointer
+var ENCODERS unsafe.Pointer
var typeDecoders map[string]Decoder
var fieldDecoders map[string]Decoder
@@ -46,19 +48,34 @@ func init() {
fieldDecoders = map[string]Decoder{}
extensions = []ExtensionFunc{}
atomic.StorePointer(&DECODERS, unsafe.Pointer(&map[string]Decoder{}))
+ atomic.StorePointer(&ENCODERS, unsafe.Pointer(&map[string]Encoder{}))
}
func addDecoderToCache(cacheKey reflect.Type, decoder Decoder) {
- retry := true
- for retry {
+ done := false
+ for !done {
ptr := atomic.LoadPointer(&DECODERS)
cache := *(*map[reflect.Type]Decoder)(ptr)
- copy := map[reflect.Type]Decoder{}
+ copied := map[reflect.Type]Decoder{}
for k, v := range cache {
- copy[k] = v
+ copied[k] = v
}
- copy[cacheKey] = decoder
- retry = !atomic.CompareAndSwapPointer(&DECODERS, ptr, unsafe.Pointer(&copy))
+ copied[cacheKey] = decoder
+ done = atomic.CompareAndSwapPointer(&DECODERS, ptr, unsafe.Pointer(&copied))
+ }
+}
+
+func addEncoderToCache(cacheKey reflect.Type, encoder Encoder) {
+ done := false
+ for !done {
+ ptr := atomic.LoadPointer(&ENCODERS)
+ cache := *(*map[reflect.Type]Encoder)(ptr)
+ copied := map[reflect.Type]Encoder{}
+ for k, v := range cache {
+ copied[k] = v
+ }
+ copied[cacheKey] = encoder
+ done = atomic.CompareAndSwapPointer(&ENCODERS, ptr, unsafe.Pointer(&copied))
}
}
@@ -68,6 +85,12 @@ func getDecoderFromCache(cacheKey reflect.Type) Decoder {
return cache[cacheKey]
}
+func getEncoderFromCache(cacheKey reflect.Type) Encoder {
+ ptr := atomic.LoadPointer(&ENCODERS)
+ cache := *(*map[reflect.Type]Encoder)(ptr)
+ return cache[cacheKey]
+}
+
// RegisterTypeDecoder can register a type for json object
func RegisterTypeDecoder(typ string, fun DecoderFunc) {
typeDecoders[typ] = &funcDecoder{fun}
@@ -241,12 +264,12 @@ func (iter *Iterator) readNumber() (ret *Any) {
}
// Read converts an Iterator instance into go interface, same as json.Unmarshal
-func (iter *Iterator) Read(obj interface{}) {
+func (iter *Iterator) ReadVal(obj interface{}) {
typ := reflect.TypeOf(obj)
cacheKey := typ.Elem()
cachedDecoder := getDecoderFromCache(cacheKey)
if cachedDecoder == nil {
- decoder, err := decoderOfType(typ)
+ decoder, err := decoderOfType(cacheKey)
if err != nil {
iter.Error = err
return
@@ -258,6 +281,27 @@ func (iter *Iterator) Read(obj interface{}) {
cachedDecoder.decode(e.word, iter)
}
+
+func (stream *Stream) WriteVal(val interface{}) {
+ typ := reflect.TypeOf(val)
+ cacheKey := typ
+ if typ.Kind() == reflect.Ptr {
+ cacheKey = typ.Elem()
+ }
+ cachedEncoder := getEncoderFromCache(cacheKey)
+ if cachedEncoder == nil {
+ encoder, err := encoderOfType(cacheKey)
+ if err != nil {
+ stream.Error = err
+ return
+ }
+ cachedEncoder = encoder
+ addEncoderToCache(cacheKey, encoder)
+ }
+ e := (*emptyInterface)(unsafe.Pointer(&val))
+ cachedEncoder.encode(e.word, stream)
+}
+
type prefix string
func (p prefix) addTo(decoder Decoder, err error) (Decoder, error) {
@@ -268,15 +312,6 @@ func (p prefix) addTo(decoder Decoder, err error) (Decoder, error) {
}
func decoderOfType(typ reflect.Type) (Decoder, error) {
- switch typ.Kind() {
- case reflect.Ptr:
- return prefix("ptr").addTo(decoderOfPtr(typ.Elem()))
- default:
- return nil, errors.New("expect ptr")
- }
-}
-
-func decoderOfPtr(typ reflect.Type) (Decoder, error) {
typeName := typ.String()
if typeName == "jsoniter.Any" {
return &anyDecoder{}, nil
@@ -287,9 +322,9 @@ func decoderOfPtr(typ reflect.Type) (Decoder, error) {
}
switch typ.Kind() {
case reflect.String:
- return &stringDecoder{}, nil
+ return &stringCodec{}, nil
case reflect.Int:
- return &intDecoder{}, nil
+ return &intCodec{}, nil
case reflect.Int8:
return &int8Decoder{}, nil
case reflect.Int16:
@@ -329,24 +364,37 @@ func decoderOfPtr(typ reflect.Type) (Decoder, error) {
}
}
+
+
+func encoderOfType(typ reflect.Type) (Encoder, error) {
+ switch typ.Kind() {
+ case reflect.String:
+ return &stringCodec{}, nil
+ case reflect.Int:
+ return &intCodec{}, nil
+ default:
+ return nil, fmt.Errorf("unsupported type: %v", typ)
+ }
+}
+
func decoderOfOptional(typ reflect.Type) (Decoder, error) {
- decoder, err := decoderOfPtr(typ)
+ decoder, err := decoderOfType(typ)
if err != nil {
return nil, err
}
return &optionalDecoder{typ, decoder}, nil
}
func decoderOfSlice(typ reflect.Type) (Decoder, error) {
- decoder, err := decoderOfPtr(typ.Elem())
+ decoder, err := decoderOfType(typ.Elem())
if err != nil {
return nil, err
}
return &sliceDecoder{typ, typ.Elem(), decoder}, nil
}
func decoderOfMap(typ reflect.Type) (Decoder, error) {
- decoder, err := decoderOfPtr(typ.Elem())
+ decoder, err := decoderOfType(typ.Elem())
if err != nil {
return nil, err
}
@@ -2,20 +2,28 @@ package jsoniter
import "unsafe"
-type stringDecoder struct {
+type stringCodec struct {
}
-func (decoder *stringDecoder) decode(ptr unsafe.Pointer, iter *Iterator) {
+func (codec *stringCodec) decode(ptr unsafe.Pointer, iter *Iterator) {
*((*string)(ptr)) = iter.ReadString()
}
-type intDecoder struct {
+func (codec *stringCodec) encode(ptr unsafe.Pointer, stream *Stream) {
+ stream.WriteString(*((*string)(ptr)))
}
-func (decoder *intDecoder) decode(ptr unsafe.Pointer, iter *Iterator) {
+type intCodec struct {
+}
+
+func (codec *intCodec) decode(ptr unsafe.Pointer, iter *Iterator) {
*((*int)(ptr)) = iter.ReadInt()
}
+func (codec *intCodec) encode(ptr unsafe.Pointer, stream *Stream) {
+ stream.WriteInt(*((*int)(ptr)))
+}
+
type int8Decoder struct {
}
@@ -39,7 +39,7 @@ func decoderOfStruct(typ reflect.Type) (Decoder, error) {
}
if decoder == nil {
var err error
- decoder, err = decoderOfPtr(field.Type)
+ decoder, err = decoderOfType(field.Type)
if err != nil {
return prefix(fmt.Sprintf("{%s}", field.Name)).addTo(decoder, err)
}
@@ -8,7 +8,7 @@ import (
func Test_bind_api_demo(t *testing.T) {
iter := ParseString(`[0,1,2,3]`)
val := []int{}
- iter.Read(&val)
+ iter.ReadVal(&val)
fmt.Println(val[3])
}
@@ -34,7 +34,7 @@ type ABC struct {
func Test_deep_nested_any_api(t *testing.T) {
iter := ParseString(`{"a": {"b": {"c": "d"}}}`)
abc := &ABC{}
- iter.Read(&abc)
+ iter.ReadVal(&abc)
fmt.Println(abc.a.Get("b", "c"))
}
@@ -50,7 +50,7 @@ func Test_iterator_and_bind_api(t *testing.T) {
iter.ReadArray()
user.userID = iter.ReadInt()
iter.ReadArray()
- iter.Read(&user)
+ iter.ReadVal(&user)
iter.ReadArray() // array end
fmt.Println(user)
}
View
@@ -260,6 +260,27 @@ func Test_write_int64(t *testing.T) {
should.Equal("a4294967295", buf.String())
}
+func Test_write_val_int(t *testing.T) {
+ should := require.New(t)
+ buf := &bytes.Buffer{}
+ stream := NewStream(buf, 4096)
+ stream.WriteVal(1001)
+ stream.Flush()
+ should.Nil(stream.Error)
+ should.Equal("1001", buf.String())
+}
+
+func Test_write_val_int_ptr(t *testing.T) {
+ should := require.New(t)
+ buf := &bytes.Buffer{}
+ stream := NewStream(buf, 4096)
+ val := 1001
+ stream.WriteVal(&val)
+ stream.Flush()
+ should.Nil(stream.Error)
+ should.Equal("1001", buf.String())
+}
+
func Benchmark_jsoniter_encode_int(b *testing.B) {
stream := NewStream(ioutil.Discard, 64)
for n := 0; n < b.N; n++ {
@@ -9,7 +9,7 @@ import (
func Test_read_map(t *testing.T) {
iter := ParseString(`{"hello": "world"}`)
m := map[string]string{"1": "2"}
- iter.Read(&m)
+ iter.ReadVal(&m)
copy(iter.buf, []byte{0, 0, 0, 0, 0, 0})
if !reflect.DeepEqual(map[string]string{"1": "2", "hello": "world"}, m) {
fmt.Println(iter.Error)
@@ -20,7 +20,7 @@ func Test_read_map(t *testing.T) {
func Test_read_map_of_interface(t *testing.T) {
iter := ParseString(`{"hello": "world"}`)
m := map[string]interface{}{"1": "2"}
- iter.Read(&m)
+ iter.ReadVal(&m)
if !reflect.DeepEqual(map[string]interface{}{"1": "2", "hello": "world"}, m) {
fmt.Println(iter.Error)
t.Fatal(m)
@@ -30,7 +30,7 @@ func Test_read_map_of_interface(t *testing.T) {
func Test_read_map_of_any(t *testing.T) {
iter := ParseString(`{"hello": "world"}`)
m := map[string]Any{"1": *MakeAny("2")}
- iter.Read(&m)
+ iter.ReadVal(&m)
if !reflect.DeepEqual(map[string]Any{"1": *MakeAny("2"), "hello": *MakeAny("world")}, m) {
fmt.Println(iter.Error)
t.Fatal(m)
Oops, something went wrong.

0 comments on commit 5b0609f

Please sign in to comment.