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) CartesianProduct(other Set) Set {
235	o := other.(*threadSafeSet)
236
237	set.RLock()
238	o.RLock()
239
240	unsafeCartProduct := set.s.CartesianProduct(&o.s).(*threadUnsafeSet)
241	ret := &threadSafeSet{s: *unsafeCartProduct}
242	set.RUnlock()
243	o.RUnlock()
244	return ret
245}
246
247func (set *threadSafeSet) ToSlice() []interface{} {
248	keys := make([]interface{}, 0, set.Cardinality())
249	set.RLock()
250	for elem := range set.s {
251		keys = append(keys, elem)
252	}
253	set.RUnlock()
254	return keys
255}
256
257func (set *threadSafeSet) MarshalJSON() ([]byte, error) {
258	set.RLock()
259	b, err := set.s.MarshalJSON()
260	set.RUnlock()
261
262	return b, err
263}
264
265func (set *threadSafeSet) UnmarshalJSON(p []byte) error {
266	set.RLock()
267	err := set.s.UnmarshalJSON(p)
268	set.RUnlock()
269
270	return err
271}
272