1/*
2Open Source Initiative OSI - The MIT License (MIT):Licensing
3
4The MIT License (MIT)
5Copyright (c) 2013 Ralph Caraveo (deckarep@gmail.com)
6
7Permission is hereby granted, free of charge, to any person obtaining a copy of
8this software and associated documentation files (the "Software"), to deal in
9the Software without restriction, including without limitation the rights to
10use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
11of the Software, and to permit persons to whom the Software is furnished to do
12so, subject to the following conditions:
13
14The above copyright notice and this permission notice shall be included in all
15copies or substantial portions of the Software.
16
17THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23SOFTWARE.
24*/
25
26package mapset
27
28import "sync"
29
30type threadSafeSet struct {
31	s threadUnsafeSet
32	sync.RWMutex
33}
34
35func newThreadSafeSet() threadSafeSet {
36	return threadSafeSet{s: newThreadUnsafeSet()}
37}
38
39func (set *threadSafeSet) Add(i interface{}) bool {
40	set.Lock()
41	ret := set.s.Add(i)
42	set.Unlock()
43	return ret
44}
45
46func (set *threadSafeSet) Contains(i ...interface{}) bool {
47	set.RLock()
48	ret := set.s.Contains(i...)
49	set.RUnlock()
50	return ret
51}
52
53func (set *threadSafeSet) IsSubset(other Set) bool {
54	o := other.(*threadSafeSet)
55
56	set.RLock()
57	o.RLock()
58
59	ret := set.s.IsSubset(&o.s)
60	set.RUnlock()
61	o.RUnlock()
62	return ret
63}
64
65func (set *threadSafeSet) IsProperSubset(other Set) bool {
66	o := other.(*threadSafeSet)
67
68	set.RLock()
69	defer set.RUnlock()
70	o.RLock()
71	defer o.RUnlock()
72
73	return set.s.IsProperSubset(&o.s)
74}
75
76func (set *threadSafeSet) IsSuperset(other Set) bool {
77	return other.IsSubset(set)
78}
79
80func (set *threadSafeSet) IsProperSuperset(other Set) bool {
81	return other.IsProperSubset(set)
82}
83
84func (set *threadSafeSet) Union(other Set) Set {
85	o := other.(*threadSafeSet)
86
87	set.RLock()
88	o.RLock()
89
90	unsafeUnion := set.s.Union(&o.s).(*threadUnsafeSet)
91	ret := &threadSafeSet{s: *unsafeUnion}
92	set.RUnlock()
93	o.RUnlock()
94	return ret
95}
96
97func (set *threadSafeSet) Intersect(other Set) Set {
98	o := other.(*threadSafeSet)
99
100	set.RLock()
101	o.RLock()
102
103	unsafeIntersection := set.s.Intersect(&o.s).(*threadUnsafeSet)
104	ret := &threadSafeSet{s: *unsafeIntersection}
105	set.RUnlock()
106	o.RUnlock()
107	return ret
108}
109
110func (set *threadSafeSet) Difference(other Set) Set {
111	o := other.(*threadSafeSet)
112
113	set.RLock()
114	o.RLock()
115
116	unsafeDifference := set.s.Difference(&o.s).(*threadUnsafeSet)
117	ret := &threadSafeSet{s: *unsafeDifference}
118	set.RUnlock()
119	o.RUnlock()
120	return ret
121}
122
123func (set *threadSafeSet) SymmetricDifference(other Set) Set {
124	o := other.(*threadSafeSet)
125
126	set.RLock()
127	o.RLock()
128
129	unsafeDifference := set.s.SymmetricDifference(&o.s).(*threadUnsafeSet)
130	ret := &threadSafeSet{s: *unsafeDifference}
131	set.RUnlock()
132	o.RUnlock()
133	return ret
134}
135
136func (set *threadSafeSet) Clear() {
137	set.Lock()
138	set.s = newThreadUnsafeSet()
139	set.Unlock()
140}
141
142func (set *threadSafeSet) Remove(i interface{}) {
143	set.Lock()
144	delete(set.s, i)
145	set.Unlock()
146}
147
148func (set *threadSafeSet) Cardinality() int {
149	set.RLock()
150	defer set.RUnlock()
151	return len(set.s)
152}
153
154func (set *threadSafeSet) Each(cb func(interface{}) bool) {
155	set.RLock()
156	for elem := range set.s {
157		if cb(elem) {
158			break
159		}
160	}
161	set.RUnlock()
162}
163
164func (set *threadSafeSet) Iter() <-chan interface{} {
165	ch := make(chan interface{})
166	go func() {
167		set.RLock()
168
169		for elem := range set.s {
170			ch <- elem
171		}
172		close(ch)
173		set.RUnlock()
174	}()
175
176	return ch
177}
178
179func (set *threadSafeSet) Iterator() *Iterator {
180	iterator, ch, stopCh := newIterator()
181
182	go func() {
183		set.RLock()
184	L:
185		for elem := range set.s {
186			select {
187			case <-stopCh:
188				break L
189			case ch <- elem:
190			}
191		}
192		close(ch)
193		set.RUnlock()
194	}()
195
196	return iterator
197}
198
199func (set *threadSafeSet) Equal(other Set) bool {
200	o := other.(*threadSafeSet)
201
202	set.RLock()
203	o.RLock()
204
205	ret := set.s.Equal(&o.s)
206	set.RUnlock()
207	o.RUnlock()
208	return ret
209}
210
211func (set *threadSafeSet) Clone() Set {
212	set.RLock()
213
214	unsafeClone := set.s.Clone().(*threadUnsafeSet)
215	ret := &threadSafeSet{s: *unsafeClone}
216	set.RUnlock()
217	return ret
218}
219
220func (set *threadSafeSet) String() string {
221	set.RLock()
222	ret := set.s.String()
223	set.RUnlock()
224	return ret
225}
226
227func (set *threadSafeSet) PowerSet() Set {
228	set.RLock()
229	ret := set.s.PowerSet()
230	set.RUnlock()
231	return ret
232}
233
234func (set *threadSafeSet) Pop() interface{} {
235	set.Lock()
236	defer set.Unlock()
237	return set.s.Pop()
238}
239
240func (set *threadSafeSet) CartesianProduct(other Set) Set {
241	o := other.(*threadSafeSet)
242
243	set.RLock()
244	o.RLock()
245
246	unsafeCartProduct := set.s.CartesianProduct(&o.s).(*threadUnsafeSet)
247	ret := &threadSafeSet{s: *unsafeCartProduct}
248	set.RUnlock()
249	o.RUnlock()
250	return ret
251}
252
253func (set *threadSafeSet) ToSlice() []interface{} {
254	keys := make([]interface{}, 0, set.Cardinality())
255	set.RLock()
256	for elem := range set.s {
257		keys = append(keys, elem)
258	}
259	set.RUnlock()
260	return keys
261}
262
263func (set *threadSafeSet) MarshalJSON() ([]byte, error) {
264	set.RLock()
265	b, err := set.s.MarshalJSON()
266	set.RUnlock()
267
268	return b, err
269}
270
271func (set *threadSafeSet) UnmarshalJSON(p []byte) error {
272	set.RLock()
273	err := set.s.UnmarshalJSON(p)
274	set.RUnlock()
275
276	return err
277}
278