1
0
mirror of https://github.com/json-iterator/go.git synced 2024-11-27 08:30:57 +02:00

int lazy any

This commit is contained in:
Tao Wen 2017-01-22 23:29:48 +08:00
parent 9df37bbd68
commit ba410b045b
7 changed files with 248 additions and 0 deletions

View File

@ -13,9 +13,24 @@ func Unmarshal(data []byte, v interface{}) error {
if iter.Error == io.EOF {
return nil
}
if iter.Error == nil {
iter.reportError("UnmarshalAny", "there are bytes left after unmarshal")
}
return iter.Error
}
func UnmarshalAny(data []byte) (Any, error) {
iter := ParseBytes(data)
any := iter.ReadAny()
if iter.Error == io.EOF {
return any, nil
}
if iter.Error == nil {
iter.reportError("UnmarshalAny", "there are bytes left after unmarshal")
}
return any, iter.Error
}
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))
@ -24,9 +39,26 @@ func UnmarshalFromString(str string, v interface{}) error {
if iter.Error == io.EOF {
return nil
}
if iter.Error == nil {
iter.reportError("UnmarshalFromString", "there are bytes left after unmarshal")
}
return iter.Error
}
func UnmarshalAnyFromString(str string) (Any, error) {
// safe to do the unsafe cast here, as str is always referenced in this scope
data := *(*[]byte)(unsafe.Pointer(&str))
iter := ParseBytes(data)
any := iter.ReadAny()
if iter.Error == io.EOF {
return any, nil
}
if iter.Error == nil {
iter.reportError("UnmarshalAnyFromString", "there are bytes left after unmarshal")
}
return nil, iter.Error
}
func Marshal(v interface{}) ([]byte, error) {
buf := &bytes.Buffer{}
stream := NewStream(buf, 4096)

57
feature_any.go Normal file
View File

@ -0,0 +1,57 @@
package jsoniter
import "fmt"
type Any interface {
LastError() error
ToBool() bool
ToInt() int
ToInt32() int32
ToInt64() int64
ToFloat32() float32
ToFloat64() float64
ToString() string
}
func (iter *Iterator) ReadAny() Any {
valueType := iter.WhatIsNext()
switch valueType {
case Nil:
iter.skipFixedBytes(4)
return &nilAny{}
case Number:
dotFound, lazyBuf := iter.skipNumber()
if dotFound {
return &floatLazyAny{lazyBuf, nil, nil}
} else {
return &intLazyAny{lazyBuf, nil, nil, 0}
}
}
iter.reportError("ReadAny", fmt.Sprintf("unexpected value type: %v", valueType))
return nil
}
func (iter *Iterator) skipNumber() (bool, []byte) {
dotFound := false
var lazyBuf []byte
for {
for i := iter.head; i < iter.tail; i++ {
c := iter.buf[i]
if c == '.' {
dotFound = true
continue
}
switch c {
case ' ', '\n', '\r', '\t', ',', '}', ']':
lazyBuf = append(lazyBuf, iter.buf[iter.head:i]...)
iter.head = i
return dotFound, lazyBuf
}
}
lazyBuf = append(lazyBuf, iter.buf[iter.head:iter.tail]...)
if !iter.loadMore() {
iter.head = iter.tail;
return dotFound, lazyBuf
}
}
}

39
feature_any_float.go Normal file
View File

@ -0,0 +1,39 @@
package jsoniter
type floatLazyAny struct {
buf []byte
iter *Iterator
err error
}
func (any *floatLazyAny) LastError() error {
return any.err
}
func (any *floatLazyAny) ToBool() bool {
return false
}
func (any *floatLazyAny) ToInt() int {
return 0
}
func (any *floatLazyAny) ToInt32() int32 {
return 0
}
func (any *floatLazyAny) ToInt64() int64 {
return 0
}
func (any *floatLazyAny) ToFloat32() float32 {
return 0
}
func (any *floatLazyAny) ToFloat64() float64 {
return 0
}
func (any *floatLazyAny) ToString() string {
return ""
}

66
feature_any_int.go Normal file
View File

@ -0,0 +1,66 @@
package jsoniter
import (
"io"
"unsafe"
)
type intLazyAny struct {
buf []byte
iter *Iterator
err error
cache int64
}
func (any *intLazyAny) fillCache() {
if any.err != nil {
return
}
iter := any.iter
if iter == nil {
iter = NewIterator()
}
iter.ResetBytes(any.buf)
any.cache = iter.ReadInt64()
if iter.Error != io.EOF {
iter.reportError("intLazyAny", "there are bytes left")
}
any.err = iter.Error
}
func (any *intLazyAny) LastError() error {
return any.err
}
func (any *intLazyAny) ToBool() bool {
return any.ToInt64() != 0
}
func (any *intLazyAny) ToInt() int {
any.fillCache()
return int(any.cache)
}
func (any *intLazyAny) ToInt32() int32 {
any.fillCache()
return int32(any.cache)
}
func (any *intLazyAny) ToInt64() int64 {
any.fillCache()
return any.cache
}
func (any *intLazyAny) ToFloat32() float32 {
any.fillCache()
return float32(any.cache)
}
func (any *intLazyAny) ToFloat64() float64 {
any.fillCache()
return float64(any.cache)
}
func (any *intLazyAny) ToString() string {
return *(*string)(unsafe.Pointer(&any.buf))
}

36
feature_any_nil.go Normal file
View File

@ -0,0 +1,36 @@
package jsoniter
type nilAny struct {
}
func (any *nilAny) LastError() error {
return nil
}
func (any *nilAny) ToBool() bool {
return false
}
func (any *nilAny) ToInt() int {
return 0
}
func (any *nilAny) ToInt32() int32 {
return 0
}
func (any *nilAny) ToInt64() int64 {
return 0
}
func (any *nilAny) ToFloat32() float32 {
return 0
}
func (any *nilAny) ToFloat64() float64 {
return 0
}
func (any *nilAny) ToString() string {
return ""
}

View File

@ -8,6 +8,7 @@ import (
"fmt"
"strconv"
"io/ioutil"
"io"
)
func Test_read_uint64_invalid(t *testing.T) {
@ -99,6 +100,16 @@ func Test_read_int64_overflow(t *testing.T) {
should.NotNil(iter.Error)
}
func Test_read_int64_as_any(t *testing.T) {
should := require.New(t)
any, err := UnmarshalAnyFromString("1234")
should.Nil(err)
should.Equal(1234, any.ToInt())
should.Equal(io.EOF, any.LastError())
should.Equal("1234", any.ToString())
should.True(any.ToBool())
}
func Test_write_uint8(t *testing.T) {
vals := []uint8{0, 1, 11, 111, 255}
for _, val := range vals {

View File

@ -12,6 +12,13 @@ func Test_read_null(t *testing.T) {
should.True(iter.ReadNil())
iter = ParseString(`null`)
should.Nil(iter.Read())
iter = ParseString(`null`)
any, err := UnmarshalAnyFromString(`null`)
should.Nil(err)
should.Equal(0, any.ToInt())
should.Equal(float64(0), any.ToFloat64())
should.Equal("", any.ToString())
should.False(any.ToBool())
}
func Test_write_null(t *testing.T) {