Files
weave-scope/report/string_set.go
2016-03-03 16:17:55 +00:00

126 lines
3.0 KiB
Go

package report
import (
"sort"
)
// StringSet is a sorted set of unique strings. Clients must use the Add
// method to add strings.
type StringSet []string
// EmptyStringSet is an empty string set.
var EmptyStringSet StringSet
// MakeStringSet makes a new StringSet with the given strings.
func MakeStringSet(strs ...string) StringSet {
if len(strs) <= 0 {
return nil
}
result := make([]string, len(strs))
copy(result, strs)
sort.Strings(result)
for i := 1; i < len(result); { // shuffle down any duplicates
if result[i-1] == result[i] {
result = append(result[:i-1], result[i:]...)
continue
}
i++
}
return StringSet(result)
}
// Contains returns true if the string set includes the given string
func (s StringSet) Contains(str string) bool {
i := sort.Search(len(s), func(i int) bool { return s[i] >= str })
return i < len(s) && s[i] == str
}
// Intersection returns the intersections of a and b
func (s StringSet) Intersection(b StringSet) StringSet {
result, i, j := EmptyStringSet, 0, 0
for i < len(s) && j < len(b) {
if s[i] == b[j] {
result = result.Add(s[i])
}
if s[i] < b[j] {
i++
} else {
j++
}
}
return result
}
// 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
}
// Remove removes the strings from the StringSet. Remove is the only valid way
// to shrink a StringSet. Remove returns the StringSet to enable chaining.
func (s StringSet) Remove(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 does not have the element.
continue
}
// has the element, remove it.
s = append(s[:i], s[i+1:]...)
}
return s
}
// Merge combines the two StringSets and returns a new result.
func (s StringSet) Merge(other StringSet) StringSet {
switch {
case len(other) <= 0: // Optimise special case, to avoid allocating
return s // (note unit test DeepEquals breaks if we don't do this)
case len(s) <= 0:
return other
}
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 {
if s == nil {
return s
}
result := make(StringSet, len(s))
copy(result, s)
return result
}