From a84cdaa694f819e64ba1acae91bd2c8c9d1f3de7 Mon Sep 17 00:00:00 2001 From: Tao Wen Date: Sun, 18 Jun 2017 22:40:18 +0800 Subject: [PATCH] #61 remove internal buffer from arrayAny --- feature_any.go | 10 +++- feature_any_array.go | 108 +++++++------------------------------ feature_any_string.go | 27 ++++------ jsoniter_any_array_test.go | 7 ++- 4 files changed, 43 insertions(+), 109 deletions(-) diff --git a/feature_any.go b/feature_any.go index eea9a79..36e61f0 100644 --- a/feature_any.go +++ b/feature_any.go @@ -71,7 +71,7 @@ func WrapFloat64(val float64) Any { } func WrapString(val string) Any { - return &stringAny{baseAny{}, nil, val} + return &stringAny{baseAny{}, val} } func Wrap(val interface{}) Any { @@ -135,7 +135,7 @@ func (iter *Iterator) readAny() Any { switch c { case '"': iter.unreadByte() - return &stringAny{baseAny{}, nil, iter.ReadString()} + return &stringAny{baseAny{}, iter.ReadString()} case 'n': iter.skipFixedBytes(3) // null return &nilAny{} @@ -222,6 +222,12 @@ func locatePath(iter *Iterator, path []interface{}) Any { case int: valueBytes := locateArrayElement(iter, pathKey) iter.ResetBytes(valueBytes) + case int32: + if '*' == pathKey { + return iter.readAny().Get(path[i:]...) + } else { + return newInvalidAny(path) + } default: return newInvalidAny(path[i:]) } diff --git a/feature_any_array.go b/feature_any_array.go index 487d551..743bcd8 100644 --- a/feature_any_array.go +++ b/feature_any_array.go @@ -1,7 +1,6 @@ package jsoniter import ( - "fmt" "reflect" "unsafe" ) @@ -166,25 +165,19 @@ func (any *arrayLazyAny) GetInterface() interface{} { type arrayAny struct { baseAny - err error - cache []Any val reflect.Value } func wrapArray(val interface{}) *arrayAny { - return &arrayAny{baseAny{}, nil, nil, reflect.ValueOf(val)} + return &arrayAny{baseAny{}, reflect.ValueOf(val)} } func (any *arrayAny) ValueType() ValueType { return Array } -func (any *arrayAny) Parse() *Iterator { - return nil -} - func (any *arrayAny) LastError() error { - return any.err + return nil } func (any *arrayAny) ToBool() bool { @@ -248,115 +241,54 @@ func (any *arrayAny) ToFloat64() float64 { } func (any *arrayAny) ToString() string { - if len(any.cache) == 0 { - // nothing has been parsed yet - str, err := MarshalToString(any.val.Interface()) - any.err = err - return str - } else { - any.fillCache() - str, err := MarshalToString(any.cache) - any.err = err - return str - } -} - -func (any *arrayAny) fillCacheUntil(idx int) Any { - if idx < len(any.cache) { - return any.cache[idx] - } else { - for i := len(any.cache); i < any.val.Len(); i++ { - element := Wrap(any.val.Index(i).Interface()) - any.cache = append(any.cache, element) - if idx == i { - return element - } - } - return nil - } -} - -func (any *arrayAny) fillCache() { - any.cache = make([]Any, any.val.Len()) - for i := 0; i < any.val.Len(); i++ { - any.cache[i] = Wrap(any.val.Index(i).Interface()) - } + str, _ := MarshalToString(any.val.Interface()) + return str } func (any *arrayAny) Get(path ...interface{}) Any { if len(path) == 0 { return any } - var element Any switch firstPath := path[0].(type) { case int: - element = any.fillCacheUntil(firstPath) - if element == nil { - element = &invalidAny{baseAny{}, fmt.Errorf("%v not found in %v", firstPath, any.cache)} + if firstPath < 0 || firstPath >= any.val.Len() { + return newInvalidAny(path) } + return Wrap(any.val.Index(firstPath).Interface()) case int32: if '*' == firstPath { - any.fillCache() - mappedAll := make([]Any, 0, len(any.cache)) - for _, element := range any.cache { - mapped := element.Get(path[1:]...) + mappedAll := make([]Any, 0) + for i := 0; i < any.val.Len(); i++ { + mapped := Wrap(any.val.Index(i).Interface()).Get(path[1:]...) if mapped.ValueType() != Invalid { mappedAll = append(mappedAll, mapped) } } return wrapArray(mappedAll) } else { - element = &invalidAny{baseAny{}, fmt.Errorf("%v not found in %v", path[0], any.cache)} + return newInvalidAny(path) } default: - element = &invalidAny{baseAny{}, fmt.Errorf("%v not found in %v", path[0], any.cache)} - } - if len(path) == 1 { - return element - } else { - return element.Get(path[1:]...) + return newInvalidAny(path) } } func (any *arrayAny) Size() int { - any.fillCache() - return len(any.cache) -} - -func (any *arrayAny) IterateArray() (func() (Any, bool), bool) { - if any.val.Len() == 0 { - return nil, false - } - i := 0 - return func() (Any, bool) { - if i == any.val.Len() { - return nil, false - } - if i == len(any.cache) { - any.cache = append(any.cache, Wrap(any.val.Index(i).Interface())) - } - val := any.cache[i] - i++ - return val, i != any.val.Len() - }, true + return any.val.Len() } func (any *arrayAny) GetArray() []Any { - any.fillCache() - return any.cache + elements := make([]Any, any.val.Len()) + for i := 0; i < any.val.Len(); i++ { + elements[i] = Wrap(any.val.Index(i).Interface()) + } + return elements } func (any *arrayAny) WriteTo(stream *Stream) { - if len(any.cache) == 0 { - // nothing has been parsed yet - stream.WriteVal(any.val) - } else { - any.fillCache() - stream.WriteVal(any.cache) - } + stream.WriteVal(any.val) } func (any *arrayAny) GetInterface() interface{} { - any.fillCache() - return any.cache + return any.val.Interface() } diff --git a/feature_any_string.go b/feature_any_string.go index 99252f3..293624d 100644 --- a/feature_any_string.go +++ b/feature_any_string.go @@ -6,7 +6,6 @@ import ( type stringAny struct { baseAny - err error val string } @@ -19,7 +18,7 @@ func (any *stringAny) ValueType() ValueType { } func (any *stringAny) LastError() error { - return any.err + return nil } func (any *stringAny) ToBool() bool { @@ -38,50 +37,42 @@ func (any *stringAny) ToBool() bool { } func (any *stringAny) ToInt() int { - parsed, err := strconv.ParseInt(any.val, 10, 64) - any.err = err + parsed, _ := strconv.ParseInt(any.val, 10, 64) return int(parsed) } func (any *stringAny) ToInt32() int32 { - parsed, err := strconv.ParseInt(any.val, 10, 32) - any.err = err + parsed, _ := strconv.ParseInt(any.val, 10, 32) return int32(parsed) } func (any *stringAny) ToInt64() int64 { - parsed, err := strconv.ParseInt(any.val, 10, 64) - any.err = err + parsed, _ := strconv.ParseInt(any.val, 10, 64) return parsed } func (any *stringAny) ToUint() uint { - parsed, err := strconv.ParseUint(any.val, 10, 64) - any.err = err + parsed, _ := strconv.ParseUint(any.val, 10, 64) return uint(parsed) } func (any *stringAny) ToUint32() uint32 { - parsed, err := strconv.ParseUint(any.val, 10, 32) - any.err = err + parsed, _ := strconv.ParseUint(any.val, 10, 32) return uint32(parsed) } func (any *stringAny) ToUint64() uint64 { - parsed, err := strconv.ParseUint(any.val, 10, 64) - any.err = err + parsed, _ := strconv.ParseUint(any.val, 10, 64) return parsed } func (any *stringAny) ToFloat32() float32 { - parsed, err := strconv.ParseFloat(any.val, 32) - any.err = err + parsed, _ := strconv.ParseFloat(any.val, 32) return float32(parsed) } func (any *stringAny) ToFloat64() float64 { - parsed, err := strconv.ParseFloat(any.val, 64) - any.err = err + parsed, _ := strconv.ParseFloat(any.val, 64) return parsed } diff --git a/jsoniter_any_array_test.go b/jsoniter_any_array_test.go index 06a8088..64aa984 100644 --- a/jsoniter_any_array_test.go +++ b/jsoniter_any_array_test.go @@ -60,6 +60,8 @@ func Test_array_lazy_any_get_all(t *testing.T) { should := require.New(t) any := Get([]byte("[[1],[2],[3,4]]")) should.Equal("[1,2,3]", any.Get('*', 0).ToString()) + any = Get([]byte("[[[1],[2],[3,4]]]"), 0, '*', 0) + should.Equal("[1,2,3]", any.ToString()) } func Test_array_wrapper_any_get_all(t *testing.T) { @@ -70,6 +72,9 @@ func Test_array_wrapper_any_get_all(t *testing.T) { {5, 6}, }) should.Equal("[1,3,5]", any.Get('*', 0).ToString()) + should.Equal(Array, any.ValueType()) + should.True(any.ToBool()) + should.Equal(1, any.Get(0, 0).ToInt()) } func Test_array_lazy_any_get_invalid(t *testing.T) { @@ -85,4 +90,4 @@ func Test_invalid_array(t *testing.T) { should := require.New(t) any := Get([]byte("["), 0) should.Equal(Invalid, any.ValueType()) -} \ No newline at end of file +}