1// Copyright 2017 Google Inc. 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14package sets 15 16import ( 17 "fmt" 18 "sort" 19 "strings" 20) 21 22// IntSet stores a set of unique int elements. 23type IntSet struct { 24 set map[int]present 25} 26 27// NewIntSet creates an IntSet containing the supplied initial int elements. 28func NewIntSet(elements ...int) *IntSet { 29 s := &IntSet{} 30 s.set = make(map[int]present) 31 s.Insert(elements...) 32 return s 33} 34 35// Copy returns a newly allocated copy of the supplied IntSet. 36func (s *IntSet) Copy() *IntSet { 37 c := NewIntSet() 38 if s != nil { 39 for e := range s.set { 40 c.set[e] = present{} 41 } 42 } 43 return c 44} 45 46// Insert zero or more int elements into the IntSet. As expected for a Set, 47// elements already present in the IntSet are simply ignored. 48func (s *IntSet) Insert(elements ...int) { 49 for _, e := range elements { 50 s.set[e] = present{} 51 } 52} 53 54// Delete zero or more int elements from the IntSet. Any elements not present 55// in the IntSet are simply ignored. 56func (s *IntSet) Delete(elements ...int) { 57 for _, e := range elements { 58 delete(s.set, e) 59 } 60} 61 62// Intersect returns a new IntSet containing the intersection of the receiver 63// and argument IntSets. Returns an empty set if the argument is nil. 64func (s *IntSet) Intersect(other *IntSet) *IntSet { 65 if other == nil { 66 return NewIntSet() 67 } 68 69 // Point a and b to the maps, setting a to the smaller of the two. 70 a, b := s.set, other.set 71 if len(b) < len(a) { 72 a, b = b, a 73 } 74 75 // Perform the intersection. 76 intersect := NewIntSet() 77 for e := range a { 78 if _, ok := b[e]; ok { 79 intersect.set[e] = present{} 80 } 81 } 82 return intersect 83} 84 85// Disjoint returns true if the intersection of the receiver and the argument 86// IntSets is the empty set. Returns true if the argument is nil or either 87// IntSet is the empty set. 88func (s *IntSet) Disjoint(other *IntSet) bool { 89 if other == nil || len(other.set) == 0 || len(s.set) == 0 { 90 return true 91 } 92 93 // Point a and b to the maps, setting a to the smaller of the two. 94 a, b := s.set, other.set 95 if len(b) < len(a) { 96 a, b = b, a 97 } 98 99 // Check for non-empty intersection. 100 for e := range a { 101 if _, ok := b[e]; ok { 102 return false // Early-exit because intersecting. 103 } 104 } 105 return true 106} 107 108// Difference returns a new IntSet containing the elements in the receiver that 109// are not present in the argument IntSet. Returns a copy of the receiver if 110// the argument is nil. 111func (s *IntSet) Difference(other *IntSet) *IntSet { 112 if other == nil { 113 return s.Copy() 114 } 115 116 // Insert only the elements in the receiver that are not present in the 117 // argument IntSet. 118 diff := NewIntSet() 119 for e := range s.set { 120 if _, ok := other.set[e]; !ok { 121 diff.set[e] = present{} 122 } 123 } 124 return diff 125} 126 127// Unique returns a new IntSet containing the elements in the receiver that are 128// not present in the argument IntSet *and* the elements in the argument IntSet 129// that are not in the receiver. Returns a copy of the receiver if the argument 130// is nil. 131func (s *IntSet) Unique(other *IntSet) *IntSet { 132 if other == nil { 133 return s.Copy() 134 } 135 136 sNotInOther := s.Difference(other) 137 otherNotInS := other.Difference(s) 138 139 // Duplicate Union implementation here to avoid extra Copy, since both 140 // sNotInOther and otherNotInS are already copies. 141 unique := sNotInOther 142 for e := range otherNotInS.set { 143 unique.set[e] = present{} 144 } 145 return unique 146} 147 148// Equal returns true if the receiver and the argument IntSet contain exactly 149// the same elements. Returns false if the argument is nil. 150func (s *IntSet) Equal(other *IntSet) bool { 151 if s == nil || other == nil { 152 return s == nil && other == nil 153 } 154 155 // Two sets of different length cannot have the exact same unique 156 // elements. 157 if len(s.set) != len(other.set) { 158 return false 159 } 160 161 // Only one loop is needed. If the two sets are known to be of equal 162 // length, then the two sets are equal only if exactly all of the 163 // elements in the first set are found in the second. 164 for e := range s.set { 165 if _, ok := other.set[e]; !ok { 166 return false 167 } 168 } 169 170 return true 171} 172 173// Union returns a new IntSet containing the union of the receiver and argument 174// IntSets. Returns a copy of the receiver if the argument is nil. 175func (s *IntSet) Union(other *IntSet) *IntSet { 176 union := s.Copy() 177 if other != nil { 178 for e := range other.set { 179 union.set[e] = present{} 180 } 181 } 182 return union 183} 184 185// Contains returns true if element is in the IntSet. 186func (s *IntSet) Contains(element int) bool { 187 _, in := s.set[element] 188 return in 189} 190 191// Len returns the number of unique elements in the IntSet. 192func (s *IntSet) Len() int { 193 return len(s.set) 194} 195 196// Empty returns true if the receiver is the empty set. 197func (s *IntSet) Empty() bool { 198 return len(s.set) == 0 199} 200 201// Elements returns a []int of the elements in the IntSet, in no particular (or 202// consistent) order. 203func (s *IntSet) Elements() []int { 204 elements := []int{} // Return at least an empty slice rather than nil. 205 for e := range s.set { 206 elements = append(elements, e) 207 } 208 return elements 209} 210 211// Sorted returns a sorted []int of the elements in the IntSet. 212func (s *IntSet) Sorted() []int { 213 elements := s.Elements() 214 sort.Ints(elements) 215 return elements 216} 217 218// String formats the IntSet elements as sorted ints, representing them in 219// "array initializer" syntax. 220func (s *IntSet) String() string { 221 elements := s.Sorted() 222 var quoted []string 223 for _, e := range elements { 224 quoted = append(quoted, fmt.Sprintf("\"%d\"", e)) 225 } 226 return fmt.Sprintf("{%s}", strings.Join(quoted, ", ")) 227} 228