34d0e516e0
Golang-set library is added to make it easier to support set operations.
284 lines
5.6 KiB
Go
284 lines
5.6 KiB
Go
/*
|
|
Open Source Initiative OSI - The MIT License (MIT):Licensing
|
|
|
|
The MIT License (MIT)
|
|
Copyright (c) 2013 Ralph Caraveo (deckarep@gmail.com)
|
|
|
|
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
|
this software and associated documentation files (the "Software"), to deal in
|
|
the Software without restriction, including without limitation the rights to
|
|
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
|
of the Software, and to permit persons to whom the Software is furnished to do
|
|
so, subject to the following conditions:
|
|
|
|
The above copyright notice and this permission notice shall be included in all
|
|
copies or substantial portions of the Software.
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
SOFTWARE.
|
|
*/
|
|
|
|
package mapset
|
|
|
|
import "sync"
|
|
|
|
type threadSafeSet struct {
|
|
s threadUnsafeSet
|
|
sync.RWMutex
|
|
}
|
|
|
|
func newThreadSafeSet() threadSafeSet {
|
|
return threadSafeSet{s: newThreadUnsafeSet()}
|
|
}
|
|
|
|
func (set *threadSafeSet) Add(i interface{}) bool {
|
|
set.Lock()
|
|
ret := set.s.Add(i)
|
|
set.Unlock()
|
|
return ret
|
|
}
|
|
|
|
func (set *threadSafeSet) Contains(i ...interface{}) bool {
|
|
set.RLock()
|
|
ret := set.s.Contains(i...)
|
|
set.RUnlock()
|
|
return ret
|
|
}
|
|
|
|
func (set *threadSafeSet) IsSubset(other Set) bool {
|
|
o := other.(*threadSafeSet)
|
|
|
|
set.RLock()
|
|
o.RLock()
|
|
|
|
ret := set.s.IsSubset(&o.s)
|
|
set.RUnlock()
|
|
o.RUnlock()
|
|
return ret
|
|
}
|
|
|
|
func (set *threadSafeSet) IsProperSubset(other Set) bool {
|
|
o := other.(*threadSafeSet)
|
|
|
|
set.RLock()
|
|
defer set.RUnlock()
|
|
o.RLock()
|
|
defer o.RUnlock()
|
|
|
|
return set.s.IsProperSubset(&o.s)
|
|
}
|
|
|
|
func (set *threadSafeSet) IsSuperset(other Set) bool {
|
|
return other.IsSubset(set)
|
|
}
|
|
|
|
func (set *threadSafeSet) IsProperSuperset(other Set) bool {
|
|
return other.IsProperSubset(set)
|
|
}
|
|
|
|
func (set *threadSafeSet) Union(other Set) Set {
|
|
o := other.(*threadSafeSet)
|
|
|
|
set.RLock()
|
|
o.RLock()
|
|
|
|
unsafeUnion := set.s.Union(&o.s).(*threadUnsafeSet)
|
|
ret := &threadSafeSet{s: *unsafeUnion}
|
|
set.RUnlock()
|
|
o.RUnlock()
|
|
return ret
|
|
}
|
|
|
|
func (set *threadSafeSet) Intersect(other Set) Set {
|
|
o := other.(*threadSafeSet)
|
|
|
|
set.RLock()
|
|
o.RLock()
|
|
|
|
unsafeIntersection := set.s.Intersect(&o.s).(*threadUnsafeSet)
|
|
ret := &threadSafeSet{s: *unsafeIntersection}
|
|
set.RUnlock()
|
|
o.RUnlock()
|
|
return ret
|
|
}
|
|
|
|
func (set *threadSafeSet) Difference(other Set) Set {
|
|
o := other.(*threadSafeSet)
|
|
|
|
set.RLock()
|
|
o.RLock()
|
|
|
|
unsafeDifference := set.s.Difference(&o.s).(*threadUnsafeSet)
|
|
ret := &threadSafeSet{s: *unsafeDifference}
|
|
set.RUnlock()
|
|
o.RUnlock()
|
|
return ret
|
|
}
|
|
|
|
func (set *threadSafeSet) SymmetricDifference(other Set) Set {
|
|
o := other.(*threadSafeSet)
|
|
|
|
set.RLock()
|
|
o.RLock()
|
|
|
|
unsafeDifference := set.s.SymmetricDifference(&o.s).(*threadUnsafeSet)
|
|
ret := &threadSafeSet{s: *unsafeDifference}
|
|
set.RUnlock()
|
|
o.RUnlock()
|
|
return ret
|
|
}
|
|
|
|
func (set *threadSafeSet) Clear() {
|
|
set.Lock()
|
|
set.s = newThreadUnsafeSet()
|
|
set.Unlock()
|
|
}
|
|
|
|
func (set *threadSafeSet) Remove(i interface{}) {
|
|
set.Lock()
|
|
delete(set.s, i)
|
|
set.Unlock()
|
|
}
|
|
|
|
func (set *threadSafeSet) Cardinality() int {
|
|
set.RLock()
|
|
defer set.RUnlock()
|
|
return len(set.s)
|
|
}
|
|
|
|
func (set *threadSafeSet) Each(cb func(interface{}) bool) {
|
|
set.RLock()
|
|
for elem := range set.s {
|
|
if cb(elem) {
|
|
break
|
|
}
|
|
}
|
|
set.RUnlock()
|
|
}
|
|
|
|
func (set *threadSafeSet) Iter() <-chan interface{} {
|
|
ch := make(chan interface{})
|
|
go func() {
|
|
set.RLock()
|
|
|
|
for elem := range set.s {
|
|
ch <- elem
|
|
}
|
|
close(ch)
|
|
set.RUnlock()
|
|
}()
|
|
|
|
return ch
|
|
}
|
|
|
|
func (set *threadSafeSet) Iterator() *Iterator {
|
|
iterator, ch, stopCh := newIterator()
|
|
|
|
go func() {
|
|
set.RLock()
|
|
L:
|
|
for elem := range set.s {
|
|
select {
|
|
case <-stopCh:
|
|
break L
|
|
case ch <- elem:
|
|
}
|
|
}
|
|
close(ch)
|
|
set.RUnlock()
|
|
}()
|
|
|
|
return iterator
|
|
}
|
|
|
|
func (set *threadSafeSet) Equal(other Set) bool {
|
|
o := other.(*threadSafeSet)
|
|
|
|
set.RLock()
|
|
o.RLock()
|
|
|
|
ret := set.s.Equal(&o.s)
|
|
set.RUnlock()
|
|
o.RUnlock()
|
|
return ret
|
|
}
|
|
|
|
func (set *threadSafeSet) Clone() Set {
|
|
set.RLock()
|
|
|
|
unsafeClone := set.s.Clone().(*threadUnsafeSet)
|
|
ret := &threadSafeSet{s: *unsafeClone}
|
|
set.RUnlock()
|
|
return ret
|
|
}
|
|
|
|
func (set *threadSafeSet) String() string {
|
|
set.RLock()
|
|
ret := set.s.String()
|
|
set.RUnlock()
|
|
return ret
|
|
}
|
|
|
|
func (set *threadSafeSet) PowerSet() Set {
|
|
set.RLock()
|
|
unsafePowerSet := set.s.PowerSet().(*threadUnsafeSet)
|
|
set.RUnlock()
|
|
|
|
ret := &threadSafeSet{s: newThreadUnsafeSet()}
|
|
for subset := range unsafePowerSet.Iter() {
|
|
unsafeSubset := subset.(*threadUnsafeSet)
|
|
ret.Add(&threadSafeSet{s: *unsafeSubset})
|
|
}
|
|
return ret
|
|
}
|
|
|
|
func (set *threadSafeSet) Pop() interface{} {
|
|
set.Lock()
|
|
defer set.Unlock()
|
|
return set.s.Pop()
|
|
}
|
|
|
|
func (set *threadSafeSet) CartesianProduct(other Set) Set {
|
|
o := other.(*threadSafeSet)
|
|
|
|
set.RLock()
|
|
o.RLock()
|
|
|
|
unsafeCartProduct := set.s.CartesianProduct(&o.s).(*threadUnsafeSet)
|
|
ret := &threadSafeSet{s: *unsafeCartProduct}
|
|
set.RUnlock()
|
|
o.RUnlock()
|
|
return ret
|
|
}
|
|
|
|
func (set *threadSafeSet) ToSlice() []interface{} {
|
|
keys := make([]interface{}, 0, set.Cardinality())
|
|
set.RLock()
|
|
for elem := range set.s {
|
|
keys = append(keys, elem)
|
|
}
|
|
set.RUnlock()
|
|
return keys
|
|
}
|
|
|
|
func (set *threadSafeSet) MarshalJSON() ([]byte, error) {
|
|
set.RLock()
|
|
b, err := set.s.MarshalJSON()
|
|
set.RUnlock()
|
|
|
|
return b, err
|
|
}
|
|
|
|
func (set *threadSafeSet) UnmarshalJSON(p []byte) error {
|
|
set.RLock()
|
|
err := set.s.UnmarshalJSON(p)
|
|
set.RUnlock()
|
|
|
|
return err
|
|
}
|