Skip to content

Commit 456a496

Browse files
authoredMar 14, 2023
Reintegrating optimizations originally proposed by @fy0 in issue:60 for set instantiation to utilize capacity hint where possible (#113)
1 parent d9a5ce2 commit 456a496

File tree

4 files changed

+86
-7
lines changed

4 files changed

+86
-7
lines changed
 

‎set.go

+23-6
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,9 @@ type Set[T comparable] interface {
145145
// Remove removes a single element from the set.
146146
Remove(i T)
147147

148+
// RemoveAll removes multiple elements from the set.
149+
RemoveAll(i ...T)
150+
148151
// String provides a convenient string representation
149152
// of the current state of the set.
150153
String() string
@@ -182,27 +185,41 @@ type Set[T comparable] interface {
182185
// NewSet creates and returns a new set with the given elements.
183186
// Operations on the resulting set are thread-safe.
184187
func NewSet[T comparable](vals ...T) Set[T] {
185-
s := newThreadSafeSet[T]()
188+
s := newThreadSafeSetWithSize[T](len(vals))
186189
for _, item := range vals {
187190
s.Add(item)
188191
}
189192
return s
190193
}
191194

195+
// NewSetWithSize creates and returns a reference to an empty set with a specified
196+
// capacity. Operations on the resulting set are thread-safe.
197+
func NewSetWithSize[T comparable](cardinality int) Set[T] {
198+
s := newThreadSafeSetWithSize[T](cardinality)
199+
return s
200+
}
201+
192202
// NewThreadUnsafeSet creates and returns a new set with the given elements.
193203
// Operations on the resulting set are not thread-safe.
194204
func NewThreadUnsafeSet[T comparable](vals ...T) Set[T] {
195-
s := newThreadUnsafeSet[T]()
205+
s := newThreadUnsafeSetWithSize[T](len(vals))
196206
for _, item := range vals {
197207
s.Add(item)
198208
}
199209
return s
200210
}
201211

202-
// Creates and returns a new set with the given keys of the map.
212+
// NewThreadUnsafeSetWithSize creates and returns a reference to an empty set with
213+
// a specified capacity. Operations on the resulting set are not thread-safe.
214+
func NewThreadUnsafeSetWithSize[T comparable](cardinality int) Set[T] {
215+
s := newThreadUnsafeSetWithSize[T](cardinality)
216+
return s
217+
}
218+
219+
// NewSetFromMapKeys creates and returns a new set with the given keys of the map.
203220
// Operations on the resulting set are thread-safe.
204221
func NewSetFromMapKeys[T comparable, V any](val map[T]V) Set[T] {
205-
s := NewSet[T]()
222+
s := NewSetWithSize[T](len(val))
206223

207224
for k := range val {
208225
s.Add(k)
@@ -211,10 +228,10 @@ func NewSetFromMapKeys[T comparable, V any](val map[T]V) Set[T] {
211228
return s
212229
}
213230

214-
// Creates and returns a new set with the given keys of the map.
231+
// NewThreadUnsafeSetFromMapKeys creates and returns a new set with the given keys of the map.
215232
// Operations on the resulting set are not thread-safe.
216233
func NewThreadUnsafeSetFromMapKeys[T comparable, V any](val map[T]V) Set[T] {
217-
s := NewThreadUnsafeSet[T]()
234+
s := NewThreadUnsafeSetWithSize[T](len(val))
218235

219236
for k := range val {
220237
s.Add(k)

‎set_test.go

+40
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,26 @@ func Test_RemoveSet(t *testing.T) {
185185
}
186186
}
187187

188+
func Test_RemoveAllSet(t *testing.T) {
189+
a := makeSetInt([]int{6, 3, 1, 8, 9})
190+
191+
a.RemoveAll(3, 1)
192+
193+
if a.Cardinality() != 3 {
194+
t.Error("RemoveAll should only have 2 items in the set")
195+
}
196+
197+
if !a.Contains(6, 8, 9) {
198+
t.Error("RemoveAll should have only items (6,8,9) in the set")
199+
}
200+
201+
a.RemoveAll(6, 8, 9)
202+
203+
if a.Cardinality() != 0 {
204+
t.Error("RemoveSet should be an empty set after removing 6 and 1")
205+
}
206+
}
207+
188208
func Test_RemoveUnsafeSet(t *testing.T) {
189209
a := makeUnsafeSetInt([]int{6, 3, 1})
190210

@@ -206,6 +226,26 @@ func Test_RemoveUnsafeSet(t *testing.T) {
206226
}
207227
}
208228

229+
func Test_RemoveAllUnsafeSet(t *testing.T) {
230+
a := makeUnsafeSetInt([]int{6, 3, 1, 8, 9})
231+
232+
a.RemoveAll(3, 1)
233+
234+
if a.Cardinality() != 3 {
235+
t.Error("RemoveAll should only have 2 items in the set")
236+
}
237+
238+
if !a.Contains(6, 8, 9) {
239+
t.Error("RemoveAll should have only items (6,8,9) in the set")
240+
}
241+
242+
a.RemoveAll(6, 8, 9)
243+
244+
if a.Cardinality() != 0 {
245+
t.Error("RemoveSet should be an empty set after removing 6 and 1")
246+
}
247+
}
248+
209249
func Test_ContainsSet(t *testing.T) {
210250
a := NewSet[int]()
211251

‎threadsafe.go

+12
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,12 @@ func newThreadSafeSet[T comparable]() *threadSafeSet[T] {
3838
}
3939
}
4040

41+
func newThreadSafeSetWithSize[T comparable](cardinality int) *threadSafeSet[T] {
42+
return &threadSafeSet[T]{
43+
uss: newThreadUnsafeSetWithSize[T](cardinality),
44+
}
45+
}
46+
4147
func (t *threadSafeSet[T]) Add(v T) bool {
4248
t.Lock()
4349
ret := t.uss.Add(v)
@@ -155,6 +161,12 @@ func (t *threadSafeSet[T]) Remove(v T) {
155161
t.Unlock()
156162
}
157163

164+
func (t *threadSafeSet[T]) RemoveAll(i ...T) {
165+
t.Lock()
166+
t.uss.RemoveAll(i...)
167+
t.Unlock()
168+
}
169+
158170
func (t *threadSafeSet[T]) Cardinality() int {
159171
t.RLock()
160172
defer t.RUnlock()

‎threadunsafe.go

+11-1
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,10 @@ func newThreadUnsafeSet[T comparable]() threadUnsafeSet[T] {
4141
return make(threadUnsafeSet[T])
4242
}
4343

44+
func newThreadUnsafeSetWithSize[T comparable](cardinality int) threadUnsafeSet[T] {
45+
return make(threadUnsafeSet[T], cardinality)
46+
}
47+
4448
func (s threadUnsafeSet[T]) Add(v T) bool {
4549
prevLen := len(s)
4650
s[v] = struct{}{}
@@ -74,7 +78,7 @@ func (s threadUnsafeSet[T]) Clear() {
7478
}
7579

7680
func (s threadUnsafeSet[T]) Clone() Set[T] {
77-
clonedSet := make(threadUnsafeSet[T], s.Cardinality())
81+
clonedSet := newThreadUnsafeSetWithSize[T](s.Cardinality())
7882
for elem := range s {
7983
clonedSet.add(elem)
8084
}
@@ -220,6 +224,12 @@ func (s threadUnsafeSet[T]) Remove(v T) {
220224
delete(s, v)
221225
}
222226

227+
func (s threadUnsafeSet[T]) RemoveAll(i ...T) {
228+
for _, elem := range i {
229+
delete(s, elem)
230+
}
231+
}
232+
223233
func (s threadUnsafeSet[T]) String() string {
224234
items := make([]string, 0, len(s))
225235

0 commit comments

Comments
 (0)
Please sign in to comment.