Reintegrating optimizations originally proposed by @fy0 in issue:60 for set instantiation to utilize capacity hint where possible (#113)
diff --git a/set.go b/set.go
index a315c3a..803c8ea 100644
--- a/set.go
+++ b/set.go
@@ -145,6 +145,9 @@
// Remove removes a single element from the set.
Remove(i T)
+ // RemoveAll removes multiple elements from the set.
+ RemoveAll(i ...T)
+
// String provides a convenient string representation
// of the current state of the set.
String() string
@@ -182,27 +185,41 @@
// NewSet creates and returns a new set with the given elements.
// Operations on the resulting set are thread-safe.
func NewSet[T comparable](vals ...T) Set[T] {
- s := newThreadSafeSet[T]()
+ s := newThreadSafeSetWithSize[T](len(vals))
for _, item := range vals {
s.Add(item)
}
return s
}
+// NewSetWithSize creates and returns a reference to an empty set with a specified
+// capacity. Operations on the resulting set are thread-safe.
+func NewSetWithSize[T comparable](cardinality int) Set[T] {
+ s := newThreadSafeSetWithSize[T](cardinality)
+ return s
+}
+
// NewThreadUnsafeSet creates and returns a new set with the given elements.
// Operations on the resulting set are not thread-safe.
func NewThreadUnsafeSet[T comparable](vals ...T) Set[T] {
- s := newThreadUnsafeSet[T]()
+ s := newThreadUnsafeSetWithSize[T](len(vals))
for _, item := range vals {
s.Add(item)
}
return s
}
-// Creates and returns a new set with the given keys of the map.
+// NewThreadUnsafeSetWithSize creates and returns a reference to an empty set with
+// a specified capacity. Operations on the resulting set are not thread-safe.
+func NewThreadUnsafeSetWithSize[T comparable](cardinality int) Set[T] {
+ s := newThreadUnsafeSetWithSize[T](cardinality)
+ return s
+}
+
+// NewSetFromMapKeys creates and returns a new set with the given keys of the map.
// Operations on the resulting set are thread-safe.
func NewSetFromMapKeys[T comparable, V any](val map[T]V) Set[T] {
- s := NewSet[T]()
+ s := NewSetWithSize[T](len(val))
for k := range val {
s.Add(k)
@@ -211,10 +228,10 @@
return s
}
-// Creates and returns a new set with the given keys of the map.
+// NewThreadUnsafeSetFromMapKeys creates and returns a new set with the given keys of the map.
// Operations on the resulting set are not thread-safe.
func NewThreadUnsafeSetFromMapKeys[T comparable, V any](val map[T]V) Set[T] {
- s := NewThreadUnsafeSet[T]()
+ s := NewThreadUnsafeSetWithSize[T](len(val))
for k := range val {
s.Add(k)
diff --git a/set_test.go b/set_test.go
index 5c54c39..6017f45 100644
--- a/set_test.go
+++ b/set_test.go
@@ -185,6 +185,26 @@
}
}
+func Test_RemoveAllSet(t *testing.T) {
+ a := makeSetInt([]int{6, 3, 1, 8, 9})
+
+ a.RemoveAll(3, 1)
+
+ if a.Cardinality() != 3 {
+ t.Error("RemoveAll should only have 2 items in the set")
+ }
+
+ if !a.Contains(6, 8, 9) {
+ t.Error("RemoveAll should have only items (6,8,9) in the set")
+ }
+
+ a.RemoveAll(6, 8, 9)
+
+ if a.Cardinality() != 0 {
+ t.Error("RemoveSet should be an empty set after removing 6 and 1")
+ }
+}
+
func Test_RemoveUnsafeSet(t *testing.T) {
a := makeUnsafeSetInt([]int{6, 3, 1})
@@ -206,6 +226,26 @@
}
}
+func Test_RemoveAllUnsafeSet(t *testing.T) {
+ a := makeUnsafeSetInt([]int{6, 3, 1, 8, 9})
+
+ a.RemoveAll(3, 1)
+
+ if a.Cardinality() != 3 {
+ t.Error("RemoveAll should only have 2 items in the set")
+ }
+
+ if !a.Contains(6, 8, 9) {
+ t.Error("RemoveAll should have only items (6,8,9) in the set")
+ }
+
+ a.RemoveAll(6, 8, 9)
+
+ 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[int]()
diff --git a/threadsafe.go b/threadsafe.go
index 6178d5f..9e3a0ca 100644
--- a/threadsafe.go
+++ b/threadsafe.go
@@ -38,6 +38,12 @@
}
}
+func newThreadSafeSetWithSize[T comparable](cardinality int) *threadSafeSet[T] {
+ return &threadSafeSet[T]{
+ uss: newThreadUnsafeSetWithSize[T](cardinality),
+ }
+}
+
func (t *threadSafeSet[T]) Add(v T) bool {
t.Lock()
ret := t.uss.Add(v)
@@ -155,6 +161,12 @@
t.Unlock()
}
+func (t *threadSafeSet[T]) RemoveAll(i ...T) {
+ t.Lock()
+ t.uss.RemoveAll(i...)
+ t.Unlock()
+}
+
func (t *threadSafeSet[T]) Cardinality() int {
t.RLock()
defer t.RUnlock()
diff --git a/threadunsafe.go b/threadunsafe.go
index ea5635c..e5f4629 100644
--- a/threadunsafe.go
+++ b/threadunsafe.go
@@ -41,6 +41,10 @@
return make(threadUnsafeSet[T])
}
+func newThreadUnsafeSetWithSize[T comparable](cardinality int) threadUnsafeSet[T] {
+ return make(threadUnsafeSet[T], cardinality)
+}
+
func (s threadUnsafeSet[T]) Add(v T) bool {
prevLen := len(s)
s[v] = struct{}{}
@@ -74,7 +78,7 @@
}
func (s threadUnsafeSet[T]) Clone() Set[T] {
- clonedSet := make(threadUnsafeSet[T], s.Cardinality())
+ clonedSet := newThreadUnsafeSetWithSize[T](s.Cardinality())
for elem := range s {
clonedSet.add(elem)
}
@@ -220,6 +224,12 @@
delete(s, v)
}
+func (s threadUnsafeSet[T]) RemoveAll(i ...T) {
+ for _, elem := range i {
+ delete(s, elem)
+ }
+}
+
func (s threadUnsafeSet[T]) String() string {
items := make([]string, 0, len(s))