]> git.immae.eu Git - github/fretlink/terraform-provider-statuscake.git/blame - vendor/github.com/hashicorp/terraform/helper/schema/set.go
Merge branch 'master' of /Users/jake/terraform
[github/fretlink/terraform-provider-statuscake.git] / vendor / github.com / hashicorp / terraform / helper / schema / set.go
CommitLineData
bae9f6d2
JC
1package schema
2
3import (
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.
16func 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.
23func 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.
34func 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.
44type 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.
53func 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.
63func 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.
68func (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.
73func (s *Set) Remove(item interface{}) {
74 s.remove(item)
75}
76
77// Contains checks if the set has the given item.
78func (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.
84func (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.
92func (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.
103func (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.
118func (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.
133func (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
147func (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
156func (s *Set) GoString() string {
157 return fmt.Sprintf("*Set(%#v)", s.m)
158}
159
160func (s *Set) init() {
161 s.m = make(map[string]interface{})
162}
163
164func (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
179func (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
188func (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
197func (s *Set) index(item interface{}) int {
198 return sort.SearchStrings(s.listCode(), s.hash(item))
199}
200
201func (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}