adding set
This commit is contained in:
parent
18916439ef
commit
3e8a006611
24
set.go
Normal file
24
set.go
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
package set
|
||||||
|
|
||||||
|
import (
|
||||||
|
"set/simpleset"
|
||||||
|
"set/threadsafeset"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Set[T comparable] interface {
|
||||||
|
Insert(T) (inserted bool)
|
||||||
|
Contains(T) bool
|
||||||
|
Remove(T) (removed bool)
|
||||||
|
Len() int
|
||||||
|
ToSlice() []T
|
||||||
|
Clear()
|
||||||
|
}
|
||||||
|
|
||||||
|
func New[T comparable](threadsafe bool) Set[T] {
|
||||||
|
switch threadsafe {
|
||||||
|
case true:
|
||||||
|
return threadsafeset.New[T]()
|
||||||
|
default:
|
||||||
|
return simpleset.New[T]()
|
||||||
|
}
|
||||||
|
}
|
91
set_test.go
Normal file
91
set_test.go
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
package set
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestSimpleSet(t *testing.T) {
|
||||||
|
words := []string{"a", "b", "c"}
|
||||||
|
set := New[string](false)
|
||||||
|
for _, word := range words {
|
||||||
|
if !set.Insert(word) {
|
||||||
|
t.Fatalf("error: expected true while inserting '%s'; got false\n", word)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if want, got := len(words), set.Len(); want != got {
|
||||||
|
t.Fatalf("error: wanted %d entries; got %d\n", want, got)
|
||||||
|
}
|
||||||
|
for _, word := range words {
|
||||||
|
if set.Insert(word) {
|
||||||
|
t.Fatalf("error: expected false during duplicate insert for '%s'; got true\n", word)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, word := range words {
|
||||||
|
if !set.Contains(word) {
|
||||||
|
t.Fatalf("error: didn't find word '%s' in set after second insert...\n", word)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, word := range words {
|
||||||
|
if !set.Remove(word) {
|
||||||
|
t.Fatalf("error removing word '%s'\n", word)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if want, got := 0, set.Len(); want != got {
|
||||||
|
t.Fatalf("error: wanted %d entries; got %d\n", want, got)
|
||||||
|
}
|
||||||
|
for _, word := range words {
|
||||||
|
if !set.Insert(word) {
|
||||||
|
t.Fatalf("error: expected true while inserting '%s'; got false\n", word)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if want, got := len(words), set.Len(); want != got {
|
||||||
|
t.Fatalf("error: wanted %d entries; got %d\n", want, got)
|
||||||
|
}
|
||||||
|
set.Clear()
|
||||||
|
if want, got := 0, set.Len(); want != got {
|
||||||
|
t.Fatalf("error: wanted %d entries; got %d\n", want, got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestThreadsafeSet(t *testing.T) {
|
||||||
|
words := []string{"a", "b", "c"}
|
||||||
|
set := New[string](true)
|
||||||
|
for _, word := range words {
|
||||||
|
if !set.Insert(word) {
|
||||||
|
t.Fatalf("error: expected true while inserting '%s'; got false\n", word)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if want, got := len(words), set.Len(); want != got {
|
||||||
|
t.Fatalf("error: wanted %d entries; got %d\n", want, got)
|
||||||
|
}
|
||||||
|
for _, word := range words {
|
||||||
|
if set.Insert(word) {
|
||||||
|
t.Fatalf("error: expected false during duplicate insert for '%s'; got true\n", word)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, word := range words {
|
||||||
|
if !set.Contains(word) {
|
||||||
|
t.Fatalf("error: didn't find word '%s' in set after second insert...\n", word)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, word := range words {
|
||||||
|
if !set.Remove(word) {
|
||||||
|
t.Fatalf("error removing word '%s'\n", word)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if want, got := 0, set.Len(); want != got {
|
||||||
|
t.Fatalf("error: wanted %d entries; got %d\n", want, got)
|
||||||
|
}
|
||||||
|
for _, word := range words {
|
||||||
|
if !set.Insert(word) {
|
||||||
|
t.Fatalf("error: expected true while inserting '%s'; got false\n", word)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if want, got := len(words), set.Len(); want != got {
|
||||||
|
t.Fatalf("error: wanted %d entries; got %d\n", want, got)
|
||||||
|
}
|
||||||
|
set.Clear()
|
||||||
|
if want, got := 0, set.Len(); want != got {
|
||||||
|
t.Fatalf("error: wanted %d entries; got %d\n", want, got)
|
||||||
|
}
|
||||||
|
}
|
59
simpleset/simpleset.go
Normal file
59
simpleset/simpleset.go
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
package simpleset
|
||||||
|
|
||||||
|
type SimpleSet[T comparable] struct {
|
||||||
|
set map[T]any
|
||||||
|
}
|
||||||
|
|
||||||
|
func New[T comparable]() *SimpleSet[T] {
|
||||||
|
return &SimpleSet[T]{
|
||||||
|
set: make(map[T]any),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *SimpleSet[T]) lockedInitMapIfNil() {
|
||||||
|
if s.set == nil {
|
||||||
|
s.set = make(map[T]any)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *SimpleSet[T]) Insert(t T) (inserted bool) {
|
||||||
|
s.lockedInitMapIfNil()
|
||||||
|
if _, found := s.set[t]; found {
|
||||||
|
return false
|
||||||
|
} else {
|
||||||
|
s.set[t] = struct{}{}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *SimpleSet[T]) Contains(t T) bool {
|
||||||
|
s.lockedInitMapIfNil()
|
||||||
|
_, found := s.set[t]
|
||||||
|
return found
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *SimpleSet[T]) Len() int {
|
||||||
|
s.lockedInitMapIfNil()
|
||||||
|
return len(s.set)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *SimpleSet[T]) ToSlice() []T {
|
||||||
|
s.lockedInitMapIfNil()
|
||||||
|
results := make([]T, 0, s.Len())
|
||||||
|
for k := range s.set {
|
||||||
|
results = append(results, k)
|
||||||
|
}
|
||||||
|
return results
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *SimpleSet[T]) Clear() {
|
||||||
|
s.set = make(map[T]any)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *SimpleSet[T]) Remove(t T) (removed bool) {
|
||||||
|
if !s.Contains(t) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
delete(s.set, t)
|
||||||
|
return true
|
||||||
|
}
|
68
threadsafeset/threadsafeset.go
Normal file
68
threadsafeset/threadsafeset.go
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
package threadsafeset
|
||||||
|
|
||||||
|
import (
|
||||||
|
"set/simpleset"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ThreadsafeSet[T comparable] struct {
|
||||||
|
mutex sync.RWMutex
|
||||||
|
set *simpleset.SimpleSet[T]
|
||||||
|
}
|
||||||
|
|
||||||
|
func New[T comparable]() *ThreadsafeSet[T] {
|
||||||
|
return &ThreadsafeSet[T]{
|
||||||
|
set: simpleset.New[T](),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *ThreadsafeSet[T]) lockedInitMapIfNil() {
|
||||||
|
if s.set == nil {
|
||||||
|
s.set = simpleset.New[T]()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *ThreadsafeSet[T]) Insert(t T) (inserted bool) {
|
||||||
|
s.mutex.Lock()
|
||||||
|
defer s.mutex.Unlock()
|
||||||
|
s.lockedInitMapIfNil()
|
||||||
|
return s.set.Insert(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *ThreadsafeSet[T]) Contains(t T) bool {
|
||||||
|
s.mutex.RLock()
|
||||||
|
defer s.mutex.RUnlock()
|
||||||
|
return s.set != nil && s.set.Contains(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *ThreadsafeSet[T]) Len() int {
|
||||||
|
s.mutex.RLock()
|
||||||
|
defer s.mutex.RUnlock()
|
||||||
|
if s.set == nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return s.set.Len()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *ThreadsafeSet[T]) ToSlice() []T {
|
||||||
|
s.mutex.RLock()
|
||||||
|
defer s.mutex.RUnlock()
|
||||||
|
if s.set == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return s.set.ToSlice()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *ThreadsafeSet[T]) Clear() {
|
||||||
|
s.mutex.Lock()
|
||||||
|
defer s.mutex.Unlock()
|
||||||
|
s.lockedInitMapIfNil()
|
||||||
|
s.set.Clear()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *ThreadsafeSet[T]) Remove(t T) (removed bool) {
|
||||||
|
s.mutex.Lock()
|
||||||
|
defer s.mutex.Unlock()
|
||||||
|
s.lockedInitMapIfNil()
|
||||||
|
return s.set.Remove(t)
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user