Skip to content

Commit de7137c

Browse files
committed
tpl/collections: Use MapRange/SetIterKey/SetIterValue for Where, Sort and Merge
Some relevant benchmarks: Where with maps: ``` cpu: Apple M1 Pro │ master.bench │ fix-mapkeys.bench │ │ sec/op │ sec/op vs base │ WhereMap-10 79.26µ ± 1% 26.58µ ± 1% -66.46% (p=0.002 n=6) │ master.bench │ fix-mapkeys.bench │ │ B/op │ B/op vs base │ WhereMap-10 56685.0 ± 0% 111.0 ± 1% -99.80% (p=0.002 n=6) │ master.bench │ fix-mapkeys.bench │ │ allocs/op │ allocs/op vs base │ WhereMap-10 2003.000 ± 0% 4.000 ± 0% -99.80% (p=0.002 n=6) ``` Merge: ``` │ master.bench │ fix-mapkeys.bench │ │ sec/op │ sec/op vs base │ Merge-10 3.285µ ± 0% 2.268µ ± 1% -30.96% (p=0.002 n=6) │ master.bench │ fix-mapkeys.bench │ │ B/op │ B/op vs base │ Merge-10 3.079Ki ± 0% 1.891Ki ± 0% -38.58% (p=0.002 n=6) │ master.bench │ fix-mapkeys.bench │ │ allocs/op │ allocs/op vs base │ Merge-10 64.00 ± 0% 26.00 ± 0% -59.38% (p=0.002 n=6) ``` Sort: ``` cpu: Apple M1 Pro │ master.bench │ fix-mapkeys.bench │ │ sec/op │ sec/op vs base │ SortMap-10 1008.0n ± 1% 915.5n ± 0% -9.18% (p=0.002 n=6) │ master.bench │ fix-mapkeys.bench │ │ B/op │ B/op vs base │ SortMap-10 640.0 ± 0% 512.0 ± 0% -20.00% (p=0.002 n=6) │ master.bench │ fix-mapkeys.bench │ │ allocs/op │ allocs/op vs base │ SortMap-10 16.00 ± 0% 15.00 ± 0% -6.25% (p=0.002 n=6) ```
1 parent a2edf04 commit de7137c

File tree

3 files changed

+45
-23
lines changed

3 files changed

+45
-23
lines changed

tpl/collections/merge.go

+29-13
Original file line numberDiff line numberDiff line change
@@ -75,9 +75,13 @@ func caseInsensitiveLookup(m, k reflect.Value) (reflect.Value, bool) {
7575
return v, hreflect.IsTruthfulValue(v)
7676
}
7777

