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 |
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 |
this software and associated documentation files (the "Software"), to deal in |
||||||
the Software without restriction, including without limitation the rights to |
the Software without restriction, including without limitation the rights to |
||||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of |
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies |
||||||
the Software, and to permit persons to whom the Software is furnished to do so, |
of the Software, and to permit persons to whom the Software is furnished to do |
||||||
subject to the following conditions: |
so, subject to the following conditions: |
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all |
The above copyright notice and this permission notice shall be included in all |
||||||
copies or substantial portions of the Software. |
copies or substantial portions of the Software. |
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS |
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR |
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
||||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER |
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN |
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
||||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
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