Skip to content

Commit

Permalink
tpl/collections: Use MapRange() in Merge
Browse files Browse the repository at this point in the history
```
Merge-10                                     3.254µ ± ∞ ¹   2.090µ ± ∞ ¹  -35.77% (p=0.029 n=4)
Merge-10                                    3.079Ki ± ∞ ¹   2.141Ki ± ∞ ¹  -30.48% (p=0.029 n=4)
Merge-10                                      64.00 ± ∞ ¹   42.00 ± ∞ ¹  -34.38% (p=0.029 n=4)
```
  • Loading branch information
bep committed Jan 12, 2025
1 parent 2501de7 commit 32b3978
Show file tree
Hide file tree
Showing 2 changed files with 32 additions and 14 deletions.
34 changes: 20 additions & 14 deletions tpl/collections/merge.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,9 +75,11 @@ 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
iter := m.MapRange()
for iter.Next() {
k := iter.Key()
if strings.EqualFold(k.String(), k.String()) {
return m.MapIndex(k), true
}
}

Expand All @@ -91,35 +93,39 @@ func mergeMap(dst, src reflect.Value) reflect.Value {
_, lowerCase := dst.Interface().(maps.Params)

// Copy the destination map.
for _, key := range dst.MapKeys() {
v := dst.MapIndex(key)
out.SetMapIndex(key, v)
iter := dst.MapRange()
for iter.Next() {
k := iter.Key()
v := iter.Value()
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)
iter = src.MapRange()
for iter.Next() {
k := iter.Key()
v := iter.Value()
dv, found := caseInsensitiveLookup(dst, k)

if found {
// If both are the same map key type, merge.
dve := dv.Elem()
if dve.Kind() == reflect.Map {
sve := sv.Elem()
sve := v.Elem()
if sve.Kind() != reflect.Map {
continue
}

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()))
if lowerCase && k.Kind() == reflect.String {
k = reflect.ValueOf(strings.ToLower(k.String()))
}
out.SetMapIndex(key, sv)
out.SetMapIndex(k, v)
}
}

Expand Down
12 changes: 12 additions & 0 deletions tpl/collections/merge_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,18 @@ func TestMerge(t *testing.T) {
}
}

func BenchmarkMerge(b *testing.B) {
ns := newNs()

for i := 0; i < b.N; i++ {
ns.Merge(
map[string]any{"a": 42, "c": 3, "e": 11},
map[string]any{"a": 1, "b": 2},
map[string]any{"a": 9, "c": 4, "d": 7},
)
}
}

func TestMergeDataFormats(t *testing.T) {
c := qt.New(t)
ns := newNs()
Expand Down

0 comments on commit 32b3978

Please sign in to comment.