github.com/jmbataller/terraform@v0.6.8-0.20151125192640-b7a12e3a580c/helper/schema/set.go (about) 1 package schema 2 3 import ( 4 "bytes" 5 "fmt" 6 "reflect" 7 "sort" 8 "sync" 9 10 "github.com/hashicorp/terraform/helper/hashcode" 11 ) 12 13 // HashString hashes strings. If you want a Set of strings, this is the 14 // SchemaSetFunc you want. 15 func HashString(v interface{}) int { 16 return hashcode.String(v.(string)) 17 } 18 19 // HashResource hashes complex structures that are described using 20 // a *Resource. This is the default set implementation used when a set's 21 // element type is a full resource. 22 func HashResource(resource *Resource) SchemaSetFunc { 23 return func(v interface{}) int { 24 var buf bytes.Buffer 25 SerializeResourceForHash(&buf, v, resource) 26 return hashcode.String(buf.String()) 27 } 28 } 29 30 // HashSchema hashes values that are described using a *Schema. This is the 31 // default set implementation used when a set's element type is a single 32 // schema. 33 func HashSchema(schema *Schema) SchemaSetFunc { 34 return func(v interface{}) int { 35 var buf bytes.Buffer 36 SerializeValueForHash(&buf, v, schema) 37 return hashcode.String(buf.String()) 38 } 39 } 40 41 // Set is a set data structure that is returned for elements of type 42 // TypeSet. 43 type Set struct { 44 F SchemaSetFunc 45 46 m map[int]interface{} 47 once sync.Once 48 } 49 50 // NewSet is a convenience method for creating a new set with the given 51 // items. 52 func NewSet(f SchemaSetFunc, items []interface{}) *Set { 53 s := &Set{F: f} 54 for _, i := range items { 55 s.Add(i) 56 } 57 58 return s 59 } 60 61 // CopySet returns a copy of another set. 62 func CopySet(otherSet *Set) *Set { 63 return NewSet(otherSet.F, otherSet.List()) 64 } 65 66 // Add adds an item to the set if it isn't already in the set. 67 func (s *Set) Add(item interface{}) { 68 s.add(item) 69 } 70 71 // Remove removes an item if it's already in the set. Idempotent. 72 func (s *Set) Remove(item interface{}) { 73 s.remove(item) 74 } 75 76 // Contains checks if the set has the given item. 77 func (s *Set) Contains(item interface{}) bool { 78 _, ok := s.m[s.hash(item)] 79 return ok 80 } 81 82 // Len returns the amount of items in the set. 83 func (s *Set) Len() int { 84 return len(s.m) 85 } 86 87 // List returns the elements of this set in slice format. 88 // 89 // The order of the returned elements is deterministic. Given the same 90 // set, the order of this will always be the same. 91 func (s *Set) List() []interface{} { 92 result := make([]interface{}, len(s.m)) 93 for i, k := range s.listCode() { 94 result[i] = s.m[k] 95 } 96 97 return result 98 } 99 100 // Difference performs a set difference of the two sets, returning 101 // a new third set that has only the elements unique to this set. 102 func (s *Set) Difference(other *Set) *Set { 103 result := &Set{F: s.F} 104 result.once.Do(result.init) 105 106 for k, v := range s.m { 107 if _, ok := other.m[k]; !ok { 108 result.m[k] = v 109 } 110 } 111 112 return result 113 } 114 115 // Intersection performs the set intersection of the two sets 116 // and returns a new third set. 117 func (s *Set) Intersection(other *Set) *Set { 118 result := &Set{F: s.F} 119 result.once.Do(result.init) 120 121 for k, v := range s.m { 122 if _, ok := other.m[k]; ok { 123 result.m[k] = v 124 } 125 } 126 127 return result 128 } 129 130 // Union performs the set union of the two sets and returns a new third 131 // set. 132 func (s *Set) Union(other *Set) *Set { 133 result := &Set{F: s.F} 134 result.once.Do(result.init) 135 136 for k, v := range s.m { 137 result.m[k] = v 138 } 139 for k, v := range other.m { 140 result.m[k] = v 141 } 142 143 return result 144 } 145 146 func (s *Set) Equal(raw interface{}) bool { 147 other, ok := raw.(*Set) 148 if !ok { 149 return false 150 } 151 152 return reflect.DeepEqual(s.m, other.m) 153 } 154 155 func (s *Set) GoString() string { 156 return fmt.Sprintf("*Set(%#v)", s.m) 157 } 158 159 func (s *Set) init() { 160 s.m = make(map[int]interface{}) 161 } 162 163 func (s *Set) add(item interface{}) int { 164 s.once.Do(s.init) 165 166 code := s.hash(item) 167 if _, ok := s.m[code]; !ok { 168 s.m[code] = item 169 } 170 171 return code 172 } 173 174 func (s *Set) hash(item interface{}) int { 175 code := s.F(item) 176 // Always return a nonnegative hashcode. 177 if code < 0 { 178 return -code 179 } 180 return code 181 } 182 183 func (s *Set) remove(item interface{}) int { 184 s.once.Do(s.init) 185 186 code := s.F(item) 187 delete(s.m, code) 188 189 return code 190 } 191 192 func (s *Set) index(item interface{}) int { 193 return sort.SearchInts(s.listCode(), s.hash(item)) 194 } 195 196 func (s *Set) listCode() []int { 197 // Sort the hash codes so the order of the list is deterministic 198 keys := make([]int, 0, len(s.m)) 199 for k, _ := range s.m { 200 keys = append(keys, k) 201 } 202 sort.Sort(sort.IntSlice(keys)) 203 return keys 204 }