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) ```
This commit is contained in:
parent
a2edf04c27
commit
de7137cc35
3 changed files with 45 additions and 23 deletions
|
@ -75,9 +75,13 @@ func caseInsensitiveLookup(m, k reflect.Value) (reflect.Value, bool) {
|
|||
return v, hreflect.IsTruthfulValue(v)
|
||||
}
|
||||
|
||||
for _, key := range m.MapKeys() {
|
||||
if strings.EqualFold(k.String(), key.String()) {
|
||||
return m.MapIndex(key), true
|
||||
k2 := reflect.New(m.Type().Key()).Elem()
|
||||
|
||||
iter := m.MapRange()
|
||||
for iter.Next() {
|
||||
k2.SetIterKey(iter)
|
||||
if strings.EqualFold(k.String(), k2.String()) {
|
||||
return iter.Value(), true
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -90,17 +94,28 @@ func mergeMap(dst, src reflect.Value) reflect.Value {
|
|||
// If the destination is Params, we must lower case all keys.
|
||||
_, lowerCase := dst.Interface().(maps.Params)
|
||||
|
||||
k := reflect.New(dst.Type().Key()).Elem()
|
||||
v := reflect.New(dst.Type().Elem()).Elem()
|
||||
|
||||
// Copy the destination map.
|
||||
for _, key := range dst.MapKeys() {
|
||||
v := dst.MapIndex(key)
|
||||
out.SetMapIndex(key, v)
|
||||
iter := dst.MapRange()
|
||||
for iter.Next() {
|
||||
k.SetIterKey(iter)
|
||||
v.SetIterValue(iter)
|
||||
out.SetMapIndex(k, v)
|
||||
}
|
||||
|
||||
// Add all keys in src not already in destination.
|
||||
// Maps of the same type will be merged.
|
||||
for _, key := range src.MapKeys() {
|
||||
sv := src.MapIndex(key)
|
||||
dv, found := caseInsensitiveLookup(dst, key)
|
||||
k = reflect.New(src.Type().Key()).Elem()
|
||||
sv := reflect.New(src.Type().Elem()).Elem()
|
||||
|
||||
iter = src.MapRange()
|
||||
for iter.Next() {
|
||||
sv.SetIterValue(iter)
|
||||
k.SetIterKey(iter)
|
||||
|
||||
dv, found := caseInsensitiveLookup(dst, k)
|
||||
|
||||
if found {
|
||||
// If both are the same map key type, merge.
|
||||
|
@ -112,14 +127,15 @@ func mergeMap(dst, src reflect.Value) reflect.Value {
|
|||
}
|
||||
|
||||
if dve.Type().Key() == sve.Type().Key() {
|
||||
out.SetMapIndex(key, mergeMap(dve, sve))
|
||||
out.SetMapIndex(k, mergeMap(dve, sve))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if lowerCase && key.Kind() == reflect.String {
|
||||
key = reflect.ValueOf(strings.ToLower(key.String()))
|
||||
kk := k
|
||||
if lowerCase && k.Kind() == reflect.String {
|
||||
kk = reflect.ValueOf(strings.ToLower(k.String()))
|
||||
}
|
||||
out.SetMapIndex(key, sv)
|
||||
out.SetMapIndex(kk, sv)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -99,18 +99,21 @@ func (ns *Namespace) Sort(ctx context.Context, l any, args ...any) (any, error)
|
|||
}
|
||||
|
||||
case reflect.Map:
|
||||
keys := seqv.MapKeys()
|
||||
for i := 0; i < seqv.Len(); i++ {
|
||||
p.Pairs[i].Value = seqv.MapIndex(keys[i])
|
||||
|
||||
iter := seqv.MapRange()
|
||||
i := 0
|
||||
for iter.Next() {
|
||||
key := iter.Key()
|
||||
value := iter.Value()
|
||||
p.Pairs[i].Value = value
|
||||
if sortByField == "" {
|
||||
p.Pairs[i].Key = keys[i]
|
||||
p.Pairs[i].Key = key
|
||||
} else if sortByField == "value" {
|
||||
p.Pairs[i].Key = p.Pairs[i].Value
|
||||
} else {
|
||||
v := p.Pairs[i].Value
|
||||
var err error
|
||||
for i, elemName := range path {
|
||||
for j, elemName := range path {
|
||||
v, err = evaluateSubElem(ctxv, v, elemName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -120,12 +123,13 @@ func (ns *Namespace) Sort(ctx context.Context, l any, args ...any) (any, error)
|
|||
}
|
||||
// Special handling of lower cased maps.
|
||||
if params, ok := v.Interface().(maps.Params); ok {
|
||||
v = reflect.ValueOf(params.GetNested(path[i+1:]...))
|
||||
v = reflect.ValueOf(params.GetNested(path[j+1:]...))
|
||||
break
|
||||
}
|
||||
}
|
||||
p.Pairs[i].Key = v
|
||||
}
|
||||
i++
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -409,7 +409,6 @@ func (ns *Namespace) checkWhereArray(ctxv, seqv, kv, mv reflect.Value, path []st
|
|||
for i, elemName := range path {
|
||||
var err error
|
||||
vvv, err = evaluateSubElem(ctxv, vvv, elemName)
|
||||
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
@ -442,9 +441,12 @@ func (ns *Namespace) checkWhereArray(ctxv, seqv, kv, mv reflect.Value, path []st
|
|||
// checkWhereMap handles the where-matching logic when the seqv value is a Map.
|
||||
func (ns *Namespace) checkWhereMap(ctxv, seqv, kv, mv reflect.Value, path []string, op string) (any, error) {
|
||||
rv := reflect.MakeMap(seqv.Type())
|
||||
keys := seqv.MapKeys()
|
||||
for _, k := range keys {
|
||||
elemv := seqv.MapIndex(k)
|
||||
k := reflect.New(seqv.Type().Key()).Elem()
|
||||
elemv := reflect.New(seqv.Type().Elem()).Elem()
|
||||
iter := seqv.MapRange()
|
||||
for iter.Next() {
|
||||
k.SetIterKey(iter)
|
||||
elemv.SetIterValue(iter)
|
||||
switch elemv.Kind() {
|
||||
case reflect.Array, reflect.Slice:
|
||||
r, err := ns.checkWhereArray(ctxv, elemv, kv, mv, path, op)
|
||||
|
|
Loading…
Add table
Reference in a new issue