78-
for _, key := range m.MapKeys() {
79-
if strings.EqualFold(k.String(), key.String()) {
80-
return m.MapIndex(key), true
78+
k2 := reflect.New(m.Type().Key()).Elem()
79+
80+
iter := m.MapRange()
81+
for iter.Next() {
82+
k2.SetIterKey(iter)
83+
if strings.EqualFold(k.String(), k2.String()) {
84+
return iter.Value(), true
8185
}
8286
}
8387

@@ -90,17 +94,28 @@ func mergeMap(dst, src reflect.Value) reflect.Value {
9094
// If the destination is Params, we must lower case all keys.
9195
_, lowerCase := dst.Interface().(maps.Params)
9296

97+
k := reflect.New(dst.Type().Key()).Elem()
98+
v := reflect.New(dst.Type().Elem()).Elem()
99+
93100
// Copy the destination map.
94-
for _, key := range dst.MapKeys() {
95-
v := dst.MapIndex(key)
96-
out.SetMapIndex(key, v)
101+
iter := dst.MapRange()
102+
for iter.Next() {
103+
k.SetIterKey(iter)
104+
v.SetIterValue(iter)
105+
out.SetMapIndex(k, v)
97106
}
98107

99108
// Add all keys in src not already in destination.
100109
// Maps of the same type will be merged.
101-
for _, key := range src.MapKeys() {
102-
sv := src.MapIndex(key)
103-
dv, found := caseInsensitiveLookup(dst, key)
110+
k = reflect.New(src.Type().Key()).Elem()
111+
sv := reflect.New(src.Type().Elem()).Elem()
112+
113+
iter = src.MapRange()
114+
for iter.Next() {
115+
sv.SetIterValue(iter)
116+
k.SetIterKey(iter)
117+
118+
dv, found := caseInsensitiveLookup(dst, k)
104119

105120
if found {
106121
// If both are the same map key type, merge.
@@ -112,14 +127,15 @@ func mergeMap(dst, src reflect.Value) reflect.Value {
112127
}
113128

114129
if dve.Type().Key() == sve.Type().Key() {
115-
out.SetMapIndex(key, mergeMap(dve, sve))
130+
out.SetMapIndex(k, mergeMap(dve, sve))
116131
}
117132
}
118133
} else {
119-
if lowerCase && key.Kind() == reflect.String {
120-
key = reflect.ValueOf(strings.ToLower(key.String()))
134+
kk := k
135+
if lowerCase && k.Kind() == reflect.String {
136+
kk = reflect.ValueOf(strings.ToLower(k.String()))
121137
}
122-
out.SetMapIndex(key, sv)
138+
out.SetMapIndex(kk, sv)
123139
}
124140
}
125141

tpl/collections/sort.go

+10-6
Original file line numberDiff line numberDiff line change
@@ -99,18 +99,21 @@ func (ns *Namespace) Sort(ctx context.Context, l any, args ...any) (any, error)
9999
}
100100

101101
case reflect.Map:
102-
keys := seqv.MapKeys()
103-
for i := 0; i < seqv.Len(); i++ {
104-
p.Pairs[i].Value = seqv.MapIndex(keys[i])
105102

103+
iter := seqv.MapRange()
104+
i := 0
105+
for iter.Next() {
106+
key := iter.Key()
107+
value := iter.Value()
108+
p.Pairs[i].Value = value
106109
if sortByField == "" {
107-
p.Pairs[i].Key = keys[i]
110+
p.Pairs[i].Key = key
108111
} else if sortByField == "value" {
109112
p.Pairs[i].Key = p.Pairs[i].Value
110113
} else {
111114
v := p.Pairs[i].Value
112115
var err error
113-
for i, elemName := range path {
116+
for j, elemName := range path {
114117
v, err = evaluateSubElem(ctxv, v, elemName)
115118
if err != nil {
116119
return nil, err
@@ -120,12 +123,13 @@ func (ns *Namespace) Sort(ctx context.Context, l any, args ...any) (any, error)
120123
}
121124
// Special handling of lower cased maps.
122125
if params, ok := v.Interface().(maps.Params); ok {
123-
v = reflect.ValueOf(params.GetNested(path[i+1:]...))
126+
v = reflect.ValueOf(params.GetNested(path[j+1:]...))
124127
break
125128
}
126129
}
127130
p.Pairs[i].Key = v
128131
}
132+
i++
129133
}
130134
}
131135

tpl/collections/where.go

+6-4
Original file line numberDiff line numberDiff line change
@@ -409,7 +409,6 @@ func (ns *Namespace) checkWhereArray(ctxv, seqv, kv, mv reflect.Value, path []st
409409
for i, elemName := range path {
410410
var err error
411411
vvv, err = evaluateSubElem(ctxv, vvv, elemName)
412-
413412
if err != nil {
414413
continue
415414
}
@@ -442,9 +441,12 @@ func (ns *Namespace) checkWhereArray(ctxv, seqv, kv, mv reflect.Value, path []st
442441
// checkWhereMap handles the where-matching logic when the seqv value is a Map.
443442
func (ns *Namespace) checkWhereMap(ctxv, seqv, kv, mv reflect.Value, path []string, op string) (any, error) {
444443
rv := reflect.MakeMap(seqv.Type())
445-
keys := seqv.MapKeys()
446-
for _, k := range keys {
447-
elemv := seqv.MapIndex(k)
444+
k := reflect.New(seqv.Type().Key()).Elem()
445+
elemv := reflect.New(seqv.Type().Elem()).Elem()
446+
iter := seqv.MapRange()
447+
for iter.Next() {
448+
k.SetIterKey(iter)
449+
elemv.SetIterValue(iter)
448450
switch elemv.Kind() {
449451
case reflect.Array, reflect.Slice:
450452
r, err := ns.checkWhereArray(ctxv, elemv, kv, mv, path, op)

0 commit comments

Comments
 (0)