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