1
0
mirror of https://github.com/json-iterator/go.git synced 2025-05-13 21:36:29 +02:00

#64 support fixed array

This commit is contained in:
Tao Wen 2017-06-19 23:43:28 +08:00
parent c6a598e292
commit c3f5a2c536
4 changed files with 229 additions and 104 deletions

View File

@ -348,6 +348,8 @@ func createDecoderOfType(cfg *frozenConfig, typ reflect.Type) (Decoder, error) {
} }
case reflect.Struct: case reflect.Struct:
return prefix(fmt.Sprintf("[%s]", typ.String())).addToDecoder(decoderOfStruct(cfg, typ)) return prefix(fmt.Sprintf("[%s]", typ.String())).addToDecoder(decoderOfStruct(cfg, typ))
case reflect.Array:
return prefix("[array]").addToDecoder(decoderOfArray(cfg, typ))
case reflect.Slice: case reflect.Slice:
return prefix("[slice]").addToDecoder(decoderOfSlice(cfg, typ)) return prefix("[slice]").addToDecoder(decoderOfSlice(cfg, typ))
case reflect.Map: case reflect.Map:
@ -442,6 +444,8 @@ func createEncoderOfType(cfg *frozenConfig, typ reflect.Type) (Encoder, error) {
} }
case reflect.Struct: case reflect.Struct:
return prefix(fmt.Sprintf("[%s]", typ.String())).addToEncoder(encoderOfStruct(cfg, typ)) return prefix(fmt.Sprintf("[%s]", typ.String())).addToEncoder(encoderOfStruct(cfg, typ))
case reflect.Array:
return prefix("[array]").addToEncoder(encoderOfArray(cfg, typ))
case reflect.Slice: case reflect.Slice:
return prefix("[slice]").addToEncoder(encoderOfSlice(cfg, typ)) return prefix("[slice]").addToEncoder(encoderOfSlice(cfg, typ))
case reflect.Map: case reflect.Map:

View File

