diff --git a/Makefile b/Makefile index e80998a..80c8da8 100644 --- a/Makefile +++ b/Makefile @@ -4,6 +4,6 @@ dependency: test: echo "" > coverage.txt for d in $(shell go list ./... | grep -v vendor); do \ - go test -mod=vendor -race -v -coverprofile=profile.out -covermode=atomic $$d || exit 1; \ + go test -mod=mod -race -v -coverprofile=profile.out -covermode=atomic $$d || exit 1; \ [ -f profile.out ] && cat profile.out >> coverage.txt && rm profile.out; \ done diff --git a/go.mod b/go.mod index c015d2f..8d8c25f 100644 --- a/go.mod +++ b/go.mod @@ -1,5 +1,14 @@ module github.com/StudioSol/set -go 1.12 +go 1.18 -require github.com/stretchr/testify v1.6.1 +require ( + github.com/stretchr/testify v1.6.1 + golang.org/x/exp v0.0.0-20220325121720-054d8573a5d8 +) + +require ( + github.com/davecgh/go-spew v1.1.0 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect +) diff --git a/go.sum b/go.sum index 1f1e7af..2f7f89c 100644 --- a/go.sum +++ b/go.sum @@ -2,10 +2,11 @@ github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +golang.org/x/exp v0.0.0-20220325121720-054d8573a5d8 h1:Xt4/LzbTwfocTk9ZLEu4onjeFucl88iW+v4j4PWbQuE= +golang.org/x/exp v0.0.0-20220325121720-054d8573a5d8/go.mod h1:lgLbSvA5ygNOMpwM/9anMpWVlVJ7Z+cHWq/eFuinpGE= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= diff --git a/linkedhashset.go b/linkedhashset.go new file mode 100644 index 0000000..14e69ff --- /dev/null +++ b/linkedhashset.go @@ -0,0 +1,84 @@ +package set + +import "golang.org/x/exp/constraints" + +// LinkedHashSet linked hash set implementation using linkedHashMap as its +// underlying data structure. +// +// - Does not allow storing duplicated values +// - Does not allow storing nil values +// - Maintains insertion order over iteration +type LinkedHashSet[T constraints.Ordered] struct { + linkedHashMap *linkedHashMap +} + +// Add adds elements to the linked hash set +func (l *LinkedHashSet[T]) Add(elements []T) { + for _, element := range elements { + l.linkedHashMap.Put(element, nil) + } +} + +// Remove removes elements from the linked hash set +func (l *LinkedHashSet[T]) Remove(elements []T) { + for _, element := range elements { + l.linkedHashMap.Remove(element) + } +} + +// Iter iterates over each element of the linked hash set +func (l *LinkedHashSet[T]) Iter() <-chan T { + ch := make(chan T, l.Length()) + go func() { + for element := range l.linkedHashMap.Iter() { + ch <- element.key.(T) + } + close(ch) + }() + return ch +} + +// Length returns the length of the linked hash set +func (l *LinkedHashSet[T]) Length() int { + return l.linkedHashMap.Length() +} + +// AsSlice returns a slice of all values of the linked hash set +func (l *LinkedHashSet[T]) AsSlice() []T { + values := make([]T, 0, l.Length()) + for value := range l.Iter() { + values = append(values, value) + } + return values +} + +// AsInterface returns a slice of all values of the linked hash set +// as interface{} +func (l *LinkedHashSet[T]) AsInterface() []interface{} { + values := make([]interface{}, 0, l.Length()) + for value := range l.Iter() { + values = append(values, value) + } + return values +} + +// InArray returns whether the given item is in array or not +func (l *LinkedHashSet[T]) InArray(search T) bool { + for item := range l.Iter() { + if item == search { + return true + } + } + return false +} + +// NewLinkedHashSet returns a new LinkedHashSet with the provided items +func NewLinkedHashSet[T constraints.Ordered](values []T) *LinkedHashSet[T] { + lhm := &LinkedHashSet[T]{ + linkedHashMap: newLinkedHashMap(), + } + if len(values) > 0 { + lhm.Add(values) + } + return lhm +}