1package set 2 3import "sync" 4 5// Set defines a thread safe set data structure. 6type Set struct { 7 set 8 l sync.RWMutex // we name it because we don't want to expose it 9} 10 11// New creates and initialize a new Set. It's accept a variable number of 12// arguments to populate the initial set. If nothing passed a Set with zero 13// size is created. 14func newTS() *Set { 15 s := &Set{} 16 s.m = make(map[interface{}]struct{}) 17 18 // Ensure interface compliance 19 var _ Interface = s 20 21 return s 22} 23 24// Add includes the specified items (one or more) to the set. The underlying 25// Set s is modified. If passed nothing it silently returns. 26func (s *Set) Add(items ...interface{}) { 27 if len(items) == 0 { 28 return 29 } 30 31 s.l.Lock() 32 defer s.l.Unlock() 33 34 for _, item := range items { 35 s.m[item] = keyExists 36 } 37} 38 39// Remove deletes the specified items from the set. The underlying Set s is 40// modified. If passed nothing it silently returns. 41func (s *Set) Remove(items ...interface{}) { 42 if len(items) == 0 { 43 return 44 } 45 46 s.l.Lock() 47 defer s.l.Unlock() 48 49 for _, item := range items { 50 delete(s.m, item) 51 } 52} 53 54// Pop deletes and return an item from the set. The underlying Set s is 55// modified. If set is empty, nil is returned. 56func (s *Set) Pop() interface{} { 57 s.l.RLock() 58 for item := range s.m { 59 s.l.RUnlock() 60 s.l.Lock() 61 delete(s.m, item) 62 s.l.Unlock() 63 return item 64 } 65 s.l.RUnlock() 66 return nil 67} 68 69// Has looks for the existence of items passed. It returns false if nothing is 70// passed. For multiple items it returns true only if all of the items exist. 71func (s *Set) Has(items ...interface{}) bool { 72 // assume checked for empty item, which not exist 73 if len(items) == 0 { 74 return false 75 } 76 77 s.l.RLock() 78 defer s.l.RUnlock() 79 80 has := true 81 for _, item := range items { 82 if _, has = s.m[item]; !has { 83 break 84 } 85 } 86 return has 87} 88 89// Size returns the number of items in a set. 90func (s *Set) Size() int { 91 s.l.RLock() 92 defer s.l.RUnlock() 93 94 l := len(s.m) 95 return l 96} 97 98// Clear removes all items from the set. 99func (s *Set) Clear() { 100 s.l.Lock() 101 defer s.l.Unlock() 102 103 s.m = make(map[interface{}]struct{}) 104} 105 106// IsEqual test whether s and t are the same in size and have the same items. 107func (s *Set) IsEqual(t Interface) bool { 108 s.l.RLock() 109 defer s.l.RUnlock() 110 111 // Force locking only if given set is threadsafe. 112 if conv, ok := t.(*Set); ok { 113 conv.l.RLock() 114 defer conv.l.RUnlock() 115 } 116 117 // return false if they are no the same size 118 if sameSize := len(s.m) == t.Size(); !sameSize { 119 return false 120 } 121 122 equal := true 123 t.Each(func(item interface{}) bool { 124 _, equal = s.m[item] 125 return equal // if false, Each() will end 126 }) 127 128 return equal 129} 130 131// IsSubset tests whether t is a subset of s. 132func (s *Set) IsSubset(t Interface) (subset bool) { 133 s.l.RLock() 134 defer s.l.RUnlock() 135 136 subset = true 137 138 t.Each(func(item interface{}) bool { 139 _, subset = s.m[item] 140 return subset 141 }) 142 143 return 144} 145 146// Each traverses the items in the Set, calling the provided function for each 147// set member. Traversal will continue until all items in the Set have been 148// visited, or if the closure returns false. 149func (s *Set) Each(f func(item interface{}) bool) { 150 s.l.RLock() 151 defer s.l.RUnlock() 152 153 for item := range s.m { 154 if !f(item) { 155 break 156 } 157 } 158} 159 160// List returns a slice of all items. There is also StringSlice() and 161// IntSlice() methods for returning slices of type string or int. 162func (s *Set) List() []interface{} { 163 s.l.RLock() 164 defer s.l.RUnlock() 165 166 list := make([]interface{}, 0, len(s.m)) 167 168 for item := range s.m { 169 list = append(list, item) 170 } 171 172 return list 173} 174 175// Copy returns a new Set with a copy of s. 176func (s *Set) Copy() Interface { 177 u := newTS() 178 for item := range s.m { 179 u.Add(item) 180 } 181 return u 182} 183 184// Merge is like Union, however it modifies the current set it's applied on 185// with the given t set. 186func (s *Set) Merge(t Interface) { 187 s.l.Lock() 188 defer s.l.Unlock() 189 190 t.Each(func(item interface{}) bool { 191 s.m[item] = keyExists 192 return true 193 }) 194} 195