]>
Commit | Line | Data |
---|---|---|
15c0b25d AP |
1 | package set |
2 | ||
3 | import ( | |
4 | "sort" | |
5 | ) | |
6 | ||
7 | // Add inserts the given value into the receiving Set. | |
8 | // | |
9 | // This mutates the set in-place. This operation is not thread-safe. | |
10 | func (s Set) Add(val interface{}) { | |
11 | hv := s.rules.Hash(val) | |
12 | if _, ok := s.vals[hv]; !ok { | |
13 | s.vals[hv] = make([]interface{}, 0, 1) | |
14 | } | |
15 | bucket := s.vals[hv] | |
16 | ||
17 | // See if an equivalent value is already present | |
18 | for _, ev := range bucket { | |
19 | if s.rules.Equivalent(val, ev) { | |
20 | return | |
21 | } | |
22 | } | |
23 | ||
24 | s.vals[hv] = append(bucket, val) | |
25 | } | |
26 | ||
27 | // Remove deletes the given value from the receiving set, if indeed it was | |
28 | // there in the first place. If the value is not present, this is a no-op. | |
29 | func (s Set) Remove(val interface{}) { | |
30 | hv := s.rules.Hash(val) | |
31 | bucket, ok := s.vals[hv] | |
32 | if !ok { | |
33 | return | |
34 | } | |
35 | ||
36 | for i, ev := range bucket { | |
37 | if s.rules.Equivalent(val, ev) { | |
38 | newBucket := make([]interface{}, 0, len(bucket)-1) | |
39 | newBucket = append(newBucket, bucket[:i]...) | |
40 | newBucket = append(newBucket, bucket[i+1:]...) | |
41 | if len(newBucket) > 0 { | |
42 | s.vals[hv] = newBucket | |
43 | } else { | |
44 | delete(s.vals, hv) | |
45 | } | |
46 | return | |
47 | } | |
48 | } | |
49 | } | |
50 | ||
51 | // Has returns true if the given value is in the receiving set, or false if | |
52 | // it is not. | |
53 | func (s Set) Has(val interface{}) bool { | |
54 | hv := s.rules.Hash(val) | |
55 | bucket, ok := s.vals[hv] | |
56 | if !ok { | |
57 | return false | |
58 | } | |
59 | ||
60 | for _, ev := range bucket { | |
61 | if s.rules.Equivalent(val, ev) { | |
62 | return true | |
63 | } | |
64 | } | |
65 | return false | |
66 | } | |
67 | ||
68 | // Copy performs a shallow copy of the receiving set, returning a new set | |
69 | // with the same rules and elements. | |
70 | func (s Set) Copy() Set { | |
71 | ret := NewSet(s.rules) | |
72 | for k, v := range s.vals { | |
73 | ret.vals[k] = v | |
74 | } | |
75 | return ret | |
76 | } | |
77 | ||
107c1cdb ND |
78 | // Iterator returns an iterator over values in the set. If the set's rules |
79 | // implement OrderedRules then the result is ordered per those rules. If | |
80 | // no order is provided, or if it is not a total order, then the iteration | |
81 | // order is undefined but consistent for a particular version of cty. Do not | |
82 | // rely on specific ordering between cty releases unless the rules order is a | |
83 | // total order. | |
15c0b25d AP |
84 | // |
85 | // The pattern for using the returned iterator is: | |
86 | // | |
87 | // it := set.Iterator() | |
88 | // for it.Next() { | |
89 | // val := it.Value() | |
90 | // // ... | |
91 | // } | |
92 | // | |
93 | // Once an iterator has been created for a set, the set *must not* be mutated | |
94 | // until the iterator is no longer in use. | |
95 | func (s Set) Iterator() *Iterator { | |
107c1cdb | 96 | vals := s.Values() |
15c0b25d AP |
97 | |
98 | return &Iterator{ | |
107c1cdb ND |
99 | vals: vals, |
100 | idx: -1, | |
15c0b25d AP |
101 | } |
102 | } | |
103 | ||
104 | // EachValue calls the given callback once for each value in the set, in an | |
105 | // undefined order that callers should not depend on. | |
106 | func (s Set) EachValue(cb func(interface{})) { | |
107 | it := s.Iterator() | |
108 | for it.Next() { | |
109 | cb(it.Value()) | |
110 | } | |
111 | } | |
112 | ||
107c1cdb ND |
113 | // Values returns a slice of all the values in the set. If the set rules have |
114 | // an order then the result is in that order. If no order is provided or if | |
115 | // it is not a total order then the result order is undefined, but consistent | |
116 | // for a particular set value within a specific release of cty. | |
15c0b25d AP |
117 | func (s Set) Values() []interface{} { |
118 | var ret []interface{} | |
107c1cdb ND |
119 | // Sort the bucketIds to ensure that we always traverse in a |
120 | // consistent order. | |
121 | bucketIDs := make([]int, 0, len(s.vals)) | |
122 | for id := range s.vals { | |
123 | bucketIDs = append(bucketIDs, id) | |
124 | } | |
125 | sort.Ints(bucketIDs) | |
126 | ||
127 | for _, bucketID := range bucketIDs { | |
128 | ret = append(ret, s.vals[bucketID]...) | |
129 | } | |
130 | ||
131 | if orderRules, ok := s.rules.(OrderedRules); ok { | |
132 | sort.SliceStable(ret, func(i, j int) bool { | |
133 | return orderRules.Less(ret[i], ret[j]) | |
134 | }) | |
135 | } | |
136 | ||
15c0b25d AP |
137 | return ret |
138 | } | |
139 | ||
140 | // Length returns the number of values in the set. | |
141 | func (s Set) Length() int { | |
142 | var count int | |
143 | for _, bucket := range s.vals { | |
144 | count = count + len(bucket) | |
145 | } | |
146 | return count | |
147 | } | |
148 | ||
149 | // Union returns a new set that contains all of the members of both the | |
150 | // receiving set and the given set. Both sets must have the same rules, or | |
151 | // else this function will panic. | |
152 | func (s1 Set) Union(s2 Set) Set { | |
153 | mustHaveSameRules(s1, s2) | |
154 | rs := NewSet(s1.rules) | |
155 | s1.EachValue(func(v interface{}) { | |
156 | rs.Add(v) | |
157 | }) | |
158 | s2.EachValue(func(v interface{}) { | |
159 | rs.Add(v) | |
160 | }) | |
161 | return rs | |
162 | } | |
163 | ||
164 | // Intersection returns a new set that contains the values that both the | |
165 | // receiver and given sets have in common. Both sets must have the same rules, | |
166 | // or else this function will panic. | |
167 | func (s1 Set) Intersection(s2 Set) Set { | |
168 | mustHaveSameRules(s1, s2) | |
169 | rs := NewSet(s1.rules) | |
170 | s1.EachValue(func(v interface{}) { | |
171 | if s2.Has(v) { | |
172 | rs.Add(v) | |
173 | } | |
174 | }) | |
175 | return rs | |
176 | } | |
177 | ||
178 | // Subtract returns a new set that contains all of the values from the receiver | |
179 | // that are not also in the given set. Both sets must have the same rules, | |
180 | // or else this function will panic. | |
181 | func (s1 Set) Subtract(s2 Set) Set { | |
182 | mustHaveSameRules(s1, s2) | |
183 | rs := NewSet(s1.rules) | |
184 | s1.EachValue(func(v interface{}) { | |
185 | if !s2.Has(v) { | |
186 | rs.Add(v) | |
187 | } | |
188 | }) | |
189 | return rs | |
190 | } | |
191 | ||
192 | // SymmetricDifference returns a new set that contains all of the values from | |
193 | // both the receiver and given sets, except those that both sets have in | |
194 | // common. Both sets must have the same rules, or else this function will | |
195 | // panic. | |
196 | func (s1 Set) SymmetricDifference(s2 Set) Set { | |
197 | mustHaveSameRules(s1, s2) | |
198 | rs := NewSet(s1.rules) | |
199 | s1.EachValue(func(v interface{}) { | |
200 | if !s2.Has(v) { | |
201 | rs.Add(v) | |
202 | } | |
203 | }) | |
204 | s2.EachValue(func(v interface{}) { | |
205 | if !s1.Has(v) { | |
206 | rs.Add(v) | |
207 | } | |
208 | }) | |
209 | return rs | |
210 | } |