]> git.immae.eu Git - github/fretlink/terraform-provider-statuscake.git/blob - vendor/github.com/hashicorp/terraform/helper/schema/set.go
Upgrade to 0.12
[github/fretlink/terraform-provider-statuscake.git] / vendor / github.com / hashicorp / terraform / helper / schema / set.go
1 package schema
2
3 import (
4 "bytes"
5 "fmt"
6 "reflect"
7 "sort"
8 "strconv"
9 "sync"
10
11 "github.com/hashicorp/terraform/helper/hashcode"
12 )
13
14 // HashString hashes strings. If you want a Set of strings, this is the
15 // SchemaSetFunc you want.
16 func HashString(v interface{}) int {
17 return hashcode.String(v.(string))
18 }
19
20 // HashInt hashes integers. If you want a Set of integers, this is the
21 // SchemaSetFunc you want.
22 func HashInt(v interface{}) int {
23 return hashcode.String(strconv.Itoa(v.(int)))
24 }
25
26 // HashResource hashes complex structures that are described using
27 // a *Resource. This is the default set implementation used when a set's
28 // element type is a full resource.
29 func HashResource(resource *Resource) SchemaSetFunc {
30 return func(v interface{}) int {
31 var buf bytes.Buffer
32 SerializeResourceForHash(&buf, v, resource)
33 return hashcode.String(buf.String())
34 }
35 }
36
37 // HashSchema hashes values that are described using a *Schema. This is the
38 // default set implementation used when a set's element type is a single
39 // schema.
40 func HashSchema(schema *Schema) SchemaSetFunc {
41 return func(v interface{}) int {
42 var buf bytes.Buffer
43 SerializeValueForHash(&buf, v, schema)
44 return hashcode.String(buf.String())
45 }
46 }
47
48 // Set is a set data structure that is returned for elements of type
49 // TypeSet.
50 type Set struct {
51 F SchemaSetFunc
52
53 m map[string]interface{}
54 once sync.Once
55 }
56
57 // NewSet is a convenience method for creating a new set with the given
58 // items.
59 func NewSet(f SchemaSetFunc, items []interface{}) *Set {
60 s := &Set{F: f}
61 for _, i := range items {
62 s.Add(i)
63 }
64
65 return s
66 }
67
68 // CopySet returns a copy of another set.
69 func CopySet(otherSet *Set) *Set {
70 return NewSet(otherSet.F, otherSet.List())
71 }
72
73 // Add adds an item to the set if it isn't already in the set.
74 func (s *Set) Add(item interface{}) {
75 s.add(item, false)
76 }
77
78 // Remove removes an item if it's already in the set. Idempotent.
79 func (s *Set) Remove(item interface{}) {
80 s.remove(item)
81 }
82
83 // Contains checks if the set has the given item.
84 func (s *Set) Contains(item interface{}) bool {
85 _, ok := s.m[s.hash(item)]
86 return ok
87 }
88
89 // Len returns the amount of items in the set.
90 func (s *Set) Len() int {
91 return len(s.m)
92 }
93
94 // List returns the elements of this set in slice format.
95 //
96 // The order of the returned elements is deterministic. Given the same
97 // set, the order of this will always be the same.
98 func (s *Set) List() []interface{} {
99 result := make([]interface{}, len(s.m))
100 for i, k := range s.listCode() {
101 result[i] = s.m[k]
102 }
103
104 return result
105 }
106
107 // Difference performs a set difference of the two sets, returning
108 // a new third set that has only the elements unique to this set.
109 func (s *Set) Difference(other *Set) *Set {
110 result := &Set{F: s.F}
111 result.once.Do(result.init)
112
113 for k, v := range s.m {
114 if _, ok := other.m[k]; !ok {
115 result.m[k] = v
116 }
117 }
118
119 return result
120 }
121
122 // Intersection performs the set intersection of the two sets
123 // and returns a new third set.
124 func (s *Set) Intersection(other *Set) *Set {
125 result := &Set{F: s.F}
126 result.once.Do(result.init)
127
128 for k, v := range s.m {
129 if _, ok := other.m[k]; ok {
130 result.m[k] = v
131 }
132 }
133
134 return result
135 }
136
137 // Union performs the set union of the two sets and returns a new third
138 // set.
139 func (s *Set) Union(other *Set) *Set {
140 result := &Set{F: s.F}
141 result.once.Do(result.init)
142
143 for k, v := range s.m {
144 result.m[k] = v
145 }
146 for k, v := range other.m {
147 result.m[k] = v
148 }
149
150 return result
151 }
152
153 func (s *Set) Equal(raw interface{}) bool {
154 other, ok := raw.(*Set)
155 if !ok {
156 return false
157 }
158
159 return reflect.DeepEqual(s.m, other.m)
160 }
161
162 // HashEqual simply checks to the keys the top-level map to the keys in the
163 // other set's top-level map to see if they are equal. This obviously assumes
164 // you have a properly working hash function - use HashResource if in doubt.
165 func (s *Set) HashEqual(raw interface{}) bool {
166 other, ok := raw.(*Set)
167 if !ok {
168 return false
169 }
170
171 ks1 := make([]string, 0)
172 ks2 := make([]string, 0)
173
174 for k := range s.m {
175 ks1 = append(ks1, k)
176 }
177 for k := range other.m {
178 ks2 = append(ks2, k)
179 }
180
181 sort.Strings(ks1)
182 sort.Strings(ks2)
183
184 return reflect.DeepEqual(ks1, ks2)
185 }
186
187 func (s *Set) GoString() string {
188 return fmt.Sprintf("*Set(%#v)", s.m)
189 }
190
191 func (s *Set) init() {
192 s.m = make(map[string]interface{})
193 }
194
195 func (s *Set) add(item interface{}, computed bool) string {
196 s.once.Do(s.init)
197
198 code := s.hash(item)
199 if computed {
200 code = "~" + code
201
202 if isProto5() {
203 tmpCode := code
204 count := 0
205 for _, exists := s.m[tmpCode]; exists; _, exists = s.m[tmpCode] {
206 count++
207 tmpCode = fmt.Sprintf("%s%d", code, count)
208 }
209 code = tmpCode
210 }
211 }
212
213 if _, ok := s.m[code]; !ok {
214 s.m[code] = item
215 }
216
217 return code
218 }
219
220 func (s *Set) hash(item interface{}) string {
221 code := s.F(item)
222 // Always return a nonnegative hashcode.
223 if code < 0 {
224 code = -code
225 }
226 return strconv.Itoa(code)
227 }
228
229 func (s *Set) remove(item interface{}) string {
230 s.once.Do(s.init)
231
232 code := s.hash(item)
233 delete(s.m, code)
234
235 return code
236 }
237
238 func (s *Set) index(item interface{}) int {
239 return sort.SearchStrings(s.listCode(), s.hash(item))
240 }
241
242 func (s *Set) listCode() []string {
243 // Sort the hash codes so the order of the list is deterministic
244 keys := make([]string, 0, len(s.m))
245 for k := range s.m {
246 keys = append(keys, k)
247 }
248 sort.Sort(sort.StringSlice(keys))
249 return keys
250 }