@ -1,21 +1,21 @@
package jsoniter package jsoniter
import ( import (
"fmt"
"io"
"reflect" "reflect"
"unsafe" "unsafe"
"io"
"fmt"
) )
func decoderOfSlice(cfg *frozenConfig, typ reflect.Type) (Decoder, error) { func decoderOfArray(cfg *frozenConfig, typ reflect.Type) (Decoder, error) {
decoder, err := decoderOfType(cfg, typ.Elem()) decoder, err := decoderOfType(cfg, typ.Elem())
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &sliceDecoder{typ, typ.Elem(), decoder}, nil return &arrayDecoder{typ, typ.Elem(), decoder}, nil
} }
func encoderOfSlice(cfg *frozenConfig, typ reflect.Type) (Encoder, error) { func encoderOfArray(cfg *frozenConfig, typ reflect.Type) (Encoder, error) {
encoder, err := encoderOfType(cfg, typ.Elem()) encoder, err := encoderOfType(cfg, typ.Elem())
if err != nil { if err != nil {
return nil, err return nil, err
@ -23,140 +23,62 @@ func encoderOfSlice(cfg *frozenConfig, typ reflect.Type) (Encoder, error) {
if typ.Elem().Kind() == reflect.Map { if typ.Elem().Kind() == reflect.Map {
encoder = &optionalEncoder{encoder} encoder = &optionalEncoder{encoder}
} }
return &sliceEncoder{typ, typ.Elem(), encoder}, nil return &arrayEncoder{typ, typ.Elem(), encoder}, nil
} }
type sliceEncoder struct { type arrayEncoder struct {
sliceType reflect.Type arrayType reflect.Type
elemType reflect.Type elemType reflect.Type
elemEncoder Encoder elemEncoder Encoder
} }
func (encoder *sliceEncoder) encode(ptr unsafe.Pointer, stream *Stream) { func (encoder *arrayEncoder) encode(ptr unsafe.Pointer, stream *Stream) {
slice := (*sliceHeader)(ptr) if ptr == nil {
if slice.Data == nil {
stream.WriteNil() stream.WriteNil()
return return
} }
if slice.Len == 0 {
stream.WriteEmptyArray()
return
}
stream.WriteArrayStart() stream.WriteArrayStart()
elemPtr := uintptr(slice.Data) elemPtr := uintptr(ptr)
encoder.elemEncoder.encode(unsafe.Pointer(elemPtr), stream) encoder.elemEncoder.encode(unsafe.Pointer(elemPtr), stream)
for i := 1; i < slice.Len; i++ { for i := 1; i < encoder.arrayType.Len(); i++ {
stream.WriteMore() stream.WriteMore()
elemPtr += encoder.elemType.Size() elemPtr += encoder.elemType.Size()
encoder.elemEncoder.encode(unsafe.Pointer(elemPtr), stream) encoder.elemEncoder.encode(unsafe.Pointer(elemPtr), stream)
} }
stream.WriteArrayEnd() stream.WriteArrayEnd()
if stream.Error != nil && stream.Error != io.EOF { if stream.Error != nil && stream.Error != io.EOF {
stream.Error = fmt.Errorf("%v: %s", encoder.sliceType, stream.Error.Error()) stream.Error = fmt.Errorf("%v: %s", encoder.arrayType, stream.Error.Error())
} }
} }
func (encoder *sliceEncoder) encodeInterface(val interface{}, stream *Stream) { func (encoder *arrayEncoder) encodeInterface(val interface{}, stream *Stream) {
writeToStream(val, stream, encoder) writeToStream(val, stream, encoder)
} }
func (encoder *sliceEncoder) isEmpty(ptr unsafe.Pointer) bool { func (encoder *arrayEncoder) isEmpty(ptr unsafe.Pointer) bool {
slice := (*sliceHeader)(ptr) return false
return slice.Len == 0
} }
type sliceDecoder struct { type arrayDecoder struct {
sliceType reflect.Type arrayType reflect.Type
elemType reflect.Type elemType reflect.Type
elemDecoder Decoder elemDecoder Decoder
} }
// sliceHeader is a safe version of SliceHeader used within this package. func (decoder *arrayDecoder) decode(ptr unsafe.Pointer, iter *Iterator) {
type sliceHeader struct {
Data unsafe.Pointer
Len int
Cap int
}
func (decoder *sliceDecoder) decode(ptr unsafe.Pointer, iter *Iterator) {
decoder.doDecode(ptr, iter) decoder.doDecode(ptr, iter)
if iter.Error != nil && iter.Error != io.EOF { if iter.Error != nil && iter.Error != io.EOF {
iter.Error = fmt.Errorf("%v: %s", decoder.sliceType, iter.Error.Error()) iter.Error = fmt.Errorf("%v: %s", decoder.arrayType, iter.Error.Error())
} }
} }
func (decoder *sliceDecoder) doDecode(ptr unsafe.Pointer, iter *Iterator) { func (decoder *arrayDecoder) doDecode(ptr unsafe.Pointer, iter *Iterator) {
slice := (*sliceHeader)(ptr)
reuseSlice(slice, decoder.sliceType, 4)
if !iter.ReadArray() {
return
}
offset := uintptr(0) offset := uintptr(0)
decoder.elemDecoder.decode(unsafe.Pointer(uintptr(slice.Data)+offset), iter) for ; iter.ReadArray(); offset += decoder.elemType.Size() {
if !iter.ReadArray() { if offset < decoder.arrayType.Size() {
slice.Len = 1 decoder.elemDecoder.decode(unsafe.Pointer(uintptr(ptr)+offset), iter)
return
}
offset += decoder.elemType.Size()
decoder.elemDecoder.decode(unsafe.Pointer(uintptr(slice.Data)+offset), iter)
if !iter.ReadArray() {
slice.Len = 2
return
}
offset += decoder.elemType.Size()
decoder.elemDecoder.decode(unsafe.Pointer(uintptr(slice.Data)+offset), iter)
if !iter.ReadArray() {
slice.Len = 3
return
}
offset += decoder.elemType.Size()
decoder.elemDecoder.decode(unsafe.Pointer(uintptr(slice.Data)+offset), iter)
slice.Len = 4
for iter.ReadArray() {
growOne(slice, decoder.sliceType, decoder.elemType)
offset += decoder.elemType.Size()
decoder.elemDecoder.decode(unsafe.Pointer(uintptr(slice.Data)+offset), iter)
}
}
// grow grows the slice s so that it can hold extra more values, allocating
// more capacity if needed. It also returns the old and new slice lengths.
func growOne(slice *sliceHeader, sliceType reflect.Type, elementType reflect.Type) {
newLen := slice.Len + 1
if newLen <= slice.Cap {
slice.Len = newLen
return
}
newCap := slice.Cap
if newCap == 0 {
newCap = 1
} else { } else {
for newCap < newLen { iter.Skip()
if slice.Len < 1024 {
newCap += newCap
} else {
newCap += newCap / 4
} }
} }
}
dst := unsafe.Pointer(reflect.MakeSlice(sliceType, newLen, newCap).Pointer())
// copy old array into new array
originalBytesCount := uintptr(slice.Len) * elementType.Size()
srcPtr := (*[1 << 30]byte)(slice.Data)
dstPtr := (*[1 << 30]byte)(dst)
for i := uintptr(0); i < originalBytesCount; i++ {
dstPtr[i] = srcPtr[i]
}
slice.Len = newLen
slice.Cap = newCap
slice.Data = dst
}
func reuseSlice(slice *sliceHeader, sliceType reflect.Type, expectedCap int) {
if expectedCap <= slice.Cap {
return
}
dst := unsafe.Pointer(reflect.MakeSlice(sliceType, 0, expectedCap).Pointer())
slice.Cap = expectedCap
slice.Data = dst
} }

162
feature_reflect_slice.go Normal file
View File

@ -0,0 +1,162 @@
package jsoniter
import (
"fmt"
"io"
"reflect"
"unsafe"
)
func decoderOfSlice(cfg *frozenConfig, typ reflect.Type) (Decoder, error) {
decoder, err := decoderOfType(cfg, typ.Elem())
if err != nil {
return nil, err
}
return &sliceDecoder{typ, typ.Elem(), decoder}, nil
}
func encoderOfSlice(cfg *frozenConfig, typ reflect.Type) (Encoder, error) {
encoder, err := encoderOfType(cfg, typ.Elem())
if err != nil {
return nil, err
}
if typ.Elem().Kind() == reflect.Map {
encoder = &optionalEncoder{encoder}
}
return &sliceEncoder{typ, typ.Elem(), encoder}, nil
}
type sliceEncoder struct {
sliceType reflect.Type
elemType reflect.Type
elemEncoder Encoder
}
func (encoder *sliceEncoder) encode(ptr unsafe.Pointer, stream *Stream) {
slice := (*sliceHeader)(ptr)
if slice.Data == nil {
stream.WriteNil()
return
}
if slice.Len == 0 {
stream.WriteEmptyArray()
return
}
stream.WriteArrayStart()
elemPtr := uintptr(slice.Data)
encoder.elemEncoder.encode(unsafe.Pointer(elemPtr), stream)
for i := 1; i < slice.Len; i++ {
stream.WriteMore()
elemPtr += encoder.elemType.Size()
encoder.elemEncoder.encode(unsafe.Pointer(elemPtr), stream)
}
stream.WriteArrayEnd()
if stream.Error != nil && stream.Error != io.EOF {
stream.Error = fmt.Errorf("%v: %s", encoder.sliceType, stream.Error.Error())
}
}
func (encoder *sliceEncoder) encodeInterface(val interface{}, stream *Stream) {
writeToStream(val, stream, encoder)
}
func (encoder *sliceEncoder) isEmpty(ptr unsafe.Pointer) bool {
slice := (*sliceHeader)(ptr)
return slice.Len == 0
}
type sliceDecoder struct {
sliceType reflect.Type
elemType reflect.Type
elemDecoder Decoder
}
// sliceHeader is a safe version of SliceHeader used within this package.
type sliceHeader struct {
Data unsafe.Pointer
Len int
Cap int
}
func (decoder *sliceDecoder) decode(ptr unsafe.Pointer, iter *Iterator) {
decoder.doDecode(ptr, iter)
if iter.Error != nil && iter.Error != io.EOF {
iter.Error = fmt.Errorf("%v: %s", decoder.sliceType, iter.Error.Error())
}
}
func (decoder *sliceDecoder) doDecode(ptr unsafe.Pointer, iter *Iterator) {
slice := (*sliceHeader)(ptr)
reuseSlice(slice, decoder.sliceType, 4)
if !iter.ReadArray() {
return
}
offset := uintptr(0)
decoder.elemDecoder.decode(unsafe.Pointer(uintptr(slice.Data)+offset), iter)
if !iter.ReadArray() {
slice.Len = 1
return
}
offset += decoder.elemType.Size()
decoder.elemDecoder.decode(unsafe.Pointer(uintptr(slice.Data)+offset), iter)
if !iter.ReadArray() {
slice.Len = 2
return
}
offset += decoder.elemType.Size()
decoder.elemDecoder.decode(unsafe.Pointer(uintptr(slice.Data)+offset), iter)
if !iter.ReadArray() {
slice.Len = 3
return
}
offset += decoder.elemType.Size()
decoder.elemDecoder.decode(unsafe.Pointer(uintptr(slice.Data)+offset), iter)
slice.Len = 4
for iter.ReadArray() {
growOne(slice, decoder.sliceType, decoder.elemType)
offset += decoder.elemType.Size()
decoder.elemDecoder.decode(unsafe.Pointer(uintptr(slice.Data)+offset), iter)
}
}
// grow grows the slice s so that it can hold extra more values, allocating
// more capacity if needed. It also returns the old and new slice lengths.
func growOne(slice *sliceHeader, sliceType reflect.Type, elementType reflect.Type) {
newLen := slice.Len + 1
if newLen <= slice.Cap {
slice.Len = newLen
return
}
newCap := slice.Cap
if newCap == 0 {
newCap = 1
} else {
for newCap < newLen {
if slice.Len < 1024 {
newCap += newCap
} else {
newCap += newCap / 4
}
}
}
dst := unsafe.Pointer(reflect.MakeSlice(sliceType, newLen, newCap).Pointer())
// copy old array into new array
originalBytesCount := uintptr(slice.Len) * elementType.Size()
srcPtr := (*[1 << 30]byte)(slice.Data)
dstPtr := (*[1 << 30]byte)(dst)
for i := uintptr(0); i < originalBytesCount; i++ {
dstPtr[i] = srcPtr[i]
}
slice.Len = newLen
slice.Cap = newCap
slice.Data = dst
}
func reuseSlice(slice *sliceHeader, sliceType reflect.Type, expectedCap int) {
if expectedCap <= slice.Cap {
return
}
dst := unsafe.Pointer(reflect.MakeSlice(sliceType, 0, expectedCap).Pointer())
slice.Cap = expectedCap
slice.Data = dst
}

View File

@ -0,0 +1,37 @@
package jsoniter
import (
"testing"
"github.com/json-iterator/go/require"
"encoding/json"
)
func Test_encode_fixed_array(t *testing.T) {
should := require.New(t)
type FixedArray [2]float64
fixed := FixedArray{0.1, 1.0}
output, err := MarshalToString(fixed)
should.Nil(err)
should.Equal("[0.1,1]", output)
}
func Test_encode_fixed_array_of_map(t *testing.T) {
should := require.New(t)
type FixedArray [2]map[string]string
fixed := FixedArray{map[string]string{"1": "2"}, map[string]string{"3": "4"}}
output, err := MarshalToString(fixed)
should.Nil(err)
should.Equal(`[{"1":"2"},{"3":"4"}]`, output)
}
func Test_decode_fixed_array(t *testing.T) {
should := require.New(t)
type FixedArray [2]float64
var fixed FixedArray
should.Nil(json.Unmarshal([]byte("[1,2,3]"), &fixed))
should.Equal(float64(1), fixed[0])
should.Equal(float64(2), fixed[1])
should.Nil(Unmarshal([]byte("[1,2,3]"), &fixed))
should.Equal(float64(1), fixed[0])
should.Equal(float64(2), fixed[1])
}