1
0
mirror of https://github.com/rancher/os.git synced 2025-08-19 07:19:05 +00:00

slices union and intersection

useful for merging and splitting configs
This commit is contained in:
Ivan Mikushin 2015-08-21 13:24:55 +05:00
parent 974206235d
commit 4d6530be73
3 changed files with 146 additions and 56 deletions

View File

@ -10,55 +10,6 @@ import (
"strings" "strings"
) )
func TestNilMap(t *testing.T) {
assert := require.New(t)
var m map[string]interface{} = nil
assert.True(m == nil)
}
func TestMapCopy(t *testing.T) {
assert := require.New(t)
m0 := map[interface{}]interface{}{"a": 1, "b": map[interface{}]interface{}{"c": 3}, "d": "4"}
m1 := util.MapCopy(m0)
delete(m0, "a")
assert.Equal(len(m1), len(m0)+1)
b0 := m0["b"].(map[interface{}]interface{})
b1 := m1["b"].(map[interface{}]interface{})
b1["e"] = "queer"
assert.Equal(len(b1), len(b0)+1)
}
func TestMapsIntersection(t *testing.T) {
assert := require.New(t)
m0 := map[interface{}]interface{}{"a": 1, "b": map[interface{}]interface{}{"c": 3}, "d": "4"}
m1 := util.MapCopy(m0)
delete(m0, "a")
b1 := m1["b"].(map[interface{}]interface{})
delete(b1, "c")
expected := map[interface{}]interface{}{"b": map[interface{}]interface{}{}, "d": "4"}
assert.Equal(expected, util.MapsIntersection(m0, m1, util.Equal))
}
func TestMapsUnion(t *testing.T) {
assert := require.New(t)
m0 := map[interface{}]interface{}{"a": 1, "b": map[interface{}]interface{}{"c": 3}, "d": "4"}
m1 := util.MapCopy(m0)
m1["e"] = "added"
m1["d"] = "replaced"
delete(m0, "a")
b1 := m1["b"].(map[interface{}]interface{})
delete(b1, "c")
expected := map[interface{}]interface{}{"a": 1, "b": map[interface{}]interface{}{"c": 3}, "d": "replaced", "e": "added"}
assert.Equal(expected, util.MapsUnion(m0, m1, util.Replace))
}
func TestFilterKey(t *testing.T) { func TestFilterKey(t *testing.T) {
assert := require.New(t) assert := require.New(t)
data := map[interface{}]interface{}{ data := map[interface{}]interface{}{

View File

@ -181,6 +181,8 @@ func Copy(d interface{}) interface{} {
switch d := d.(type) { switch d := d.(type) {
case map[interface{}]interface{}: case map[interface{}]interface{}:
return MapCopy(d) return MapCopy(d)
case []interface{}:
return SliceCopy(d)
default: default:
return d return d
} }
@ -197,11 +199,40 @@ func Equal(l, r interface{}) interface{} {
return nil return nil
} }
func ExistsIn(x interface{}, s []interface{}) bool {
for _, y := range s {
if reflect.DeepEqual(x, y) {
return true
}
}
return false
}
func SlicesUnion(left, right []interface{}, op func(interface{}, interface{}) interface{}) []interface{} {
result := SliceCopy(left)
for _, r := range right {
if !ExistsIn(r, result) {
result = append(result, r)
}
}
return result
}
func SlicesIntersection(left, right []interface{}, op func(interface{}, interface{}) interface{}) []interface{} {
result := []interface{}{}
for _, r := range right {
if ExistsIn(r, left) {
result = append(result, r)
}
}
return result
}
func MapsUnion(left, right map[interface{}]interface{}, op func(interface{}, interface{}) interface{}) map[interface{}]interface{} { func MapsUnion(left, right map[interface{}]interface{}, op func(interface{}, interface{}) interface{}) map[interface{}]interface{} {
result := MapCopy(left) result := MapCopy(left)
for k, r := range right { for k, r := range right {
if l, ok := result[k]; ok { if l, ok := left[k]; ok {
switch l := l.(type) { switch l := l.(type) {
case map[interface{}]interface{}: case map[interface{}]interface{}:
switch r := r.(type) { switch r := r.(type) {
@ -210,6 +241,13 @@ func MapsUnion(left, right map[interface{}]interface{}, op func(interface{}, int
default: default:
result[k] = op(l, r) result[k] = op(l, r)
} }
case []interface{}:
switch r := r.(type) {
case []interface{}:
result[k] = SlicesUnion(l, r, op)
default:
result[k] = op(l, r)
}
default: default:
result[k] = op(l, r) result[k] = op(l, r)
} }
@ -226,19 +264,28 @@ func MapsIntersection(left, right map[interface{}]interface{}, op func(interface
for k, l := range left { for k, l := range left {
if r, ok := right[k]; ok { if r, ok := right[k]; ok {
switch r := r.(type) {
case map[interface{}]interface{}:
switch l := l.(type) { switch l := l.(type) {
case map[interface{}]interface{}:
switch r := r.(type) {
case map[interface{}]interface{}: case map[interface{}]interface{}:
result[k] = MapsIntersection(l, r, op) result[k] = MapsIntersection(l, r, op)
default: default:
if i := op(l, r); i != nil { if v := op(l, r); v != nil {
result[k] = i result[k] = v
}
}
case []interface{}:
switch r := r.(type) {
case []interface{}:
result[k] = SlicesIntersection(l, r, op)
default:
if v := op(l, r); v != nil {
result[k] = v
} }
} }
default: default:
if i := op(l, r); i != nil { if v := op(l, r); v != nil {
result[k] = i result[k] = v
} }
} }
} }
@ -255,6 +302,14 @@ func MapCopy(data map[interface{}]interface{}) map[interface{}]interface{} {
return result return result
} }
func SliceCopy(data []interface{}) []interface{} {
result := make([]interface{}, len(data), len(data))
for k, v := range data {
result[k] = Copy(v)
}
return result
}
func GetServices(urls []string) ([]string, error) { func GetServices(urls []string) ([]string, error) {
result := []string{} result := []string{}

View File

@ -6,6 +6,90 @@ import (
"testing" "testing"
) )
func TestNilMap(t *testing.T) {
assert := require.New(t)
var m map[string]interface{} = nil
assert.True(m == nil)
}
func TestMapCopy(t *testing.T) {
assert := require.New(t)
m0 := map[interface{}]interface{}{"a": 1, "b": map[interface{}]interface{}{"c": 3}, "d": "4"}
m1 := MapCopy(m0)
assert.Equal(m0, m1)
delete(m0, "a")
assert.Equal(len(m1), len(m0)+1)
b0 := m0["b"].(map[interface{}]interface{})
b1 := m1["b"].(map[interface{}]interface{})
b1["e"] = "queer"
assert.Equal(len(b1), len(b0)+1)
}
func TestSliceCopy(t *testing.T) {
assert := require.New(t)
m0 := []interface{}{1, map[interface{}]interface{}{"c": 3}, "4"}
m1 := SliceCopy(m0)
assert.Equal(m0, m1)
m0 = m0[1:]
assert.Equal(len(m1), len(m0)+1)
b0 := m0[0].(map[interface{}]interface{})
b1 := m1[1].(map[interface{}]interface{})
b1["e"] = "queer"
assert.Equal(len(b1), len(b0)+1)
}
func TestMapsIntersection(t *testing.T) {
assert := require.New(t)
m0 := map[interface{}]interface{}{
"a": 1,
"b": map[interface{}]interface{}{"c": 3},
"d": "4",
"e": []interface{}{1, 2, 3},
}
m1 := MapCopy(m0)
delete(m0, "a")
b1 := m1["b"].(map[interface{}]interface{})
delete(b1, "c")
m1["e"] = []interface{}{2, 3, 4}
expected := map[interface{}]interface{}{"b": map[interface{}]interface{}{}, "d": "4", "e": []interface{}{2, 3}}
assert.Equal(expected, MapsIntersection(m0, m1, Equal))
}
func TestMapsUnion(t *testing.T) {
assert := require.New(t)
m0 := map[interface{}]interface{}{
"a": 1,
"b": map[interface{}]interface{}{"c": 3},
"d": "4",
"f": []interface{}{1, 2, 3},
}
m1 := MapCopy(m0)
m1["e"] = "added"
m1["d"] = "replaced"
m1["f"] = []interface{}{2, 3, 4}
delete(m0, "a")
b1 := m1["b"].(map[interface{}]interface{})
delete(b1, "c")
expected := map[interface{}]interface{}{
"a": 1,
"b": map[interface{}]interface{}{"c": 3},
"d": "replaced",
"e": "added",
"f": []interface{}{1, 2, 3, 4},
}
assert.Equal(expected, MapsUnion(m0, m1, Replace))
}
func TestLoadResourceSimple(t *testing.T) { func TestLoadResourceSimple(t *testing.T) {
assert := require.New(t) assert := require.New(t)