diff --git a/glide.lock b/glide.lock index 73e38f49..b87b6d83 100644 --- a/glide.lock +++ b/glide.lock @@ -1,5 +1,5 @@ -hash: 9bf7ad53b92119a17068b8724d9b406a7ca84b5bfcd0baba44b08c696a538b14 -updated: 2018-09-06T15:58:19.234504-04:00 +hash: 3fd0e471868863d6ef4cd32bbcdc9b3d061911a15b458e7edd26cfba4faa62db +updated: 2018-09-17T13:13:44.344244-04:00 imports: - name: github.com/beorn7/perks version: 4c0e84591b9aa9e6dcfdf3e020114cd81f89d5f9 @@ -15,6 +15,8 @@ imports: version: 6d212800a42e8ab5c146b8ace3490ee17e5225f9 subpackages: - spew +- name: github.com/deckarep/golang-set + version: cbaa98ba5575e67703b32b4b19f73c91f3c4159e - name: github.com/fernet/fernet-go version: 1b2437bc582b3cfbb341ee5a29f8ef5b42912ff2 - name: github.com/golang/protobuf diff --git a/glide.yaml b/glide.yaml index e5956e18..3da576b1 100644 --- a/glide.yaml +++ b/glide.yaml @@ -28,3 +28,5 @@ import: - assert - package: gopkg.in/yaml.v2 - package: github.com/cockroachdb/cmux +- package: github.com/deckarep/golang-set + version: ^1.7.1 diff --git a/vendor/github.com/deckarep/golang-set/.gitignore b/vendor/github.com/deckarep/golang-set/.gitignore new file mode 100644 index 00000000..00268614 --- /dev/null +++ b/vendor/github.com/deckarep/golang-set/.gitignore @@ -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 diff --git a/vendor/github.com/deckarep/golang-set/.travis.yml b/vendor/github.com/deckarep/golang-set/.travis.yml new file mode 100644 index 00000000..c760d24d --- /dev/null +++ b/vendor/github.com/deckarep/golang-set/.travis.yml @@ -0,0 +1,11 @@ +language: go + +go: + - 1.8 + - 1.9 + - tip + +script: + - go test -race ./... + - go test -bench=. + diff --git a/vendor/github.com/deckarep/golang-set/LICENSE b/vendor/github.com/deckarep/golang-set/LICENSE new file mode 100644 index 00000000..b5768f89 --- /dev/null +++ b/vendor/github.com/deckarep/golang-set/LICENSE @@ -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. \ No newline at end of file diff --git a/vendor/github.com/deckarep/golang-set/README.md b/vendor/github.com/deckarep/golang-set/README.md new file mode 100644 index 00000000..c3b50b2c --- /dev/null +++ b/vendor/github.com/deckarep/golang-set/README.md @@ -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) diff --git a/vendor/github.com/deckarep/golang-set/bench_test.go b/vendor/github.com/deckarep/golang-set/bench_test.go new file mode 100644 index 00000000..f893d101 --- /dev/null +++ b/vendor/github.com/deckarep/golang-set/bench_test.go @@ -0,0 +1,674 @@ +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 benchIsProperSubset(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.IsProperSubset(t) + } +} + +func BenchmarkIsProperSubset1Safe(b *testing.B) { + benchIsProperSubset(b, 1, NewSet(), NewSet()) +} + +func BenchmarkIsProperSubset1Unsafe(b *testing.B) { + benchIsProperSubset(b, 1, NewThreadUnsafeSet(), NewThreadUnsafeSet()) +} + +func BenchmarkIsProperSubset10Safe(b *testing.B) { + benchIsProperSubset(b, 10, NewSet(), NewSet()) +} + +func BenchmarkIsProperSubset10Unsafe(b *testing.B) { + benchIsProperSubset(b, 10, NewThreadUnsafeSet(), NewThreadUnsafeSet()) +} + +func BenchmarkIsProperSubset100Safe(b *testing.B) { + benchIsProperSubset(b, 100, NewSet(), NewSet()) +} + +func BenchmarkIsProperSubset100Unsafe(b *testing.B) { + benchIsProperSubset(b, 100, NewThreadUnsafeSet(), NewThreadUnsafeSet()) +} + +func benchIsProperSuperset(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.IsProperSuperset(t) + } +} + +func BenchmarkIsProperSuperset1Safe(b *testing.B) { + benchIsProperSuperset(b, 1, NewSet(), NewSet()) +} + +func BenchmarkIsProperSuperset1Unsafe(b *testing.B) { + benchIsProperSuperset(b, 1, NewThreadUnsafeSet(), NewThreadUnsafeSet()) +} + +func BenchmarkIsProperSuperset10Safe(b *testing.B) { + benchIsProperSuperset(b, 10, NewSet(), NewSet()) +} + +func BenchmarkIsProperSuperset10Unsafe(b *testing.B) { + benchIsProperSuperset(b, 10, NewThreadUnsafeSet(), NewThreadUnsafeSet()) +} + +func BenchmarkIsProperSuperset100Safe(b *testing.B) { + benchIsProperSuperset(b, 100, NewSet(), NewSet()) +} + +func BenchmarkIsProperSuperset100Unsafe(b *testing.B) { + benchIsProperSuperset(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 benchEach(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.Each(func(elem interface{}) bool { + return false + }) + } +} + +func BenchmarkEach1Safe(b *testing.B) { + benchEach(b, 1, NewSet()) +} + +func BenchmarkEach1Unsafe(b *testing.B) { + benchEach(b, 1, NewThreadUnsafeSet()) +} + +func BenchmarkEach10Safe(b *testing.B) { + benchEach(b, 10, NewSet()) +} + +func BenchmarkEach10Unsafe(b *testing.B) { + benchEach(b, 10, NewThreadUnsafeSet()) +} + +func BenchmarkEach100Safe(b *testing.B) { + benchEach(b, 100, NewSet()) +} + +func BenchmarkEach100Unsafe(b *testing.B) { + benchEach(b, 100, 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 benchIterator(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.Iterator().C + for range c { + + } + } +} + +func BenchmarkIterator1Safe(b *testing.B) { + benchIterator(b, 1, NewSet()) +} + +func BenchmarkIterator1Unsafe(b *testing.B) { + benchIterator(b, 1, NewThreadUnsafeSet()) +} + +func BenchmarkIterator10Safe(b *testing.B) { + benchIterator(b, 10, NewSet()) +} + +func BenchmarkIterator10Unsafe(b *testing.B) { + benchIterator(b, 10, NewThreadUnsafeSet()) +} + +func BenchmarkIterator100Safe(b *testing.B) { + benchIterator(b, 100, NewSet()) +} + +func BenchmarkIterator100Unsafe(b *testing.B) { + benchIterator(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()) +} diff --git a/vendor/github.com/deckarep/golang-set/iterator.go b/vendor/github.com/deckarep/golang-set/iterator.go new file mode 100644 index 00000000..9dfecade --- /dev/null +++ b/vendor/github.com/deckarep/golang-set/iterator.go @@ -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 +} diff --git a/vendor/github.com/deckarep/golang-set/iterator_example_test.go b/vendor/github.com/deckarep/golang-set/iterator_example_test.go new file mode 100644 index 00000000..fc4235d7 --- /dev/null +++ b/vendor/github.com/deckarep/golang-set/iterator_example_test.go @@ -0,0 +1,32 @@ +package mapset + +import ( + "fmt" +) + +type YourType struct { + Name string +} + +func ExampleIterator() { + set := NewSetFromSlice([]interface{}{ + &YourType{Name: "Alise"}, + &YourType{Name: "Bob"}, + &YourType{Name: "John"}, + &YourType{Name: "Nick"}, + }) + + var found *YourType + it := set.Iterator() + + for elem := range it.C { + if elem.(*YourType).Name == "John" { + found = elem.(*YourType) + it.Stop() + } + } + + fmt.Printf("Found %+v\n", found) + + // Output: Found &{Name:John} +} diff --git a/vendor/github.com/deckarep/golang-set/set.go b/vendor/github.com/deckarep/golang-set/set.go new file mode 100644 index 00000000..29eb2e5a --- /dev/null +++ b/vendor/github.com/deckarep/golang-set/set.go @@ -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 +} diff --git a/vendor/github.com/deckarep/golang-set/set_test.go b/vendor/github.com/deckarep/golang-set/set_test.go new file mode 100644 index 00000000..6cdf5833 --- /dev/null +++ b/vendor/github.com/deckarep/golang-set/set_test.go @@ -0,0 +1,1200 @@ +/* +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 assertEqual(a, b Set, t *testing.T) { + if !a.Equal(b) { + t.Errorf("%v != %v\n", a, b) + } +} + +func Test_NewSet(t *testing.T) { + a := NewSet() + if a.Cardinality() != 0 { + t.Error("NewSet should start out as an empty set") + } + + assertEqual(NewSetFromSlice([]interface{}{}), NewSet(), t) + assertEqual(NewSetFromSlice([]interface{}{1}), NewSet(1), t) + assertEqual(NewSetFromSlice([]interface{}{1, 2}), NewSet(1, 2), t) + assertEqual(NewSetFromSlice([]interface{}{"a"}), NewSet("a"), t) + assertEqual(NewSetFromSlice([]interface{}{"a", "b"}), NewSet("a", "b"), t) +} + +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_SetIsProperSubset(t *testing.T) { + a := makeSet([]int{1, 2, 3, 5, 7}) + b := makeSet([]int{7, 5, 3, 2, 1}) + + if !a.IsSubset(b) { + t.Error("set a should be a subset of set b") + } + if a.IsProperSubset(b) { + t.Error("set a should not be a proper subset of set b (they're equal)") + } + + b.Add(72) + + if !a.IsSubset(b) { + t.Error("set a should be a subset of set b") + } + if !a.IsProperSubset(b) { + t.Error("set a should be a proper subset of set b") + } +} + +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_UnsafeSetIsProperSubset(t *testing.T) { + a := makeUnsafeSet([]int{1, 2, 3, 5, 7}) + b := NewThreadUnsafeSet() + b.Add(7) + b.Add(1) + b.Add(5) + b.Add(3) + b.Add(2) + + if !a.IsSubset(b) { + t.Error("set a should be a subset of set b") + } + if a.IsProperSubset(b) { + t.Error("set a should not be a proper subset of set b (they're equal)") + } + + b.Add(72) + + if !a.IsSubset(b) { + t.Error("set a should be a subset of set b") + } + if !a.IsProperSubset(b) { + t.Error("set a should be a proper subset of set b because set b has 72") + } +} + +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 b has a 42") + } +} + +func Test_SetIsProperSuperset(t *testing.T) { + a := NewSet() + a.Add(5) + a.Add(2) + a.Add(11) + + b := NewSet() + b.Add(2) + b.Add(5) + b.Add(11) + + if !a.IsSuperset(b) { + t.Error("set a should be a superset of set b") + } + if a.IsProperSuperset(b) { + t.Error("set a should not be a proper superset of set b (they're equal)") + } + + a.Add(9) + + if !a.IsSuperset(b) { + t.Error("set a should be a superset of set b") + } + if !a.IsProperSuperset(b) { + t.Error("set a not be a proper superset of set b because set a has a 9") + } + + b.Add(42) + + if a.IsSuperset(b) { + t.Error("set a should not be a superset of set b because set b has a 42") + } + if a.IsProperSuperset(b) { + t.Error("set a should not be a proper superset of set b because set b 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_UnsafeSetIsProperSuperset(t *testing.T) { + a := NewThreadUnsafeSet() + a.Add(5) + a.Add(2) + a.Add(11) + + b := NewThreadUnsafeSet() + b.Add(2) + b.Add(5) + b.Add(11) + + if !a.IsSuperset(b) { + t.Error("set a should be a superset of set b") + } + if a.IsProperSuperset(b) { + t.Error("set a should not be a proper superset of set b (they're equal)") + } + + a.Add(9) + + if !a.IsSuperset(b) { + t.Error("set a should be a superset of set b") + } + if !a.IsProperSuperset(b) { + t.Error("set a not be a proper superset of set b because set a has a 9") + } + + b.Add(42) + + if a.IsSuperset(b) { + t.Error("set a should not be a superset of set b because set b has a 42") + } + if a.IsProperSuperset(b) { + t.Error("set a should not be a proper superset of set b because set b 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 have 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 have 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_Each(t *testing.T) { + a := NewSet() + + a.Add("Z") + a.Add("Y") + a.Add("X") + a.Add("W") + + b := NewSet() + a.Each(func(elem interface{}) bool { + b.Add(elem) + return false + }) + + if !a.Equal(b) { + t.Error("The sets are not equal after iterating (Each) through the first set") + } + + var count int + a.Each(func(elem interface{}) bool { + if count == 2 { + return true + } + count++ + return false + }) + if count != 2 { + t.Error("Iteration should stop on the way") + } +} + +func Test_Iter(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 (Iter) through the first set") + } +} + +func Test_UnsafeIter(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 (Iter) through the first set") + } +} + +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.Iterator().C { + b.Add(val) + } + + if !a.Equal(b) { + t.Error("The sets are not equal after iterating (Iterator) 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.Iterator().C { + b.Add(val) + } + + if !a.Equal(b) { + t.Error("The sets are not equal after iterating (Iterator) through the first set") + } +} + +func Test_IteratorStop(t *testing.T) { + a := NewSet() + + a.Add("Z") + a.Add("Y") + a.Add("X") + a.Add("W") + + it := a.Iterator() + it.Stop() + for range it.C { + t.Error("The iterating (Iterator) did not stop after Stop() has been called") + } +} + +func Test_PopSafe(t *testing.T) { + a := NewSet() + + a.Add("a") + a.Add("b") + a.Add("c") + a.Add("d") + + captureSet := NewSet() + captureSet.Add(a.Pop()) + captureSet.Add(a.Pop()) + captureSet.Add(a.Pop()) + captureSet.Add(a.Pop()) + finalNil := a.Pop() + + if captureSet.Cardinality() != 4 { + t.Error("unexpected captureSet cardinality; should be 4") + } + + if a.Cardinality() != 0 { + t.Error("unepxected a cardinality; should be zero") + } + + if !captureSet.Contains("c", "a", "d", "b") { + t.Error("unexpected result set; should be a,b,c,d (any order is fine") + } + + if finalNil != nil { + t.Error("when original set is empty, further pops should result in nil") + } +} + +func Test_PopUnsafe(t *testing.T) { + a := NewThreadUnsafeSet() + + a.Add("a") + a.Add("b") + a.Add("c") + a.Add("d") + + captureSet := NewThreadUnsafeSet() + captureSet.Add(a.Pop()) + captureSet.Add(a.Pop()) + captureSet.Add(a.Pop()) + captureSet.Add(a.Pop()) + finalNil := a.Pop() + + if captureSet.Cardinality() != 4 { + t.Error("unexpected captureSet cardinality; should be 4") + } + + if a.Cardinality() != 0 { + t.Error("unepxected a cardinality; should be zero") + } + + if !captureSet.Contains("c", "a", "d", "b") { + t.Error("unexpected result set; should be a,b,c,d (any order is fine") + } + + if finalNil != nil { + t.Error("when original set is empty, further pops should result in nil") + } +} + +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_PowerSetThreadSafe(t *testing.T) { + set := NewSet().PowerSet() + _, setIsThreadSafe := set.(*threadSafeSet) + if !setIsThreadSafe { + t.Error("result of PowerSet should be thread safe") + } + + subset := set.Pop() + _, subsetIsThreadSafe := subset.(*threadSafeSet) + if !subsetIsThreadSafe { + t.Error("subsets in PowerSet result should be thread safe") + } +} + +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) + + 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 empty 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")) + */ +} diff --git a/vendor/github.com/deckarep/golang-set/threadsafe.go b/vendor/github.com/deckarep/golang-set/threadsafe.go new file mode 100644 index 00000000..269b4ab0 --- /dev/null +++ b/vendor/github.com/deckarep/golang-set/threadsafe.go @@ -0,0 +1,283 @@ +/* +Open Source Initiative OSI - The MIT License (MIT):Licensing + +The MIT License (MIT) +Copyright (c) 2013 Ralph Caraveo (deckarep@gmail.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +package mapset + +import "sync" + +type threadSafeSet struct { + s threadUnsafeSet + sync.RWMutex +} + +func newThreadSafeSet() threadSafeSet { + return threadSafeSet{s: newThreadUnsafeSet()} +} + +func (set *threadSafeSet) Add(i interface{}) bool { + set.Lock() + ret := set.s.Add(i) + set.Unlock() + return ret +} + +func (set *threadSafeSet) Contains(i ...interface{}) bool { + set.RLock() + ret := set.s.Contains(i...) + set.RUnlock() + return ret +} + +func (set *threadSafeSet) IsSubset(other Set) bool { + o := other.(*threadSafeSet) + + set.RLock() + o.RLock() + + ret := set.s.IsSubset(&o.s) + set.RUnlock() + o.RUnlock() + return ret +} + +func (set *threadSafeSet) IsProperSubset(other Set) bool { + o := other.(*threadSafeSet) + + set.RLock() + defer set.RUnlock() + o.RLock() + defer o.RUnlock() + + return set.s.IsProperSubset(&o.s) +} + +func (set *threadSafeSet) IsSuperset(other Set) bool { + return other.IsSubset(set) +} + +func (set *threadSafeSet) IsProperSuperset(other Set) bool { + return other.IsProperSubset(set) +} + +func (set *threadSafeSet) Union(other Set) Set { + o := other.(*threadSafeSet) + + set.RLock() + o.RLock() + + unsafeUnion := set.s.Union(&o.s).(*threadUnsafeSet) + ret := &threadSafeSet{s: *unsafeUnion} + set.RUnlock() + o.RUnlock() + return ret +} + +func (set *threadSafeSet) Intersect(other Set) Set { + o := other.(*threadSafeSet) + + set.RLock() + o.RLock() + + unsafeIntersection := set.s.Intersect(&o.s).(*threadUnsafeSet) + ret := &threadSafeSet{s: *unsafeIntersection} + set.RUnlock() + o.RUnlock() + return ret +} + +func (set *threadSafeSet) Difference(other Set) Set { + o := other.(*threadSafeSet) + + set.RLock() + o.RLock() + + unsafeDifference := set.s.Difference(&o.s).(*threadUnsafeSet) + ret := &threadSafeSet{s: *unsafeDifference} + set.RUnlock() + o.RUnlock() + return ret +} + +func (set *threadSafeSet) SymmetricDifference(other Set) Set { + o := other.(*threadSafeSet) + + set.RLock() + o.RLock() + + unsafeDifference := set.s.SymmetricDifference(&o.s).(*threadUnsafeSet) + ret := &threadSafeSet{s: *unsafeDifference} + set.RUnlock() + o.RUnlock() + return ret +} + +func (set *threadSafeSet) Clear() { + set.Lock() + set.s = newThreadUnsafeSet() + set.Unlock() +} + +func (set *threadSafeSet) Remove(i interface{}) { + set.Lock() + delete(set.s, i) + set.Unlock() +} + +func (set *threadSafeSet) Cardinality() int { + set.RLock() + defer set.RUnlock() + return len(set.s) +} + +func (set *threadSafeSet) Each(cb func(interface{}) bool) { + set.RLock() + for elem := range set.s { + if cb(elem) { + break + } + } + set.RUnlock() +} + +func (set *threadSafeSet) Iter() <-chan interface{} { + ch := make(chan interface{}) + go func() { + set.RLock() + + for elem := range set.s { + ch <- elem + } + close(ch) + set.RUnlock() + }() + + return ch +} + +func (set *threadSafeSet) Iterator() *Iterator { + iterator, ch, stopCh := newIterator() + + go func() { + set.RLock() + L: + for elem := range set.s { + select { + case <-stopCh: + break L + case ch <- elem: + } + } + close(ch) + set.RUnlock() + }() + + return iterator +} + +func (set *threadSafeSet) Equal(other Set) bool { + o := other.(*threadSafeSet) + + set.RLock() + o.RLock() + + ret := set.s.Equal(&o.s) + set.RUnlock() + o.RUnlock() + return ret +} + +func (set *threadSafeSet) Clone() Set { + set.RLock() + + unsafeClone := set.s.Clone().(*threadUnsafeSet) + ret := &threadSafeSet{s: *unsafeClone} + set.RUnlock() + return ret +} + +func (set *threadSafeSet) String() string { + set.RLock() + ret := set.s.String() + set.RUnlock() + return ret +} + +func (set *threadSafeSet) PowerSet() Set { + set.RLock() + unsafePowerSet := set.s.PowerSet().(*threadUnsafeSet) + set.RUnlock() + + ret := &threadSafeSet{s: newThreadUnsafeSet()} + for subset := range unsafePowerSet.Iter() { + unsafeSubset := subset.(*threadUnsafeSet) + ret.Add(&threadSafeSet{s: *unsafeSubset}) + } + return ret +} + +func (set *threadSafeSet) Pop() interface{} { + set.Lock() + defer set.Unlock() + return set.s.Pop() +} + +func (set *threadSafeSet) CartesianProduct(other Set) Set { + o := other.(*threadSafeSet) + + set.RLock() + o.RLock() + + unsafeCartProduct := set.s.CartesianProduct(&o.s).(*threadUnsafeSet) + ret := &threadSafeSet{s: *unsafeCartProduct} + set.RUnlock() + o.RUnlock() + return ret +} + +func (set *threadSafeSet) ToSlice() []interface{} { + keys := make([]interface{}, 0, set.Cardinality()) + set.RLock() + for elem := range set.s { + keys = append(keys, elem) + } + set.RUnlock() + return keys +} + +func (set *threadSafeSet) MarshalJSON() ([]byte, error) { + set.RLock() + b, err := set.s.MarshalJSON() + set.RUnlock() + + return b, err +} + +func (set *threadSafeSet) UnmarshalJSON(p []byte) error { + set.RLock() + err := set.s.UnmarshalJSON(p) + set.RUnlock() + + return err +} diff --git a/vendor/github.com/deckarep/golang-set/threadsafe_test.go b/vendor/github.com/deckarep/golang-set/threadsafe_test.go new file mode 100644 index 00000000..5c32fcbd --- /dev/null +++ b/vendor/github.com/deckarep/golang-set/threadsafe_test.go @@ -0,0 +1,524 @@ +/* +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 ( + "encoding/json" + "math/rand" + "runtime" + "sync" + "sync/atomic" + "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 { + wg.Add(1) + go func() { + s.Contains(interfaces...) + wg.Done() + }() + } + wg.Wait() +} + +func Test_DifferenceConcurrent(t *testing.T) { + runtime.GOMAXPROCS(2) + + s, ss := NewSet(), NewSet() + ints := rand.Perm(N) + for _, v := range ints { + s.Add(v) + ss.Add(v) + } + + var wg sync.WaitGroup + for range ints { + wg.Add(1) + go func() { + s.Difference(ss) + wg.Done() + }() + } + wg.Wait() +} + +func Test_EqualConcurrent(t *testing.T) { + runtime.GOMAXPROCS(2) + + s, ss := NewSet(), NewSet() + ints := rand.Perm(N) + for _, v := range ints { + s.Add(v) + ss.Add(v) + } + + var wg sync.WaitGroup + for range ints { + wg.Add(1) + go func() { + s.Equal(ss) + wg.Done() + }() + } + wg.Wait() +} + +func Test_IntersectConcurrent(t *testing.T) { + runtime.GOMAXPROCS(2) + + s, ss := NewSet(), NewSet() + ints := rand.Perm(N) + for _, v := range ints { + s.Add(v) + ss.Add(v) + } + + var wg sync.WaitGroup + for range ints { + wg.Add(1) + go func() { + s.Intersect(ss) + wg.Done() + }() + } + wg.Wait() +} + +func Test_IsSubsetConcurrent(t *testing.T) { + runtime.GOMAXPROCS(2) + + s, ss := NewSet(), NewSet() + ints := rand.Perm(N) + for _, v := range ints { + s.Add(v) + ss.Add(v) + } + + var wg sync.WaitGroup + for range ints { + wg.Add(1) + go func() { + s.IsSubset(ss) + wg.Done() + }() + } + wg.Wait() +} + +func Test_IsProperSubsetConcurrent(t *testing.T) { + runtime.GOMAXPROCS(2) + + s, ss := NewSet(), NewSet() + ints := rand.Perm(N) + for _, v := range ints { + s.Add(v) + ss.Add(v) + } + + var wg sync.WaitGroup + for range ints { + wg.Add(1) + go func() { + s.IsProperSubset(ss) + wg.Done() + }() + } + wg.Wait() +} + +func Test_IsSupersetConcurrent(t *testing.T) { + runtime.GOMAXPROCS(2) + + s, ss := NewSet(), NewSet() + ints := rand.Perm(N) + for _, v := range ints { + s.Add(v) + ss.Add(v) + } + + var wg sync.WaitGroup + for range ints { + wg.Add(1) + go func() { + s.IsSuperset(ss) + wg.Done() + }() + } + wg.Wait() +} + +func Test_IsProperSupersetConcurrent(t *testing.T) { + runtime.GOMAXPROCS(2) + + s, ss := NewSet(), NewSet() + ints := rand.Perm(N) + for _, v := range ints { + s.Add(v) + ss.Add(v) + } + + var wg sync.WaitGroup + for range ints { + wg.Add(1) + go func() { + s.IsProperSuperset(ss) + wg.Done() + }() + } + wg.Wait() +} + +func Test_EachConcurrent(t *testing.T) { + runtime.GOMAXPROCS(2) + concurrent := 10 + + s := NewSet() + ints := rand.Perm(N) + for _, v := range ints { + s.Add(v) + } + + var count int64 + wg := new(sync.WaitGroup) + wg.Add(concurrent) + for n := 0; n < concurrent; n++ { + go func() { + defer wg.Done() + s.Each(func(elem interface{}) bool { + atomic.AddInt64(&count, 1) + return false + }) + }() + } + wg.Wait() + + if count != int64(N*concurrent) { + t.Errorf("%v != %v", count, int64(N*concurrent)) + } +} + +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) + for _, v := range ints { + s.Add(v) + ss.Add(v) + } + + var wg sync.WaitGroup + for range ints { + wg.Add(1) + go func() { + s.SymmetricDifference(ss) + wg.Done() + }() + } + 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) + } + } +} + +// Test_ToSliceDeadlock - fixes issue: https://github.com/deckarep/golang-set/issues/36 +// This code reveals the deadlock however it doesn't happen consistently. +func Test_ToSliceDeadlock(t *testing.T) { + runtime.GOMAXPROCS(2) + + var wg sync.WaitGroup + set := NewSet() + workers := 10 + wg.Add(workers) + for i := 1; i <= workers; i++ { + go func() { + for j := 0; j < 1000; j++ { + set.Add(1) + set.ToSlice() + } + wg.Done() + }() + } + wg.Wait() +} + +func Test_UnmarshalJSON(t *testing.T) { + s := []byte(`["test", 1, 2, 3, ["4,5,6"]]`) + expected := NewSetFromSlice( + []interface{}{ + json.Number("1"), + json.Number("2"), + json.Number("3"), + "test", + }, + ) + actual := NewSet() + err := json.Unmarshal(s, actual) + if err != nil { + t.Errorf("Error should be nil: %v", err) + } + + if !expected.Equal(actual) { + t.Errorf("Expected no difference, got: %v", expected.Difference(actual)) + } +} + +func Test_MarshalJSON(t *testing.T) { + expected := NewSetFromSlice( + []interface{}{ + json.Number("1"), + "test", + }, + ) + + b, err := json.Marshal( + NewSetFromSlice( + []interface{}{ + 1, + "test", + }, + ), + ) + if err != nil { + t.Errorf("Error should be nil: %v", err) + } + + actual := NewSet() + err = json.Unmarshal(b, actual) + if err != nil { + t.Errorf("Error should be nil: %v", err) + } + + if !expected.Equal(actual) { + t.Errorf("Expected no difference, got: %v", expected.Difference(actual)) + } +} diff --git a/vendor/github.com/deckarep/golang-set/threadunsafe.go b/vendor/github.com/deckarep/golang-set/threadunsafe.go new file mode 100644 index 00000000..10bdd46f --- /dev/null +++ b/vendor/github.com/deckarep/golang-set/threadunsafe.go @@ -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 +}