Skip to content

Commit 84dea53

Browse files
committed
optimize mapUnstructured.Equals, apply feedback
1 parent e9a54b4 commit 84dea53

File tree

10 files changed

+142
-157
lines changed

10 files changed

+142
-157
lines changed

value/list.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,20 @@ type ListRange interface {
4141
Recycle()
4242
}
4343

44+
var EmptyRange = &emptyRange{}
45+
46+
type emptyRange struct{}
47+
48+
func (_ *emptyRange) Next() bool {
49+
return false
50+
}
51+
52+
func (_ *emptyRange) Item() (index int, value Value) {
53+
panic("Item called on empty ListRange")
54+
}
55+
56+
func (_ *emptyRange) Recycle() {}
57+
4458
// ListEquals compares two lists lexically.
4559
func ListEquals(lhs, rhs List) bool {
4660
if lhs.Length() != rhs.Length() {

value/listreflect.go

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,10 @@ limitations under the License.
1616

1717
package value
1818

19-
import "reflect"
19+
import (
20+
"reflect"
21+
"sync"
22+
)
2023

2124
type listReflect struct {
2225
Value reflect.Value
@@ -41,32 +44,44 @@ func (r listReflect) Unstructured() interface{} {
4144
return result
4245
}
4346

47+
var lrrPool = sync.Pool{
48+
New: func() interface{} {
49+
return &listReflectRange{vr: &valueReflect{}}
50+
},
51+
}
52+
4453
func (r listReflect) Range() ListRange {
45-
return &listReflectRange{r.Value, newTempValuePooler(), -1, r.Value.Len()}
54+
length := r.Value.Len()
55+
if length == 0 {
56+
return EmptyRange
57+
}
58+
rr := lrrPool.Get().(*listReflectRange)
59+
rr.list = r.Value
60+
rr.i = -1
61+
return rr
4662
}
4763

4864
type listReflectRange struct {
49-
val reflect.Value
50-
pooler *tempValuePooler
51-
i int
52-
length int
65+
list reflect.Value
66+
vr *valueReflect
67+
i int
5368
}
5469

5570
func (r *listReflectRange) Next() bool {
5671
r.i += 1
57-
return r.i < r.length
72+
return r.i < r.list.Len()
5873
}
5974

6075
func (r *listReflectRange) Item() (index int, value Value) {
6176
if r.i < 0 {
6277
panic("Item() called before first calling Next()")
6378
}
64-
if r.i >= r.length {
79+
if r.i >= r.list.Len() {
6580
panic("Item() called on ListRange with no more items")
6681
}
67-
return r.i, r.pooler.NewValueReflect(r.val.Index(r.i))
82+
return r.i, r.vr.reuse(r.list.Index(r.i))
6883
}
6984

7085
func (r *listReflectRange) Recycle() {
71-
r.pooler.Recycle()
86+
lrrPool.Put(r)
7287
}

value/listunstructured.go

Lines changed: 20 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ limitations under the License.
1616

1717
package value
1818

19+
import "sync"
20+
1921
type listUnstructured []interface{}
2022

2123
func (l listUnstructured) Length() int {
@@ -26,40 +28,43 @@ func (l listUnstructured) At(i int) Value {
2628
return NewValueInterface(l[i])
2729
}
2830

31+
var lurPool = sync.Pool{
32+
New: func() interface{} {
33+
return &listUnstructuredRange{vv: &valueUnstructured{}}
34+
},
35+
}
36+
2937
func (l listUnstructured) Range() ListRange {
3038
if len(l) == 0 {
31-
return &listUnstructuredRange{l, nil, -1, 0}
39+
return EmptyRange
3240
}
33-
vv := viPool.Get().(*valueUnstructured)
34-
return &listUnstructuredRange{l, vv, -1, len(l)}
41+
r := lurPool.Get().(*listUnstructuredRange)
42+
r.list = l
43+
r.i = -1
44+
return r
3545
}
3646

3747
type listUnstructuredRange struct {
38-
list listUnstructured
39-
vv *valueUnstructured
40-
i int
41-
length int
48+
list listUnstructured
49+
vv *valueUnstructured
50+
i int
4251
}
4352

4453
func (r *listUnstructuredRange) Next() bool {
4554
r.i += 1
46-
return r.i < r.length
55+
return r.i < len(r.list)
4756
}
4857

4958
func (r *listUnstructuredRange) Item() (index int, value Value) {
5059
if r.i < 0 {
5160
panic("Item() called before first calling Next()")
5261
}
53-
if r.i >= r.length {
62+
if r.i >= len(r.list) {
5463
panic("Item() called on ListRange with no more items")
5564
}
56-
57-
r.vv.Value = r.list[r.i]
58-
return r.i, r.vv
65+
return r.i, r.vv.reuse(r.list[r.i])
5966
}
6067

6168
func (r *listUnstructuredRange) Recycle() {
62-
if r.vv != nil {
63-
r.vv.Recycle()
64-
}
69+
lurPool.Put(r)
6570
}

value/map.go

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -111,9 +111,6 @@ func MapEquals(lhs, rhs Map) bool {
111111
}
112112
equal := Equals(v, vo)
113113
vo.Recycle()
114-
if !equal {
115-
return false
116-
}
117-
return true
114+
return equal
118115
})
119116
}

value/mapreflect.go

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -68,10 +68,10 @@ func (r mapReflect) toMapKey(key string) reflect.Value {
6868
}
6969

7070
func (r mapReflect) Iterate(fn func(string, Value) bool) bool {
71-
vp := newTempValuePooler()
72-
defer vp.Recycle()
71+
vr := reflectPool.Get().(*valueReflect)
72+
defer vr.Recycle()
7373
return eachMapEntry(r.Value, func(s string, value reflect.Value) bool {
74-
return fn(s, vp.NewValueReflect(value))
74+
return fn(s, vr.reuse(value))
7575
})
7676
}
7777

@@ -104,16 +104,16 @@ func (r mapReflect) Equals(m Map) bool {
104104
if lhsLength != rhsLength {
105105
return false
106106
}
107-
if lhsLength == 0 && rhsLength == 0 {
107+
if lhsLength == 0 {
108108
return true
109109
}
110-
vp := newTempValuePooler()
111-
defer vp.Recycle()
110+
vr := reflectPool.Get().(*valueReflect)
111+
defer vr.Recycle()
112112
return m.Iterate(func(key string, value Value) bool {
113113
_, lhsVal, ok := r.get(key)
114114
if !ok {
115115
return false
116116
}
117-
return Equals(vp.NewValueReflect(lhsVal), value)
117+
return Equals(vr.reuse(lhsVal), value)
118118
})
119119
}

value/mapunstructured.go

Lines changed: 18 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,7 @@ func (m mapUnstructuredInterface) Iterate(fn func(key string, value Value) bool)
4949
if ks, ok := k.(string); !ok {
5050
continue
5151
} else {
52-
vv.Value = v
53-
if !fn(ks, vv) {
52+
if !fn(ks, vv.reuse(v)) {
5453
return false
5554
}
5655
}
@@ -63,31 +62,23 @@ func (m mapUnstructuredInterface) Length() int {
6362
}
6463

6564
func (m mapUnstructuredInterface) Equals(other Map) bool {
66-
if m.Length() != other.Length() {
65+
lhsLength := m.Length()
66+
rhsLength := other.Length()
67+
if lhsLength != rhsLength {
6768
return false
6869
}
69-
if len(m) == 0 {
70+
if lhsLength == 0 {
7071
return true
7172
}
7273
vv := viPool.Get().(*valueUnstructured)
7374
defer vv.Recycle()
74-
for k, v := range m {
75-
ks, ok := k.(string)
76-
if !ok {
77-
return false
78-
}
79-
vo, ok := other.Get(ks)
75+
return other.Iterate(func(key string, value Value) bool {
76+
lhsVal, ok := m[key]
8077
if !ok {
8178
return false
8279
}
83-
vv.Value = v
84-
if !Equals(vv, vo) {
85-
vo.Recycle()
86-
return false
87-
}
88-
vo.Recycle()
89-
}
90-
return true
80+
return Equals(vv.reuse(lhsVal), value)
81+
})
9182
}
9283

9384
type mapUnstructuredString map[string]interface{}
@@ -120,8 +111,7 @@ func (m mapUnstructuredString) Iterate(fn func(key string, value Value) bool) bo
120111
vv := viPool.Get().(*valueUnstructured)
121112
defer vv.Recycle()
122113
for k, v := range m {
123-
vv.Value = v
124-
if !fn(k, vv) {
114+
if !fn(k, vv.reuse(v)) {
125115
return false
126116
}
127117
}
@@ -133,25 +123,21 @@ func (m mapUnstructuredString) Length() int {
133123
}
134124

135125
func (m mapUnstructuredString) Equals(other Map) bool {
136-
if m.Length() != other.Length() {
126+
lhsLength := m.Length()
127+
rhsLength := other.Length()
128+
if lhsLength != rhsLength {
137129
return false
138130
}
139-
if len(m) == 0 {
131+
if lhsLength == 0 {
140132
return true
141133
}
142134
vv := viPool.Get().(*valueUnstructured)
143135
defer vv.Recycle()
144-
for k, v := range m {
145-
vo, ok := other.Get(k)
136+
return other.Iterate(func(key string, value Value) bool {
137+
lhsVal, ok := m[key]
146138
if !ok {
147139
return false
148140
}
149-
vv.Value = v
150-
if !Equals(vv, vo) {
151-
vo.Recycle()
152-
return false
153-
}
154-
vo.Recycle()
155-
}
156-
return true
141+
return Equals(vv.reuse(lhsVal), value)
142+
})
157143
}

value/structreflect.go

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -198,10 +198,10 @@ func (r structReflect) update(fieldEntry *fieldCacheEntry, key string, oldVal, n
198198
}
199199

200200
func (r structReflect) Iterate(fn func(string, Value) bool) bool {
201-
vp := newTempValuePooler()
202-
defer vp.Recycle()
201+
vr := reflectPool.Get().(*valueReflect)
202+
defer vr.Recycle()
203203
return eachStructField(r.Value, func(s string, value reflect.Value) bool {
204-
return fn(s, vp.NewValueReflect(value))
204+
return fn(s, vr.reuse(value))
205205
})
206206
}
207207

@@ -234,20 +234,25 @@ func (r structReflect) Equals(m Map) bool {
234234
if rhsStruct, ok := m.(structReflect); ok {
235235
return reflect.DeepEqual(r.Value.Interface(), rhsStruct.Value.Interface())
236236
}
237-
if r.Length() != m.Length() {
237+
length := r.Length()
238+
if length != m.Length() {
238239
return false
239240
}
240-
structCacheEntry := getStructCacheEntry(r.Value.Type())
241241

242-
vp := newTempValuePooler()
243-
defer vp.Recycle()
242+
if length == 0 {
243+
return true
244+
}
245+
246+
structCacheEntry := getStructCacheEntry(r.Value.Type())
247+
vr := reflectPool.Get().(*valueReflect)
248+
defer vr.Recycle()
244249
return m.Iterate(func(s string, value Value) bool {
245250
fieldCacheEntry, ok := structCacheEntry[s]
246251
if !ok {
247252
return false
248253
}
249254
lhsVal := fieldCacheEntry.getFieldFromStruct(r.Value)
250-
return Equals(vp.NewValueReflect(lhsVal), value)
255+
return Equals(vr.reuse(lhsVal), value)
251256
})
252257
}
253258

0 commit comments

Comments
 (0)