mirror of https://github.com/ethereum/go-ethereum
all: switch out defunct set library to different one (#16873)
* keystore, ethash, eth, miner, rpc, whisperv6: tech debt with now defunct set. * whisperv5: swap out gopkg.in/fatih/set.v0 with supported setpull/17184/head
parent
eb7f901289
commit
5d30be412b
22
vendor/gopkg.in/fatih/set.v0/LICENSE.md → vendor/github.com/deckarep/golang-set/LICENSE
generated
vendored
22
vendor/gopkg.in/fatih/set.v0/LICENSE.md → vendor/github.com/deckarep/golang-set/LICENSE
generated
vendored
@ -1,20 +1,22 @@ |
||||
The MIT License (MIT) |
||||
Open Source Initiative OSI - The MIT License (MIT):Licensing |
||||
|
||||
Copyright (c) 2013 Fatih Arslan |
||||
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: |
||||
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. |
||||
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. |
@ -0,0 +1,95 @@ |
||||
[![Build Status](https://travis-ci.org/deckarep/golang-set.svg?branch=master)](https://travis-ci.org/deckarep/golang-set) |
||||
[![Go Report Card](https://goreportcard.com/badge/github.com/deckarep/golang-set)](https://goreportcard.com/report/github.com/deckarep/golang-set) |
||||
[![GoDoc](https://godoc.org/github.com/deckarep/golang-set?status.svg)](http://godoc.org/github.com/deckarep/golang-set) |
||||
|
||||
## golang-set |
||||
|
||||
|
||||
The missing set collection for the Go language. Until Go has sets built-in...use this. |
||||
|
||||
Coming from Python one of the things I miss is the superbly wonderful set collection. This is my attempt to mimic the primary features of the set from Python. |
||||
You can of course argue that there is no need for a set in Go, otherwise the creators would have added one to the standard library. To those I say simply ignore this repository |
||||
and carry-on and to the rest that find this useful please contribute in helping me make it better by: |
||||
|
||||
* Helping to make more idiomatic improvements to the code. |
||||
* Helping to increase the performance of it. ~~(So far, no attempt has been made, but since it uses a map internally, I expect it to be mostly performant.)~~ |
||||
* Helping to make the unit-tests more robust and kick-ass. |
||||
* Helping to fill in the [documentation.](http://godoc.org/github.com/deckarep/golang-set) |
||||
* Simply offering feedback and suggestions. (Positive, constructive feedback is appreciated.) |
||||
|
||||
I have to give some credit for helping seed the idea with this post on [stackoverflow.](http://programmers.stackexchange.com/questions/177428/sets-data-structure-in-golang) |
||||
|
||||
*Update* - as of 3/9/2014, you can use a compile-time generic version of this package in the [gen](http://clipperhouse.github.io/gen/) framework. This framework allows you to use the golang-set in a completely generic and type-safe way by allowing you to generate a supporting .go file based on your custom types. |
||||
|
||||
## Features (as of 9/22/2014) |
||||
|
||||
* a CartesianProduct() method has been added with unit-tests: [Read more about the cartesian product](http://en.wikipedia.org/wiki/Cartesian_product) |
||||
|
||||
## Features (as of 9/15/2014) |
||||
|
||||
* a PowerSet() method has been added with unit-tests: [Read more about the Power set](http://en.wikipedia.org/wiki/Power_set) |
||||
|
||||
## Features (as of 4/22/2014) |
||||
|
||||
* One common interface to both implementations |
||||
* Two set implementations to choose from |
||||
* a thread-safe implementation designed for concurrent use |
||||
* a non-thread-safe implementation designed for performance |
||||
* 75 benchmarks for both implementations |
||||
* 35 unit tests for both implementations |
||||
* 14 concurrent tests for the thread-safe implementation |
||||
|
||||
|
||||
|
||||
Please see the unit test file for additional usage examples. The Python set documentation will also do a better job than I can of explaining how a set typically [works.](http://docs.python.org/2/library/sets.html) Please keep in mind |
||||
however that the Python set is a built-in type and supports additional features and syntax that make it awesome. |
||||
|
||||
## Examples but not exhaustive: |
||||
|
||||
```go |
||||
requiredClasses := mapset.NewSet() |
||||
requiredClasses.Add("Cooking") |
||||
requiredClasses.Add("English") |
||||
requiredClasses.Add("Math") |
||||
requiredClasses.Add("Biology") |
||||
|
||||
scienceSlice := []interface{}{"Biology", "Chemistry"} |
||||
scienceClasses := mapset.NewSetFromSlice(scienceSlice) |
||||
|
||||
electiveClasses := mapset.NewSet() |
||||
electiveClasses.Add("Welding") |
||||
electiveClasses.Add("Music") |
||||
electiveClasses.Add("Automotive") |
||||
|
||||
bonusClasses := mapset.NewSet() |
||||
bonusClasses.Add("Go Programming") |
||||
bonusClasses.Add("Python Programming") |
||||
|
||||
//Show me all the available classes I can take |
||||
allClasses := requiredClasses.Union(scienceClasses).Union(electiveClasses).Union(bonusClasses) |
||||
fmt.Println(allClasses) //Set{Cooking, English, Math, Chemistry, Welding, Biology, Music, Automotive, Go Programming, Python Programming} |
||||
|
||||
|
||||
//Is cooking considered a science class? |
||||
fmt.Println(scienceClasses.Contains("Cooking")) //false |
||||
|
||||
//Show me all classes that are not science classes, since I hate science. |
||||
fmt.Println(allClasses.Difference(scienceClasses)) //Set{Music, Automotive, Go Programming, Python Programming, Cooking, English, Math, Welding} |
||||
|
||||
//Which science classes are also required classes? |
||||
fmt.Println(scienceClasses.Intersect(requiredClasses)) //Set{Biology} |
||||
|
||||
//How many bonus classes do you offer? |
||||
fmt.Println(bonusClasses.Cardinality()) //2 |
||||
|
||||
//Do you have the following classes? Welding, Automotive and English? |
||||
fmt.Println(allClasses.IsSuperset(mapset.NewSetFromSlice([]interface{}{"Welding", "Automotive", "English"}))) //true |
||||
``` |
||||
|
||||
Thanks! |
||||
|
||||
-Ralph |
||||
|
||||
[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/deckarep/golang-set/trend.png)](https://bitdeli.com/free "Bitdeli Badge") |
||||
|
||||
[![Analytics](https://ga-beacon.appspot.com/UA-42584447-2/deckarep/golang-set)](https://github.com/igrigorik/ga-beacon) |
@ -0,0 +1,58 @@ |
||||
/* |
||||
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 |
||||
|
||||
// Iterator defines an iterator over a Set, its C channel can be used to range over the Set's
|
||||
// elements.
|
||||
type Iterator struct { |
||||
C <-chan interface{} |
||||
stop chan struct{} |
||||
} |
||||
|
||||
// Stop stops the Iterator, no further elements will be received on C, C will be closed.
|
||||
func (i *Iterator) Stop() { |
||||
// Allows for Stop() to be called multiple times
|
||||
// (close() panics when called on already closed channel)
|
||||
defer func() { |
||||
recover() |
||||
}() |
||||
|
||||
close(i.stop) |
||||
|
||||
// Exhaust any remaining elements.
|
||||
for range i.C { |
||||
} |
||||
} |
||||
|
||||
// newIterator returns a new Iterator instance together with its item and stop channels.
|
||||
func newIterator() (*Iterator, chan<- interface{}, <-chan struct{}) { |
||||
itemChan := make(chan interface{}) |
||||
stopChan := make(chan struct{}) |
||||
return &Iterator{ |
||||
C: itemChan, |
||||
stop: stopChan, |
||||
}, itemChan, stopChan |
||||
} |
@ -0,0 +1,217 @@ |
||||
/* |
||||
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 implements a simple and generic set collection.
|
||||
// Items stored within it are unordered and unique. It supports
|
||||
// typical set operations: membership testing, intersection, union,
|
||||
// difference, symmetric difference and cloning.
|
||||
//
|
||||
// Package mapset provides two implementations of the Set
|
||||
// interface. The default implementation is safe for concurrent
|
||||
// access, but a non-thread-safe implementation is also provided for
|
||||
// programs that can benefit from the slight speed improvement and
|
||||
// that can enforce mutual exclusion through other means.
|
||||
package mapset |
||||
|
||||
// Set is the primary interface provided by the mapset package. It
|
||||
// represents an unordered set of data and a large number of
|
||||
// operations that can be applied to that set.
|
||||
type Set interface { |
||||
// Adds an element to the set. Returns whether
|
||||
// the item was added.
|
||||
Add(i interface{}) bool |
||||
|
||||
// Returns the number of elements in the set.
|
||||
Cardinality() int |
||||
|
||||
// Removes all elements from the set, leaving
|
||||
// the empty set.
|
||||
Clear() |
||||
|
||||
// Returns a clone of the set using the same
|
||||
// implementation, duplicating all keys.
|
||||
Clone() Set |
||||
|
||||
// Returns whether the given items
|
||||
// are all in the set.
|
||||
Contains(i ...interface{}) bool |
||||
|
||||
// Returns the difference between this set
|
||||
// and other. The returned set will contain
|
||||
// all elements of this set that are not also
|
||||
// elements of other.
|
||||
//
|
||||
// Note that the argument to Difference
|
||||
// must be of the same type as the receiver
|
||||
// of the method. Otherwise, Difference will
|
||||
// panic.
|
||||
Difference(other Set) Set |
||||
|
||||
// Determines if two sets are equal to each
|
||||
// other. If they have the same cardinality
|
||||
// and contain the same elements, they are
|
||||
// considered equal. The order in which
|
||||
// the elements were added is irrelevant.
|
||||
//
|
||||
// Note that the argument to Equal must be
|
||||
// of the same type as the receiver of the
|
||||
// method. Otherwise, Equal will panic.
|
||||
Equal(other Set) bool |
||||
|
||||
// Returns a new set containing only the elements
|
||||
// that exist only in both sets.
|
||||
//
|
||||
// Note that the argument to Intersect
|
||||
// must be of the same type as the receiver
|
||||
// of the method. Otherwise, Intersect will
|
||||
// panic.
|
||||
Intersect(other Set) Set |
||||
|
||||
// Determines if every element in this set is in
|
||||
// the other set but the two sets are not equal.
|
||||
//
|
||||
// Note that the argument to IsProperSubset
|
||||
// must be of the same type as the receiver
|
||||
// of the method. Otherwise, IsProperSubset
|
||||
// will panic.
|
||||
IsProperSubset(other Set) bool |
||||
|
||||
// Determines if every element in the other set
|
||||
// is in this set but the two sets are not
|
||||
// equal.
|
||||
//
|
||||
// Note that the argument to IsSuperset
|
||||
// must be of the same type as the receiver
|
||||
// of the method. Otherwise, IsSuperset will
|
||||
// panic.
|
||||
IsProperSuperset(other Set) bool |
||||
|
||||
// Determines if every element in this set is in
|
||||
// the other set.
|
||||
//
|
||||
// Note that the argument to IsSubset
|
||||
// must be of the same type as the receiver
|
||||
// of the method. Otherwise, IsSubset will
|
||||
// panic.
|
||||
IsSubset(other Set) bool |
||||
|
||||
// Determines if every element in the other set
|
||||
// is in this set.
|
||||
//
|
||||
// Note that the argument to IsSuperset
|
||||
// must be of the same type as the receiver
|
||||
// of the method. Otherwise, IsSuperset will
|
||||
// panic.
|
||||
IsSuperset(other Set) bool |
||||
|
||||
// Iterates over elements and executes the passed func against each element.
|
||||
// If passed func returns true, stop iteration at the time.
|
||||
Each(func(interface{}) bool) |
||||
|
||||
// Returns a channel of elements that you can
|
||||
// range over.
|
||||
Iter() <-chan interface{} |
||||
|
||||
// Returns an Iterator object that you can
|
||||
// use to range over the set.
|
||||
Iterator() *Iterator |
||||
|
||||
// Remove a single element from the set.
|
||||
Remove(i interface{}) |
||||
|
||||
// Provides a convenient string representation
|
||||
// of the current state of the set.
|
||||
String() string |
||||
|
||||
// Returns a new set with all elements which are
|
||||
// in either this set or the other set but not in both.
|
||||
//
|
||||
// Note that the argument to SymmetricDifference
|
||||
// must be of the same type as the receiver
|
||||
// of the method. Otherwise, SymmetricDifference
|
||||
// will panic.
|
||||
SymmetricDifference(other Set) Set |
||||
|
||||
// Returns a new set with all elements in both sets.
|
||||
//
|
||||
// Note that the argument to Union must be of the
|
||||
|
||||
// same type as the receiver of the method.
|
||||
// Otherwise, IsSuperset will panic.
|
||||
Union(other Set) Set |
||||
|
||||
// Pop removes and returns an arbitrary item from the set.
|
||||
Pop() interface{} |
||||
|
||||
// Returns all subsets of a given set (Power Set).
|
||||
PowerSet() Set |
||||
|
||||
// Returns the Cartesian Product of two sets.
|
||||
CartesianProduct(other Set) Set |
||||
|
||||
// Returns the members of the set as a slice.
|
||||
ToSlice() []interface{} |
||||
} |
||||
|
||||
// NewSet creates and returns a reference to an empty set. Operations
|
||||
// on the resulting set are thread-safe.
|
||||
func NewSet(s ...interface{}) Set { |
||||
set := newThreadSafeSet() |
||||
for _, item := range s { |
||||
set.Add(item) |
||||
} |
||||
return &set |
||||
} |
||||
|
||||
// NewSetWith creates and returns a new set with the given elements.
|
||||
// Operations on the resulting set are thread-safe.
|
||||
func NewSetWith(elts ...interface{}) Set { |
||||
return NewSetFromSlice(elts) |
||||
} |
||||
|
||||
// NewSetFromSlice creates and returns a reference to a set from an
|
||||
// existing slice. Operations on the resulting set are thread-safe.
|
||||
func NewSetFromSlice(s []interface{}) Set { |
||||
a := NewSet(s...) |
||||
return a |
||||
} |
||||
|
||||
// NewThreadUnsafeSet creates and returns a reference to an empty set.
|
||||
// Operations on the resulting set are not thread-safe.
|
||||
func NewThreadUnsafeSet() Set { |
||||
set := newThreadUnsafeSet() |
||||
return &set |
||||
} |
||||
|
||||
// NewThreadUnsafeSetFromSlice creates and returns a reference to a
|
||||
// set from an existing slice. Operations on the resulting set are
|
||||
// not thread-safe.
|
||||
func NewThreadUnsafeSetFromSlice(s []interface{}) Set { |
||||
a := NewThreadUnsafeSet() |
||||
for _, item := range s { |
||||
a.Add(item) |
||||
} |
||||
return a |
||||
} |
@ -0,0 +1,277 @@ |
||||
/* |
||||
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() |
||||
ret := set.s.PowerSet() |
||||
set.RUnlock() |
||||
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 |
||||
} |
@ -0,0 +1,337 @@ |
||||
/* |
||||
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 ( |
||||
"bytes" |
||||
"encoding/json" |
||||
"fmt" |
||||
"reflect" |
||||
"strings" |
||||
) |
||||
|
||||
type threadUnsafeSet map[interface{}]struct{} |
||||
|
||||
// An OrderedPair represents a 2-tuple of values.
|
||||
type OrderedPair struct { |
||||
First interface{} |
||||
Second interface{} |
||||
} |
||||
|
||||
func newThreadUnsafeSet() threadUnsafeSet { |
||||
return make(threadUnsafeSet) |
||||
} |
||||
|
||||
// Equal says whether two 2-tuples contain the same values in the same order.
|
||||
func (pair *OrderedPair) Equal(other OrderedPair) bool { |
||||
if pair.First == other.First && |
||||
pair.Second == other.Second { |
||||
return true |
||||
} |
||||
|
||||
return false |
||||
} |
||||
|
||||
func (set *threadUnsafeSet) Add(i interface{}) bool { |
||||
_, found := (*set)[i] |
||||
if found { |
||||
return false //False if it existed already
|
||||
} |
||||
|
||||
(*set)[i] = struct{}{} |
||||
return true |
||||
} |
||||
|
||||
func (set *threadUnsafeSet) Contains(i ...interface{}) bool { |
||||
for _, val := range i { |
||||
if _, ok := (*set)[val]; !ok { |
||||
return false |
||||
} |
||||
} |
||||
return true |
||||
} |
||||
|
||||
func (set *threadUnsafeSet) IsSubset(other Set) bool { |
||||
_ = other.(*threadUnsafeSet) |
||||
for elem := range *set { |
||||
if !other.Contains(elem) { |
||||
return false |
||||
} |
||||
} |
||||
return true |
||||
} |
||||
|
||||
func (set *threadUnsafeSet) IsProperSubset(other Set) bool { |
||||
return set.IsSubset(other) && !set.Equal(other) |
||||
} |
||||
|
||||
func (set *threadUnsafeSet) IsSuperset(other Set) bool { |
||||
return other.IsSubset(set) |
||||
} |
||||
|
||||
func (set *threadUnsafeSet) IsProperSuperset(other Set) bool { |
||||
return set.IsSuperset(other) && !set.Equal(other) |
||||
} |
||||
|
||||
func (set *threadUnsafeSet) Union(other Set) Set { |
||||
o := other.(*threadUnsafeSet) |
||||
|
||||
unionedSet := newThreadUnsafeSet() |
||||
|
||||
for elem := range *set { |
||||
unionedSet.Add(elem) |
||||
} |
||||
for elem := range *o { |
||||
unionedSet.Add(elem) |
||||
} |
||||
return &unionedSet |
||||
} |
||||
|
||||
func (set *threadUnsafeSet) Intersect(other Set) Set { |
||||
o := other.(*threadUnsafeSet) |
||||
|
||||
intersection := newThreadUnsafeSet() |
||||
// loop over smaller set
|
||||
if set.Cardinality() < other.Cardinality() { |
||||
for elem := range *set { |
||||
if other.Contains(elem) { |
||||
intersection.Add(elem) |
||||
} |
||||
} |
||||
} else { |
||||
for elem := range *o { |
||||
if set.Contains(elem) { |
||||
intersection.Add(elem) |
||||
} |
||||
} |
||||
} |
||||
return &intersection |
||||
} |
||||
|
||||
func (set *threadUnsafeSet) Difference(other Set) Set { |
||||
_ = other.(*threadUnsafeSet) |
||||
|
||||
difference := newThreadUnsafeSet() |
||||
for elem := range *set { |
||||
if !other.Contains(elem) { |
||||
difference.Add(elem) |
||||
} |
||||
} |
||||
return &difference |
||||
} |
||||
|
||||
func (set *threadUnsafeSet) SymmetricDifference(other Set) Set { |
||||
_ = other.(*threadUnsafeSet) |
||||
|
||||
aDiff := set.Difference(other) |
||||
bDiff := other.Difference(set) |
||||
return aDiff.Union(bDiff) |
||||
} |
||||
|
||||
func (set *threadUnsafeSet) Clear() { |
||||
*set = newThreadUnsafeSet() |
||||
} |
||||
|
||||
func (set *threadUnsafeSet) Remove(i interface{}) { |
||||
delete(*set, i) |
||||
} |
||||
|
||||
func (set *threadUnsafeSet) Cardinality() int { |
||||
return len(*set) |
||||
} |
||||
|
||||
func (set *threadUnsafeSet) Each(cb func(interface{}) bool) { |
||||
for elem := range *set { |
||||
if cb(elem) { |
||||
break |
||||
} |
||||
} |
||||
} |
||||
|
||||
func (set *threadUnsafeSet) Iter() <-chan interface{} { |
||||
ch := make(chan interface{}) |
||||
go func() { |
||||
for elem := range *set { |
||||
ch <- elem |
||||
} |
||||
close(ch) |
||||
}() |
||||
|
||||
return ch |
||||
} |
||||
|
||||
func (set *threadUnsafeSet) Iterator() *Iterator { |
||||
iterator, ch, stopCh := newIterator() |
||||
|
||||
go func() { |
||||
L: |
||||
for elem := range *set { |
||||
select { |
||||
case <-stopCh: |
||||
break L |
||||
case ch <- elem: |
||||
} |
||||
} |
||||
close(ch) |
||||
}() |
||||
|
||||
return iterator |
||||
} |
||||
|
||||
func (set *threadUnsafeSet) Equal(other Set) bool { |
||||
_ = other.(*threadUnsafeSet) |
||||
|
||||
if set.Cardinality() != other.Cardinality() { |
||||
return false |
||||
} |
||||
for elem := range *set { |
||||
if !other.Contains(elem) { |
||||
return false |
||||
} |
||||
} |
||||
return true |
||||
} |
||||
|
||||
func (set *threadUnsafeSet) Clone() Set { |
||||
clonedSet := newThreadUnsafeSet() |
||||
for elem := range *set { |
||||
clonedSet.Add(elem) |
||||
} |
||||
return &clonedSet |
||||
} |
||||
|
||||
func (set *threadUnsafeSet) String() string { |
||||
items := make([]string, 0, len(*set)) |
||||
|
||||
for elem := range *set { |
||||
items = append(items, fmt.Sprintf("%v", elem)) |
||||
} |
||||
return fmt.Sprintf("Set{%s}", strings.Join(items, ", ")) |
||||
} |
||||
|
||||
// String outputs a 2-tuple in the form "(A, B)".
|
||||
func (pair OrderedPair) String() string { |
||||
return fmt.Sprintf("(%v, %v)", pair.First, pair.Second) |
||||
} |
||||
|
||||
func (set *threadUnsafeSet) Pop() interface{} { |
||||
for item := range *set { |
||||
delete(*set, item) |
||||
return item |
||||
} |
||||
return nil |
||||
} |
||||
|
||||
func (set *threadUnsafeSet) PowerSet() Set { |
||||
powSet := NewThreadUnsafeSet() |
||||
nullset := newThreadUnsafeSet() |
||||
powSet.Add(&nullset) |
||||
|
||||
for es := range *set { |
||||
u := newThreadUnsafeSet() |
||||
j := powSet.Iter() |
||||
for er := range j { |
||||
p := newThreadUnsafeSet() |
||||
if reflect.TypeOf(er).Name() == "" { |
||||
k := er.(*threadUnsafeSet) |
||||
for ek := range *(k) { |
||||
p.Add(ek) |
||||
} |
||||
} else { |
||||
p.Add(er) |
||||
} |
||||
p.Add(es) |
||||
u.Add(&p) |
||||
} |
||||
|
||||
powSet = powSet.Union(&u) |
||||
} |
||||
|
||||
return powSet |
||||
} |
||||
|
||||
func (set *threadUnsafeSet) CartesianProduct(other Set) Set { |
||||
o := other.(*threadUnsafeSet) |
||||
cartProduct := NewThreadUnsafeSet() |
||||
|
||||
for i := range *set { |
||||
for j := range *o { |
||||
elem := OrderedPair{First: i, Second: j} |
||||
cartProduct.Add(elem) |
||||
} |
||||
} |
||||
|
||||
return cartProduct |
||||
} |
||||
|
||||
func (set *threadUnsafeSet) ToSlice() []interface{} { |
||||
keys := make([]interface{}, 0, set.Cardinality()) |
||||
for elem := range *set { |
||||
keys = append(keys, elem) |
||||
} |
||||
|
||||
return keys |
||||
} |
||||
|
||||
// MarshalJSON creates a JSON array from the set, it marshals all elements
|
||||
func (set *threadUnsafeSet) MarshalJSON() ([]byte, error) { |
||||
items := make([]string, 0, set.Cardinality()) |
||||
|
||||
for elem := range *set { |
||||
b, err := json.Marshal(elem) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
items = append(items, string(b)) |
||||
} |
||||
|
||||
return []byte(fmt.Sprintf("[%s]", strings.Join(items, ","))), nil |
||||
} |
||||
|
||||
// UnmarshalJSON recreates a set from a JSON array, it only decodes
|
||||
// primitive types. Numbers are decoded as json.Number.
|
||||
func (set *threadUnsafeSet) UnmarshalJSON(b []byte) error { |
||||
var i []interface{} |
||||
|
||||
d := json.NewDecoder(bytes.NewReader(b)) |
||||
d.UseNumber() |
||||
err := d.Decode(&i) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
|
||||
for _, v := range i { |
||||
switch t := v.(type) { |
||||
case []interface{}, map[string]interface{}: |
||||
continue |
||||
default: |
||||
set.Add(t) |
||||
} |
||||
} |
||||
|
||||
return nil |
||||
} |
@ -1,245 +0,0 @@ |
||||
# Set [![GoDoc](http://img.shields.io/badge/go-documentation-blue.svg?style=flat-square)](https://godoc.org/gopkg.in/fatih/set.v0) [![Build Status](http://img.shields.io/travis/fatih/set.svg?style=flat-square)](https://travis-ci.org/fatih/set) |
||||
|
||||
Set is a basic and simple, hash-based, **Set** data structure implementation |
||||
in Go (Golang). |
||||
|
||||
Set provides both threadsafe and non-threadsafe implementations of a generic |
||||
set data structure. The thread safety encompasses all operations on one set. |
||||
Operations on multiple sets are consistent in that the elements of each set |
||||
used was valid at exactly one point in time between the start and the end of |
||||
the operation. Because it's thread safe, you can use it concurrently with your |
||||
goroutines. |
||||
|
||||
For usage see examples below or click on the godoc badge. |
||||
|
||||
## Install and Usage |
||||
|
||||
Install the package with: |
||||
|
||||
```bash |
||||
go get gopkg.in/fatih/set.v0 |
||||
``` |
||||
|
||||
Import it with: |
||||
|
||||
```go |
||||
import "gopkg.in/fatih/set.v0" |
||||
``` |
||||
|
||||
and use `set` as the package name inside the code. |
||||
|
||||
## Examples |
||||
|
||||
#### Initialization of a new Set |
||||
|
||||
```go |
||||
|
||||
// create a set with zero items |
||||
s := set.New() |
||||
s := set.NewNonTS() // non thread-safe version |
||||
|
||||
// ... or with some initial values |
||||
s := set.New("istanbul", "frankfurt", 30.123, "san francisco", 1234) |
||||
s := set.NewNonTS("kenya", "ethiopia", "sumatra") |
||||
|
||||
``` |
||||
|
||||
#### Basic Operations |
||||
|
||||
```go |
||||
// add items |
||||
s.Add("istanbul") |
||||
s.Add("istanbul") // nothing happens if you add duplicate item |
||||
|
||||
// add multiple items |
||||
s.Add("ankara", "san francisco", 3.14) |
||||
|
||||
// remove item |
||||
s.Remove("frankfurt") |
||||
s.Remove("frankfurt") // nothing happes if you remove a nonexisting item |
||||
|
||||
// remove multiple items |
||||
s.Remove("barcelona", 3.14, "ankara") |
||||
|
||||
// removes an arbitary item and return it |
||||
item := s.Pop() |
||||
|
||||
// create a new copy |
||||
other := s.Copy() |
||||
|
||||
// remove all items |
||||
s.Clear() |
||||
|
||||
// number of items in the set |
||||
len := s.Size() |
||||
|
||||
// return a list of items |
||||
items := s.List() |
||||
|
||||
// string representation of set |
||||
fmt.Printf("set is %s", s.String()) |
||||
|
||||
``` |
||||
|
||||
#### Check Operations |
||||
|
||||
```go |
||||
// check for set emptiness, returns true if set is empty |
||||
s.IsEmpty() |
||||
|
||||
// check for a single item exist |
||||
s.Has("istanbul") |
||||
|
||||
// ... or for multiple items. This will return true if all of the items exist. |
||||
s.Has("istanbul", "san francisco", 3.14) |
||||
|
||||
// create two sets for the following checks... |
||||
s := s.New("1", "2", "3", "4", "5") |
||||
t := s.New("1", "2", "3") |
||||
|
||||
|
||||
// check if they are the same |
||||
if !s.IsEqual(t) { |
||||
fmt.Println("s is not equal to t") |
||||
} |
||||
|
||||
// if s contains all elements of t |
||||
if s.IsSubset(t) { |
||||
fmt.Println("t is a subset of s") |
||||
} |
||||
|
||||
// ... or if s is a superset of t |
||||
if t.IsSuperset(s) { |
||||
fmt.Println("s is a superset of t") |
||||
} |
||||
|
||||
|
||||
``` |
||||
|
||||
#### Set Operations |
||||
|
||||
|
||||
```go |
||||
// let us initialize two sets with some values |
||||
a := set.New("ankara", "berlin", "san francisco") |
||||
b := set.New("frankfurt", "berlin") |
||||
|
||||
// creates a new set with the items in a and b combined. |
||||
// [frankfurt, berlin, ankara, san francisco] |
||||
c := set.Union(a, b) |
||||
|
||||
// contains items which is in both a and b |
||||
// [berlin] |
||||
c := set.Intersection(a, b) |
||||
|
||||
// contains items which are in a but not in b |
||||
// [ankara, san francisco] |
||||
c := set.Difference(a, b) |
||||
|
||||
// contains items which are in one of either, but not in both. |
||||
// [frankfurt, ankara, san francisco] |
||||
c := set.SymmetricDifference(a, b) |
||||
|
||||
``` |
||||
|
||||
```go |
||||
// like Union but saves the result back into a. |
||||
a.Merge(b) |
||||
|
||||
// removes the set items which are in b from a and saves the result back into a. |
||||
a.Separate(b) |
||||
|
||||
``` |
||||
|
||||
#### Multiple Set Operations |
||||
|
||||
```go |
||||
a := set.New("1", "3", "4", "5") |
||||
b := set.New("2", "3", "4", "5") |
||||
c := set.New("4", "5", "6", "7") |
||||
|
||||
// creates a new set with items in a, b and c |
||||
// [1 2 3 4 5 6 7] |
||||
u := set.Union(a, b, c) |
||||
|
||||
// creates a new set with items in a but not in b and c |
||||
// [1] |
||||
u := set.Difference(a, b, c) |
||||
|
||||
// creates a new set with items that are common to a, b and c |
||||
// [5] |
||||
u := set.Intersection(a, b, c) |
||||
``` |
||||
|
||||
#### Helper methods |
||||
|
||||
The Slice functions below are a convenient way to extract or convert your Set data |
||||
into basic data types. |
||||
|
||||
|
||||
```go |
||||
// create a set of mixed types |
||||
s := set.New("ankara", "5", "8", "san francisco", 13, 21) |
||||
|
||||
|
||||
// convert s into a slice of strings (type is []string) |
||||
// [ankara 5 8 san francisco] |
||||
t := set.StringSlice(s) |
||||
|
||||
|
||||
// u contains a slice of ints (type is []int) |
||||
// [13, 21] |
||||
u := set.IntSlice(s) |
||||
|
||||
``` |
||||
|
||||
#### Concurrent safe usage |
||||
|
||||
Below is an example of a concurrent way that uses set. We call ten functions |
||||
concurrently and wait until they are finished. It basically creates a new |
||||
string for each goroutine and adds it to our set. |
||||
|
||||
```go |
||||
package main |
||||
|
||||
import ( |
||||
"fmt" |
||||
"github.com/fatih/set" |
||||
"strconv" |
||||
"sync" |
||||
) |
||||
|
||||
func main() { |
||||
var wg sync.WaitGroup // this is just for waiting until all goroutines finish |
||||
|
||||
// Initialize our thread safe Set |
||||
s := set.New() |
||||
|
||||
// Add items concurrently (item1, item2, and so on) |
||||
for i := 0; i < 10; i++ { |
||||
wg.Add(1) |
||||
go func(i int) { |
||||
item := "item" + strconv.Itoa(i) |
||||
fmt.Println("adding", item) |
||||
s.Add(item) |
||||
wg.Done() |
||||
}(i) |
||||
} |
||||
|
||||
// Wait until all concurrent calls finished and print our set |
||||
wg.Wait() |
||||
fmt.Println(s) |
||||
} |
||||
``` |
||||
|
||||
## Credits |
||||
|
||||
* [Fatih Arslan](https://github.com/fatih) |
||||
* [Arne Hormann](https://github.com/arnehormann) |
||||
* [Sam Boyer](https://github.com/sdboyer) |
||||
* [Ralph Loizzo](https://github.com/friartech) |
||||
|
||||
## License |
||||
|
||||
The MIT License (MIT) - see LICENSE.md for more details |
||||
|
@ -1,121 +0,0 @@ |
||||
// Package set provides both threadsafe and non-threadsafe implementations of
|
||||
// a generic set data structure. In the threadsafe set, safety encompasses all
|
||||
// operations on one set. Operations on multiple sets are consistent in that
|
||||
// the elements of each set used was valid at exactly one point in time
|
||||
// between the start and the end of the operation.
|
||||
package set |
||||
|
||||
// Interface is describing a Set. Sets are an unordered, unique list of values.
|
||||
type Interface interface { |
||||
New(items ...interface{}) Interface |
||||
Add(items ...interface{}) |
||||
Remove(items ...interface{}) |
||||
Pop() interface{} |
||||
Has(items ...interface{}) bool |
||||
Size() int |
||||
Clear() |
||||
IsEmpty() bool |
||||
IsEqual(s Interface) bool |
||||
IsSubset(s Interface) bool |
||||
IsSuperset(s Interface) bool |
||||
Each(func(interface{}) bool) |
||||
String() string |
||||
List() []interface{} |
||||
Copy() Interface |
||||
Merge(s Interface) |
||||
Separate(s Interface) |
||||
} |
||||
|
||||
// helpful to not write everywhere struct{}{}
|
||||
var keyExists = struct{}{} |
||||
|
||||
// Union is the merger of multiple sets. It returns a new set with all the
|
||||
// elements present in all the sets that are passed.
|
||||
//
|
||||
// The dynamic type of the returned set is determined by the first passed set's
|
||||
// implementation of the New() method.
|
||||
func Union(set1, set2 Interface, sets ...Interface) Interface { |
||||
u := set1.Copy() |
||||
set2.Each(func(item interface{}) bool { |
||||
u.Add(item) |
||||
return true |
||||
}) |
||||
for _, set := range sets { |
||||
set.Each(func(item interface{}) bool { |
||||
u.Add(item) |
||||
return true |
||||
}) |
||||
} |
||||
|
||||
return u |
||||
} |
||||
|
||||
// Difference returns a new set which contains items which are in in the first
|
||||
// set but not in the others. Unlike the Difference() method you can use this
|
||||
// function separately with multiple sets.
|
||||
func Difference(set1, set2 Interface, sets ...Interface) Interface { |
||||
s := set1.Copy() |
||||
s.Separate(set2) |
||||
for _, set := range sets { |
||||
s.Separate(set) // seperate is thread safe
|
||||
} |
||||
return s |
||||
} |
||||
|
||||
// Intersection returns a new set which contains items that only exist in all given sets.
|
||||
func Intersection(set1, set2 Interface, sets ...Interface) Interface { |
||||
all := Union(set1, set2, sets...) |
||||
result := Union(set1, set2, sets...) |
||||
|
||||
all.Each(func(item interface{}) bool { |
||||
if !set1.Has(item) || !set2.Has(item) { |
||||
result.Remove(item) |
||||
} |
||||
|
||||
for _, set := range sets { |
||||
if !set.Has(item) { |
||||
result.Remove(item) |
||||
} |
||||
} |
||||
return true |
||||
}) |
||||
return result |
||||
} |
||||
|
||||
// SymmetricDifference returns a new set which s is the difference of items which are in
|
||||
// one of either, but not in both.
|
||||
func SymmetricDifference(s Interface, t Interface) Interface { |
||||
u := Difference(s, t) |
||||
v := Difference(t, s) |
||||
return Union(u, v) |
||||
} |
||||
|
||||
// StringSlice is a helper function that returns a slice of strings of s. If
|
||||
// the set contains mixed types of items only items of type string are returned.
|
||||
func StringSlice(s Interface) []string { |
||||
slice := make([]string, 0) |
||||
for _, item := range s.List() { |
||||
v, ok := item.(string) |
||||
if !ok { |
||||
continue |
||||
} |
||||
|
||||
slice = append(slice, v) |
||||
} |
||||
return slice |
||||
} |
||||
|
||||
// IntSlice is a helper function that returns a slice of ints of s. If
|
||||
// the set contains mixed types of items only items of type int are returned.
|
||||
func IntSlice(s Interface) []int { |
||||
slice := make([]int, 0) |
||||
for _, item := range s.List() { |
||||
v, ok := item.(int) |
||||
if !ok { |
||||
continue |
||||
} |
||||
|
||||
slice = append(slice, v) |
||||
} |
||||
return slice |
||||
} |
@ -1,195 +0,0 @@ |
||||
package set |
||||
|
||||
import ( |
||||
"fmt" |
||||
"strings" |
||||
) |
||||
|
||||
// Provides a common set baseline for both threadsafe and non-ts Sets.
|
||||
type set struct { |
||||
m map[interface{}]struct{} // struct{} doesn't take up space
|
||||
} |
||||
|
||||
// SetNonTS defines a non-thread safe set data structure.
|
||||
type SetNonTS struct { |
||||
set |
||||
} |
||||
|
||||
// NewNonTS creates and initialize a new non-threadsafe Set.
|
||||
// It accepts a variable number of arguments to populate the initial set.
|
||||
// If nothing is passed a SetNonTS with zero size is created.
|
||||
func NewNonTS(items ...interface{}) *SetNonTS { |
||||
s := &SetNonTS{} |
||||
s.m = make(map[interface{}]struct{}) |
||||
|
||||
// Ensure interface compliance
|
||||
var _ Interface = s |
||||
|
||||
s.Add(items...) |
||||
return s |
||||
} |
||||
|
||||
// New creates and initalizes a new Set interface. It accepts a variable
|
||||
// number of arguments to populate the initial set. If nothing is passed a
|
||||
// zero size Set based on the struct is created.
|
||||
func (s *set) New(items ...interface{}) Interface { |
||||
return NewNonTS(items...) |
||||
} |
||||
|
||||
// Add includes the specified items (one or more) to the set. The underlying
|
||||
// Set s is modified. If passed nothing it silently returns.
|
||||
func (s *set) Add(items ...interface{}) { |
||||
if len(items) == 0 { |
||||
return |
||||
} |
||||
|
||||
for _, item := range items { |
||||
s.m[item] = keyExists |
||||
} |
||||
} |
||||
|
||||
// Remove deletes the specified items from the set. The underlying Set s is
|
||||
// modified. If passed nothing it silently returns.
|
||||
func (s *set) Remove(items ...interface{}) { |
||||
if len(items) == 0 { |
||||
return |
||||
} |
||||
|
||||
for _, item := range items { |
||||
delete(s.m, item) |
||||
} |
||||
} |
||||
|
||||
// Pop deletes and return an item from the set. The underlying Set s is
|
||||
// modified. If set is empty, nil is returned.
|
||||
func (s *set) Pop() interface{} { |
||||
for item := range s.m { |
||||
delete(s.m, item) |
||||
return item |
||||
} |
||||
return nil |
||||
} |
||||
|
||||
// Has looks for the existence of items passed. It returns false if nothing is
|
||||
// passed. For multiple items it returns true only if all of the items exist.
|
||||
func (s *set) Has(items ...interface{}) bool { |
||||
// assume checked for empty item, which not exist
|
||||
if len(items) == 0 { |
||||
return false |
||||
} |
||||
|
||||
has := true |
||||
for _, item := range items { |
||||
if _, has = s.m[item]; !has { |
||||
break |
||||
} |
||||
} |
||||
return has |
||||
} |
||||
|
||||
// Size returns the number of items in a set.
|
||||
func (s *set) Size() int { |
||||
return len(s.m) |
||||
} |
||||
|
||||
// Clear removes all items from the set.
|
||||
func (s *set) Clear() { |
||||
s.m = make(map[interface{}]struct{}) |
||||
} |
||||
|
||||
// IsEmpty reports whether the Set is empty.
|
||||
func (s *set) IsEmpty() bool { |
||||
return s.Size() == 0 |
||||
} |
||||
|
||||
// IsEqual test whether s and t are the same in size and have the same items.
|
||||
func (s *set) IsEqual(t Interface) bool { |
||||
// Force locking only if given set is threadsafe.
|
||||
if conv, ok := t.(*Set); ok { |
||||
conv.l.RLock() |
||||
defer conv.l.RUnlock() |
||||
} |
||||
|
||||
// return false if they are no the same size
|
||||
if sameSize := len(s.m) == t.Size(); !sameSize { |
||||
return false |
||||
} |
||||
|
||||
equal := true |
||||
t.Each(func(item interface{}) bool { |
||||
_, equal = s.m[item] |
||||
return equal // if false, Each() will end
|
||||
}) |
||||
|
||||
return equal |
||||
} |
||||
|
||||
// IsSubset tests whether t is a subset of s.
|
||||
func (s *set) IsSubset(t Interface) (subset bool) { |
||||
subset = true |
||||
|
||||
t.Each(func(item interface{}) bool { |
||||
_, subset = s.m[item] |
||||
return subset |
||||
}) |
||||
|
||||
return |
||||
} |
||||
|
||||
// IsSuperset tests whether t is a superset of s.
|
||||
func (s *set) IsSuperset(t Interface) bool { |
||||
return t.IsSubset(s) |
||||
} |
||||
|
||||
// Each traverses the items in the Set, calling the provided function for each
|
||||
// set member. Traversal will continue until all items in the Set have been
|
||||
// visited, or if the closure returns false.
|
||||
func (s *set) Each(f func(item interface{}) bool) { |
||||
for item := range s.m { |
||||
if !f(item) { |
||||
break |
||||
} |
||||
} |
||||
} |
||||
|
||||
// String returns a string representation of s
|
||||
func (s *set) String() string { |
||||
t := make([]string, 0, len(s.List())) |
||||
for _, item := range s.List() { |
||||
t = append(t, fmt.Sprintf("%v", item)) |
||||
} |
||||
|
||||
return fmt.Sprintf("[%s]", strings.Join(t, ", ")) |
||||
} |
||||
|
||||
// List returns a slice of all items. There is also StringSlice() and
|
||||
// IntSlice() methods for returning slices of type string or int.
|
||||
func (s *set) List() []interface{} { |
||||
list := make([]interface{}, 0, len(s.m)) |
||||
|
||||
for item := range s.m { |
||||
list = append(list, item) |
||||
} |
||||
|
||||
return list |
||||
} |
||||
|
||||
// Copy returns a new Set with a copy of s.
|
||||
func (s *set) Copy() Interface { |
||||
return NewNonTS(s.List()...) |
||||
} |
||||
|
||||
// Merge is like Union, however it modifies the current set it's applied on
|
||||
// with the given t set.
|
||||
func (s *set) Merge(t Interface) { |
||||
t.Each(func(item interface{}) bool { |
||||
s.m[item] = keyExists |
||||
return true |
||||
}) |
||||
} |
||||
|
||||
// it's not the opposite of Merge.
|
||||
// Separate removes the set items containing in t from set s. Please aware that
|
||||
func (s *set) Separate(t Interface) { |
||||
s.Remove(t.List()...) |
||||
} |
@ -1,200 +0,0 @@ |
||||
package set |
||||
|
||||
import ( |
||||
"sync" |
||||
) |
||||
|
||||
// Set defines a thread safe set data structure.
|
||||
type Set struct { |
||||
set |
||||
l sync.RWMutex // we name it because we don't want to expose it
|
||||
} |
||||
|
||||
// New creates and initialize a new Set. It's accept a variable number of
|
||||
// arguments to populate the initial set. If nothing passed a Set with zero
|
||||
// size is created.
|
||||
func New(items ...interface{}) *Set { |
||||
s := &Set{} |
||||
s.m = make(map[interface{}]struct{}) |
||||
|
||||
// Ensure interface compliance
|
||||
var _ Interface = s |
||||
|
||||
s.Add(items...) |
||||
return s |
||||
} |
||||
|
||||
// New creates and initalizes a new Set interface. It accepts a variable
|
||||
// number of arguments to populate the initial set. If nothing is passed a
|
||||
// zero size Set based on the struct is created.
|
||||
func (s *Set) New(items ...interface{}) Interface { |
||||
return New(items...) |
||||
} |
||||
|
||||
// Add includes the specified items (one or more) to the set. The underlying
|
||||
// Set s is modified. If passed nothing it silently returns.
|
||||
func (s *Set) Add(items ...interface{}) { |
||||
if len(items) == 0 { |
||||
return |
||||
} |
||||
|
||||
s.l.Lock() |
||||
defer s.l.Unlock() |
||||
|
||||
for _, item := range items { |
||||
s.m[item] = keyExists |
||||
} |
||||
} |
||||
|
||||
// Remove deletes the specified items from the set. The underlying Set s is
|
||||
// modified. If passed nothing it silently returns.
|
||||
func (s *Set) Remove(items ...interface{}) { |
||||
if len(items) == 0 { |
||||
return |
||||
} |
||||
|
||||
s.l.Lock() |
||||
defer s.l.Unlock() |
||||
|
||||
for _, item := range items { |
||||
delete(s.m, item) |
||||
} |
||||
} |
||||
|
||||
// Pop deletes and return an item from the set. The underlying Set s is
|
||||
// modified. If set is empty, nil is returned.
|
||||
func (s *Set) Pop() interface{} { |
||||
s.l.RLock() |
||||
for item := range s.m { |
||||
s.l.RUnlock() |
||||
s.l.Lock() |
||||
delete(s.m, item) |
||||
s.l.Unlock() |
||||
return item |
||||
} |
||||
s.l.RUnlock() |
||||
return nil |
||||
} |
||||
|
||||
// Has looks for the existence of items passed. It returns false if nothing is
|
||||
// passed. For multiple items it returns true only if all of the items exist.
|
||||
func (s *Set) Has(items ...interface{}) bool { |
||||
// assume checked for empty item, which not exist
|
||||
if len(items) == 0 { |
||||
return false |
||||
} |
||||
|
||||
s.l.RLock() |
||||
defer s.l.RUnlock() |
||||
|
||||
has := true |
||||
for _, item := range items { |
||||
if _, has = s.m[item]; !has { |
||||
break |
||||
} |
||||
} |
||||
return has |
||||
} |
||||
|
||||
// Size returns the number of items in a set.
|
||||
func (s *Set) Size() int { |
||||
s.l.RLock() |
||||
defer s.l.RUnlock() |
||||
|
||||
l := len(s.m) |
||||
return l |
||||
} |
||||
|
||||
// Clear removes all items from the set.
|
||||
func (s *Set) Clear() { |
||||
s.l.Lock() |
||||
defer s.l.Unlock() |
||||
|
||||
s.m = make(map[interface{}]struct{}) |
||||
} |
||||
|
||||
// IsEqual test whether s and t are the same in size and have the same items.
|
||||
func (s *Set) IsEqual(t Interface) bool { |
||||
s.l.RLock() |
||||
defer s.l.RUnlock() |
||||
|
||||
// Force locking only if given set is threadsafe.
|
||||
if conv, ok := t.(*Set); ok { |
||||
conv.l.RLock() |
||||
defer conv.l.RUnlock() |
||||
} |
||||
|
||||
// return false if they are no the same size
|
||||
if sameSize := len(s.m) == t.Size(); !sameSize { |
||||
return false |
||||
} |
||||
|
||||
equal := true |
||||
t.Each(func(item interface{}) bool { |
||||
_, equal = s.m[item] |
||||
return equal // if false, Each() will end
|
||||
}) |
||||
|
||||
return equal |
||||
} |
||||
|
||||
// IsSubset tests whether t is a subset of s.
|
||||
func (s *Set) IsSubset(t Interface) (subset bool) { |
||||
s.l.RLock() |
||||
defer s.l.RUnlock() |
||||
|
||||
subset = true |
||||
|
||||
t.Each(func(item interface{}) bool { |
||||
_, subset = s.m[item] |
||||
return subset |
||||
}) |
||||
|
||||
return |
||||
} |
||||
|
||||
// Each traverses the items in the Set, calling the provided function for each
|
||||
// set member. Traversal will continue until all items in the Set have been
|
||||
// visited, or if the closure returns false.
|
||||
func (s *Set) Each(f func(item interface{}) bool) { |
||||
s.l.RLock() |
||||
defer s.l.RUnlock() |
||||
|
||||
for item := range s.m { |
||||
if !f(item) { |
||||
break |
||||
} |
||||
} |
||||
} |
||||
|
||||
// List returns a slice of all items. There is also StringSlice() and
|
||||
// IntSlice() methods for returning slices of type string or int.
|
||||
func (s *Set) List() []interface{} { |
||||
s.l.RLock() |
||||
defer s.l.RUnlock() |
||||
|
||||
list := make([]interface{}, 0, len(s.m)) |
||||
|
||||
for item := range s.m { |
||||
list = append(list, item) |
||||
} |
||||
|
||||
return list |
||||
} |
||||
|
||||
// Copy returns a new Set with a copy of s.
|
||||
func (s *Set) Copy() Interface { |
||||
return New(s.List()...) |
||||
} |
||||
|
||||
// Merge is like Union, however it modifies the current set it's applied on
|
||||
// with the given t set.
|
||||
func (s *Set) Merge(t Interface) { |
||||
s.l.Lock() |
||||
defer s.l.Unlock() |
||||
|
||||
t.Each(func(item interface{}) bool { |
||||
s.m[item] = keyExists |
||||
return true |
||||
}) |
||||
} |
Loading…
Reference in new issue