package report import ( "sort" ) // StringSet is a sorted set of unique strings. Clients must use the Add // method to add strings. type StringSet []string 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 } // Equal returns true if a and b have the same contents func (s StringSet) Equal(b StringSet) bool { if len(s) != len(b) { return false } for i := range s { if s[i] != b[i] { return false } } return true } // 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. // Second return value is true if the return value is s func (s StringSet) Merge(other StringSet) (StringSet, bool) { switch { case len(other) <= 0: // Optimise special case, to avoid allocating return s, true // (note unit test DeepEquals breaks if we don't do this) case len(s) <= 0: return other, false } i, j := 0, 0 loop: for i < len(s) { switch { case j >= len(other): return s, true case s[i] == other[j]: i++ j++ case s[i] < other[j]: i++ default: break loop } } if i >= len(s) && j >= len(other) { return s, true } result := make(StringSet, i, len(s)+len(other)) copy(result, s[:i]) for i < len(s) { switch { case j >= len(other): result = append(result, s[i:]...) return result, false case s[i] == other[j]: result = append(result, s[i]) i++ j++ case s[i] < other[j]: result = append(result, s[i]) i++ default: result = append(result, other[j]) j++ } } result = append(result, other[j:]...) return result, false }