Skip to content

Commit

Permalink
tpl/collections: Use MapRange/SetIterKey/SetIterValue for Where, Sort…
Browse files Browse the repository at this point in the history
… 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)
```
  • Loading branch information
bep committed Jan 13, 2025
1 parent a2edf04 commit de7137c
Show file tree
Hide file tree
Showing 3 changed files with 45 additions and 23 deletions.
42 changes: 29 additions & 13 deletions tpl/collections/merge.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
}

Expand All @@ -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.
Expand All @@ -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)
}
}

Expand Down
16 changes: 10 additions & 6 deletions tpl/collections/sort.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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++
}
}

Expand Down
10 changes: 6 additions & 4 deletions tpl/collections/where.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down Expand Up @@ -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)
Expand Down

0 comments on commit de7137c

Please sign in to comment.