mirror of
https://github.com/weaveworks/scope.git
synced 2026-07-19 05:19:35 +00:00
report: add StringSet (port of IDList, effectively)
This commit is contained in:
committed by
Tom Wilkie
parent
6a4c997048
commit
c68516ec22
@@ -2,6 +2,7 @@ package report
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
"strings"
|
||||
)
|
||||
|
||||
@@ -78,8 +79,9 @@ func (n Nodes) Merge(other Nodes) Nodes {
|
||||
// given node in a given topology, along with the edges emanating from the
|
||||
// node and metadata about those edges.
|
||||
type Node struct {
|
||||
Metadata `json:"metadata,omitempty"`
|
||||
Counters `json:"counters,omitempty"`
|
||||
Metadata Metadata `json:"metadata,omitempty"`
|
||||
Counters Counters `json:"counters,omitempty"`
|
||||
Sets Sets `json:"sets,omitempty"`
|
||||
Adjacency IDList `json:"adjacency"`
|
||||
Edges EdgeMetadatas `json:"edges,omitempty"`
|
||||
}
|
||||
@@ -195,6 +197,100 @@ func (c Counters) Copy() Counters {
|
||||
return result
|
||||
}
|
||||
|
||||
// Sets is a string->set-of-strings map.
|
||||
type Sets map[string]StringSet
|
||||
|
||||
// Merge merges two sets maps into a fresh set, performing set-union merges as
|
||||
// appropriate.
|
||||
func (s Sets) Merge(other Sets) Sets {
|
||||
result := s.Copy()
|
||||
for k, v := range other {
|
||||
result[k].Merge(v)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// Copy returns a value copy of the sets map.
|
||||
func (s Sets) Copy() Sets {
|
||||
result := Sets{}
|
||||
for k, v := range s {
|
||||
result[k] = v.Copy()
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// StringSet is a sorted set of unique strings. Clients must use the Add
|
||||
// method to add strings.
|
||||
type StringSet []string
|
||||
|
||||
// MakeStringSet makes a new StringSet with the given strings.
|
||||
func MakeStringSet(strs ...string) StringSet {
|
||||
if len(strs) <= 0 {
|
||||
return StringSet{}
|
||||
}
|
||||
sort.Strings(strs)
|
||||
for i := 1; i < len(strs); { // shuffle down any duplicates
|
||||
if strs[i-1] == strs[i] {
|
||||
strs = append(strs[:i-1], strs[i:]...)
|
||||
continue
|
||||
}
|
||||
i++
|
||||
}
|
||||
return StringSet(strs)
|
||||
}
|
||||
|
||||
// Add adds the strings to the StringSet. Add is the only valid way to grow a
|
||||
// StringSet. Add returns the StringSet to enable chaining.
|
||||
func (s StringSet) Add(strs ...string) StringSet {
|
||||
for _, str := range strs {
|
||||
i := sort.Search(len(s), func(i int) bool { return s[i] >= str })
|
||||
if i < len(s) && s[i] == str {
|
||||
// The list already has the element.
|
||||
continue
|
||||
}
|
||||
// It a new element, insert it in order.
|
||||
s = append(s, "")
|
||||
copy(s[i+1:], s[i:])
|
||||
s[i] = str
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// Merge combines the two StringSets and returns a new result.
|
||||
func (s StringSet) Merge(other StringSet) StringSet {
|
||||
if len(other) == 0 { // Optimise special case, to avoid allocating
|
||||
return s // (note unit test DeepEquals breaks if we don't do this)
|
||||
}
|
||||
result := make(StringSet, len(s)+len(other))
|
||||
for i, j, k := 0, 0, 0; ; k++ {
|
||||
switch {
|
||||
case i >= len(s):
|
||||
copy(result[k:], other[j:])
|
||||
return result[:k+len(other)-j]
|
||||
case j >= len(other):
|
||||
copy(result[k:], s[i:])
|
||||
return result[:k+len(s)-i]
|
||||
case s[i] < other[j]:
|
||||
result[k] = s[i]
|
||||
i++
|
||||
case s[i] > other[j]:
|
||||
result[k] = other[j]
|
||||
j++
|
||||
default: // equal
|
||||
result[k] = s[i]
|
||||
i++
|
||||
j++
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Copy returns a value copy of the StringSet.
|
||||
func (s StringSet) Copy() StringSet {
|
||||
result := make(StringSet, len(s))
|
||||
copy(result, s)
|
||||
return result
|
||||
}
|
||||
|
||||
// EdgeMetadatas collect metadata about each edge in a topology. Keys are the
|
||||
// remote node IDs, as in Adjacency.
|
||||
type EdgeMetadatas map[string]EdgeMetadata
|
||||
|
||||
66
report/topology_test.go
Normal file
66
report/topology_test.go
Normal file
@@ -0,0 +1,66 @@
|
||||
package report_test
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/weaveworks/scope/report"
|
||||
)
|
||||
|
||||
func TestMakeStringSet(t *testing.T) {
|
||||
for _, testcase := range []struct {
|
||||
input []string
|
||||
want report.StringSet
|
||||
}{
|
||||
{input: []string{}, want: report.MakeStringSet()},
|
||||
{input: []string{"a"}, want: report.MakeStringSet("a")},
|
||||
{input: []string{"a", "a"}, want: report.MakeStringSet("a")},
|
||||
{input: []string{"b", "c", "a"}, want: report.MakeStringSet("a", "b", "c")},
|
||||
} {
|
||||
if want, have := testcase.want, report.MakeStringSet(testcase.input...); !reflect.DeepEqual(want, have) {
|
||||
t.Errorf("%v: want %v, have %v", testcase.input, want, have)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestStringSetAdd(t *testing.T) {
|
||||
for _, testcase := range []struct {
|
||||
input report.StringSet
|
||||
strs []string
|
||||
want report.StringSet
|
||||
}{
|
||||
{input: report.MakeStringSet(), strs: []string{}, want: report.MakeStringSet()},
|
||||
{input: report.MakeStringSet("a"), strs: []string{}, want: report.MakeStringSet("a")},
|
||||
{input: report.MakeStringSet(), strs: []string{"a"}, want: report.MakeStringSet("a")},
|
||||
{input: report.MakeStringSet("a"), strs: []string{"a"}, want: report.MakeStringSet("a")},
|
||||
{input: report.MakeStringSet("b"), strs: []string{"a", "b"}, want: report.MakeStringSet("a", "b")},
|
||||
{input: report.MakeStringSet("a"), strs: []string{"c", "b"}, want: report.MakeStringSet("a", "b", "c")},
|
||||
{input: report.MakeStringSet("a", "c"), strs: []string{"b", "b", "b"}, want: report.MakeStringSet("a", "b", "c")},
|
||||
} {
|
||||
if want, have := testcase.want, testcase.input.Add(testcase.strs...); !reflect.DeepEqual(want, have) {
|
||||
t.Errorf("%v + %v: want %v, have %v", testcase.input, testcase.strs, want, have)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestStringSetMerge(t *testing.T) {
|
||||
for _, testcase := range []struct {
|
||||
input report.StringSet
|
||||
other report.StringSet
|
||||
want report.StringSet
|
||||
}{
|
||||
{input: report.MakeStringSet(), other: report.MakeStringSet(), want: report.MakeStringSet()},
|
||||
{input: report.MakeStringSet("a"), other: report.MakeStringSet(), want: report.MakeStringSet("a")},
|
||||
{input: report.MakeStringSet(), other: report.MakeStringSet("a"), want: report.MakeStringSet("a")},
|
||||
{input: report.MakeStringSet("a"), other: report.MakeStringSet("b"), want: report.MakeStringSet("a", "b")},
|
||||
{input: report.MakeStringSet("b"), other: report.MakeStringSet("a"), want: report.MakeStringSet("a", "b")},
|
||||
{input: report.MakeStringSet("a"), other: report.MakeStringSet("a"), want: report.MakeStringSet("a")},
|
||||
{input: report.MakeStringSet("a", "c"), other: report.MakeStringSet("a", "b"), want: report.MakeStringSet("a", "b", "c")},
|
||||
{input: report.MakeStringSet("b"), other: report.MakeStringSet("a"), want: report.MakeStringSet("a", "b")},
|
||||
} {
|
||||
if want, have := testcase.want, testcase.input.Merge(testcase.other); !reflect.DeepEqual(want, have) {
|
||||
t.Errorf("%v + %v: want %v, have %v", testcase.input, testcase.other, want, have)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user