Updating Godep to pull in Set functionality

Signed-off-by: Madhu Venugopal <madhu@docker.com>
This commit is contained in:
Madhu Venugopal 2015-05-20 16:39:56 -07:00
parent 481568035f
commit ef1293ce5a
11 changed files with 2581 additions and 2 deletions

View file

@ -20,6 +20,11 @@
"Comment": "v2.0.0-7-g73a8ef7",
"Rev": "73a8ef737e8ea002281a28b4cb92a1de121ad4c6"
},
{
"ImportPath": "github.com/deckarep/golang-set",
"Comment": "v1-26-gef32fa3",
"Rev": "ef32fa3046d9f249d399f98ebaf9be944430fd1d"
},
{
"ImportPath": "github.com/docker/docker/pkg/homedir",
"Comment": "v1.4.1-3479-ga9172f5",
@ -92,8 +97,8 @@
{
"ImportPath": "github.com/gorilla/mux",
"Rev": "8096f47503459bcc74d1f4c487b7e6e42e5746b5"
},
{
},
{
"ImportPath": "github.com/hashicorp/consul/api",
"Comment": "v0.5.0rc1-66-g954aec6",
"Rev": "954aec66231b79c161a4122b023fbcad13047f79"

View file

@ -0,0 +1,22 @@
# Compiled Object files, Static and Dynamic libs (Shared Objects)
*.o
*.a
*.so
# Folders
_obj
_test
# Architecture specific extensions/prefixes
*.[568vq]
[568vq].out
*.cgo1.go
*.cgo2.c
_cgo_defun.c
_cgo_gotypes.go
_cgo_export.*
_testmain.go
*.exe

View file

@ -0,0 +1,9 @@
language: go
go:
- 1.2
script:
- go test ./...
#- go test -race ./...

View file

@ -0,0 +1,22 @@
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.

View file

@ -0,0 +1,94 @@
[![Build Status](https://travis-ci.org/deckarep/golang-set.png?branch=master)](https://travis-ci.org/deckarep/golang-set)
[![GoDoc](https://godoc.org/github.com/deckarep/golang-set?status.png)](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 CartesionProduct() method has been added with unit-tests: [Read more about the cartesion 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)

View file

@ -0,0 +1,523 @@
package mapset
import (
"math/rand"
"testing"
)
func nrand(n int) []int {
i := make([]int, n)
for ind := range i {
i[ind] = rand.Int()
}
return i
}
func toInterfaces(i []int) []interface{} {
ifs := make([]interface{}, len(i))
for ind, v := range i {
ifs[ind] = v
}
return ifs
}
func benchAdd(b *testing.B, s Set) {
nums := nrand(b.N)
b.ResetTimer()
for _, v := range nums {
s.Add(v)
}
}
func BenchmarkAddSafe(b *testing.B) {
benchAdd(b, NewSet())
}
func BenchmarkAddUnsafe(b *testing.B) {
benchAdd(b, NewThreadUnsafeSet())
}
func benchRemove(b *testing.B, s Set) {
nums := nrand(b.N)
for _, v := range nums {
s.Add(v)
}
b.ResetTimer()
for _, v := range nums {
s.Remove(v)
}
}
func BenchmarkRemoveSafe(b *testing.B) {
benchRemove(b, NewSet())
}
func BenchmarkRemoveUnsafe(b *testing.B) {
benchRemove(b, NewThreadUnsafeSet())
}
func benchCardinality(b *testing.B, s Set) {
for i := 0; i < b.N; i++ {
s.Cardinality()
}
}
func BenchmarkCardinalitySafe(b *testing.B) {
benchCardinality(b, NewSet())
}
func BenchmarkCardinalityUnsafe(b *testing.B) {
benchCardinality(b, NewThreadUnsafeSet())
}
func benchClear(b *testing.B, s Set) {
b.ResetTimer()
for i := 0; i < b.N; i++ {
s.Clear()
}
}
func BenchmarkClearSafe(b *testing.B) {
benchClear(b, NewSet())
}
func BenchmarkClearUnsafe(b *testing.B) {
benchClear(b, NewThreadUnsafeSet())
}
func benchClone(b *testing.B, n int, s Set) {
nums := toInterfaces(nrand(n))
for _, v := range nums {
s.Add(v)
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
s.Clone()
}
}
func BenchmarkClone1Safe(b *testing.B) {
benchClone(b, 1, NewSet())
}
func BenchmarkClone1Unsafe(b *testing.B) {
benchClone(b, 1, NewThreadUnsafeSet())
}
func BenchmarkClone10Safe(b *testing.B) {
benchClone(b, 10, NewSet())
}
func BenchmarkClone10Unsafe(b *testing.B) {
benchClone(b, 10, NewThreadUnsafeSet())
}
func BenchmarkClone100Safe(b *testing.B) {
benchClone(b, 100, NewSet())
}
func BenchmarkClone100Unsafe(b *testing.B) {
benchClone(b, 100, NewThreadUnsafeSet())
}
func benchContains(b *testing.B, n int, s Set) {
nums := toInterfaces(nrand(n))
for _, v := range nums {
s.Add(v)
}
nums[n-1] = -1 // Definitely not in s
b.ResetTimer()
for i := 0; i < b.N; i++ {
s.Contains(nums...)
}
}
func BenchmarkContains1Safe(b *testing.B) {
benchContains(b, 1, NewSet())
}
func BenchmarkContains1Unsafe(b *testing.B) {
benchContains(b, 1, NewThreadUnsafeSet())
}
func BenchmarkContains10Safe(b *testing.B) {
benchContains(b, 10, NewSet())
}
func BenchmarkContains10Unsafe(b *testing.B) {
benchContains(b, 10, NewThreadUnsafeSet())
}
func BenchmarkContains100Safe(b *testing.B) {
benchContains(b, 100, NewSet())
}
func BenchmarkContains100Unsafe(b *testing.B) {
benchContains(b, 100, NewThreadUnsafeSet())
}
func benchEqual(b *testing.B, n int, s, t Set) {
nums := nrand(n)
for _, v := range nums {
s.Add(v)
t.Add(v)
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
s.Equal(t)
}
}
func BenchmarkEqual1Safe(b *testing.B) {
benchEqual(b, 1, NewSet(), NewSet())
}
func BenchmarkEqual1Unsafe(b *testing.B) {
benchEqual(b, 1, NewThreadUnsafeSet(), NewThreadUnsafeSet())
}
func BenchmarkEqual10Safe(b *testing.B) {
benchEqual(b, 10, NewSet(), NewSet())
}
func BenchmarkEqual10Unsafe(b *testing.B) {
benchEqual(b, 10, NewThreadUnsafeSet(), NewThreadUnsafeSet())
}
func BenchmarkEqual100Safe(b *testing.B) {
benchEqual(b, 100, NewSet(), NewSet())
}
func BenchmarkEqual100Unsafe(b *testing.B) {
benchEqual(b, 100, NewThreadUnsafeSet(), NewThreadUnsafeSet())
}
func benchDifference(b *testing.B, n int, s, t Set) {
nums := nrand(n)
for _, v := range nums {
s.Add(v)
}
for _, v := range nums[:n/2] {
t.Add(v)
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
s.Difference(t)
}
}
func benchIsSubset(b *testing.B, n int, s, t Set) {
nums := nrand(n)
for _, v := range nums {
s.Add(v)
t.Add(v)
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
s.IsSubset(t)
}
}
func BenchmarkIsSubset1Safe(b *testing.B) {
benchIsSubset(b, 1, NewSet(), NewSet())
}
func BenchmarkIsSubset1Unsafe(b *testing.B) {
benchIsSubset(b, 1, NewThreadUnsafeSet(), NewThreadUnsafeSet())
}
func BenchmarkIsSubset10Safe(b *testing.B) {
benchIsSubset(b, 10, NewSet(), NewSet())
}
func BenchmarkIsSubset10Unsafe(b *testing.B) {
benchIsSubset(b, 10, NewThreadUnsafeSet(), NewThreadUnsafeSet())
}
func BenchmarkIsSubset100Safe(b *testing.B) {
benchIsSubset(b, 100, NewSet(), NewSet())
}
func BenchmarkIsSubset100Unsafe(b *testing.B) {
benchIsSubset(b, 100, NewThreadUnsafeSet(), NewThreadUnsafeSet())
}
func benchIsSuperset(b *testing.B, n int, s, t Set) {
nums := nrand(n)
for _, v := range nums {
s.Add(v)
t.Add(v)
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
s.IsSuperset(t)
}
}
func BenchmarkIsSuperset1Safe(b *testing.B) {
benchIsSuperset(b, 1, NewSet(), NewSet())
}
func BenchmarkIsSuperset1Unsafe(b *testing.B) {
benchIsSuperset(b, 1, NewThreadUnsafeSet(), NewThreadUnsafeSet())
}
func BenchmarkIsSuperset10Safe(b *testing.B) {
benchIsSuperset(b, 10, NewSet(), NewSet())
}
func BenchmarkIsSuperset10Unsafe(b *testing.B) {
benchIsSuperset(b, 10, NewThreadUnsafeSet(), NewThreadUnsafeSet())
}
func BenchmarkIsSuperset100Safe(b *testing.B) {
benchIsSuperset(b, 100, NewSet(), NewSet())
}
func BenchmarkIsSuperset100Unsafe(b *testing.B) {
benchIsSuperset(b, 100, NewThreadUnsafeSet(), NewThreadUnsafeSet())
}
func BenchmarkDifference1Safe(b *testing.B) {
benchDifference(b, 1, NewSet(), NewSet())
}
func BenchmarkDifference1Unsafe(b *testing.B) {
benchDifference(b, 1, NewThreadUnsafeSet(), NewThreadUnsafeSet())
}
func BenchmarkDifference10Safe(b *testing.B) {
benchDifference(b, 10, NewSet(), NewSet())
}
func BenchmarkDifference10Unsafe(b *testing.B) {
benchDifference(b, 10, NewThreadUnsafeSet(), NewThreadUnsafeSet())
}
func BenchmarkDifference100Safe(b *testing.B) {
benchDifference(b, 100, NewSet(), NewSet())
}
func BenchmarkDifference100Unsafe(b *testing.B) {
benchDifference(b, 100, NewThreadUnsafeSet(), NewThreadUnsafeSet())
}
func benchIntersect(b *testing.B, n int, s, t Set) {
nums := nrand(int(float64(n) * float64(1.5)))
for _, v := range nums[:n] {
s.Add(v)
}
for _, v := range nums[n/2:] {
t.Add(v)
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
s.Intersect(t)
}
}
func BenchmarkIntersect1Safe(b *testing.B) {
benchIntersect(b, 1, NewSet(), NewSet())
}
func BenchmarkIntersect1Unsafe(b *testing.B) {
benchIntersect(b, 1, NewThreadUnsafeSet(), NewThreadUnsafeSet())
}
func BenchmarkIntersect10Safe(b *testing.B) {
benchIntersect(b, 10, NewSet(), NewSet())
}
func BenchmarkIntersect10Unsafe(b *testing.B) {
benchIntersect(b, 10, NewThreadUnsafeSet(), NewThreadUnsafeSet())
}
func BenchmarkIntersect100Safe(b *testing.B) {
benchIntersect(b, 100, NewSet(), NewSet())
}
func BenchmarkIntersect100Unsafe(b *testing.B) {
benchIntersect(b, 100, NewThreadUnsafeSet(), NewThreadUnsafeSet())
}
func benchSymmetricDifference(b *testing.B, n int, s, t Set) {
nums := nrand(int(float64(n) * float64(1.5)))
for _, v := range nums[:n] {
s.Add(v)
}
for _, v := range nums[n/2:] {
t.Add(v)
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
s.SymmetricDifference(t)
}
}
func BenchmarkSymmetricDifference1Safe(b *testing.B) {
benchSymmetricDifference(b, 1, NewSet(), NewSet())
}
func BenchmarkSymmetricDifference1Unsafe(b *testing.B) {
benchSymmetricDifference(b, 1, NewThreadUnsafeSet(), NewThreadUnsafeSet())
}
func BenchmarkSymmetricDifference10Safe(b *testing.B) {
benchSymmetricDifference(b, 10, NewSet(), NewSet())
}
func BenchmarkSymmetricDifference10Unsafe(b *testing.B) {
benchSymmetricDifference(b, 10, NewThreadUnsafeSet(), NewThreadUnsafeSet())
}
func BenchmarkSymmetricDifference100Safe(b *testing.B) {
benchSymmetricDifference(b, 100, NewSet(), NewSet())
}
func BenchmarkSymmetricDifference100Unsafe(b *testing.B) {
benchSymmetricDifference(b, 100, NewThreadUnsafeSet(), NewThreadUnsafeSet())
}
func benchUnion(b *testing.B, n int, s, t Set) {
nums := nrand(n)
for _, v := range nums[:n/2] {
s.Add(v)
}
for _, v := range nums[n/2:] {
t.Add(v)
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
s.Union(t)
}
}
func BenchmarkUnion1Safe(b *testing.B) {
benchUnion(b, 1, NewSet(), NewSet())
}
func BenchmarkUnion1Unsafe(b *testing.B) {
benchUnion(b, 1, NewThreadUnsafeSet(), NewThreadUnsafeSet())
}
func BenchmarkUnion10Safe(b *testing.B) {
benchUnion(b, 10, NewSet(), NewSet())
}
func BenchmarkUnion10Unsafe(b *testing.B) {
benchUnion(b, 10, NewThreadUnsafeSet(), NewThreadUnsafeSet())
}
func BenchmarkUnion100Safe(b *testing.B) {
benchUnion(b, 100, NewSet(), NewSet())
}
func BenchmarkUnion100Unsafe(b *testing.B) {
benchUnion(b, 100, NewThreadUnsafeSet(), NewThreadUnsafeSet())
}
func benchIter(b *testing.B, n int, s Set) {
nums := nrand(n)
for _, v := range nums {
s.Add(v)
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
c := s.Iter()
for _ = range c {
}
}
}
func BenchmarkIter1Safe(b *testing.B) {
benchIter(b, 1, NewSet())
}
func BenchmarkIter1Unsafe(b *testing.B) {
benchIter(b, 1, NewThreadUnsafeSet())
}
func BenchmarkIter10Safe(b *testing.B) {
benchIter(b, 10, NewSet())
}
func BenchmarkIter10Unsafe(b *testing.B) {
benchIter(b, 10, NewThreadUnsafeSet())
}
func BenchmarkIter100Safe(b *testing.B) {
benchIter(b, 100, NewSet())
}
func BenchmarkIter100Unsafe(b *testing.B) {
benchIter(b, 100, NewThreadUnsafeSet())
}
func benchString(b *testing.B, n int, s Set) {
nums := nrand(n)
for _, v := range nums {
s.Add(v)
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
s.String()
}
}
func BenchmarkString1Safe(b *testing.B) {
benchString(b, 1, NewSet())
}
func BenchmarkString1Unsafe(b *testing.B) {
benchString(b, 1, NewThreadUnsafeSet())
}
func BenchmarkString10Safe(b *testing.B) {
benchString(b, 10, NewSet())
}
func BenchmarkString10Unsafe(b *testing.B) {
benchString(b, 10, NewThreadUnsafeSet())
}
func BenchmarkString100Safe(b *testing.B) {
benchString(b, 100, NewSet())
}
func BenchmarkString100Unsafe(b *testing.B) {
benchString(b, 100, NewThreadUnsafeSet())
}
func benchToSlice(b *testing.B, s Set) {
nums := nrand(b.N)
for _, v := range nums {
s.Add(v)
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
s.ToSlice()
}
}
func BenchmarkToSliceSafe(b *testing.B) {
benchToSlice(b, NewSet())
}
func BenchmarkToSliceUnsafe(b *testing.B) {
benchToSlice(b, NewThreadUnsafeSet())
}

View file

@ -0,0 +1,168 @@
/*
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. The default
// implementation is safe for concurrent access. There is a non-threadsafe
// implementation which is slightly more performant.
package mapset
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 emtpy 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 the other set
// is in this 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 this set is in
// the other 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
// Returns a channel of elements that you can
// range over.
Iter() <-chan interface{}
// 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
// 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{}
}
// Creates and returns a reference to an empty set.
func NewSet() Set {
set := newThreadSafeSet()
return &set
}
// Creates and returns a reference to a set from an existing slice
func NewSetFromSlice(s []interface{}) Set {
a := NewSet()
for _, item := range s {
a.Add(item)
}
return a
}
func NewThreadUnsafeSet() Set {
set := newThreadUnsafeSet()
return &set
}
func NewThreadUnsafeSetFromSlice(s []interface{}) Set {
a := NewThreadUnsafeSet()
for _, item := range s {
a.Add(item)
}
return a
}

View file

@ -0,0 +1,910 @@
/*
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 "testing"
func makeSet(ints []int) Set {
set := NewSet()
for _, i := range ints {
set.Add(i)
}
return set
}
func makeUnsafeSet(ints []int) Set {
set := NewThreadUnsafeSet()
for _, i := range ints {
set.Add(i)
}
return set
}
func Test_NewSet(t *testing.T) {
a := NewSet()
if a.Cardinality() != 0 {
t.Error("NewSet should start out as an empty set")
}
}
func Test_NewUnsafeSet(t *testing.T) {
a := NewThreadUnsafeSet()
if a.Cardinality() != 0 {
t.Error("NewSet should start out as an empty set")
}
}
func Test_AddSet(t *testing.T) {
a := makeSet([]int{1, 2, 3})
if a.Cardinality() != 3 {
t.Error("AddSet does not have a size of 3 even though 3 items were added to a new set")
}
}
func Test_AddUnsafeSet(t *testing.T) {
a := makeUnsafeSet([]int{1, 2, 3})
if a.Cardinality() != 3 {
t.Error("AddSet does not have a size of 3 even though 3 items were added to a new set")
}
}
func Test_AddSetNoDuplicate(t *testing.T) {
a := makeSet([]int{7, 5, 3, 7})
if a.Cardinality() != 3 {
t.Error("AddSetNoDuplicate set should have 3 elements since 7 is a duplicate")
}
if !(a.Contains(7) && a.Contains(5) && a.Contains(3)) {
t.Error("AddSetNoDuplicate set should have a 7, 5, and 3 in it.")
}
}
func Test_AddUnsafeSetNoDuplicate(t *testing.T) {
a := makeUnsafeSet([]int{7, 5, 3, 7})
if a.Cardinality() != 3 {
t.Error("AddSetNoDuplicate set should have 3 elements since 7 is a duplicate")
}
if !(a.Contains(7) && a.Contains(5) && a.Contains(3)) {
t.Error("AddSetNoDuplicate set should have a 7, 5, and 3 in it.")
}
}
func Test_RemoveSet(t *testing.T) {
a := makeSet([]int{6, 3, 1})
a.Remove(3)
if a.Cardinality() != 2 {
t.Error("RemoveSet should only have 2 items in the set")
}
if !(a.Contains(6) && a.Contains(1)) {
t.Error("RemoveSet should have only items 6 and 1 in the set")
}
a.Remove(6)
a.Remove(1)
if a.Cardinality() != 0 {
t.Error("RemoveSet should be an empty set after removing 6 and 1")
}
}
func Test_RemoveUnsafeSet(t *testing.T) {
a := makeUnsafeSet([]int{6, 3, 1})
a.Remove(3)
if a.Cardinality() != 2 {
t.Error("RemoveSet should only have 2 items in the set")
}
if !(a.Contains(6) && a.Contains(1)) {
t.Error("RemoveSet should have only items 6 and 1 in the set")
}
a.Remove(6)
a.Remove(1)
if a.Cardinality() != 0 {
t.Error("RemoveSet should be an empty set after removing 6 and 1")
}
}
func Test_ContainsSet(t *testing.T) {
a := NewSet()
a.Add(71)
if !a.Contains(71) {
t.Error("ContainsSet should contain 71")
}
a.Remove(71)
if a.Contains(71) {
t.Error("ContainsSet should not contain 71")
}
a.Add(13)
a.Add(7)
a.Add(1)
if !(a.Contains(13) && a.Contains(7) && a.Contains(1)) {
t.Error("ContainsSet should contain 13, 7, 1")
}
}
func Test_ContainsUnsafeSet(t *testing.T) {
a := NewThreadUnsafeSet()
a.Add(71)
if !a.Contains(71) {
t.Error("ContainsSet should contain 71")
}
a.Remove(71)
if a.Contains(71) {
t.Error("ContainsSet should not contain 71")
}
a.Add(13)
a.Add(7)
a.Add(1)
if !(a.Contains(13) && a.Contains(7) && a.Contains(1)) {
t.Error("ContainsSet should contain 13, 7, 1")
}
}
func Test_ContainsMultipleSet(t *testing.T) {
a := makeSet([]int{8, 6, 7, 5, 3, 0, 9})
if !a.Contains(8, 6, 7, 5, 3, 0, 9) {
t.Error("ContainsAll should contain Jenny's phone number")
}
if a.Contains(8, 6, 11, 5, 3, 0, 9) {
t.Error("ContainsAll should not have all of these numbers")
}
}
func Test_ContainsMultipleUnsafeSet(t *testing.T) {
a := makeUnsafeSet([]int{8, 6, 7, 5, 3, 0, 9})
if !a.Contains(8, 6, 7, 5, 3, 0, 9) {
t.Error("ContainsAll should contain Jenny's phone number")
}
if a.Contains(8, 6, 11, 5, 3, 0, 9) {
t.Error("ContainsAll should not have all of these numbers")
}
}
func Test_ClearSet(t *testing.T) {
a := makeSet([]int{2, 5, 9, 10})
a.Clear()
if a.Cardinality() != 0 {
t.Error("ClearSet should be an empty set")
}
}
func Test_ClearUnsafeSet(t *testing.T) {
a := makeUnsafeSet([]int{2, 5, 9, 10})
a.Clear()
if a.Cardinality() != 0 {
t.Error("ClearSet should be an empty set")
}
}
func Test_CardinalitySet(t *testing.T) {
a := NewSet()
if a.Cardinality() != 0 {
t.Error("set should be an empty set")
}
a.Add(1)
if a.Cardinality() != 1 {
t.Error("set should have a size of 1")
}
a.Remove(1)
if a.Cardinality() != 0 {
t.Error("set should be an empty set")
}
a.Add(9)
if a.Cardinality() != 1 {
t.Error("set should have a size of 1")
}
a.Clear()
if a.Cardinality() != 0 {
t.Error("set should have a size of 1")
}
}
func Test_CardinalityUnsafeSet(t *testing.T) {
a := NewThreadUnsafeSet()
if a.Cardinality() != 0 {
t.Error("set should be an empty set")
}
a.Add(1)
if a.Cardinality() != 1 {
t.Error("set should have a size of 1")
}
a.Remove(1)
if a.Cardinality() != 0 {
t.Error("set should be an empty set")
}
a.Add(9)
if a.Cardinality() != 1 {
t.Error("set should have a size of 1")
}
a.Clear()
if a.Cardinality() != 0 {
t.Error("set should have a size of 1")
}
}
func Test_SetIsSubset(t *testing.T) {
a := makeSet([]int{1, 2, 3, 5, 7})
b := NewSet()
b.Add(3)
b.Add(5)
b.Add(7)
if !b.IsSubset(a) {
t.Error("set b should be a subset of set a")
}
b.Add(72)
if b.IsSubset(a) {
t.Error("set b should not be a subset of set a because it contains 72 which is not in the set of a")
}
}
func Test_UnsafeSetIsSubset(t *testing.T) {
a := makeUnsafeSet([]int{1, 2, 3, 5, 7})
b := NewThreadUnsafeSet()
b.Add(3)
b.Add(5)
b.Add(7)
if !b.IsSubset(a) {
t.Error("set b should be a subset of set a")
}
b.Add(72)
if b.IsSubset(a) {
t.Error("set b should not be a subset of set a because it contains 72 which is not in the set of a")
}
}
func Test_SetIsSuperSet(t *testing.T) {
a := NewSet()
a.Add(9)
a.Add(5)
a.Add(2)
a.Add(1)
a.Add(11)
b := NewSet()
b.Add(5)
b.Add(2)
b.Add(11)
if !a.IsSuperset(b) {
t.Error("set a should be a superset of set b")
}
b.Add(42)
if a.IsSuperset(b) {
t.Error("set a should not be a superset of set b because set a has a 42")
}
}
func Test_UnsafeSetIsSuperSet(t *testing.T) {
a := NewThreadUnsafeSet()
a.Add(9)
a.Add(5)
a.Add(2)
a.Add(1)
a.Add(11)
b := NewThreadUnsafeSet()
b.Add(5)
b.Add(2)
b.Add(11)
if !a.IsSuperset(b) {
t.Error("set a should be a superset of set b")
}
b.Add(42)
if a.IsSuperset(b) {
t.Error("set a should not be a superset of set b because set a has a 42")
}
}
func Test_SetUnion(t *testing.T) {
a := NewSet()
b := NewSet()
b.Add(1)
b.Add(2)
b.Add(3)
b.Add(4)
b.Add(5)
c := a.Union(b)
if c.Cardinality() != 5 {
t.Error("set c is unioned with an empty set and therefore should have 5 elements in it")
}
d := NewSet()
d.Add(10)
d.Add(14)
d.Add(0)
e := c.Union(d)
if e.Cardinality() != 8 {
t.Error("set e should should have 8 elements in it after being unioned with set c to d")
}
f := NewSet()
f.Add(14)
f.Add(3)
g := f.Union(e)
if g.Cardinality() != 8 {
t.Error("set g should still ahve 8 elements in it after being unioned with set f that has duplicates")
}
}
func Test_UnsafeSetUnion(t *testing.T) {
a := NewThreadUnsafeSet()
b := NewThreadUnsafeSet()
b.Add(1)
b.Add(2)
b.Add(3)
b.Add(4)
b.Add(5)
c := a.Union(b)
if c.Cardinality() != 5 {
t.Error("set c is unioned with an empty set and therefore should have 5 elements in it")
}
d := NewThreadUnsafeSet()
d.Add(10)
d.Add(14)
d.Add(0)
e := c.Union(d)
if e.Cardinality() != 8 {
t.Error("set e should should have 8 elements in it after being unioned with set c to d")
}
f := NewThreadUnsafeSet()
f.Add(14)
f.Add(3)
g := f.Union(e)
if g.Cardinality() != 8 {
t.Error("set g should still ahve 8 elements in it after being unioned with set f that has duplicates")
}
}
func Test_SetIntersect(t *testing.T) {
a := NewSet()
a.Add(1)
a.Add(3)
a.Add(5)
b := NewSet()
a.Add(2)
a.Add(4)
a.Add(6)
c := a.Intersect(b)
if c.Cardinality() != 0 {
t.Error("set c should be the empty set because there is no common items to intersect")
}
a.Add(10)
b.Add(10)
d := a.Intersect(b)
if !(d.Cardinality() == 1 && d.Contains(10)) {
t.Error("set d should have a size of 1 and contain the item 10")
}
}
func Test_UnsafeSetIntersect(t *testing.T) {
a := NewThreadUnsafeSet()
a.Add(1)
a.Add(3)
a.Add(5)
b := NewThreadUnsafeSet()
a.Add(2)
a.Add(4)
a.Add(6)
c := a.Intersect(b)
if c.Cardinality() != 0 {
t.Error("set c should be the empty set because there is no common items to intersect")
}
a.Add(10)
b.Add(10)
d := a.Intersect(b)
if !(d.Cardinality() == 1 && d.Contains(10)) {
t.Error("set d should have a size of 1 and contain the item 10")
}
}
func Test_SetDifference(t *testing.T) {
a := NewSet()
a.Add(1)
a.Add(2)
a.Add(3)
b := NewSet()
b.Add(1)
b.Add(3)
b.Add(4)
b.Add(5)
b.Add(6)
b.Add(99)
c := a.Difference(b)
if !(c.Cardinality() == 1 && c.Contains(2)) {
t.Error("the difference of set a to b is the set of 1 item: 2")
}
}
func Test_UnsafeSetDifference(t *testing.T) {
a := NewThreadUnsafeSet()
a.Add(1)
a.Add(2)
a.Add(3)
b := NewThreadUnsafeSet()
b.Add(1)
b.Add(3)
b.Add(4)
b.Add(5)
b.Add(6)
b.Add(99)
c := a.Difference(b)
if !(c.Cardinality() == 1 && c.Contains(2)) {
t.Error("the difference of set a to b is the set of 1 item: 2")
}
}
func Test_SetSymmetricDifference(t *testing.T) {
a := NewSet()
a.Add(1)
a.Add(2)
a.Add(3)
a.Add(45)
b := NewSet()
b.Add(1)
b.Add(3)
b.Add(4)
b.Add(5)
b.Add(6)
b.Add(99)
c := a.SymmetricDifference(b)
if !(c.Cardinality() == 6 && c.Contains(2) && c.Contains(45) && c.Contains(4) && c.Contains(5) && c.Contains(6) && c.Contains(99)) {
t.Error("the symmetric difference of set a to b is the set of 6 items: 2, 45, 4, 5, 6, 99")
}
}
func Test_UnsafeSetSymmetricDifference(t *testing.T) {
a := NewThreadUnsafeSet()
a.Add(1)
a.Add(2)
a.Add(3)
a.Add(45)
b := NewThreadUnsafeSet()
b.Add(1)
b.Add(3)
b.Add(4)
b.Add(5)
b.Add(6)
b.Add(99)
c := a.SymmetricDifference(b)
if !(c.Cardinality() == 6 && c.Contains(2) && c.Contains(45) && c.Contains(4) && c.Contains(5) && c.Contains(6) && c.Contains(99)) {
t.Error("the symmetric difference of set a to b is the set of 6 items: 2, 45, 4, 5, 6, 99")
}
}
func Test_SetEqual(t *testing.T) {
a := NewSet()
b := NewSet()
if !a.Equal(b) {
t.Error("Both a and b are empty sets, and should be equal")
}
a.Add(10)
if a.Equal(b) {
t.Error("a should not be equal to b because b is empty and a has item 1 in it")
}
b.Add(10)
if !a.Equal(b) {
t.Error("a is now equal again to b because both have the item 10 in them")
}
b.Add(8)
b.Add(3)
b.Add(47)
if a.Equal(b) {
t.Error("b has 3 more elements in it so therefore should not be equal to a")
}
a.Add(8)
a.Add(3)
a.Add(47)
if !a.Equal(b) {
t.Error("a and b should be equal with the same number of elements")
}
}
func Test_UnsafeSetEqual(t *testing.T) {
a := NewThreadUnsafeSet()
b := NewThreadUnsafeSet()
if !a.Equal(b) {
t.Error("Both a and b are empty sets, and should be equal")
}
a.Add(10)
if a.Equal(b) {
t.Error("a should not be equal to b because b is empty and a has item 1 in it")
}
b.Add(10)
if !a.Equal(b) {
t.Error("a is now equal again to b because both have the item 10 in them")
}
b.Add(8)
b.Add(3)
b.Add(47)
if a.Equal(b) {
t.Error("b has 3 more elements in it so therefore should not be equal to a")
}
a.Add(8)
a.Add(3)
a.Add(47)
if !a.Equal(b) {
t.Error("a and b should be equal with the same number of elements")
}
}
func Test_SetClone(t *testing.T) {
a := NewSet()
a.Add(1)
a.Add(2)
b := a.Clone()
if !a.Equal(b) {
t.Error("Clones should be equal")
}
a.Add(3)
if a.Equal(b) {
t.Error("a contains one more element, they should not be equal")
}
c := a.Clone()
c.Remove(1)
if a.Equal(c) {
t.Error("C contains one element less, they should not be equal")
}
}
func Test_UnsafeSetClone(t *testing.T) {
a := NewThreadUnsafeSet()
a.Add(1)
a.Add(2)
b := a.Clone()
if !a.Equal(b) {
t.Error("Clones should be equal")
}
a.Add(3)
if a.Equal(b) {
t.Error("a contains one more element, they should not be equal")
}
c := a.Clone()
c.Remove(1)
if a.Equal(c) {
t.Error("C contains one element less, they should not be equal")
}
}
func Test_Iterator(t *testing.T) {
a := NewSet()
a.Add("Z")
a.Add("Y")
a.Add("X")
a.Add("W")
b := NewSet()
for val := range a.Iter() {
b.Add(val)
}
if !a.Equal(b) {
t.Error("The sets are not equal after iterating through the first set")
}
}
func Test_UnsafeIterator(t *testing.T) {
a := NewThreadUnsafeSet()
a.Add("Z")
a.Add("Y")
a.Add("X")
a.Add("W")
b := NewThreadUnsafeSet()
for val := range a.Iter() {
b.Add(val)
}
if !a.Equal(b) {
t.Error("The sets are not equal after iterating through the first set")
}
}
func Test_PowerSet(t *testing.T) {
a := NewThreadUnsafeSet()
a.Add(1)
a.Add("delta")
a.Add("chi")
a.Add(4)
b := a.PowerSet()
if b.Cardinality() != 16 {
t.Error("unexpected PowerSet cardinality")
}
}
func Test_EmptySetProperties(t *testing.T) {
empty := NewSet()
a := NewSet()
a.Add(1)
a.Add("foo")
a.Add("bar")
b := NewSet()
b.Add("one")
b.Add("two")
b.Add(3)
b.Add(4)
c := NewSet()
if !empty.IsSubset(a) || !empty.IsSubset(b) {
t.Error("The empty set is supposed to be a subset of all sets")
}
if !a.IsSuperset(empty) || !b.IsSuperset(empty) {
t.Error("All sets are supposed to be a superset of the empty set")
}
if !empty.IsSubset(empty) || !empty.IsSuperset(empty) {
t.Error("The empty set is supposed to be a subset and a superset of itself")
}
c = a.Union(empty)
if !c.Equal(a) {
t.Error("The union of any set with the empty set is supposed to be equal to itself")
}
c = a.Intersect(empty)
if !c.Equal(empty) {
t.Error("The intesection of any set with the empty set is supposed to be the empty set")
}
c = a.CartesianProduct(empty)
if c.Cardinality() != 0 {
t.Error("Cartesian product of any set and the empty set must be the empty set")
}
if empty.Cardinality() != 0 {
t.Error("Cardinality of the empty set is supposed to be zero")
}
c = empty.PowerSet()
if c.Cardinality() != 1 {
t.Error("Cardinality of the power set of the empty set is supposed to be one { {} }")
}
}
func Test_CartesianProduct(t *testing.T) {
a := NewThreadUnsafeSet()
b := NewThreadUnsafeSet()
empty := NewThreadUnsafeSet()
a.Add(1)
a.Add(2)
a.Add(3)
b.Add("one")
b.Add("two")
b.Add("three")
b.Add("alpha")
b.Add("gamma")
c := a.CartesianProduct(b)
d := b.CartesianProduct(a)
if c.Cardinality() != d.Cardinality() {
t.Error("Cardinality of AxB must be equal to BxA")
}
if c.Cardinality() != (a.Cardinality() * b.Cardinality()) {
t.Error("Unexpected cardinality for cartesian product set")
}
c = a.CartesianProduct(empty)
d = empty.CartesianProduct(b)
if c.Cardinality() != 0 || d.Cardinality() != 0 {
t.Error("Cartesian product of any set and the emtpy set Ax0 || 0xA must be the empty set")
}
}
func Test_ToSliceUnthreadsafe(t *testing.T) {
s := makeUnsafeSet([]int{1, 2, 3})
setAsSlice := s.ToSlice()
if len(setAsSlice) != s.Cardinality() {
t.Errorf("Set length is incorrect: %v", len(setAsSlice))
}
for _, i := range setAsSlice {
if !s.Contains(i) {
t.Errorf("Set is missing element: %v", i)
}
}
}
func Test_Example(t *testing.T) {
/*
requiredClasses := NewSet()
requiredClasses.Add("Cooking")
requiredClasses.Add("English")
requiredClasses.Add("Math")
requiredClasses.Add("Biology")
scienceSlice := []interface{}{"Biology", "Chemistry"}
scienceClasses := NewSetFromSlice(scienceSlice)
electiveClasses := NewSet()
electiveClasses.Add("Welding")
electiveClasses.Add("Music")
electiveClasses.Add("Automotive")
bonusClasses := 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{English, Chemistry, Automotive, Cooking, Math, Biology, Welding, Music, Go 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{English, Automotive, Cooking, Math, Welding, Music, Go Programming}
//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.ContainsAll("Welding", "Automotive", "English"))
*/
}

View file

@ -0,0 +1,204 @@
/*
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) IsSuperset(other Set) bool {
return other.IsSubset(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)
unsafeDifference := set.s.SymmetricDifference(&o.s).(*threadUnsafeSet)
return &threadSafeSet{s: *unsafeDifference}
}
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) 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) 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) 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{} {
set.RLock()
keys := make([]interface{}, 0, set.Cardinality())
for elem := range set.s {
keys = append(keys, elem)
}
set.RUnlock()
return keys
}

View file

@ -0,0 +1,376 @@
/*
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 (
"math/rand"
"runtime"
"sync"
"testing"
)
const N = 1000
func Test_AddConcurrent(t *testing.T) {
runtime.GOMAXPROCS(2)
s := NewSet()
ints := rand.Perm(N)
var wg sync.WaitGroup
wg.Add(len(ints))
for i := 0; i < len(ints); i++ {
go func(i int) {
s.Add(i)
wg.Done()
}(i)
}
wg.Wait()
for _, i := range ints {
if !s.Contains(i) {
t.Errorf("Set is missing element: %v", i)
}
}
}
func Test_CardinalityConcurrent(t *testing.T) {
runtime.GOMAXPROCS(2)
s := NewSet()
var wg sync.WaitGroup
wg.Add(1)
go func() {
elems := s.Cardinality()
for i := 0; i < N; i++ {
newElems := s.Cardinality()
if newElems < elems {
t.Errorf("Cardinality shrunk from %v to %v", elems, newElems)
}
}
wg.Done()
}()
for i := 0; i < N; i++ {
s.Add(rand.Int())
}
wg.Wait()
}
func Test_ClearConcurrent(t *testing.T) {
runtime.GOMAXPROCS(2)
s := NewSet()
ints := rand.Perm(N)
var wg sync.WaitGroup
wg.Add(len(ints))
for i := 0; i < len(ints); i++ {
go func() {
s.Clear()
wg.Done()
}()
go func(i int) {
s.Add(i)
}(i)
}
wg.Wait()
}
func Test_CloneConcurrent(t *testing.T) {
runtime.GOMAXPROCS(2)
s := NewSet()
ints := rand.Perm(N)
for _, v := range ints {
s.Add(v)
}
var wg sync.WaitGroup
wg.Add(len(ints))
for i := range ints {
go func(i int) {
s.Remove(i)
wg.Done()
}(i)
}
s.Clone()
}
func Test_ContainsConcurrent(t *testing.T) {
runtime.GOMAXPROCS(2)
s := NewSet()
ints := rand.Perm(N)
interfaces := make([]interface{}, 0)
for _, v := range ints {
s.Add(v)
interfaces = append(interfaces, v)
}
var wg sync.WaitGroup
for _ = range ints {
go func() {
s.Contains(interfaces...)
}()
}
wg.Wait()
}
func Test_DifferenceConcurrent(t *testing.T) {
runtime.GOMAXPROCS(2)
s, ss := NewSet(), NewSet()
ints := rand.Perm(N)
interfaces := make([]interface{}, 0)
for _, v := range ints {
s.Add(v)
ss.Add(v)
interfaces = append(interfaces, v)
}
var wg sync.WaitGroup
for _ = range ints {
go func() {
s.Difference(ss)
}()
}
wg.Wait()
}
func Test_EqualConcurrent(t *testing.T) {
runtime.GOMAXPROCS(2)
s, ss := NewSet(), NewSet()
ints := rand.Perm(N)
interfaces := make([]interface{}, 0)
for _, v := range ints {
s.Add(v)
ss.Add(v)
interfaces = append(interfaces, v)
}
var wg sync.WaitGroup
for _ = range ints {
go func() {
s.Equal(ss)
}()
}
wg.Wait()
}
func Test_IntersectConcurrent(t *testing.T) {
runtime.GOMAXPROCS(2)
s, ss := NewSet(), NewSet()
ints := rand.Perm(N)
interfaces := make([]interface{}, 0)
for _, v := range ints {
s.Add(v)
ss.Add(v)
interfaces = append(interfaces, v)
}
var wg sync.WaitGroup
for _ = range ints {
go func() {
s.Intersect(ss)
}()
}
wg.Wait()
}
func Test_IsSubsetConcurrent(t *testing.T) {
runtime.GOMAXPROCS(2)
s, ss := NewSet(), NewSet()
ints := rand.Perm(N)
interfaces := make([]interface{}, 0)
for _, v := range ints {
s.Add(v)
ss.Add(v)
interfaces = append(interfaces, v)
}
var wg sync.WaitGroup
for _ = range ints {
go func() {
s.IsSubset(ss)
}()
}
wg.Wait()
}
func Test_IsSupersetConcurrent(t *testing.T) {
runtime.GOMAXPROCS(2)
s, ss := NewSet(), NewSet()
ints := rand.Perm(N)
interfaces := make([]interface{}, 0)
for _, v := range ints {
s.Add(v)
ss.Add(v)
interfaces = append(interfaces, v)
}
var wg sync.WaitGroup
for _ = range ints {
go func() {
s.IsSuperset(ss)
}()
}
wg.Wait()
}
func Test_IterConcurrent(t *testing.T) {
runtime.GOMAXPROCS(2)
s := NewSet()
ints := rand.Perm(N)
for _, v := range ints {
s.Add(v)
}
cs := make([]<-chan interface{}, 0)
for _ = range ints {
cs = append(cs, s.Iter())
}
c := make(chan interface{})
go func() {
for n := 0; n < len(ints)*N; {
for _, d := range cs {
select {
case <-d:
n++
c <- nil
default:
}
}
}
close(c)
}()
for _ = range c {
}
}
func Test_RemoveConcurrent(t *testing.T) {
runtime.GOMAXPROCS(2)
s := NewSet()
ints := rand.Perm(N)
for _, v := range ints {
s.Add(v)
}
var wg sync.WaitGroup
wg.Add(len(ints))
for _, v := range ints {
go func(i int) {
s.Remove(i)
wg.Done()
}(v)
}
wg.Wait()
if s.Cardinality() != 0 {
t.Errorf("Expected cardinality 0; got %v", s.Cardinality())
}
}
func Test_StringConcurrent(t *testing.T) {
runtime.GOMAXPROCS(2)
s := NewSet()
ints := rand.Perm(N)
for _, v := range ints {
s.Add(v)
}
var wg sync.WaitGroup
wg.Add(len(ints))
for _ = range ints {
go func() {
s.String()
wg.Done()
}()
}
wg.Wait()
}
func Test_SymmetricDifferenceConcurrent(t *testing.T) {
runtime.GOMAXPROCS(2)
s, ss := NewSet(), NewSet()
ints := rand.Perm(N)
interfaces := make([]interface{}, 0)
for _, v := range ints {
s.Add(v)
ss.Add(v)
interfaces = append(interfaces, v)
}
var wg sync.WaitGroup
for _ = range ints {
go func() {
s.SymmetricDifference(ss)
}()
}
wg.Wait()
}
func Test_ToSlice(t *testing.T) {
runtime.GOMAXPROCS(2)
s := NewSet()
ints := rand.Perm(N)
var wg sync.WaitGroup
wg.Add(len(ints))
for i := 0; i < len(ints); i++ {
go func(i int) {
s.Add(i)
wg.Done()
}(i)
}
wg.Wait()
setAsSlice := s.ToSlice()
if len(setAsSlice) != s.Cardinality() {
t.Errorf("Set length is incorrect: %v", len(setAsSlice))
}
for _, i := range setAsSlice {
if !s.Contains(i) {
t.Errorf("Set is missing element: %v", i)
}
}
}

View file

@ -0,0 +1,246 @@
/*
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 (
"fmt"
"reflect"
"strings"
)
type threadUnsafeSet map[interface{}]struct{}
type orderedPair struct {
first interface{}
second interface{}
}
func newThreadUnsafeSet() threadUnsafeSet {
return make(threadUnsafeSet)
}
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]
(*set)[i] = struct{}{}
return !found //False if it existed already
}
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) IsSuperset(other Set) bool {
return other.IsSubset(set)
}
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) Iter() <-chan interface{} {
ch := make(chan interface{})
go func() {
for elem := range *set {
ch <- elem
}
close(ch)
}()
return ch
}
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, ", "))
}
func (pair orderedPair) String() string {
return fmt.Sprintf("(%v, %v)", pair.first, pair.second)
}
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
}